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 | |
| 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')
| -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 | ||
