mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-04 18:16:42 +07:00
drm/nouveau: ensure we've parsed i2c table entry for INIT_*I2C* handlers
We may not have parsed the entry yet if the i2c_index is for an i2c bus that's not referenced by a DCB encoder. This could be done oh so much more nicely, except we have to care about prehistoric DCB tables too, and they make life painful. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
92b9618761
commit
f8b0be1a75
@ -715,6 +715,83 @@ 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)
|
||||
{
|
||||
@ -734,6 +811,17 @@ init_i2c_device_find(struct drm_device *dev, int i2c_index)
|
||||
if (i2c_index == 0x80) /* g80+ */
|
||||
i2c_index = dcb->i2c_default_indices & 0xf;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -5090,83 +5178,6 @@ static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 dcb_gpio_entry *
|
||||
new_gpio_entry(struct nvbios *bios)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user