Commit 486a45c2 authored by Ben Skeggs's avatar Ben Skeggs

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 6b5a81a2
...@@ -720,116 +720,20 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev) ...@@ -720,116 +720,20 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
return dcb_entry; 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 * static struct nouveau_i2c_chan *
init_i2c_device_find(struct drm_device *dev, int i2c_index) 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) { 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 */ /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
int idx = dcb_entry_idx_from_crtchead(dev), shift = 0; int idx = dcb_entry_idx_from_crtchead(dev);
int default_indices = dcb->i2c_default_indices;
i2c_index = NV_I2C_DEFAULT(0);
if (idx != 0x7f && dcb->entry[idx].i2c_upper_default) if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
shift = 4; i2c_index = NV_I2C_DEFAULT(1);
i2c_index = (default_indices >> shift) & 0xf;
}
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); return nouveau_i2c_find(dev, i2c_index);
} }
...@@ -5595,10 +5499,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi ...@@ -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; uint16_t legacy_scripts_offset, legacy_i2c_offset;
/* load needed defaults in case we can't parse this info */ /* 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->digital_min_front_porch = 0x4b;
bios->fmaxvco = 256000; bios->fmaxvco = 256000;
bios->fminvco = 128000; bios->fminvco = 128000;
...@@ -5706,14 +5606,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi ...@@ -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.crt = bios->data[legacy_i2c_offset];
bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1]; bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2]; 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) { if (bmplength > 74) {
bios->fmaxvco = ROM32(bmp[67]); bios->fmaxvco = ROM32(bmp[67]);
...@@ -6549,10 +6441,6 @@ parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp) ...@@ -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); ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
if (!ret) if (!ret)
return 1; /* stop parsing */ return 1; /* stop parsing */
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
entry->i2c_index,
&dcb->i2c[entry->i2c_index]);
} }
return 0; return 0;
...@@ -6562,7 +6450,6 @@ static int ...@@ -6562,7 +6450,6 @@ static int
parse_dcb_table(struct drm_device *dev, struct nvbios *bios) parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
{ {
struct dcb_table *dcb = &bios->dcb; struct dcb_table *dcb = &bios->dcb;
u16 i2ctabptr = 0x0000;
u8 *dcbt; u8 *dcbt;
dcbt = dcb_table(dev); dcbt = dcb_table(dev);
...@@ -6580,32 +6467,8 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios) ...@@ -6580,32 +6467,8 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
dcb->version = dcbt[0]; dcb->version = dcbt[0];
if (dcb->version >= 0x30) { if (dcb->version >= 0x30) {
i2ctabptr = ROM16(dcbt[4]);
dcb->gpio_table_ptr = ROM16(dcbt[10]); dcb->gpio_table_ptr = ROM16(dcbt[10]);
dcb->connector_table_ptr = ROM16(dcbt[20]); 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); dcb_outp_foreach(dev, NULL, parse_dcb_entry);
...@@ -6893,19 +6756,6 @@ nouveau_run_vbios_init(struct drm_device *dev) ...@@ -6893,19 +6756,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
return ret; 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 static bool
nouveau_bios_posted(struct drm_device *dev) nouveau_bios_posted(struct drm_device *dev)
{ {
...@@ -6942,6 +6792,10 @@ nouveau_bios_init(struct drm_device *dev) ...@@ -6942,6 +6792,10 @@ nouveau_bios_init(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
ret = nouveau_i2c_init(dev);
if (ret)
return ret;
ret = parse_dcb_table(dev, bios); ret = parse_dcb_table(dev, bios);
if (ret) if (ret)
return ret; return ret;
...@@ -6984,5 +6838,5 @@ nouveau_bios_init(struct drm_device *dev) ...@@ -6984,5 +6838,5 @@ nouveau_bios_init(struct drm_device *dev)
void void
nouveau_bios_takedown(struct drm_device *dev) nouveau_bios_takedown(struct drm_device *dev)
{ {
nouveau_bios_i2c_devices_takedown(dev); nouveau_i2c_fini(dev);
} }
...@@ -53,13 +53,6 @@ struct bit_entry { ...@@ -53,13 +53,6 @@ struct bit_entry {
int bit_table(struct drm_device *, u8 id, 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 { enum dcb_gpio_tag {
DCB_GPIO_TVDAC0 = 0xc, DCB_GPIO_TVDAC0 = 0xc,
DCB_GPIO_TVDAC1 = 0x2d, DCB_GPIO_TVDAC1 = 0x2d,
...@@ -166,10 +159,6 @@ struct dcb_table { ...@@ -166,10 +159,6 @@ struct dcb_table {
int entries; int entries;
struct dcb_entry entry[DCB_MAX_NUM_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; uint16_t gpio_table_ptr;
struct dcb_gpio_table gpio; struct dcb_gpio_table gpio;
uint16_t connector_table_ptr; uint16_t connector_table_ptr;
......
...@@ -793,6 +793,7 @@ struct drm_nouveau_private { ...@@ -793,6 +793,7 @@ struct drm_nouveau_private {
struct nouveau_vm *chan_vm; struct nouveau_vm *chan_vm;
struct nvbios vbios; struct nvbios vbios;
struct list_head i2c_ports;
struct nv04_mode_state mode_reg; struct nv04_mode_state mode_reg;
struct nv04_mode_state saved_reg; struct nv04_mode_state saved_reg;
......
...@@ -109,13 +109,6 @@ nv4e_i2c_getsda(void *data) ...@@ -109,13 +109,6 @@ nv4e_i2c_getsda(void *data)
return !!((nv_rd32(dev, i2c->rd) >> 16) & 8); 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 static int
nv50_i2c_getscl(void *data) nv50_i2c_getscl(void *data)
{ {
...@@ -125,7 +118,6 @@ nv50_i2c_getscl(void *data) ...@@ -125,7 +118,6 @@ nv50_i2c_getscl(void *data)
return !!(nv_rd32(dev, i2c->rd) & 1); return !!(nv_rd32(dev, i2c->rd) & 1);
} }
static int static int
nv50_i2c_getsda(void *data) nv50_i2c_getsda(void *data)
{ {
...@@ -166,125 +158,233 @@ nvd0_i2c_getsda(void *data) ...@@ -166,125 +158,233 @@ nvd0_i2c_getsda(void *data)
return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20); 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 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 drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_i2c_chan *i2c; struct nvbios *bios = &dev_priv->vbios;
int ret; struct nouveau_i2c_chan *port;
u8 *i2c, *entry, legacy[2][4] = {};
if (entry->chan) u8 version, entries, recordlen;
return -EEXIST; int ret, i;
INIT_LIST_HEAD(&dev_priv->i2c_ports);
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];
}
if (dev_priv->card_type >= NV_50 && if (i2c && version >= 0x30) {
dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) { entry = i2c[1] + i2c;
NV_ERROR(dev, "unknown i2c port %d\n", entry->read); entries = i2c[2];
return -EINVAL; recordlen = i2c[3];
} else
if (i2c) {
entry = i2c;
entries = 16;
recordlen = 4;
} else {
entry = legacy[0];
entries = 2;
recordlen = 4;
} }
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); for (i = 0; i < entries; i++, entry += recordlen) {
if (i2c == NULL) port = kzalloc(sizeof(*port), GFP_KERNEL);
return -ENOMEM; if (port == NULL) {
nouveau_i2c_fini(dev);
switch (entry->port_type) { return -ENOMEM;
case 0: }
i2c->bit.setsda = nv04_i2c_setsda;
i2c->bit.setscl = nv04_i2c_setscl; port->type = entry[3];
i2c->bit.getsda = nv04_i2c_getsda; if (version < 0x30) {
i2c->bit.getscl = nv04_i2c_getscl; port->type &= 0x07;
i2c->rd = entry->read; if (port->type == 0x07)
i2c->wr = entry->write; port->type = 0xff;
break; }
case 4:
i2c->bit.setsda = nv4e_i2c_setsda; if (port->type == 0xff) {
i2c->bit.setscl = nv4e_i2c_setscl; kfree(port);
i2c->bit.getsda = nv4e_i2c_getsda; continue;
i2c->bit.getscl = nv4e_i2c_getscl; }
i2c->rd = 0x600800 + entry->read;
i2c->wr = 0x600800 + entry->write; switch (port->type) {
break; case 0: /* NV04:NV50 */
case 5: port->wr = entry[0];
i2c->bit.setsda = nv50_i2c_setsda; port->rd = entry[1];
i2c->bit.setscl = nv50_i2c_setscl; port->bit.setsda = nv04_i2c_setsda;
if (dev_priv->card_type < NV_D0) { port->bit.setscl = nv04_i2c_setscl;
i2c->bit.getsda = nv50_i2c_getsda; port->bit.getsda = nv04_i2c_getsda;
i2c->bit.getscl = nv50_i2c_getscl; port->bit.getscl = nv04_i2c_getscl;
i2c->rd = nv50_i2c_port[entry->read]; break;
i2c->wr = i2c->rd; 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 { } else {
i2c->bit.getsda = nvd0_i2c_getsda; port->adapter.algo = &nouveau_dp_i2c_algo;
i2c->bit.getscl = nvd0_i2c_getscl; ret = i2c_add_adapter(&port->adapter);
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), if (ret) {
"nouveau-%s-%d", pci_name(dev->pdev), index); NV_ERROR(dev, "I2C%d: failed register: %d\n", i, ret);
i2c->adapter.owner = THIS_MODULE; kfree(port);
i2c->adapter.dev.parent = &dev->pdev->dev; continue;
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);
} else {
i2c->adapter.algo = &nouveau_dp_i2c_algo;
ret = i2c_add_adapter(&i2c->adapter);
}
if (ret) { list_add_tail(&port->head, &dev_priv->i2c_ports);
NV_ERROR(dev, "Failed to register i2c %d\n", index);
kfree(i2c);
return ret;
} }
entry->chan = i2c;
return 0; return 0;
} }
void void
nouveau_i2c_fini(struct drm_device *dev, struct dcb_i2c_entry *entry) nouveau_i2c_fini(struct drm_device *dev)
{ {
if (!entry->chan) struct drm_nouveau_private *dev_priv = dev->dev_private;
return; struct nouveau_i2c_chan *port, *tmp;
i2c_del_adapter(&entry->chan->adapter); list_for_each_entry_safe(port, tmp, &dev_priv->i2c_ports, head) {
kfree(entry->chan); i2c_del_adapter(&port->adapter);
entry->chan = NULL; kfree(port);
}
} }
struct nouveau_i2c_chan * 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 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 == 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;
}
}
if (index >= DCB_MAX_NUM_I2C_ENTRIES) list_for_each_entry(port, &dev_priv->i2c_ports, head) {
return NULL; if (port->index == index)
break;
}
if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) { if (&port->head == &dev_priv->i2c_ports)
uint32_t reg = 0xe500, val; return NULL;
if (i2c->port_type == 6) { if (dev_priv->card_type >= NV_50 && (port->dcb & 0x00000100)) {
reg += i2c->read * 0x50; u32 reg = 0x00e500, val;
if (port->type == 6) {
reg += port->rd * 0x50;
val = 0x2002; val = 0x2002;
} else { } else {
reg += ((i2c->entry & 0x1e00) >> 9) * 0x50; reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
val = 0xe001; val = 0xe001;
} }
...@@ -294,9 +394,7 @@ nouveau_i2c_find(struct drm_device *dev, int index) ...@@ -294,9 +394,7 @@ nouveau_i2c_find(struct drm_device *dev, int index)
nv_mask(dev, reg + 0x00, 0x0000f003, val); nv_mask(dev, reg + 0x00, 0x0000f003, val);
} }
if (!i2c->chan && nouveau_i2c_init(dev, i2c, index)) return port;
return NULL;
return i2c->chan;
} }
bool bool
......
...@@ -27,20 +27,26 @@ ...@@ -27,20 +27,26 @@
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include "drm_dp_helper.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 nouveau_i2c_chan {
struct i2c_adapter adapter; struct i2c_adapter adapter;
struct drm_device *dev; struct drm_device *dev;
struct i2c_algo_bit_data bit; struct i2c_algo_bit_data bit;
struct list_head head;
u8 index;
u8 type;
u32 dcb;
unsigned rd; unsigned rd;
unsigned wr; unsigned wr;
unsigned data; unsigned data;
}; };
int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); int nouveau_i2c_init(struct drm_device *);
void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); void nouveau_i2c_fini(struct drm_device *);
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, u8 index);
bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr); bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
int nouveau_i2c_identify(struct drm_device *dev, const char *what, int nouveau_i2c_identify(struct drm_device *dev, const char *what,
struct i2c_board_info *info, struct i2c_board_info *info,
......
...@@ -286,8 +286,6 @@ probe_monitoring_device(struct nouveau_i2c_chan *i2c, ...@@ -286,8 +286,6 @@ probe_monitoring_device(struct nouveau_i2c_chan *i2c,
static void static void
nouveau_temp_probe_i2c(struct drm_device *dev) 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[] = { struct i2c_board_info info[] = {
{ I2C_BOARD_INFO("w83l785ts", 0x2d) }, { I2C_BOARD_INFO("w83l785ts", 0x2d) },
{ I2C_BOARD_INFO("w83781d", 0x2d) }, { I2C_BOARD_INFO("w83781d", 0x2d) },
...@@ -296,11 +294,9 @@ nouveau_temp_probe_i2c(struct drm_device *dev) ...@@ -296,11 +294,9 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
{ I2C_BOARD_INFO("lm99", 0x4c) }, { I2C_BOARD_INFO("lm99", 0x4c) },
{ } { }
}; };
int idx = (dcb->version >= 0x40 ?
dcb->i2c_default_indices & 0xf : 2);
nouveau_i2c_identify(dev, "monitoring device", info, nouveau_i2c_identify(dev, "monitoring device", info,
probe_monitoring_device, idx); probe_monitoring_device, NV_I2C_DEFAULT(0));
} }
void void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment