drm/nouveau/i2c: do parsing of i2c-related vbios info in nouveau_i2c.c
Not much point parsing the vbios data into a struct which is only used once to parse the data into another struct, go directly from vbios to nouveau_i2c_chan. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
6b5a81a2e7
commit
486a45c2a6
|
@ -720,115 +720,19 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
|
|||
return dcb_entry;
|
||||
}
|
||||
|
||||
static int
|
||||
read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, int index, struct dcb_i2c_entry *i2c)
|
||||
{
|
||||
uint8_t dcb_i2c_ver = dcb_version, headerlen = 0, entry_len = 4;
|
||||
int i2c_entries = DCB_MAX_NUM_I2C_ENTRIES;
|
||||
int recordoffset = 0, rdofs = 1, wrofs = 0;
|
||||
uint8_t port_type = 0;
|
||||
|
||||
if (!i2ctable)
|
||||
return -EINVAL;
|
||||
|
||||
if (dcb_version >= 0x30) {
|
||||
if (i2ctable[0] != dcb_version) /* necessary? */
|
||||
NV_WARN(dev,
|
||||
"DCB I2C table version mismatch (%02X vs %02X)\n",
|
||||
i2ctable[0], dcb_version);
|
||||
dcb_i2c_ver = i2ctable[0];
|
||||
headerlen = i2ctable[1];
|
||||
if (i2ctable[2] <= DCB_MAX_NUM_I2C_ENTRIES)
|
||||
i2c_entries = i2ctable[2];
|
||||
else
|
||||
NV_WARN(dev,
|
||||
"DCB I2C table has more entries than indexable "
|
||||
"(%d entries, max %d)\n", i2ctable[2],
|
||||
DCB_MAX_NUM_I2C_ENTRIES);
|
||||
entry_len = i2ctable[3];
|
||||
/* [4] is i2c_default_indices, read in parse_dcb_table() */
|
||||
}
|
||||
/*
|
||||
* It's your own fault if you call this function on a DCB 1.1 BIOS --
|
||||
* the test below is for DCB 1.2
|
||||
*/
|
||||
if (dcb_version < 0x14) {
|
||||
recordoffset = 2;
|
||||
rdofs = 0;
|
||||
wrofs = 1;
|
||||
}
|
||||
|
||||
if (index == 0xf)
|
||||
return 0;
|
||||
if (index >= i2c_entries) {
|
||||
NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n",
|
||||
index, i2ctable[2]);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (i2ctable[headerlen + entry_len * index + 3] == 0xff) {
|
||||
NV_ERROR(dev, "DCB I2C entry invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dcb_i2c_ver >= 0x30) {
|
||||
port_type = i2ctable[headerlen + recordoffset + 3 + entry_len * index];
|
||||
|
||||
/*
|
||||
* Fixup for chips using same address offset for read and
|
||||
* write.
|
||||
*/
|
||||
if (port_type == 4) /* seen on C51 */
|
||||
rdofs = wrofs = 1;
|
||||
if (port_type >= 5) /* G80+ */
|
||||
rdofs = wrofs = 0;
|
||||
}
|
||||
|
||||
if (dcb_i2c_ver >= 0x40) {
|
||||
if (port_type != 5 && port_type != 6)
|
||||
NV_WARN(dev, "DCB I2C table has port type %d\n", port_type);
|
||||
|
||||
i2c->entry = ROM32(i2ctable[headerlen + recordoffset + entry_len * index]);
|
||||
}
|
||||
|
||||
i2c->port_type = port_type;
|
||||
i2c->read = i2ctable[headerlen + recordoffset + rdofs + entry_len * index];
|
||||
i2c->write = i2ctable[headerlen + recordoffset + wrofs + entry_len * index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_i2c_chan *
|
||||
init_i2c_device_find(struct drm_device *dev, int i2c_index)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct dcb_table *dcb = &dev_priv->vbios.dcb;
|
||||
|
||||
if (i2c_index == 0xff) {
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct dcb_table *dcb = &dev_priv->vbios.dcb;
|
||||
/* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
|
||||
int idx = dcb_entry_idx_from_crtchead(dev), shift = 0;
|
||||
int default_indices = dcb->i2c_default_indices;
|
||||
int idx = dcb_entry_idx_from_crtchead(dev);
|
||||
|
||||
i2c_index = NV_I2C_DEFAULT(0);
|
||||
if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
|
||||
shift = 4;
|
||||
|
||||
i2c_index = (default_indices >> shift) & 0xf;
|
||||
i2c_index = NV_I2C_DEFAULT(1);
|
||||
}
|
||||
if (i2c_index == 0x80) /* g80+ */
|
||||
i2c_index = dcb->i2c_default_indices & 0xf;
|
||||
else
|
||||
if (i2c_index == 0x81)
|
||||
i2c_index = (dcb->i2c_default_indices & 0xf0) >> 4;
|
||||
|
||||
if (i2c_index >= DCB_MAX_NUM_I2C_ENTRIES) {
|
||||
NV_ERROR(dev, "invalid i2c_index 0x%x\n", i2c_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure i2c table entry has been parsed, it may not
|
||||
* have been if this is a bus not referenced by a DCB encoder
|
||||
*/
|
||||
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
|
||||
i2c_index, &dcb->i2c[i2c_index]);
|
||||
|
||||
return nouveau_i2c_find(dev, i2c_index);
|
||||
}
|
||||
|
@ -5595,10 +5499,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
|
|||
uint16_t legacy_scripts_offset, legacy_i2c_offset;
|
||||
|
||||
/* load needed defaults in case we can't parse this info */
|
||||
bios->dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX;
|
||||
bios->dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX;
|
||||
bios->dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX;
|
||||
bios->dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX;
|
||||
bios->digital_min_front_porch = 0x4b;
|
||||
bios->fmaxvco = 256000;
|
||||
bios->fminvco = 128000;
|
||||
|
@ -5706,14 +5606,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
|
|||
bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset];
|
||||
bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
|
||||
bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2];
|
||||
if (bios->data[legacy_i2c_offset + 4])
|
||||
bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
|
||||
if (bios->data[legacy_i2c_offset + 5])
|
||||
bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
|
||||
if (bios->data[legacy_i2c_offset + 6])
|
||||
bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
|
||||
if (bios->data[legacy_i2c_offset + 7])
|
||||
bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
|
||||
|
||||
if (bmplength > 74) {
|
||||
bios->fmaxvco = ROM32(bmp[67]);
|
||||
|
@ -6549,10 +6441,6 @@ parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp)
|
|||
ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
|
||||
if (!ret)
|
||||
return 1; /* stop parsing */
|
||||
|
||||
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
|
||||
entry->i2c_index,
|
||||
&dcb->i2c[entry->i2c_index]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -6562,7 +6450,6 @@ static int
|
|||
parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
|
||||
{
|
||||
struct dcb_table *dcb = &bios->dcb;
|
||||
u16 i2ctabptr = 0x0000;
|
||||
u8 *dcbt;
|
||||
|
||||
dcbt = dcb_table(dev);
|
||||
|
@ -6580,32 +6467,8 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
|
|||
|
||||
dcb->version = dcbt[0];
|
||||
if (dcb->version >= 0x30) {
|
||||
i2ctabptr = ROM16(dcbt[4]);
|
||||
dcb->gpio_table_ptr = ROM16(dcbt[10]);
|
||||
dcb->connector_table_ptr = ROM16(dcbt[20]);
|
||||
} else
|
||||
if (dcb->version >= 0x15) {
|
||||
i2ctabptr = ROM16(dcbt[2]);
|
||||
}
|
||||
|
||||
if (!i2ctabptr)
|
||||
NV_WARN(dev, "No pointer to DCB I2C port table\n");
|
||||
else {
|
||||
dcb->i2c_table = &bios->data[i2ctabptr];
|
||||
if (dcb->version >= 0x30)
|
||||
dcb->i2c_default_indices = dcb->i2c_table[4];
|
||||
|
||||
/*
|
||||
* Parse the "management" I2C bus, used for hardware
|
||||
* monitoring and some external TMDS transmitters.
|
||||
*/
|
||||
if (dcb->version >= 0x22) {
|
||||
int idx = (dcb->version >= 0x40 ?
|
||||
dcb->i2c_default_indices & 0xf : 2);
|
||||
|
||||
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
|
||||
idx, &dcb->i2c[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
dcb_outp_foreach(dev, NULL, parse_dcb_entry);
|
||||
|
@ -6893,19 +6756,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nvbios *bios = &dev_priv->vbios;
|
||||
struct dcb_i2c_entry *entry;
|
||||
int i;
|
||||
|
||||
entry = &bios->dcb.i2c[0];
|
||||
for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++)
|
||||
nouveau_i2c_fini(dev, entry);
|
||||
}
|
||||
|
||||
static bool
|
||||
nouveau_bios_posted(struct drm_device *dev)
|
||||
{
|
||||
|
@ -6942,6 +6792,10 @@ nouveau_bios_init(struct drm_device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_i2c_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = parse_dcb_table(dev, bios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -6984,5 +6838,5 @@ nouveau_bios_init(struct drm_device *dev)
|
|||
void
|
||||
nouveau_bios_takedown(struct drm_device *dev)
|
||||
{
|
||||
nouveau_bios_i2c_devices_takedown(dev);
|
||||
nouveau_i2c_fini(dev);
|
||||
}
|
||||
|
|
|
@ -53,13 +53,6 @@ struct bit_entry {
|
|||
|
||||
int bit_table(struct drm_device *, u8 id, struct bit_entry *);
|
||||
|
||||
struct dcb_i2c_entry {
|
||||
uint32_t entry;
|
||||
uint8_t port_type;
|
||||
uint8_t read, write;
|
||||
struct nouveau_i2c_chan *chan;
|
||||
};
|
||||
|
||||
enum dcb_gpio_tag {
|
||||
DCB_GPIO_TVDAC0 = 0xc,
|
||||
DCB_GPIO_TVDAC1 = 0x2d,
|
||||
|
@ -166,10 +159,6 @@ struct dcb_table {
|
|||
int entries;
|
||||
struct dcb_entry entry[DCB_MAX_NUM_ENTRIES];
|
||||
|
||||
uint8_t *i2c_table;
|
||||
uint8_t i2c_default_indices;
|
||||
struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
|
||||
|
||||
uint16_t gpio_table_ptr;
|
||||
struct dcb_gpio_table gpio;
|
||||
uint16_t connector_table_ptr;
|
||||
|
|
|
@ -793,6 +793,7 @@ struct drm_nouveau_private {
|
|||
struct nouveau_vm *chan_vm;
|
||||
|
||||
struct nvbios vbios;
|
||||
struct list_head i2c_ports;
|
||||
|
||||
struct nv04_mode_state mode_reg;
|
||||
struct nv04_mode_state saved_reg;
|
||||
|
|
|
@ -109,13 +109,6 @@ nv4e_i2c_getsda(void *data)
|
|||
return !!((nv_rd32(dev, i2c->rd) >> 16) & 8);
|
||||
}
|
||||
|
||||
static const uint32_t nv50_i2c_port[] = {
|
||||
0x00e138, 0x00e150, 0x00e168, 0x00e180,
|
||||
0x00e254, 0x00e274, 0x00e764, 0x00e780,
|
||||
0x00e79c, 0x00e7b8
|
||||
};
|
||||
#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port)
|
||||
|
||||
static int
|
||||
nv50_i2c_getscl(void *data)
|
||||
{
|
||||
|
@ -125,7 +118,6 @@ nv50_i2c_getscl(void *data)
|
|||
return !!(nv_rd32(dev, i2c->rd) & 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
nv50_i2c_getsda(void *data)
|
||||
{
|
||||
|
@ -166,125 +158,233 @@ nvd0_i2c_getsda(void *data)
|
|||
return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20);
|
||||
}
|
||||
|
||||
static const uint32_t nv50_i2c_port[] = {
|
||||
0x00e138, 0x00e150, 0x00e168, 0x00e180,
|
||||
0x00e254, 0x00e274, 0x00e764, 0x00e780,
|
||||
0x00e79c, 0x00e7b8
|
||||
};
|
||||
|
||||
static u8 *
|
||||
i2c_table(struct drm_device *dev, u8 *version)
|
||||
{
|
||||
u8 *dcb = dcb_table(dev), *i2c = NULL;
|
||||
if (dcb) {
|
||||
if (dcb[0] >= 0x15)
|
||||
i2c = ROMPTR(dev, dcb[2]);
|
||||
if (dcb[0] >= 0x30)
|
||||
i2c = ROMPTR(dev, dcb[4]);
|
||||
}
|
||||
|
||||
/* early revisions had no version number, use dcb version */
|
||||
if (i2c) {
|
||||
*version = dcb[0];
|
||||
if (*version >= 0x30)
|
||||
*version = i2c[0];
|
||||
}
|
||||
|
||||
return i2c;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
|
||||
nouveau_i2c_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_i2c_chan *i2c;
|
||||
int ret;
|
||||
struct nvbios *bios = &dev_priv->vbios;
|
||||
struct nouveau_i2c_chan *port;
|
||||
u8 *i2c, *entry, legacy[2][4] = {};
|
||||
u8 version, entries, recordlen;
|
||||
int ret, i;
|
||||
|
||||
if (entry->chan)
|
||||
return -EEXIST;
|
||||
INIT_LIST_HEAD(&dev_priv->i2c_ports);
|
||||
|
||||
if (dev_priv->card_type >= NV_50 &&
|
||||
dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) {
|
||||
NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
|
||||
return -EINVAL;
|
||||
i2c = i2c_table(dev, &version);
|
||||
if (!i2c) {
|
||||
u8 *bmp = &bios->data[bios->offset];
|
||||
if (bios->type != NVBIOS_BMP)
|
||||
return -ENODEV;
|
||||
|
||||
legacy[0][0] = NV_CIO_CRE_DDC_WR__INDEX;
|
||||
legacy[0][1] = NV_CIO_CRE_DDC_STATUS__INDEX;
|
||||
legacy[1][0] = NV_CIO_CRE_DDC0_WR__INDEX;
|
||||
legacy[1][1] = NV_CIO_CRE_DDC0_STATUS__INDEX;
|
||||
|
||||
/* BMP (from v4.0) has i2c info in the structure, it's in a
|
||||
* fixed location on earlier VBIOS
|
||||
*/
|
||||
if (bmp[5] < 4)
|
||||
i2c = &bios->data[0x48];
|
||||
else
|
||||
i2c = &bmp[0x36];
|
||||
|
||||
if (i2c[4]) legacy[0][0] = i2c[4];
|
||||
if (i2c[5]) legacy[0][1] = i2c[5];
|
||||
if (i2c[6]) legacy[1][0] = i2c[6];
|
||||
if (i2c[7]) legacy[1][1] = i2c[7];
|
||||
}
|
||||
|
||||
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
|
||||
if (i2c == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (entry->port_type) {
|
||||
case 0:
|
||||
i2c->bit.setsda = nv04_i2c_setsda;
|
||||
i2c->bit.setscl = nv04_i2c_setscl;
|
||||
i2c->bit.getsda = nv04_i2c_getsda;
|
||||
i2c->bit.getscl = nv04_i2c_getscl;
|
||||
i2c->rd = entry->read;
|
||||
i2c->wr = entry->write;
|
||||
break;
|
||||
case 4:
|
||||
i2c->bit.setsda = nv4e_i2c_setsda;
|
||||
i2c->bit.setscl = nv4e_i2c_setscl;
|
||||
i2c->bit.getsda = nv4e_i2c_getsda;
|
||||
i2c->bit.getscl = nv4e_i2c_getscl;
|
||||
i2c->rd = 0x600800 + entry->read;
|
||||
i2c->wr = 0x600800 + entry->write;
|
||||
break;
|
||||
case 5:
|
||||
i2c->bit.setsda = nv50_i2c_setsda;
|
||||
i2c->bit.setscl = nv50_i2c_setscl;
|
||||
if (dev_priv->card_type < NV_D0) {
|
||||
i2c->bit.getsda = nv50_i2c_getsda;
|
||||
i2c->bit.getscl = nv50_i2c_getscl;
|
||||
i2c->rd = nv50_i2c_port[entry->read];
|
||||
i2c->wr = i2c->rd;
|
||||
} else {
|
||||
i2c->bit.getsda = nvd0_i2c_getsda;
|
||||
i2c->bit.getscl = nvd0_i2c_getscl;
|
||||
i2c->rd = 0x00d014 + (entry->read * 0x20);
|
||||
i2c->wr = i2c->rd;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
i2c->rd = entry->read;
|
||||
i2c->wr = entry->write;
|
||||
break;
|
||||
default:
|
||||
NV_ERROR(dev, "DCB I2C port type %d unknown\n",
|
||||
entry->port_type);
|
||||
kfree(i2c);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
|
||||
"nouveau-%s-%d", pci_name(dev->pdev), index);
|
||||
i2c->adapter.owner = THIS_MODULE;
|
||||
i2c->adapter.dev.parent = &dev->pdev->dev;
|
||||
i2c->dev = dev;
|
||||
i2c_set_adapdata(&i2c->adapter, i2c);
|
||||
|
||||
if (entry->port_type < 6) {
|
||||
i2c->adapter.algo_data = &i2c->bit;
|
||||
i2c->bit.udelay = 40;
|
||||
i2c->bit.timeout = usecs_to_jiffies(5000);
|
||||
i2c->bit.data = i2c;
|
||||
ret = i2c_bit_add_bus(&i2c->adapter);
|
||||
if (i2c && version >= 0x30) {
|
||||
entry = i2c[1] + i2c;
|
||||
entries = i2c[2];
|
||||
recordlen = i2c[3];
|
||||
} else
|
||||
if (i2c) {
|
||||
entry = i2c;
|
||||
entries = 16;
|
||||
recordlen = 4;
|
||||
} else {
|
||||
i2c->adapter.algo = &nouveau_dp_i2c_algo;
|
||||
ret = i2c_add_adapter(&i2c->adapter);
|
||||
entry = legacy[0];
|
||||
entries = 2;
|
||||
recordlen = 4;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
NV_ERROR(dev, "Failed to register i2c %d\n", index);
|
||||
kfree(i2c);
|
||||
return ret;
|
||||
for (i = 0; i < entries; i++, entry += recordlen) {
|
||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||
if (port == NULL) {
|
||||
nouveau_i2c_fini(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
port->type = entry[3];
|
||||
if (version < 0x30) {
|
||||
port->type &= 0x07;
|
||||
if (port->type == 0x07)
|
||||
port->type = 0xff;
|
||||
}
|
||||
|
||||
if (port->type == 0xff) {
|
||||
kfree(port);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (port->type) {
|
||||
case 0: /* NV04:NV50 */
|
||||
port->wr = entry[0];
|
||||
port->rd = entry[1];
|
||||
port->bit.setsda = nv04_i2c_setsda;
|
||||
port->bit.setscl = nv04_i2c_setscl;
|
||||
port->bit.getsda = nv04_i2c_getsda;
|
||||
port->bit.getscl = nv04_i2c_getscl;
|
||||
break;
|
||||
case 4: /* NV4E */
|
||||
port->wr = 0x600800 + entry[1];
|
||||
port->rd = port->wr;
|
||||
port->bit.setsda = nv4e_i2c_setsda;
|
||||
port->bit.setscl = nv4e_i2c_setscl;
|
||||
port->bit.getsda = nv4e_i2c_getsda;
|
||||
port->bit.getscl = nv4e_i2c_getscl;
|
||||
break;
|
||||
case 5: /* NV50- */
|
||||
port->wr = entry[0] & 0x0f;
|
||||
if (dev_priv->card_type < NV_D0) {
|
||||
if (port->wr >= ARRAY_SIZE(nv50_i2c_port))
|
||||
break;
|
||||
port->wr = nv50_i2c_port[port->wr];
|
||||
port->rd = port->wr;
|
||||
port->bit.getsda = nv50_i2c_getsda;
|
||||
port->bit.getscl = nv50_i2c_getscl;
|
||||
} else {
|
||||
port->wr = 0x00d014 + (port->wr * 0x20);
|
||||
port->rd = port->wr;
|
||||
port->bit.getsda = nvd0_i2c_getsda;
|
||||
port->bit.getscl = nvd0_i2c_getscl;
|
||||
}
|
||||
port->bit.setsda = nv50_i2c_setsda;
|
||||
port->bit.setscl = nv50_i2c_setscl;
|
||||
break;
|
||||
case 6: /* NV50- DP AUX */
|
||||
port->wr = entry[0];
|
||||
port->rd = port->wr;
|
||||
port->adapter.algo = &nouveau_dp_i2c_algo;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!port->adapter.algo && !port->wr) {
|
||||
NV_ERROR(dev, "I2C%d: type %d index %x/%x unknown\n",
|
||||
i, port->type, port->wr, port->rd);
|
||||
kfree(port);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(port->adapter.name, sizeof(port->adapter.name),
|
||||
"nouveau-%s-%d", pci_name(dev->pdev), i);
|
||||
port->adapter.owner = THIS_MODULE;
|
||||
port->adapter.dev.parent = &dev->pdev->dev;
|
||||
port->dev = dev;
|
||||
port->index = i;
|
||||
port->dcb = ROM32(entry[0]);
|
||||
i2c_set_adapdata(&port->adapter, i2c);
|
||||
|
||||
if (port->adapter.algo != &nouveau_dp_i2c_algo) {
|
||||
port->adapter.algo_data = &port->bit;
|
||||
port->bit.udelay = 40;
|
||||
port->bit.timeout = usecs_to_jiffies(5000);
|
||||
port->bit.data = port;
|
||||
ret = i2c_bit_add_bus(&port->adapter);
|
||||
} else {
|
||||
port->adapter.algo = &nouveau_dp_i2c_algo;
|
||||
ret = i2c_add_adapter(&port->adapter);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
NV_ERROR(dev, "I2C%d: failed register: %d\n", i, ret);
|
||||
kfree(port);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_add_tail(&port->head, &dev_priv->i2c_ports);
|
||||
}
|
||||
|
||||
entry->chan = i2c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_i2c_fini(struct drm_device *dev, struct dcb_i2c_entry *entry)
|
||||
nouveau_i2c_fini(struct drm_device *dev)
|
||||
{
|
||||
if (!entry->chan)
|
||||
return;
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_i2c_chan *port, *tmp;
|
||||
|
||||
i2c_del_adapter(&entry->chan->adapter);
|
||||
kfree(entry->chan);
|
||||
entry->chan = NULL;
|
||||
list_for_each_entry_safe(port, tmp, &dev_priv->i2c_ports, head) {
|
||||
i2c_del_adapter(&port->adapter);
|
||||
kfree(port);
|
||||
}
|
||||
}
|
||||
|
||||
struct nouveau_i2c_chan *
|
||||
nouveau_i2c_find(struct drm_device *dev, int index)
|
||||
nouveau_i2c_find(struct drm_device *dev, u8 index)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct dcb_i2c_entry *i2c = &dev_priv->vbios.dcb.i2c[index];
|
||||
struct nouveau_i2c_chan *port;
|
||||
|
||||
if (index >= DCB_MAX_NUM_I2C_ENTRIES)
|
||||
if (index == NV_I2C_DEFAULT(0) ||
|
||||
index == NV_I2C_DEFAULT(1)) {
|
||||
u8 version, *i2c = i2c_table(dev, &version);
|
||||
if (i2c && version >= 0x30) {
|
||||
if (index == NV_I2C_DEFAULT(0))
|
||||
index = (i2c[4] & 0x0f);
|
||||
else
|
||||
index = (i2c[4] & 0xf0) >> 4;
|
||||
} else {
|
||||
index = 2;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(port, &dev_priv->i2c_ports, head) {
|
||||
if (port->index == index)
|
||||
break;
|
||||
}
|
||||
|
||||
if (&port->head == &dev_priv->i2c_ports)
|
||||
return NULL;
|
||||
|
||||
if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
|
||||
uint32_t reg = 0xe500, val;
|
||||
|
||||
if (i2c->port_type == 6) {
|
||||
reg += i2c->read * 0x50;
|
||||
if (dev_priv->card_type >= NV_50 && (port->dcb & 0x00000100)) {
|
||||
u32 reg = 0x00e500, val;
|
||||
if (port->type == 6) {
|
||||
reg += port->rd * 0x50;
|
||||
val = 0x2002;
|
||||
} else {
|
||||
reg += ((i2c->entry & 0x1e00) >> 9) * 0x50;
|
||||
reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
|
||||
val = 0xe001;
|
||||
}
|
||||
|
||||
|
@ -294,9 +394,7 @@ nouveau_i2c_find(struct drm_device *dev, int index)
|
|||
nv_mask(dev, reg + 0x00, 0x0000f003, val);
|
||||
}
|
||||
|
||||
if (!i2c->chan && nouveau_i2c_init(dev, i2c, index))
|
||||
return NULL;
|
||||
return i2c->chan;
|
||||
return port;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -27,20 +27,26 @@
|
|||
#include <linux/i2c-algo-bit.h>
|
||||
#include "drm_dp_helper.h"
|
||||
|
||||
struct dcb_i2c_entry;
|
||||
#define NV_I2C_PORT(n) (0x00 + (n))
|
||||
#define NV_I2C_PORT_NUM 0x10
|
||||
#define NV_I2C_DEFAULT(n) (0x80 + (n))
|
||||
|
||||
struct nouveau_i2c_chan {
|
||||
struct i2c_adapter adapter;
|
||||
struct drm_device *dev;
|
||||
struct i2c_algo_bit_data bit;
|
||||
struct list_head head;
|
||||
u8 index;
|
||||
u8 type;
|
||||
u32 dcb;
|
||||
unsigned rd;
|
||||
unsigned wr;
|
||||
unsigned data;
|
||||
};
|
||||
|
||||
int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index);
|
||||
void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
|
||||
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
|
||||
int nouveau_i2c_init(struct drm_device *);
|
||||
void nouveau_i2c_fini(struct drm_device *);
|
||||
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, u8 index);
|
||||
bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
|
||||
int nouveau_i2c_identify(struct drm_device *dev, const char *what,
|
||||
struct i2c_board_info *info,
|
||||
|
|
|
@ -286,8 +286,6 @@ probe_monitoring_device(struct nouveau_i2c_chan *i2c,
|
|||
static void
|
||||
nouveau_temp_probe_i2c(struct drm_device *dev)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct dcb_table *dcb = &dev_priv->vbios.dcb;
|
||||
struct i2c_board_info info[] = {
|
||||
{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
|
||||
{ I2C_BOARD_INFO("w83781d", 0x2d) },
|
||||
|
@ -296,11 +294,9 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
|
|||
{ I2C_BOARD_INFO("lm99", 0x4c) },
|
||||
{ }
|
||||
};
|
||||
int idx = (dcb->version >= 0x40 ?
|
||||
dcb->i2c_default_indices & 0xf : 2);
|
||||
|
||||
nouveau_i2c_identify(dev, "monitoring device", info,
|
||||
probe_monitoring_device, idx);
|
||||
probe_monitoring_device, NV_I2C_DEFAULT(0));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in New Issue