diff options
author | Marcin KoĆcielnicki <koriakin@0x04.net> | 2010-07-03 22:47:16 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-08-05 18:35:50 -0400 |
commit | b715d64028ea90bcb67b3823ae1cc908a4ae0bc6 (patch) | |
tree | 0725debf2f98cb2709805e011d2f818c9e50b9a1 /drivers/gpu/drm/nouveau/nouveau_bios.c | |
parent | e3a1924f3e5aeabdb1a1ae1a87b4097e48b7f2c5 (diff) |
drm/nouveau: implement init table opcodex 0x5e and 0x9a
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Marcin KoĆcielnicki <koriakin@0x04.net>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_bios.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 6dd00ffa63a0..8f1f16276f03 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c | |||
@@ -2020,6 +2020,64 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | |||
2020 | } | 2020 | } |
2021 | 2021 | ||
2022 | static int | 2022 | static int |
2023 | init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | ||
2024 | { | ||
2025 | /* | ||
2026 | * INIT_I2C_IF opcode: 0x5E ('^') | ||
2027 | * | ||
2028 | * offset (8 bit): opcode | ||
2029 | * offset + 1 (8 bit): DCB I2C table entry index | ||
2030 | * offset + 2 (8 bit): I2C slave address | ||
2031 | * offset + 3 (8 bit): I2C register | ||
2032 | * offset + 4 (8 bit): mask | ||
2033 | * offset + 5 (8 bit): data | ||
2034 | * | ||
2035 | * Read the register given by "I2C register" on the device addressed | ||
2036 | * by "I2C slave address" on the I2C bus given by "DCB I2C table | ||
2037 | * entry index". Compare the result AND "mask" to "data". | ||
2038 | * If they're not equal, skip subsequent opcodes until condition is | ||
2039 | * inverted (INIT_NOT), or we hit INIT_RESUME | ||
2040 | */ | ||
2041 | |||
2042 | uint8_t i2c_index = bios->data[offset + 1]; | ||
2043 | uint8_t i2c_address = bios->data[offset + 2] >> 1; | ||
2044 | uint8_t reg = bios->data[offset + 3]; | ||
2045 | uint8_t mask = bios->data[offset + 4]; | ||
2046 | uint8_t data = bios->data[offset + 5]; | ||
2047 | struct nouveau_i2c_chan *chan; | ||
2048 | union i2c_smbus_data val; | ||
2049 | int ret; | ||
2050 | |||
2051 | /* no execute check by design */ | ||
2052 | |||
2053 | BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n", | ||
2054 | offset, i2c_index, i2c_address); | ||
2055 | |||
2056 | chan = init_i2c_device_find(bios->dev, i2c_index); | ||
2057 | if (!chan) | ||
2058 | return -ENODEV; | ||
2059 | |||
2060 | ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, | ||
2061 | I2C_SMBUS_READ, reg, | ||
2062 | I2C_SMBUS_BYTE_DATA, &val); | ||
2063 | if (ret < 0) { | ||
2064 | BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], " | ||
2065 | "Mask: 0x%02X, Data: 0x%02X\n", | ||
2066 | offset, reg, mask, data); | ||
2067 | iexec->execute = 0; | ||
2068 | return 6; | ||
2069 | } | ||
2070 | |||
2071 | BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, " | ||
2072 | "Mask: 0x%02X, Data: 0x%02X\n", | ||
2073 | offset, reg, val.byte, mask, data); | ||
2074 | |||
2075 | iexec->execute = ((val.byte & mask) == data); | ||
2076 | |||
2077 | return 6; | ||
2078 | } | ||
2079 | |||
2080 | static int | ||
2023 | init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | 2081 | init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) |
2024 | { | 2082 | { |
2025 | /* | 2083 | /* |
@@ -3517,6 +3575,69 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | |||
3517 | return len; | 3575 | return len; |
3518 | } | 3576 | } |
3519 | 3577 | ||
3578 | static int | ||
3579 | init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | ||
3580 | { | ||
3581 | /* | ||
3582 | * INIT_I2C_LONG_IF opcode: 0x9A ('') | ||
3583 | * | ||
3584 | * offset (8 bit): opcode | ||
3585 | * offset + 1 (8 bit): DCB I2C table entry index | ||
3586 | * offset + 2 (8 bit): I2C slave address | ||
3587 | * offset + 3 (16 bit): I2C register | ||
3588 | * offset + 5 (8 bit): mask | ||
3589 | * offset + 6 (8 bit): data | ||
3590 | * | ||
3591 | * Read the register given by "I2C register" on the device addressed | ||
3592 | * by "I2C slave address" on the I2C bus given by "DCB I2C table | ||
3593 | * entry index". Compare the result AND "mask" to "data". | ||
3594 | * If they're not equal, skip subsequent opcodes until condition is | ||
3595 | * inverted (INIT_NOT), or we hit INIT_RESUME | ||
3596 | */ | ||
3597 | |||
3598 | uint8_t i2c_index = bios->data[offset + 1]; | ||
3599 | uint8_t i2c_address = bios->data[offset + 2] >> 1; | ||
3600 | uint8_t reglo = bios->data[offset + 3]; | ||
3601 | uint8_t reghi = bios->data[offset + 4]; | ||
3602 | uint8_t mask = bios->data[offset + 5]; | ||
3603 | uint8_t data = bios->data[offset + 6]; | ||
3604 | struct nouveau_i2c_chan *chan; | ||
3605 | uint8_t buf0[2] = { reghi, reglo }; | ||
3606 | uint8_t buf1[1]; | ||
3607 | struct i2c_msg msg[2] = { | ||
3608 | { i2c_address, 0, 1, buf0 }, | ||
3609 | { i2c_address, I2C_M_RD, 1, buf1 }, | ||
3610 | }; | ||
3611 | int ret; | ||
3612 | |||
3613 | /* no execute check by design */ | ||
3614 | |||
3615 | BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n", | ||
3616 | offset, i2c_index, i2c_address); | ||
3617 | |||
3618 | chan = init_i2c_device_find(bios->dev, i2c_index); | ||
3619 | if (!chan) | ||
3620 | return -ENODEV; | ||
3621 | |||
3622 | |||
3623 | ret = i2c_transfer(&chan->adapter, msg, 2); | ||
3624 | if (ret < 0) { | ||
3625 | BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], " | ||
3626 | "Mask: 0x%02X, Data: 0x%02X\n", | ||
3627 | offset, reghi, reglo, mask, data); | ||
3628 | iexec->execute = 0; | ||
3629 | return 7; | ||
3630 | } | ||
3631 | |||
3632 | BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, " | ||
3633 | "Mask: 0x%02X, Data: 0x%02X\n", | ||
3634 | offset, reghi, reglo, buf1[0], mask, data); | ||
3635 | |||
3636 | iexec->execute = ((buf1[0] & mask) == data); | ||
3637 | |||
3638 | return 7; | ||
3639 | } | ||
3640 | |||
3520 | static struct init_tbl_entry itbl_entry[] = { | 3641 | static struct init_tbl_entry itbl_entry[] = { |
3521 | /* command name , id , length , offset , mult , command handler */ | 3642 | /* command name , id , length , offset , mult , command handler */ |
3522 | /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */ | 3643 | /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */ |
@@ -3547,6 +3668,7 @@ static struct init_tbl_entry itbl_entry[] = { | |||
3547 | { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, | 3668 | { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, |
3548 | /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ | 3669 | /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ |
3549 | { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, | 3670 | { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, |
3671 | { "INIT_I2C_IF" , 0x5E, init_i2c_if }, | ||
3550 | { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg }, | 3672 | { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg }, |
3551 | { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io }, | 3673 | { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io }, |
3552 | { "INIT_COMPUTE_MEM" , 0x63, init_compute_mem }, | 3674 | { "INIT_COMPUTE_MEM" , 0x63, init_compute_mem }, |
@@ -3580,6 +3702,7 @@ static struct init_tbl_entry itbl_entry[] = { | |||
3580 | { "INIT_97" , 0x97, init_97 }, | 3702 | { "INIT_97" , 0x97, init_97 }, |
3581 | { "INIT_AUXCH" , 0x98, init_auxch }, | 3703 | { "INIT_AUXCH" , 0x98, init_auxch }, |
3582 | { "INIT_ZM_AUXCH" , 0x99, init_zm_auxch }, | 3704 | { "INIT_ZM_AUXCH" , 0x99, init_zm_auxch }, |
3705 | { "INIT_I2C_LONG_IF" , 0x9A, init_i2c_long_if }, | ||
3583 | { NULL , 0 , NULL } | 3706 | { NULL , 0 , NULL } |
3584 | }; | 3707 | }; |
3585 | 3708 | ||