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,33 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/subdev/i2c/base.o
nvkm-y += nvkm/subdev/i2c/nv04.o
nvkm-y += nvkm/subdev/i2c/nv4e.o
nvkm-y += nvkm/subdev/i2c/nv50.o
nvkm-y += nvkm/subdev/i2c/g94.o
nvkm-y += nvkm/subdev/i2c/gf117.o
nvkm-y += nvkm/subdev/i2c/gf119.o
nvkm-y += nvkm/subdev/i2c/gk104.o
nvkm-y += nvkm/subdev/i2c/gk110.o
nvkm-y += nvkm/subdev/i2c/gm200.o
nvkm-y += nvkm/subdev/i2c/pad.o
nvkm-y += nvkm/subdev/i2c/padnv04.o
nvkm-y += nvkm/subdev/i2c/padnv4e.o
nvkm-y += nvkm/subdev/i2c/padnv50.o
nvkm-y += nvkm/subdev/i2c/padg94.o
nvkm-y += nvkm/subdev/i2c/padgf119.o
nvkm-y += nvkm/subdev/i2c/padgm200.o
nvkm-y += nvkm/subdev/i2c/bus.o
nvkm-y += nvkm/subdev/i2c/busnv04.o
nvkm-y += nvkm/subdev/i2c/busnv4e.o
nvkm-y += nvkm/subdev/i2c/busnv50.o
nvkm-y += nvkm/subdev/i2c/busgf119.o
nvkm-y += nvkm/subdev/i2c/bit.o
nvkm-y += nvkm/subdev/i2c/auxch.o
nvkm-y += nvkm/subdev/i2c/auxg94.o
nvkm-y += nvkm/subdev/i2c/auxgf119.o
nvkm-y += nvkm/subdev/i2c/auxgm200.o
nvkm-y += nvkm/subdev/i2c/anx9805.o
@@ -0,0 +1,278 @@
/*
* Copyright 2013 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 <bskeggs@redhat.com>
*/
#define anx9805_pad(p) container_of((p), struct anx9805_pad, base)
#define anx9805_bus(p) container_of((p), struct anx9805_bus, base)
#define anx9805_aux(p) container_of((p), struct anx9805_aux, base)
#include "auxch.h"
#include "bus.h"
struct anx9805_pad {
struct nvkm_i2c_pad base;
struct nvkm_i2c_bus *bus;
u8 addr;
};
struct anx9805_bus {
struct nvkm_i2c_bus base;
struct anx9805_pad *pad;
u8 addr;
};
static int
anx9805_bus_xfer(struct nvkm_i2c_bus *base, struct i2c_msg *msgs, int num)
{
struct anx9805_bus *bus = anx9805_bus(base);
struct anx9805_pad *pad = bus->pad;
struct i2c_adapter *adap = &pad->bus->i2c;
struct i2c_msg *msg = msgs;
int ret = -ETIMEDOUT;
int i, j, cnt = num;
u8 seg = 0x00, off = 0x00, tmp;
tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x10;
nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x10);
nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
nvkm_wri2cr(adap, bus->addr, 0x43, 0x05);
mdelay(5);
while (cnt--) {
if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
nvkm_wri2cr(adap, bus->addr, 0x40, msg->addr << 1);
nvkm_wri2cr(adap, bus->addr, 0x41, seg);
nvkm_wri2cr(adap, bus->addr, 0x42, off);
nvkm_wri2cr(adap, bus->addr, 0x44, msg->len);
nvkm_wri2cr(adap, bus->addr, 0x45, 0x00);
nvkm_wri2cr(adap, bus->addr, 0x43, 0x01);
for (i = 0; i < msg->len; i++) {
j = 0;
while (nvkm_rdi2cr(adap, bus->addr, 0x46) & 0x10) {
mdelay(5);
if (j++ == 32)
goto done;
}
msg->buf[i] = nvkm_rdi2cr(adap, bus->addr, 0x47);
}
} else
if (!(msg->flags & I2C_M_RD)) {
if (msg->addr == 0x50 && msg->len == 0x01) {
off = msg->buf[0];
} else
if (msg->addr == 0x30 && msg->len == 0x01) {
seg = msg->buf[0];
} else
goto done;
} else {
goto done;
}
msg++;
}
ret = num;
done:
nvkm_wri2cr(adap, bus->addr, 0x43, 0x00);
return ret;
}
static const struct nvkm_i2c_bus_func
anx9805_bus_func = {
.xfer = anx9805_bus_xfer,
};
static int
anx9805_bus_new(struct nvkm_i2c_pad *base, int id, u8 drive,
struct nvkm_i2c_bus **pbus)
{
struct anx9805_pad *pad = anx9805_pad(base);
struct anx9805_bus *bus;
int ret;
if (!(bus = kzalloc_obj(*bus)))
return -ENOMEM;
*pbus = &bus->base;
bus->pad = pad;
ret = nvkm_i2c_bus_ctor(&anx9805_bus_func, &pad->base, id, &bus->base);
if (ret)
return ret;
switch (pad->addr) {
case 0x39: bus->addr = 0x3d; break;
case 0x3b: bus->addr = 0x3f; break;
default:
return -ENOSYS;
}
return 0;
}
struct anx9805_aux {
struct nvkm_i2c_aux base;
struct anx9805_pad *pad;
u8 addr;
};
static int
anx9805_aux_xfer(struct nvkm_i2c_aux *base, bool retry,
u8 type, u32 addr, u8 *data, u8 *size)
{
struct anx9805_aux *aux = anx9805_aux(base);
struct anx9805_pad *pad = aux->pad;
struct i2c_adapter *adap = &pad->bus->i2c;
int i, ret = -ETIMEDOUT;
u8 buf[16] = {};
u8 tmp;
AUX_DBG(&aux->base, "%02x %05x %d", type, addr, *size);
tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x04;
nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x04);
nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
nvkm_wri2cr(adap, aux->addr, 0xe4, 0x80);
if (!(type & 1)) {
memcpy(buf, data, *size);
AUX_DBG(&aux->base, "%16ph", buf);
for (i = 0; i < *size; i++)
nvkm_wri2cr(adap, aux->addr, 0xf0 + i, buf[i]);
}
nvkm_wri2cr(adap, aux->addr, 0xe5, ((*size - 1) << 4) | type);
nvkm_wri2cr(adap, aux->addr, 0xe6, (addr & 0x000ff) >> 0);
nvkm_wri2cr(adap, aux->addr, 0xe7, (addr & 0x0ff00) >> 8);
nvkm_wri2cr(adap, aux->addr, 0xe8, (addr & 0xf0000) >> 16);
nvkm_wri2cr(adap, aux->addr, 0xe9, 0x01);
i = 0;
while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xe9)) & 0x01) {
mdelay(5);
if (i++ == 32)
goto done;
}
if ((tmp = nvkm_rdi2cr(adap, pad->addr, 0xf7)) & 0x01) {
ret = -EIO;
goto done;
}
if (type & 1) {
for (i = 0; i < *size; i++)
buf[i] = nvkm_rdi2cr(adap, aux->addr, 0xf0 + i);
AUX_DBG(&aux->base, "%16ph", buf);
memcpy(data, buf, *size);
}
ret = 0;
done:
nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
return ret;
}
static int
anx9805_aux_lnk_ctl(struct nvkm_i2c_aux *base,
int link_nr, int link_bw, bool enh)
{
struct anx9805_aux *aux = anx9805_aux(base);
struct anx9805_pad *pad = aux->pad;
struct i2c_adapter *adap = &pad->bus->i2c;
u8 tmp, i;
AUX_DBG(&aux->base, "ANX9805 train %d %02x %d",
link_nr, link_bw, enh);
nvkm_wri2cr(adap, aux->addr, 0xa0, link_bw);
nvkm_wri2cr(adap, aux->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
nvkm_wri2cr(adap, aux->addr, 0xa2, 0x01);
nvkm_wri2cr(adap, aux->addr, 0xa8, 0x01);
i = 0;
while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xa8)) & 0x01) {
mdelay(5);
if (i++ == 100) {
AUX_ERR(&aux->base, "link training timeout");
return -ETIMEDOUT;
}
}
if (tmp & 0x70) {
AUX_ERR(&aux->base, "link training failed");
return -EIO;
}
return 0;
}
static const struct nvkm_i2c_aux_func
anx9805_aux_func = {
.xfer = anx9805_aux_xfer,
.lnk_ctl = anx9805_aux_lnk_ctl,
};
static int
anx9805_aux_new(struct nvkm_i2c_pad *base, int id, u8 drive,
struct nvkm_i2c_aux **pbus)
{
struct anx9805_pad *pad = anx9805_pad(base);
struct anx9805_aux *aux;
int ret;
if (!(aux = kzalloc_obj(*aux)))
return -ENOMEM;
*pbus = &aux->base;
aux->pad = pad;
ret = nvkm_i2c_aux_ctor(&anx9805_aux_func, &pad->base, id, &aux->base);
if (ret)
return ret;
switch (pad->addr) {
case 0x39: aux->addr = 0x38; break;
case 0x3b: aux->addr = 0x3c; break;
default:
return -ENOSYS;
}
return 0;
}
static const struct nvkm_i2c_pad_func
anx9805_pad_func = {
.bus_new_4 = anx9805_bus_new,
.aux_new_6 = anx9805_aux_new,
};
int
anx9805_pad_new(struct nvkm_i2c_bus *bus, int id, u8 addr,
struct nvkm_i2c_pad **ppad)
{
struct anx9805_pad *pad;
if (!(pad = kzalloc_obj(*pad)))
return -ENOMEM;
*ppad = &pad->base;
nvkm_i2c_pad_ctor(&anx9805_pad_func, bus->pad->i2c, id, &pad->base);
pad->bus = bus;
pad->addr = addr;
return 0;
}
@@ -0,0 +1,215 @@
/*
* Copyright 2009 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 <linux/string_helpers.h>
#include "auxch.h"
#include "pad.h"
static int
nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c);
struct i2c_msg *msg = msgs;
int ret, mcnt = num;
ret = nvkm_i2c_aux_acquire(aux);
if (ret)
return ret;
while (mcnt--) {
u8 remaining = msg->len;
u8 *ptr = msg->buf;
while (remaining) {
u8 cnt, retries, cmd;
if (msg->flags & I2C_M_RD)
cmd = 1;
else
cmd = 0;
if (mcnt || remaining > 16)
cmd |= 4; /* MOT */
for (retries = 0, cnt = 0;
retries < 32 && !cnt;
retries++) {
cnt = min_t(u8, remaining, 16);
ret = aux->func->xfer(aux, true, cmd,
msg->addr, ptr, &cnt);
if (ret < 0)
goto out;
}
if (!cnt) {
AUX_TRACE(aux, "no data after 32 retries");
ret = -EIO;
goto out;
}
ptr += cnt;
remaining -= cnt;
}
msg++;
}
ret = num;
out:
nvkm_i2c_aux_release(aux);
return ret;
}
static u32
nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm
nvkm_i2c_aux_i2c_algo = {
.master_xfer = nvkm_i2c_aux_i2c_xfer,
.functionality = nvkm_i2c_aux_i2c_func
};
void
nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor)
{
struct nvkm_i2c_pad *pad = aux->pad;
AUX_TRACE(aux, "monitor: %s", str_yes_no(monitor));
if (monitor)
nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX);
else
nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF);
}
void
nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux)
{
struct nvkm_i2c_pad *pad = aux->pad;
AUX_TRACE(aux, "release");
nvkm_i2c_pad_release(pad);
mutex_unlock(&aux->mutex);
}
int
nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux)
{
struct nvkm_i2c_pad *pad = aux->pad;
int ret;
AUX_TRACE(aux, "acquire");
mutex_lock(&aux->mutex);
if (aux->enabled)
ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX);
else
ret = -EIO;
if (ret)
mutex_unlock(&aux->mutex);
return ret;
}
int
nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type,
u32 addr, u8 *data, u8 *size)
{
if (!*size && !aux->func->address_only) {
AUX_ERR(aux, "address-only transaction dropped");
return -ENOSYS;
}
return aux->func->xfer(aux, retry, type, addr, data, size);
}
int
nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef)
{
if (aux->func->lnk_ctl)
return aux->func->lnk_ctl(aux, nr, bw, ef);
return -ENODEV;
}
void
nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux)
{
struct nvkm_i2c_aux *aux = *paux;
if (aux && !WARN_ON(!aux->func)) {
AUX_TRACE(aux, "dtor");
list_del(&aux->head);
i2c_del_adapter(&aux->i2c);
kfree(*paux);
*paux = NULL;
}
}
void
nvkm_i2c_aux_init(struct nvkm_i2c_aux *aux)
{
AUX_TRACE(aux, "init");
mutex_lock(&aux->mutex);
aux->enabled = true;
mutex_unlock(&aux->mutex);
}
void
nvkm_i2c_aux_fini(struct nvkm_i2c_aux *aux)
{
AUX_TRACE(aux, "fini");
mutex_lock(&aux->mutex);
aux->enabled = false;
mutex_unlock(&aux->mutex);
}
int
nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func,
struct nvkm_i2c_pad *pad, int id,
struct nvkm_i2c_aux *aux)
{
struct nvkm_device *device = pad->i2c->subdev.device;
aux->func = func;
aux->pad = pad;
aux->id = id;
mutex_init(&aux->mutex);
list_add_tail(&aux->head, &pad->i2c->aux);
AUX_TRACE(aux, "ctor");
snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x",
dev_name(device->dev), id);
aux->i2c.owner = THIS_MODULE;
aux->i2c.dev.parent = device->dev;
aux->i2c.algo = &nvkm_i2c_aux_i2c_algo;
return i2c_add_adapter(&aux->i2c);
}
int
nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func,
struct nvkm_i2c_pad *pad, int id,
struct nvkm_i2c_aux **paux)
{
if (!(*paux = kzalloc_obj(**paux)))
return -ENOMEM;
return nvkm_i2c_aux_ctor(func, pad, id, *paux);
}
@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_I2C_AUX_H__
#define __NVKM_I2C_AUX_H__
#include "pad.h"
static inline void
nvkm_i2c_aux_autodpcd(struct nvkm_i2c *i2c, int aux, bool enable)
{
if (i2c->func->aux_autodpcd)
i2c->func->aux_autodpcd(i2c, aux, false);
}
struct nvkm_i2c_aux_func {
bool address_only;
int (*xfer)(struct nvkm_i2c_aux *, bool retry, u8 type,
u32 addr, u8 *data, u8 *size);
int (*lnk_ctl)(struct nvkm_i2c_aux *, int link_nr, int link_bw,
bool enhanced_framing);
};
int nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
int id, struct nvkm_i2c_aux *);
int nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
int id, struct nvkm_i2c_aux **);
void nvkm_i2c_aux_del(struct nvkm_i2c_aux **);
void nvkm_i2c_aux_init(struct nvkm_i2c_aux *);
void nvkm_i2c_aux_fini(struct nvkm_i2c_aux *);
int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type,
u32 addr, u8 *data, u8 *size);
int g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
int, u8, struct nvkm_i2c_aux **);
int g94_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
int g94_i2c_aux_xfer(struct nvkm_i2c_aux *, bool, u8, u32, u8 *, u8 *);
int gf119_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
int gm200_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
#define AUX_MSG(b,l,f,a...) do { \
struct nvkm_i2c_aux *_aux = (b); \
nvkm_##l(&_aux->pad->i2c->subdev, "aux %04x: "f"\n", _aux->id, ##a); \
} while(0)
#define AUX_ERR(b,f,a...) AUX_MSG((b), error, f, ##a)
#define AUX_DBG(b,f,a...) AUX_MSG((b), debug, f, ##a)
#define AUX_TRACE(b,f,a...) AUX_MSG((b), trace, f, ##a)
#endif
@@ -0,0 +1,194 @@
/*
* Copyright 2015 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 busions 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 <bskeggs@redhat.com>
*/
#define g94_i2c_aux(p) container_of((p), struct g94_i2c_aux, base)
#include "auxch.h"
struct g94_i2c_aux {
struct nvkm_i2c_aux base;
int ch;
};
static void
g94_i2c_aux_fini(struct g94_i2c_aux *aux)
{
struct nvkm_device *device = aux->base.pad->i2c->subdev.device;
nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00310000, 0x00000000);
}
static int
g94_i2c_aux_init(struct g94_i2c_aux *aux)
{
struct nvkm_device *device = aux->base.pad->i2c->subdev.device;
const u32 unksel = 1; /* nfi which to use, or if it matters.. */
const u32 ureq = unksel ? 0x00100000 : 0x00200000;
const u32 urep = unksel ? 0x01000000 : 0x02000000;
u32 ctrl, timeout;
/* wait up to 1ms for any previous transaction to be done... */
timeout = 1000;
do {
ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50));
udelay(1);
if (!timeout--) {
AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl);
return -EBUSY;
}
} while (ctrl & 0x03010000);
/* set some magic, and wait up to 1ms for it to appear */
nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00300000, ureq);
timeout = 1000;
do {
ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50));
udelay(1);
if (!timeout--) {
AUX_ERR(&aux->base, "magic wait %08x", ctrl);
g94_i2c_aux_fini(aux);
return -EBUSY;
}
} while ((ctrl & 0x03000000) != urep);
return 0;
}
int
g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
u8 type, u32 addr, u8 *data, u8 *size)
{
struct g94_i2c_aux *aux = g94_i2c_aux(obj);
struct nvkm_i2c *i2c = aux->base.pad->i2c;
struct nvkm_device *device = i2c->subdev.device;
const u32 base = aux->ch * 0x50;
u32 ctrl, stat, timeout, retries = 0;
u32 xbuf[4] = {};
int ret, i;
AUX_TRACE(&aux->base, "%d: %08x %d", type, addr, *size);
ret = g94_i2c_aux_init(aux);
if (ret < 0)
goto out;
stat = nvkm_rd32(device, 0x00e4e8 + base);
if (!(stat & 0x10000000)) {
AUX_TRACE(&aux->base, "sink not detected");
ret = -ENXIO;
goto out;
}
nvkm_i2c_aux_autodpcd(i2c, aux->ch, false);
if (!(type & 1)) {
memcpy(xbuf, data, *size);
for (i = 0; i < 16; i += 4) {
AUX_TRACE(&aux->base, "wr %08x", xbuf[i / 4]);
nvkm_wr32(device, 0x00e4c0 + base + i, xbuf[i / 4]);
}
}
ctrl = nvkm_rd32(device, 0x00e4e4 + base);
ctrl &= ~0x0001f1ff;
ctrl |= type << 12;
ctrl |= (*size ? (*size - 1) : 0x00000100);
nvkm_wr32(device, 0x00e4e0 + base, addr);
/* (maybe) retry transaction a number of times on failure... */
do {
/* reset, and delay a while if this is a retry */
nvkm_wr32(device, 0x00e4e4 + base, 0x80000000 | ctrl);
nvkm_wr32(device, 0x00e4e4 + base, 0x00000000 | ctrl);
if (retries)
udelay(400);
/* transaction request, wait up to 2ms for it to complete */
nvkm_wr32(device, 0x00e4e4 + base, 0x00010000 | ctrl);
timeout = 2000;
do {
ctrl = nvkm_rd32(device, 0x00e4e4 + base);
udelay(1);
if (!timeout--) {
AUX_ERR(&aux->base, "timeout %08x", ctrl);
ret = -EIO;
goto out_err;
}
} while (ctrl & 0x00010000);
ret = 0;
/* read status, and check if transaction completed ok */
stat = nvkm_mask(device, 0x00e4e8 + base, 0, 0);
if ((stat & 0x000f0000) == 0x00080000 ||
(stat & 0x000f0000) == 0x00020000)
ret = 1;
if ((stat & 0x00000100))
ret = -ETIMEDOUT;
if ((stat & 0x00000e00))
ret = -EIO;
AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat);
} while (ret && retry && retries++ < 32);
if (type & 1) {
for (i = 0; i < 16; i += 4) {
xbuf[i / 4] = nvkm_rd32(device, 0x00e4d0 + base + i);
AUX_TRACE(&aux->base, "rd %08x", xbuf[i / 4]);
}
memcpy(data, xbuf, *size);
*size = stat & 0x0000001f;
}
out_err:
nvkm_i2c_aux_autodpcd(i2c, aux->ch, true);
out:
g94_i2c_aux_fini(aux);
return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
}
int
g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *func,
struct nvkm_i2c_pad *pad, int index, u8 drive,
struct nvkm_i2c_aux **paux)
{
struct g94_i2c_aux *aux;
if (!(aux = kzalloc_obj(*aux)))
return -ENOMEM;
*paux = &aux->base;
nvkm_i2c_aux_ctor(func, pad, index, &aux->base);
aux->ch = drive;
aux->base.intr = 1 << aux->ch;
return 0;
}
static const struct nvkm_i2c_aux_func
g94_i2c_aux = {
.xfer = g94_i2c_aux_xfer,
};
int
g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
struct nvkm_i2c_aux **paux)
{
return g94_i2c_aux_new_(&g94_i2c_aux, pad, index, drive, paux);
}
@@ -0,0 +1,35 @@
/*
* Copyright 2017 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 "auxch.h"
static const struct nvkm_i2c_aux_func
gf119_i2c_aux = {
.address_only = true,
.xfer = g94_i2c_aux_xfer,
};
int
gf119_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
struct nvkm_i2c_aux **paux)
{
return g94_i2c_aux_new_(&gf119_i2c_aux, pad, index, drive, paux);
}
@@ -0,0 +1,188 @@
/*
* Copyright 2015 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 busions 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 <bskeggs@redhat.com>
*/
#define gm200_i2c_aux(p) container_of((p), struct gm200_i2c_aux, base)
#include "auxch.h"
struct gm200_i2c_aux {
struct nvkm_i2c_aux base;
int ch;
};
static void
gm200_i2c_aux_fini(struct gm200_i2c_aux *aux)
{
struct nvkm_device *device = aux->base.pad->i2c->subdev.device;
nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00710000, 0x00000000);
}
static int
gm200_i2c_aux_init(struct gm200_i2c_aux *aux)
{
struct nvkm_device *device = aux->base.pad->i2c->subdev.device;
const u32 unksel = 1; /* nfi which to use, or if it matters.. */
const u32 ureq = unksel ? 0x00100000 : 0x00200000;
const u32 urep = unksel ? 0x01000000 : 0x02000000;
u32 ctrl, timeout;
/* wait up to 1ms for any previous transaction to be done... */
timeout = 1000;
do {
ctrl = nvkm_rd32(device, 0x00d954 + (aux->ch * 0x50));
udelay(1);
if (!timeout--) {
AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl);
return -EBUSY;
}
} while (ctrl & 0x07010000);
/* set some magic, and wait up to 1ms for it to appear */
nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00700000, ureq);
timeout = 1000;
do {
ctrl = nvkm_rd32(device, 0x00d954 + (aux->ch * 0x50));
udelay(1);
if (!timeout--) {
AUX_ERR(&aux->base, "magic wait %08x", ctrl);
gm200_i2c_aux_fini(aux);
return -EBUSY;
}
} while ((ctrl & 0x07000000) != urep);
return 0;
}
static int
gm200_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
u8 type, u32 addr, u8 *data, u8 *size)
{
struct gm200_i2c_aux *aux = gm200_i2c_aux(obj);
struct nvkm_i2c *i2c = aux->base.pad->i2c;
struct nvkm_device *device = i2c->subdev.device;
const u32 base = aux->ch * 0x50;
u32 ctrl, stat, timeout, retries = 0;
u32 xbuf[4] = {};
int ret, i;
AUX_TRACE(&aux->base, "%d: %08x %d", type, addr, *size);
ret = gm200_i2c_aux_init(aux);
if (ret < 0)
goto out;
stat = nvkm_rd32(device, 0x00d958 + base);
if (!(stat & 0x10000000)) {
AUX_TRACE(&aux->base, "sink not detected");
ret = -ENXIO;
goto out;
}
nvkm_i2c_aux_autodpcd(i2c, aux->ch, false);
if (!(type & 1)) {
memcpy(xbuf, data, *size);
for (i = 0; i < 16; i += 4) {
AUX_TRACE(&aux->base, "wr %08x", xbuf[i / 4]);
nvkm_wr32(device, 0x00d930 + base + i, xbuf[i / 4]);
}
}
ctrl = nvkm_rd32(device, 0x00d954 + base);
ctrl &= ~0x0001f1ff;
ctrl |= type << 12;
ctrl |= (*size ? (*size - 1) : 0x00000100);
nvkm_wr32(device, 0x00d950 + base, addr);
/* (maybe) retry transaction a number of times on failure... */
do {
/* reset, and delay a while if this is a retry */
nvkm_wr32(device, 0x00d954 + base, 0x80000000 | ctrl);
nvkm_wr32(device, 0x00d954 + base, 0x00000000 | ctrl);
if (retries)
udelay(400);
/* transaction request, wait up to 2ms for it to complete */
nvkm_wr32(device, 0x00d954 + base, 0x00010000 | ctrl);
timeout = 2000;
do {
ctrl = nvkm_rd32(device, 0x00d954 + base);
udelay(1);
if (!timeout--) {
AUX_ERR(&aux->base, "timeout %08x", ctrl);
ret = -EIO;
goto out_err;
}
} while (ctrl & 0x00010000);
ret = 0;
/* read status, and check if transaction completed ok */
stat = nvkm_mask(device, 0x00d958 + base, 0, 0);
if ((stat & 0x000f0000) == 0x00080000 ||
(stat & 0x000f0000) == 0x00020000)
ret = 1;
if ((stat & 0x00000100))
ret = -ETIMEDOUT;
if ((stat & 0x00000e00))
ret = -EIO;
AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat);
} while (ret && retry && retries++ < 32);
if (type & 1) {
for (i = 0; i < 16; i += 4) {
xbuf[i / 4] = nvkm_rd32(device, 0x00d940 + base + i);
AUX_TRACE(&aux->base, "rd %08x", xbuf[i / 4]);
}
memcpy(data, xbuf, *size);
*size = stat & 0x0000001f;
}
out_err:
nvkm_i2c_aux_autodpcd(i2c, aux->ch, true);
out:
gm200_i2c_aux_fini(aux);
return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
}
static const struct nvkm_i2c_aux_func
gm200_i2c_aux_func = {
.address_only = true,
.xfer = gm200_i2c_aux_xfer,
};
int
gm200_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
struct nvkm_i2c_aux **paux)
{
struct gm200_i2c_aux *aux;
if (!(aux = kzalloc_obj(*aux)))
return -ENOMEM;
*paux = &aux->base;
nvkm_i2c_aux_ctor(&gm200_i2c_aux_func, pad, index, &aux->base);
aux->ch = drive;
aux->base.intr = 1 << aux->ch;
return 0;
}
@@ -0,0 +1,417 @@
/*
* Copyright 2013 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 "auxch.h"
#include "bus.h"
#include "pad.h"
#include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/i2c.h>
static struct nvkm_i2c_pad *
nvkm_i2c_pad_find(struct nvkm_i2c *i2c, int id)
{
struct nvkm_i2c_pad *pad;
list_for_each_entry(pad, &i2c->pad, head) {
if (pad->id == id)
return pad;
}
return NULL;
}
struct nvkm_i2c_bus *
nvkm_i2c_bus_find(struct nvkm_i2c *i2c, int id)
{
struct nvkm_bios *bios = i2c->subdev.device->bios;
struct nvkm_i2c_bus *bus;
if (id == NVKM_I2C_BUS_PRI || id == NVKM_I2C_BUS_SEC) {
u8 ver, hdr, cnt, len;
u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
if (i2c && ver >= 0x30) {
u8 auxidx = nvbios_rd08(bios, i2c + 4);
if (id == NVKM_I2C_BUS_PRI)
id = NVKM_I2C_BUS_CCB((auxidx & 0x0f) >> 0);
else
id = NVKM_I2C_BUS_CCB((auxidx & 0xf0) >> 4);
} else {
id = NVKM_I2C_BUS_CCB(2);
}
}
list_for_each_entry(bus, &i2c->bus, head) {
if (bus->id == id)
return bus;
}
return NULL;
}
struct nvkm_i2c_aux *
nvkm_i2c_aux_find(struct nvkm_i2c *i2c, int id)
{
struct nvkm_i2c_aux *aux;
list_for_each_entry(aux, &i2c->aux, head) {
if (aux->id == id)
return aux;
}
return NULL;
}
static void
nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int id)
{
struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id);
if (aux)
i2c->func->aux_mask(i2c, type, aux->intr, 0);
}
static void
nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id)
{
struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id);
if (aux)
i2c->func->aux_mask(i2c, type, aux->intr, aux->intr);
}
static const struct nvkm_event_func
nvkm_i2c_intr_func = {
.init = nvkm_i2c_intr_init,
.fini = nvkm_i2c_intr_fini,
};
static void
nvkm_i2c_intr(struct nvkm_subdev *subdev)
{
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
struct nvkm_i2c_aux *aux;
u32 hi, lo, rq, tx;
if (!i2c->func->aux_stat)
return;
i2c->func->aux_stat(i2c, &hi, &lo, &rq, &tx);
if (!hi && !lo && !rq && !tx)
return;
list_for_each_entry(aux, &i2c->aux, head) {
u32 mask = 0;
if (hi & aux->intr) mask |= NVKM_I2C_PLUG;
if (lo & aux->intr) mask |= NVKM_I2C_UNPLUG;
if (rq & aux->intr) mask |= NVKM_I2C_IRQ;
if (tx & aux->intr) mask |= NVKM_I2C_DONE;
if (mask)
nvkm_event_ntfy(&i2c->event, aux->id, mask);
}
}
static int
nvkm_i2c_fini(struct nvkm_subdev *subdev, enum nvkm_suspend_state suspend)
{
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
struct nvkm_i2c_pad *pad;
struct nvkm_i2c_bus *bus;
struct nvkm_i2c_aux *aux;
u32 mask;
list_for_each_entry(aux, &i2c->aux, head) {
nvkm_i2c_aux_fini(aux);
}
list_for_each_entry(bus, &i2c->bus, head) {
nvkm_i2c_bus_fini(bus);
}
if ((mask = (1 << i2c->func->aux) - 1), i2c->func->aux_stat) {
i2c->func->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
i2c->func->aux_stat(i2c, &mask, &mask, &mask, &mask);
}
list_for_each_entry(pad, &i2c->pad, head) {
nvkm_i2c_pad_fini(pad);
}
return 0;
}
static int
nvkm_i2c_preinit(struct nvkm_subdev *subdev)
{
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
struct nvkm_i2c_bus *bus;
struct nvkm_i2c_pad *pad;
/*
* We init our i2c busses as early as possible, since they may be
* needed by the vbios init scripts on some cards
*/
list_for_each_entry(pad, &i2c->pad, head)
nvkm_i2c_pad_init(pad);
list_for_each_entry(bus, &i2c->bus, head)
nvkm_i2c_bus_init(bus);
return 0;
}
static int
nvkm_i2c_init(struct nvkm_subdev *subdev)
{
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
struct nvkm_i2c_bus *bus;
struct nvkm_i2c_pad *pad;
struct nvkm_i2c_aux *aux;
list_for_each_entry(pad, &i2c->pad, head) {
nvkm_i2c_pad_init(pad);
}
list_for_each_entry(bus, &i2c->bus, head) {
nvkm_i2c_bus_init(bus);
}
list_for_each_entry(aux, &i2c->aux, head) {
nvkm_i2c_aux_init(aux);
}
return 0;
}
static void *
nvkm_i2c_dtor(struct nvkm_subdev *subdev)
{
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
nvkm_event_fini(&i2c->event);
while (!list_empty(&i2c->aux)) {
struct nvkm_i2c_aux *aux =
list_first_entry(&i2c->aux, typeof(*aux), head);
nvkm_i2c_aux_del(&aux);
}
while (!list_empty(&i2c->bus)) {
struct nvkm_i2c_bus *bus =
list_first_entry(&i2c->bus, typeof(*bus), head);
nvkm_i2c_bus_del(&bus);
}
while (!list_empty(&i2c->pad)) {
struct nvkm_i2c_pad *pad =
list_first_entry(&i2c->pad, typeof(*pad), head);
nvkm_i2c_pad_del(&pad);
}
return i2c;
}
static const struct nvkm_subdev_func
nvkm_i2c = {
.dtor = nvkm_i2c_dtor,
.preinit = nvkm_i2c_preinit,
.init = nvkm_i2c_init,
.fini = nvkm_i2c_fini,
.intr = nvkm_i2c_intr,
};
static const struct nvkm_i2c_drv {
u8 bios;
u8 addr;
int (*pad_new)(struct nvkm_i2c_bus *, int id, u8 addr,
struct nvkm_i2c_pad **);
}
nvkm_i2c_drv[] = {
{ 0x0d, 0x39, anx9805_pad_new },
{ 0x0e, 0x3b, anx9805_pad_new },
{}
};
int
nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_i2c **pi2c)
{
struct nvkm_bios *bios = device->bios;
struct nvkm_i2c *i2c;
struct nvkm_i2c_aux *aux;
struct dcb_i2c_entry ccbE;
struct dcb_output dcbE;
u8 ver, hdr;
int ret, i, ids;
if (!(i2c = *pi2c = kzalloc_obj(*i2c)))
return -ENOMEM;
nvkm_subdev_ctor(&nvkm_i2c, device, type, inst, &i2c->subdev);
i2c->func = func;
INIT_LIST_HEAD(&i2c->pad);
INIT_LIST_HEAD(&i2c->bus);
INIT_LIST_HEAD(&i2c->aux);
i = -1;
while (!dcb_i2c_parse(bios, ++i, &ccbE)) {
struct nvkm_i2c_pad *pad = NULL;
struct nvkm_i2c_bus *bus = NULL;
struct nvkm_i2c_aux *aux = NULL;
nvkm_debug(&i2c->subdev, "ccb %02x: type %02x drive %02x "
"sense %02x share %02x auxch %02x\n", i, ccbE.type,
ccbE.drive, ccbE.sense, ccbE.share, ccbE.auxch);
if (ccbE.share != DCB_I2C_UNUSED) {
const int id = NVKM_I2C_PAD_HYBRID(ccbE.share);
if (!(pad = nvkm_i2c_pad_find(i2c, id)))
ret = func->pad_s_new(i2c, id, &pad);
else
ret = 0;
} else {
ret = func->pad_x_new(i2c, NVKM_I2C_PAD_CCB(i), &pad);
}
if (ret) {
nvkm_error(&i2c->subdev, "ccb %02x pad, %d\n", i, ret);
nvkm_i2c_pad_del(&pad);
continue;
}
if (pad->func->bus_new_0 && ccbE.type == DCB_I2C_NV04_BIT) {
ret = pad->func->bus_new_0(pad, NVKM_I2C_BUS_CCB(i),
ccbE.drive,
ccbE.sense, &bus);
} else
if (pad->func->bus_new_4 &&
( ccbE.type == DCB_I2C_NV4E_BIT ||
ccbE.type == DCB_I2C_NVIO_BIT ||
(ccbE.type == DCB_I2C_PMGR &&
ccbE.drive != DCB_I2C_UNUSED))) {
ret = pad->func->bus_new_4(pad, NVKM_I2C_BUS_CCB(i),
ccbE.drive, &bus);
}
if (ret) {
nvkm_error(&i2c->subdev, "ccb %02x bus, %d\n", i, ret);
nvkm_i2c_bus_del(&bus);
}
if (pad->func->aux_new_6 &&
( ccbE.type == DCB_I2C_NVIO_AUX ||
(ccbE.type == DCB_I2C_PMGR &&
ccbE.auxch != DCB_I2C_UNUSED))) {
ret = pad->func->aux_new_6(pad, NVKM_I2C_BUS_CCB(i),
ccbE.auxch, &aux);
} else {
ret = 0;
}
if (ret) {
nvkm_error(&i2c->subdev, "ccb %02x aux, %d\n", i, ret);
nvkm_i2c_aux_del(&aux);
}
if (ccbE.type != DCB_I2C_UNUSED && !bus && !aux) {
nvkm_warn(&i2c->subdev, "ccb %02x was ignored\n", i);
continue;
}
}
i = -1;
while (dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE)) {
const struct nvkm_i2c_drv *drv = nvkm_i2c_drv;
struct nvkm_i2c_bus *bus;
struct nvkm_i2c_pad *pad;
/* internal outputs handled by native i2c busses (above) */
if (!dcbE.location)
continue;
/* we need an i2c bus to talk to the external encoder */
bus = nvkm_i2c_bus_find(i2c, dcbE.i2c_index);
if (!bus) {
nvkm_debug(&i2c->subdev, "dcb %02x no bus\n", i);
continue;
}
/* ... and a driver for it */
while (drv->pad_new) {
if (drv->bios == dcbE.extdev)
break;
drv++;
}
if (!drv->pad_new) {
nvkm_debug(&i2c->subdev, "dcb %02x drv %02x unknown\n",
i, dcbE.extdev);
continue;
}
/* find/create an instance of the driver */
pad = nvkm_i2c_pad_find(i2c, NVKM_I2C_PAD_EXT(dcbE.extdev));
if (!pad) {
const int id = NVKM_I2C_PAD_EXT(dcbE.extdev);
ret = drv->pad_new(bus, id, drv->addr, &pad);
if (ret) {
nvkm_error(&i2c->subdev, "dcb %02x pad, %d\n",
i, ret);
nvkm_i2c_pad_del(&pad);
continue;
}
}
/* create any i2c bus / aux channel required by the output */
if (pad->func->aux_new_6 && dcbE.type == DCB_OUTPUT_DP) {
const int id = NVKM_I2C_AUX_EXT(dcbE.extdev);
struct nvkm_i2c_aux *aux = NULL;
ret = pad->func->aux_new_6(pad, id, 0, &aux);
if (ret) {
nvkm_error(&i2c->subdev, "dcb %02x aux, %d\n",
i, ret);
nvkm_i2c_aux_del(&aux);
}
} else
if (pad->func->bus_new_4) {
const int id = NVKM_I2C_BUS_EXT(dcbE.extdev);
struct nvkm_i2c_bus *bus = NULL;
ret = pad->func->bus_new_4(pad, id, 0, &bus);
if (ret) {
nvkm_error(&i2c->subdev, "dcb %02x bus, %d\n",
i, ret);
nvkm_i2c_bus_del(&bus);
}
}
}
ids = 0;
list_for_each_entry(aux, &i2c->aux, head)
ids = max(ids, aux->id + 1);
if (!ids)
return 0;
return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, ids, &i2c->event);
}
@@ -0,0 +1,216 @@
/*
* 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 busions 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 "bus.h"
#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
#define T_TIMEOUT 2200000
#define T_RISEFALL 1000
#define T_HOLD 5000
static inline void
nvkm_i2c_drive_scl(struct nvkm_i2c_bus *bus, int state)
{
bus->func->drive_scl(bus, state);
}
static inline void
nvkm_i2c_drive_sda(struct nvkm_i2c_bus *bus, int state)
{
bus->func->drive_sda(bus, state);
}
static inline int
nvkm_i2c_sense_scl(struct nvkm_i2c_bus *bus)
{
return bus->func->sense_scl(bus);
}
static inline int
nvkm_i2c_sense_sda(struct nvkm_i2c_bus *bus)
{
return bus->func->sense_sda(bus);
}
static void
nvkm_i2c_delay(struct nvkm_i2c_bus *bus, u32 nsec)
{
udelay((nsec + 500) / 1000);
}
static bool
nvkm_i2c_raise_scl(struct nvkm_i2c_bus *bus)
{
u32 timeout = T_TIMEOUT / T_RISEFALL;
nvkm_i2c_drive_scl(bus, 1);
do {
nvkm_i2c_delay(bus, T_RISEFALL);
} while (!nvkm_i2c_sense_scl(bus) && --timeout);
return timeout != 0;
}
static int
i2c_start(struct nvkm_i2c_bus *bus)
{
int ret = 0;
if (!nvkm_i2c_sense_scl(bus) ||
!nvkm_i2c_sense_sda(bus)) {
nvkm_i2c_drive_scl(bus, 0);
nvkm_i2c_drive_sda(bus, 1);
if (!nvkm_i2c_raise_scl(bus))
ret = -EBUSY;
}
nvkm_i2c_drive_sda(bus, 0);
nvkm_i2c_delay(bus, T_HOLD);
nvkm_i2c_drive_scl(bus, 0);
nvkm_i2c_delay(bus, T_HOLD);
return ret;
}
static void
i2c_stop(struct nvkm_i2c_bus *bus)
{
nvkm_i2c_drive_scl(bus, 0);
nvkm_i2c_drive_sda(bus, 0);
nvkm_i2c_delay(bus, T_RISEFALL);
nvkm_i2c_drive_scl(bus, 1);
nvkm_i2c_delay(bus, T_HOLD);
nvkm_i2c_drive_sda(bus, 1);
nvkm_i2c_delay(bus, T_HOLD);
}
static int
i2c_bitw(struct nvkm_i2c_bus *bus, int sda)
{
nvkm_i2c_drive_sda(bus, sda);
nvkm_i2c_delay(bus, T_RISEFALL);
if (!nvkm_i2c_raise_scl(bus))
return -ETIMEDOUT;
nvkm_i2c_delay(bus, T_HOLD);
nvkm_i2c_drive_scl(bus, 0);
nvkm_i2c_delay(bus, T_HOLD);
return 0;
}
static int
i2c_bitr(struct nvkm_i2c_bus *bus)
{
int sda;
nvkm_i2c_drive_sda(bus, 1);
nvkm_i2c_delay(bus, T_RISEFALL);
if (!nvkm_i2c_raise_scl(bus))
return -ETIMEDOUT;
nvkm_i2c_delay(bus, T_HOLD);
sda = nvkm_i2c_sense_sda(bus);
nvkm_i2c_drive_scl(bus, 0);
nvkm_i2c_delay(bus, T_HOLD);
return sda;
}
static int
nvkm_i2c_get_byte(struct nvkm_i2c_bus *bus, u8 *byte, bool last)
{
int i, bit;
*byte = 0;
for (i = 7; i >= 0; i--) {
bit = i2c_bitr(bus);
if (bit < 0)
return bit;
*byte |= bit << i;
}
return i2c_bitw(bus, last ? 1 : 0);
}
static int
nvkm_i2c_put_byte(struct nvkm_i2c_bus *bus, u8 byte)
{
int i, ret;
for (i = 7; i >= 0; i--) {
ret = i2c_bitw(bus, !!(byte & (1 << i)));
if (ret < 0)
return ret;
}
ret = i2c_bitr(bus);
if (ret == 1) /* nack */
ret = -EIO;
return ret;
}
static int
i2c_addr(struct nvkm_i2c_bus *bus, struct i2c_msg *msg)
{
u32 addr = msg->addr << 1;
if (msg->flags & I2C_M_RD)
addr |= 1;
return nvkm_i2c_put_byte(bus, addr);
}
int
nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *bus, struct i2c_msg *msgs, int num)
{
struct i2c_msg *msg = msgs;
int ret = 0, mcnt = num;
while (!ret && mcnt--) {
u8 remaining = msg->len;
u8 *ptr = msg->buf;
ret = i2c_start(bus);
if (ret == 0)
ret = i2c_addr(bus, msg);
if (msg->flags & I2C_M_RD) {
while (!ret && remaining--)
ret = nvkm_i2c_get_byte(bus, ptr++, !remaining);
} else {
while (!ret && remaining--)
ret = nvkm_i2c_put_byte(bus, *ptr++);
}
msg++;
}
i2c_stop(bus);
return (ret < 0) ? ret : num;
}
#else
int
nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *bus, struct i2c_msg *msgs, int num)
{
return -ENODEV;
}
#endif
@@ -0,0 +1,264 @@
/*
* Copyright 2015 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 <bskeggs@redhat.com>
*/
#include "bus.h"
#include "pad.h"
#include <core/option.h>
/*******************************************************************************
* i2c-algo-bit
******************************************************************************/
static int
nvkm_i2c_bus_pre_xfer(struct i2c_adapter *adap)
{
struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c);
return nvkm_i2c_bus_acquire(bus);
}
static void
nvkm_i2c_bus_post_xfer(struct i2c_adapter *adap)
{
struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c);
return nvkm_i2c_bus_release(bus);
}
static void
nvkm_i2c_bus_setscl(void *data, int state)
{
struct nvkm_i2c_bus *bus = data;
bus->func->drive_scl(bus, state);
}
static void
nvkm_i2c_bus_setsda(void *data, int state)
{
struct nvkm_i2c_bus *bus = data;
bus->func->drive_sda(bus, state);
}
static int
nvkm_i2c_bus_getscl(void *data)
{
struct nvkm_i2c_bus *bus = data;
return bus->func->sense_scl(bus);
}
static int
nvkm_i2c_bus_getsda(void *data)
{
struct nvkm_i2c_bus *bus = data;
return bus->func->sense_sda(bus);
}
/*******************************************************************************
* !i2c-algo-bit (off-chip i2c bus / hw i2c / internal bit-banging algo)
******************************************************************************/
static int
nvkm_i2c_bus_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c);
int ret;
ret = nvkm_i2c_bus_acquire(bus);
if (ret)
return ret;
ret = bus->func->xfer(bus, msgs, num);
nvkm_i2c_bus_release(bus);
return ret;
}
static u32
nvkm_i2c_bus_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm
nvkm_i2c_bus_algo = {
.master_xfer = nvkm_i2c_bus_xfer,
.functionality = nvkm_i2c_bus_func,
};
/*******************************************************************************
* nvkm_i2c_bus base
******************************************************************************/
void
nvkm_i2c_bus_init(struct nvkm_i2c_bus *bus)
{
BUS_TRACE(bus, "init");
if (bus->func->init)
bus->func->init(bus);
mutex_lock(&bus->mutex);
bus->enabled = true;
mutex_unlock(&bus->mutex);
}
void
nvkm_i2c_bus_fini(struct nvkm_i2c_bus *bus)
{
BUS_TRACE(bus, "fini");
mutex_lock(&bus->mutex);
bus->enabled = false;
mutex_unlock(&bus->mutex);
}
void
nvkm_i2c_bus_release(struct nvkm_i2c_bus *bus)
{
struct nvkm_i2c_pad *pad = bus->pad;
BUS_TRACE(bus, "release");
nvkm_i2c_pad_release(pad);
mutex_unlock(&bus->mutex);
}
int
nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *bus)
{
struct nvkm_i2c_pad *pad = bus->pad;
int ret;
BUS_TRACE(bus, "acquire");
mutex_lock(&bus->mutex);
if (bus->enabled)
ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C);
else
ret = -EIO;
if (ret)
mutex_unlock(&bus->mutex);
return ret;
}
int
nvkm_i2c_bus_probe(struct nvkm_i2c_bus *bus, const char *what,
struct nvkm_i2c_bus_probe *info,
bool (*match)(struct nvkm_i2c_bus *,
struct i2c_board_info *, void *), void *data)
{
int i;
BUS_DBG(bus, "probing %ss", what);
for (i = 0; info[i].dev.addr; i++) {
u8 orig_udelay = 0;
if ((bus->i2c.algo == &i2c_bit_algo) && (info[i].udelay != 0)) {
struct i2c_algo_bit_data *algo = bus->i2c.algo_data;
BUS_DBG(bus, "%dms delay instead of %dms",
info[i].udelay, algo->udelay);
orig_udelay = algo->udelay;
algo->udelay = info[i].udelay;
}
if (nvkm_probe_i2c(&bus->i2c, info[i].dev.addr) &&
(!match || match(bus, &info[i].dev, data))) {
BUS_DBG(bus, "detected %s: %s",
what, info[i].dev.type);
return i;
}
if (orig_udelay) {
struct i2c_algo_bit_data *algo = bus->i2c.algo_data;
algo->udelay = orig_udelay;
}
}
BUS_DBG(bus, "no devices found.");
return -ENODEV;
}
void
nvkm_i2c_bus_del(struct nvkm_i2c_bus **pbus)
{
struct nvkm_i2c_bus *bus = *pbus;
if (bus && !WARN_ON(!bus->func)) {
BUS_TRACE(bus, "dtor");
list_del(&bus->head);
i2c_del_adapter(&bus->i2c);
kfree(bus->i2c.algo_data);
kfree(*pbus);
*pbus = NULL;
}
}
int
nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *func,
struct nvkm_i2c_pad *pad, int id,
struct nvkm_i2c_bus *bus)
{
struct nvkm_device *device = pad->i2c->subdev.device;
struct i2c_algo_bit_data *bit;
#ifndef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
const bool internal = false;
#else
const bool internal = true;
#endif
int ret;
bus->func = func;
bus->pad = pad;
bus->id = id;
mutex_init(&bus->mutex);
list_add_tail(&bus->head, &pad->i2c->bus);
BUS_TRACE(bus, "ctor");
snprintf(bus->i2c.name, sizeof(bus->i2c.name), "nvkm-%s-bus-%04x",
dev_name(device->dev), id);
bus->i2c.owner = THIS_MODULE;
bus->i2c.dev.parent = device->dev;
if ( bus->func->drive_scl &&
!nvkm_boolopt(device->cfgopt, "NvI2C", internal)) {
if (!(bit = kzalloc_obj(*bit)))
return -ENOMEM;
bit->udelay = 10;
bit->timeout = usecs_to_jiffies(2200);
bit->data = bus;
bit->pre_xfer = nvkm_i2c_bus_pre_xfer;
bit->post_xfer = nvkm_i2c_bus_post_xfer;
bit->setscl = nvkm_i2c_bus_setscl;
bit->setsda = nvkm_i2c_bus_setsda;
bit->getscl = nvkm_i2c_bus_getscl;
bit->getsda = nvkm_i2c_bus_getsda;
bus->i2c.algo_data = bit;
ret = i2c_bit_add_bus(&bus->i2c);
} else {
bus->i2c.algo = &nvkm_i2c_bus_algo;
ret = i2c_add_adapter(&bus->i2c);
}
return ret;
}
int
nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *func,
struct nvkm_i2c_pad *pad, int id,
struct nvkm_i2c_bus **pbus)
{
if (!(*pbus = kzalloc_obj(**pbus)))
return -ENOMEM;
return nvkm_i2c_bus_ctor(func, pad, id, *pbus);
}
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_I2C_BUS_H__
#define __NVKM_I2C_BUS_H__
#include "pad.h"
struct nvkm_i2c_bus_func {
void (*init)(struct nvkm_i2c_bus *);
void (*drive_scl)(struct nvkm_i2c_bus *, int state);
void (*drive_sda)(struct nvkm_i2c_bus *, int state);
int (*sense_scl)(struct nvkm_i2c_bus *);
int (*sense_sda)(struct nvkm_i2c_bus *);
int (*xfer)(struct nvkm_i2c_bus *, struct i2c_msg *, int num);
};
int nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *, struct nvkm_i2c_pad *,
int id, struct nvkm_i2c_bus *);
int nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *, struct nvkm_i2c_pad *,
int id, struct nvkm_i2c_bus **);
void nvkm_i2c_bus_del(struct nvkm_i2c_bus **);
void nvkm_i2c_bus_init(struct nvkm_i2c_bus *);
void nvkm_i2c_bus_fini(struct nvkm_i2c_bus *);
int nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *, struct i2c_msg *, int);
int nv04_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, u8,
struct nvkm_i2c_bus **);
int nv4e_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **);
int nv50_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **);
int gf119_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **);
#define BUS_MSG(b,l,f,a...) do { \
struct nvkm_i2c_bus *_bus = (b); \
nvkm_##l(&_bus->pad->i2c->subdev, "bus %04x: "f"\n", _bus->id, ##a); \
} while(0)
#define BUS_ERR(b,f,a...) BUS_MSG((b), error, f, ##a)
#define BUS_DBG(b,f,a...) BUS_MSG((b), debug, f, ##a)
#define BUS_TRACE(b,f,a...) BUS_MSG((b), trace, f, ##a)
#endif
@@ -0,0 +1,95 @@
/*
* Copyright 2015 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 busions 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 <bskeggs@redhat.com>
*/
#define gf119_i2c_bus(p) container_of((p), struct gf119_i2c_bus, base)
#include "bus.h"
struct gf119_i2c_bus {
struct nvkm_i2c_bus base;
u32 addr;
};
static void
gf119_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state)
{
struct gf119_i2c_bus *bus = gf119_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
nvkm_mask(device, bus->addr, 0x00000001, state ? 0x00000001 : 0);
}
static void
gf119_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state)
{
struct gf119_i2c_bus *bus = gf119_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
nvkm_mask(device, bus->addr, 0x00000002, state ? 0x00000002 : 0);
}
static int
gf119_i2c_bus_sense_scl(struct nvkm_i2c_bus *base)
{
struct gf119_i2c_bus *bus = gf119_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rd32(device, bus->addr) & 0x00000010);
}
static int
gf119_i2c_bus_sense_sda(struct nvkm_i2c_bus *base)
{
struct gf119_i2c_bus *bus = gf119_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rd32(device, bus->addr) & 0x00000020);
}
static void
gf119_i2c_bus_init(struct nvkm_i2c_bus *base)
{
struct gf119_i2c_bus *bus = gf119_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
nvkm_wr32(device, bus->addr, 0x00000007);
}
static const struct nvkm_i2c_bus_func
gf119_i2c_bus_func = {
.init = gf119_i2c_bus_init,
.drive_scl = gf119_i2c_bus_drive_scl,
.drive_sda = gf119_i2c_bus_drive_sda,
.sense_scl = gf119_i2c_bus_sense_scl,
.sense_sda = gf119_i2c_bus_sense_sda,
.xfer = nvkm_i2c_bit_xfer,
};
int
gf119_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive,
struct nvkm_i2c_bus **pbus)
{
struct gf119_i2c_bus *bus;
if (!(bus = kzalloc_obj(*bus)))
return -ENOMEM;
*pbus = &bus->base;
nvkm_i2c_bus_ctor(&gf119_i2c_bus_func, pad, id, &bus->base);
bus->addr = 0x00d014 + (drive * 0x20);
return 0;
}
@@ -0,0 +1,96 @@
/*
* Copyright 2015 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 busions 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 <bskeggs@redhat.com>
*/
#define nv04_i2c_bus(p) container_of((p), struct nv04_i2c_bus, base)
#include "bus.h"
#include <subdev/vga.h>
struct nv04_i2c_bus {
struct nvkm_i2c_bus base;
u8 drive;
u8 sense;
};
static void
nv04_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state)
{
struct nv04_i2c_bus *bus = nv04_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
u8 val = nvkm_rdvgac(device, 0, bus->drive);
if (state) val |= 0x20;
else val &= 0xdf;
nvkm_wrvgac(device, 0, bus->drive, val | 0x01);
}
static void
nv04_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state)
{
struct nv04_i2c_bus *bus = nv04_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
u8 val = nvkm_rdvgac(device, 0, bus->drive);
if (state) val |= 0x10;
else val &= 0xef;
nvkm_wrvgac(device, 0, bus->drive, val | 0x01);
}
static int
nv04_i2c_bus_sense_scl(struct nvkm_i2c_bus *base)
{
struct nv04_i2c_bus *bus = nv04_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rdvgac(device, 0, bus->sense) & 0x04);
}
static int
nv04_i2c_bus_sense_sda(struct nvkm_i2c_bus *base)
{
struct nv04_i2c_bus *bus = nv04_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rdvgac(device, 0, bus->sense) & 0x08);
}
static const struct nvkm_i2c_bus_func
nv04_i2c_bus_func = {
.drive_scl = nv04_i2c_bus_drive_scl,
.drive_sda = nv04_i2c_bus_drive_sda,
.sense_scl = nv04_i2c_bus_sense_scl,
.sense_sda = nv04_i2c_bus_sense_sda,
.xfer = nvkm_i2c_bit_xfer,
};
int
nv04_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, u8 sense,
struct nvkm_i2c_bus **pbus)
{
struct nv04_i2c_bus *bus;
if (!(bus = kzalloc_obj(*bus)))
return -ENOMEM;
*pbus = &bus->base;
nvkm_i2c_bus_ctor(&nv04_i2c_bus_func, pad, id, &bus->base);
bus->drive = drive;
bus->sense = sense;
return 0;
}
@@ -0,0 +1,86 @@
/*
* Copyright 2015 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 busions 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 <bskeggs@redhat.com>
*/
#define nv4e_i2c_bus(p) container_of((p), struct nv4e_i2c_bus, base)
#include "bus.h"
struct nv4e_i2c_bus {
struct nvkm_i2c_bus base;
u32 addr;
};
static void
nv4e_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state)
{
struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
nvkm_mask(device, bus->addr, 0x2f, state ? 0x21 : 0x01);
}
static void
nv4e_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state)
{
struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
nvkm_mask(device, bus->addr, 0x1f, state ? 0x11 : 0x01);
}
static int
nv4e_i2c_bus_sense_scl(struct nvkm_i2c_bus *base)
{
struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rd32(device, bus->addr) & 0x00040000);
}
static int
nv4e_i2c_bus_sense_sda(struct nvkm_i2c_bus *base)
{
struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rd32(device, bus->addr) & 0x00080000);
}
static const struct nvkm_i2c_bus_func
nv4e_i2c_bus_func = {
.drive_scl = nv4e_i2c_bus_drive_scl,
.drive_sda = nv4e_i2c_bus_drive_sda,
.sense_scl = nv4e_i2c_bus_sense_scl,
.sense_sda = nv4e_i2c_bus_sense_sda,
.xfer = nvkm_i2c_bit_xfer,
};
int
nv4e_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive,
struct nvkm_i2c_bus **pbus)
{
struct nv4e_i2c_bus *bus;
if (!(bus = kzalloc_obj(*bus)))
return -ENOMEM;
*pbus = &bus->base;
nvkm_i2c_bus_ctor(&nv4e_i2c_bus_func, pad, id, &bus->base);
bus->addr = 0x600800 + drive;
return 0;
}
@@ -0,0 +1,113 @@
/*
* Copyright 2015 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 busions 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 <bskeggs@redhat.com>
*/
#define nv50_i2c_bus(p) container_of((p), struct nv50_i2c_bus, base)
#include "bus.h"
#include <subdev/vga.h>
struct nv50_i2c_bus {
struct nvkm_i2c_bus base;
u32 addr;
u32 data;
};
static void
nv50_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state)
{
struct nv50_i2c_bus *bus = nv50_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
if (state) bus->data |= 0x01;
else bus->data &= 0xfe;
nvkm_wr32(device, bus->addr, bus->data);
}
static void
nv50_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state)
{
struct nv50_i2c_bus *bus = nv50_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
if (state) bus->data |= 0x02;
else bus->data &= 0xfd;
nvkm_wr32(device, bus->addr, bus->data);
}
static int
nv50_i2c_bus_sense_scl(struct nvkm_i2c_bus *base)
{
struct nv50_i2c_bus *bus = nv50_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rd32(device, bus->addr) & 0x00000001);
}
static int
nv50_i2c_bus_sense_sda(struct nvkm_i2c_bus *base)
{
struct nv50_i2c_bus *bus = nv50_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
return !!(nvkm_rd32(device, bus->addr) & 0x00000002);
}
static void
nv50_i2c_bus_init(struct nvkm_i2c_bus *base)
{
struct nv50_i2c_bus *bus = nv50_i2c_bus(base);
struct nvkm_device *device = bus->base.pad->i2c->subdev.device;
nvkm_wr32(device, bus->addr, (bus->data = 0x00000007));
}
static const struct nvkm_i2c_bus_func
nv50_i2c_bus_func = {
.init = nv50_i2c_bus_init,
.drive_scl = nv50_i2c_bus_drive_scl,
.drive_sda = nv50_i2c_bus_drive_sda,
.sense_scl = nv50_i2c_bus_sense_scl,
.sense_sda = nv50_i2c_bus_sense_sda,
.xfer = nvkm_i2c_bit_xfer,
};
int
nv50_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive,
struct nvkm_i2c_bus **pbus)
{
static const u32 addr[] = {
0x00e138, 0x00e150, 0x00e168, 0x00e180,
0x00e254, 0x00e274, 0x00e764, 0x00e780,
0x00e79c, 0x00e7b8
};
struct nv50_i2c_bus *bus;
if (drive >= ARRAY_SIZE(addr)) {
nvkm_warn(&pad->i2c->subdev, "bus %d unknown\n", drive);
return -ENODEV;
}
if (!(bus = kzalloc_obj(*bus)))
return -ENOMEM;
*pbus = &bus->base;
nvkm_i2c_bus_ctor(&nv50_i2c_bus_func, pad, id, &bus->base);
bus->addr = addr[drive];
bus->data = 0x00000007;
return 0;
}
@@ -0,0 +1,73 @@
/*
* 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 "pad.h"
void
g94_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
{
struct nvkm_device *device = i2c->subdev.device;
u32 intr = nvkm_rd32(device, 0x00e06c);
u32 stat = nvkm_rd32(device, 0x00e068) & intr, i;
for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
}
nvkm_wr32(device, 0x00e06c, intr);
}
void
g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data)
{
struct nvkm_device *device = i2c->subdev.device;
u32 temp = nvkm_rd32(device, 0x00e068), i;
for (i = 0; i < 8; i++) {
if (mask & (1 << i)) {
if (!(data & (1 << i))) {
temp &= ~(type << (i * 4));
continue;
}
temp |= type << (i * 4);
}
}
nvkm_wr32(device, 0x00e068, temp);
}
static const struct nvkm_i2c_func
g94_i2c = {
.pad_x_new = g94_i2c_pad_x_new,
.pad_s_new = g94_i2c_pad_s_new,
.aux = 4,
.aux_stat = g94_aux_stat,
.aux_mask = g94_aux_mask,
};
int
g94_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&g94_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,37 @@
/*
* 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 "pad.h"
static const struct nvkm_i2c_func
gf117_i2c = {
.pad_x_new = gf119_i2c_pad_x_new,
};
int
gf117_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&gf117_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,41 @@
/*
* 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 "pad.h"
static const struct nvkm_i2c_func
gf119_i2c = {
.pad_x_new = gf119_i2c_pad_x_new,
.pad_s_new = gf119_i2c_pad_s_new,
.aux = 4,
.aux_stat = g94_aux_stat,
.aux_mask = g94_aux_mask,
};
int
gf119_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&gf119_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,73 @@
/*
* 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 "pad.h"
void
gk104_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
{
struct nvkm_device *device = i2c->subdev.device;
u32 intr = nvkm_rd32(device, 0x00dc60);
u32 stat = nvkm_rd32(device, 0x00dc68) & intr, i;
for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
}
nvkm_wr32(device, 0x00dc60, intr);
}
void
gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data)
{
struct nvkm_device *device = i2c->subdev.device;
u32 temp = nvkm_rd32(device, 0x00dc68), i;
for (i = 0; i < 8; i++) {
if (mask & (1 << i)) {
if (!(data & (1 << i))) {
temp &= ~(type << (i * 4));
continue;
}
temp |= type << (i * 4);
}
}
nvkm_wr32(device, 0x00dc68, temp);
}
static const struct nvkm_i2c_func
gk104_i2c = {
.pad_x_new = gf119_i2c_pad_x_new,
.pad_s_new = gf119_i2c_pad_s_new,
.aux = 4,
.aux_stat = gk104_aux_stat,
.aux_mask = gk104_aux_mask,
};
int
gk104_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&gk104_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,46 @@
/*
* 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 "pad.h"
static void
gk110_aux_autodpcd(struct nvkm_i2c *i2c, int aux, bool enable)
{
nvkm_mask(i2c->subdev.device, 0x00e4f8 + (aux * 0x50), 0x00010000, enable << 16);
}
static const struct nvkm_i2c_func
gk110_i2c = {
.pad_x_new = gf119_i2c_pad_x_new,
.pad_s_new = gf119_i2c_pad_s_new,
.aux = 4,
.aux_stat = gk104_aux_stat,
.aux_mask = gk104_aux_mask,
.aux_autodpcd = gk110_aux_autodpcd,
};
int
gk110_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&gk110_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,53 @@
/*
* 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 "pad.h"
#include <subdev/gsp.h>
static void
gm200_aux_autodpcd(struct nvkm_i2c *i2c, int aux, bool enable)
{
nvkm_mask(i2c->subdev.device, 0x00d968 + (aux * 0x50), 0x00010000, enable << 16);
}
static const struct nvkm_i2c_func
gm200_i2c = {
.pad_x_new = gf119_i2c_pad_x_new,
.pad_s_new = gm200_i2c_pad_s_new,
.aux = 8,
.aux_stat = gk104_aux_stat,
.aux_mask = gk104_aux_mask,
.aux_autodpcd = gm200_aux_autodpcd,
};
int
gm200_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
if (nvkm_gsp_rm(device->gsp))
return -ENODEV;
return nvkm_i2c_new_(&gm200_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,37 @@
/*
* 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 "pad.h"
static const struct nvkm_i2c_func
nv04_i2c = {
.pad_x_new = nv04_i2c_pad_new,
};
int
nv04_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&nv04_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,37 @@
/*
* 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 "pad.h"
static const struct nvkm_i2c_func
nv4e_i2c = {
.pad_x_new = nv4e_i2c_pad_new,
};
int
nv4e_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&nv4e_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,37 @@
/*
* 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 "pad.h"
static const struct nvkm_i2c_func
nv50_i2c = {
.pad_x_new = nv50_i2c_pad_new,
};
int
nv50_i2c_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_i2c **pi2c)
{
return nvkm_i2c_new_(&nv50_i2c, device, type, inst, pi2c);
}
@@ -0,0 +1,116 @@
/*
* Copyright 2015 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 <bskeggs@redhat.com>
*/
#include "pad.h"
static void
nvkm_i2c_pad_mode_locked(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode)
{
PAD_TRACE(pad, "-> %s", (mode == NVKM_I2C_PAD_AUX) ? "aux" :
(mode == NVKM_I2C_PAD_I2C) ? "i2c" : "off");
if (pad->func->mode)
pad->func->mode(pad, mode);
}
void
nvkm_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode)
{
PAD_TRACE(pad, "mode %d", mode);
mutex_lock(&pad->mutex);
nvkm_i2c_pad_mode_locked(pad, mode);
pad->mode = mode;
mutex_unlock(&pad->mutex);
}
void
nvkm_i2c_pad_release(struct nvkm_i2c_pad *pad)
{
PAD_TRACE(pad, "release");
if (pad->mode == NVKM_I2C_PAD_OFF)
nvkm_i2c_pad_mode_locked(pad, pad->mode);
mutex_unlock(&pad->mutex);
}
int
nvkm_i2c_pad_acquire(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode)
{
PAD_TRACE(pad, "acquire");
mutex_lock(&pad->mutex);
if (pad->mode != mode) {
if (pad->mode != NVKM_I2C_PAD_OFF) {
mutex_unlock(&pad->mutex);
return -EBUSY;
}
nvkm_i2c_pad_mode_locked(pad, mode);
}
return 0;
}
void
nvkm_i2c_pad_fini(struct nvkm_i2c_pad *pad)
{
PAD_TRACE(pad, "fini");
nvkm_i2c_pad_mode_locked(pad, NVKM_I2C_PAD_OFF);
}
void
nvkm_i2c_pad_init(struct nvkm_i2c_pad *pad)
{
PAD_TRACE(pad, "init");
nvkm_i2c_pad_mode_locked(pad, pad->mode);
}
void
nvkm_i2c_pad_del(struct nvkm_i2c_pad **ppad)
{
struct nvkm_i2c_pad *pad = *ppad;
if (pad) {
PAD_TRACE(pad, "dtor");
list_del(&pad->head);
kfree(pad);
pad = NULL;
}
}
void
nvkm_i2c_pad_ctor(const struct nvkm_i2c_pad_func *func, struct nvkm_i2c *i2c,
int id, struct nvkm_i2c_pad *pad)
{
pad->func = func;
pad->i2c = i2c;
pad->id = id;
pad->mode = NVKM_I2C_PAD_OFF;
mutex_init(&pad->mutex);
list_add_tail(&pad->head, &i2c->pad);
PAD_TRACE(pad, "ctor");
}
int
nvkm_i2c_pad_new_(const struct nvkm_i2c_pad_func *func, struct nvkm_i2c *i2c,
int id, struct nvkm_i2c_pad **ppad)
{
if (!(*ppad = kzalloc_obj(**ppad)))
return -ENOMEM;
nvkm_i2c_pad_ctor(func, i2c, id, *ppad);
return 0;
}
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_I2C_PAD_H__
#define __NVKM_I2C_PAD_H__
#include "priv.h"
struct nvkm_i2c_pad {
const struct nvkm_i2c_pad_func *func;
struct nvkm_i2c *i2c;
#define NVKM_I2C_PAD_HYBRID(n) /* 'n' is hw pad index */ (n)
#define NVKM_I2C_PAD_CCB(n) /* 'n' is ccb index */ ((n) + 0x100)
#define NVKM_I2C_PAD_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x200)
int id;
enum nvkm_i2c_pad_mode {
NVKM_I2C_PAD_OFF,
NVKM_I2C_PAD_I2C,
NVKM_I2C_PAD_AUX,
} mode;
struct mutex mutex;
struct list_head head;
};
struct nvkm_i2c_pad_func {
int (*bus_new_0)(struct nvkm_i2c_pad *, int id, u8 drive, u8 sense,
struct nvkm_i2c_bus **);
int (*bus_new_4)(struct nvkm_i2c_pad *, int id, u8 drive,
struct nvkm_i2c_bus **);
int (*aux_new_6)(struct nvkm_i2c_pad *, int id, u8 drive,
struct nvkm_i2c_aux **);
void (*mode)(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode);
};
void nvkm_i2c_pad_ctor(const struct nvkm_i2c_pad_func *, struct nvkm_i2c *,
int id, struct nvkm_i2c_pad *);
int nvkm_i2c_pad_new_(const struct nvkm_i2c_pad_func *, struct nvkm_i2c *,
int id, struct nvkm_i2c_pad **);
void nvkm_i2c_pad_del(struct nvkm_i2c_pad **);
void nvkm_i2c_pad_init(struct nvkm_i2c_pad *);
void nvkm_i2c_pad_fini(struct nvkm_i2c_pad *);
void nvkm_i2c_pad_mode(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode);
int nvkm_i2c_pad_acquire(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode);
void nvkm_i2c_pad_release(struct nvkm_i2c_pad *);
void g94_i2c_pad_mode(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode);
int nv04_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int nv4e_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int nv50_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int g94_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int gf119_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int gm200_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int g94_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int gf119_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int gm200_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **);
int anx9805_pad_new(struct nvkm_i2c_bus *, int, u8, struct nvkm_i2c_pad **);
#define PAD_MSG(p,l,f,a...) do { \
struct nvkm_i2c_pad *_pad = (p); \
nvkm_##l(&_pad->i2c->subdev, "pad %04x: "f"\n", _pad->id, ##a); \
} while(0)
#define PAD_ERR(p,f,a...) PAD_MSG((p), error, f, ##a)
#define PAD_DBG(p,f,a...) PAD_MSG((p), debug, f, ##a)
#define PAD_TRACE(p,f,a...) PAD_MSG((p), trace, f, ##a)
#endif
@@ -0,0 +1,76 @@
/*
* Copyright 2014 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 "pad.h"
#include "auxch.h"
#include "bus.h"
void
g94_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode)
{
struct nvkm_subdev *subdev = &pad->i2c->subdev;
struct nvkm_device *device = subdev->device;
const u32 base = (pad->id - NVKM_I2C_PAD_HYBRID(0)) * 0x50;
switch (mode) {
case NVKM_I2C_PAD_OFF:
nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000001);
break;
case NVKM_I2C_PAD_I2C:
nvkm_mask(device, 0x00e500 + base, 0x0000c003, 0x0000c001);
nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000000);
break;
case NVKM_I2C_PAD_AUX:
nvkm_mask(device, 0x00e500 + base, 0x0000c003, 0x00000002);
nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000000);
break;
default:
WARN_ON(1);
break;
}
}
static const struct nvkm_i2c_pad_func
g94_i2c_pad_s_func = {
.bus_new_4 = nv50_i2c_bus_new,
.aux_new_6 = g94_i2c_aux_new,
.mode = g94_i2c_pad_mode,
};
int
g94_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&g94_i2c_pad_s_func, i2c, id, ppad);
}
static const struct nvkm_i2c_pad_func
g94_i2c_pad_x_func = {
.bus_new_4 = nv50_i2c_bus_new,
.aux_new_6 = g94_i2c_aux_new,
};
int
g94_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&g94_i2c_pad_x_func, i2c, id, ppad);
}
@@ -0,0 +1,51 @@
/*
* Copyright 2014 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 "pad.h"
#include "auxch.h"
#include "bus.h"
static const struct nvkm_i2c_pad_func
gf119_i2c_pad_s_func = {
.bus_new_4 = gf119_i2c_bus_new,
.aux_new_6 = gf119_i2c_aux_new,
.mode = g94_i2c_pad_mode,
};
int
gf119_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&gf119_i2c_pad_s_func, i2c, id, ppad);
}
static const struct nvkm_i2c_pad_func
gf119_i2c_pad_x_func = {
.bus_new_4 = gf119_i2c_bus_new,
.aux_new_6 = gf119_i2c_aux_new,
};
int
gf119_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&gf119_i2c_pad_x_func, i2c, id, ppad);
}
@@ -0,0 +1,76 @@
/*
* Copyright 2014 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 "pad.h"
#include "auxch.h"
#include "bus.h"
static void
gm200_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode)
{
struct nvkm_subdev *subdev = &pad->i2c->subdev;
struct nvkm_device *device = subdev->device;
const u32 base = (pad->id - NVKM_I2C_PAD_HYBRID(0)) * 0x50;
switch (mode) {
case NVKM_I2C_PAD_OFF:
nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000001);
break;
case NVKM_I2C_PAD_I2C:
nvkm_mask(device, 0x00d970 + base, 0x0000c003, 0x0000c001);
nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000000);
break;
case NVKM_I2C_PAD_AUX:
nvkm_mask(device, 0x00d970 + base, 0x0000c003, 0x00000002);
nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000000);
break;
default:
WARN_ON(1);
break;
}
}
static const struct nvkm_i2c_pad_func
gm200_i2c_pad_s_func = {
.bus_new_4 = gf119_i2c_bus_new,
.aux_new_6 = gm200_i2c_aux_new,
.mode = gm200_i2c_pad_mode,
};
int
gm200_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&gm200_i2c_pad_s_func, i2c, id, ppad);
}
static const struct nvkm_i2c_pad_func
gm200_i2c_pad_x_func = {
.bus_new_4 = gf119_i2c_bus_new,
.aux_new_6 = gm200_i2c_aux_new,
};
int
gm200_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&gm200_i2c_pad_x_func, i2c, id, ppad);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2014 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 "pad.h"
#include "bus.h"
static const struct nvkm_i2c_pad_func
nv04_i2c_pad_func = {
.bus_new_0 = nv04_i2c_bus_new,
};
int
nv04_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&nv04_i2c_pad_func, i2c, id, ppad);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2014 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 "pad.h"
#include "bus.h"
static const struct nvkm_i2c_pad_func
nv4e_i2c_pad_func = {
.bus_new_4 = nv4e_i2c_bus_new,
};
int
nv4e_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&nv4e_i2c_pad_func, i2c, id, ppad);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2014 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 "pad.h"
#include "bus.h"
static const struct nvkm_i2c_pad_func
nv50_i2c_pad_func = {
.bus_new_4 = nv50_i2c_bus_new,
};
int
nv50_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
{
return nvkm_i2c_pad_new_(&nv50_i2c_pad_func, i2c, id, ppad);
}
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_I2C_PRIV_H__
#define __NVKM_I2C_PRIV_H__
#define nvkm_i2c(p) container_of((p), struct nvkm_i2c, subdev)
#include <subdev/i2c.h>
int nvkm_i2c_new_(const struct nvkm_i2c_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_i2c **);
struct nvkm_i2c_func {
int (*pad_x_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **);
int (*pad_s_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **);
/* number of native dp aux channels present */
int aux;
/* read and ack pending interrupts, returning only data
* for ports that have not been masked off, while still
* performing the ack for anything that was pending.
*/
void (*aux_stat)(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
/* mask on/off interrupt types for a given set of auxch
*/
void (*aux_mask)(struct nvkm_i2c *, u32, u32, u32);
/* enable/disable HW-initiated DPCD reads
*/
void (*aux_autodpcd)(struct nvkm_i2c *, int aux, bool enable);
};
void g94_aux_stat(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
void g94_aux_mask(struct nvkm_i2c *, u32, u32, u32);
void gk104_aux_stat(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
void gk104_aux_mask(struct nvkm_i2c *, u32, u32, u32);
#endif