diff options
| author | Ben Skeggs <bskeggs@redhat.com> | 2010-05-12 00:38:25 -0400 |
|---|---|---|
| committer | Ben Skeggs <bskeggs@redhat.com> | 2010-05-19 02:22:05 -0400 |
| commit | f8b0be1a75dc62d2b5f5b9a8406c97d6c5f82b7d (patch) | |
| tree | ebfae41b6b36206b26b47af26e5461a2a2725c75 | |
| parent | 92b9618761465d190b68519bcc6a6fbd8847cf2c (diff) | |
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>
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 165 |
1 files changed, 88 insertions, 77 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index d8dcb362e8b5..b0b98d7f4ea9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c | |||
| @@ -715,6 +715,83 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev) | |||
| 715 | return dcb_entry; | 715 | return dcb_entry; |
| 716 | } | 716 | } |
| 717 | 717 | ||
| 718 | static int | ||
| 719 | read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, int index, struct dcb_i2c_entry *i2c) | ||
| 720 | { | ||
| 721 | uint8_t dcb_i2c_ver = dcb_version, headerlen = 0, entry_len = 4; | ||
| 722 | int i2c_entries = DCB_MAX_NUM_I2C_ENTRIES; | ||
| 723 | int recordoffset = 0, rdofs = 1, wrofs = 0; | ||
| 724 | uint8_t port_type = 0; | ||
| 725 | |||
| 726 | if (!i2ctable) | ||
| 727 | return -EINVAL; | ||
| 728 | |||
| 729 | if (dcb_version >= 0x30) { | ||
| 730 | if (i2ctable[0] != dcb_version) /* necessary? */ | ||
| 731 | NV_WARN(dev, | ||
| 732 | "DCB I2C table version mismatch (%02X vs %02X)\n", | ||
| 733 | i2ctable[0], dcb_version); | ||
| 734 | dcb_i2c_ver = i2ctable[0]; | ||
| 735 | headerlen = i2ctable[1]; | ||
| 736 | if (i2ctable[2] <= DCB_MAX_NUM_I2C_ENTRIES) | ||
| 737 | i2c_entries = i2ctable[2]; | ||
| 738 | else | ||
| 739 | NV_WARN(dev, | ||
| 740 | "DCB I2C table has more entries than indexable " | ||
| 741 | "(%d entries, max %d)\n", i2ctable[2], | ||
| 742 | DCB_MAX_NUM_I2C_ENTRIES); | ||
| 743 | entry_len = i2ctable[3]; | ||
| 744 | /* [4] is i2c_default_indices, read in parse_dcb_table() */ | ||
| 745 | } | ||
| 746 | /* | ||
| 747 | * It's your own fault if you call this function on a DCB 1.1 BIOS -- | ||
| 748 | * the test below is for DCB 1.2 | ||
| 749 | */ | ||
| 750 | if (dcb_version < 0x14) { | ||
| 751 | recordoffset = 2; | ||
| 752 | rdofs = 0; | ||
| 753 | wrofs = 1; | ||
| 754 | } | ||
| 755 | |||
| 756 | if (index == 0xf) | ||
| 757 | return 0; | ||
| 758 | if (index >= i2c_entries) { | ||
| 759 | NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n", | ||
| 760 | index, i2ctable[2]); | ||
| 761 | return -ENOENT; | ||
| 762 | } | ||
| 763 | if (i2ctable[headerlen + entry_len * index + 3] == 0xff) { | ||
| 764 | NV_ERROR(dev, "DCB I2C entry invalid\n"); | ||
| 765 | return -EINVAL; | ||
| 766 | } | ||
| 767 | |||
| 768 | if (dcb_i2c_ver >= 0x30) { | ||
| 769 | port_type = i2ctable[headerlen + recordoffset + 3 + entry_len * index]; | ||
| 770 | |||
| 771 | /* | ||
| 772 | * Fixup for chips using same address offset for read and | ||
| 773 | * write. | ||
| 774 | */ | ||
| 775 | if (port_type == 4) /* seen on C51 */ | ||
| 776 | rdofs = wrofs = 1; | ||
| 777 | if (port_type >= 5) /* G80+ */ | ||
| 778 | rdofs = wrofs = 0; | ||
| 779 | } | ||
| 780 | |||
| 781 | if (dcb_i2c_ver >= 0x40) { | ||
| 782 | if (port_type != 5 && port_type != 6) | ||
| 783 | NV_WARN(dev, "DCB I2C table has port type %d\n", port_type); | ||
| 784 | |||
| 785 | i2c->entry = ROM32(i2ctable[headerlen + recordoffset + entry_len * index]); | ||
| 786 | } | ||
| 787 | |||
| 788 | i2c->port_type = port_type; | ||
| 789 | i2c->read = i2ctable[headerlen + recordoffset + rdofs + entry_len * index]; | ||
| 790 | i2c->write = i2ctable[headerlen + recordoffset + wrofs + entry_len * index]; | ||
| 791 | |||
| 792 | return 0; | ||
| 793 | } | ||
| 794 | |||
| 718 | static struct nouveau_i2c_chan * | 795 | static struct nouveau_i2c_chan * |
| 719 | init_i2c_device_find(struct drm_device *dev, int i2c_index) | 796 | init_i2c_device_find(struct drm_device *dev, int i2c_index) |
| 720 | { | 797 | { |
| @@ -734,6 +811,17 @@ init_i2c_device_find(struct drm_device *dev, int i2c_index) | |||
| 734 | if (i2c_index == 0x80) /* g80+ */ | 811 | if (i2c_index == 0x80) /* g80+ */ |
| 735 | i2c_index = dcb->i2c_default_indices & 0xf; | 812 | i2c_index = dcb->i2c_default_indices & 0xf; |
| 736 | 813 | ||
| 814 | if (i2c_index > DCB_MAX_NUM_I2C_ENTRIES) { | ||
| 815 | NV_ERROR(dev, "invalid i2c_index 0x%x\n", i2c_index); | ||
| 816 | return NULL; | ||
| 817 | } | ||
| 818 | |||
| 819 | /* Make sure i2c table entry has been parsed, it may not | ||
| 820 | * have been if this is a bus not referenced by a DCB encoder | ||
| 821 | */ | ||
| 822 | read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, | ||
| 823 | i2c_index, &dcb->i2c[i2c_index]); | ||
| 824 | |||
| 737 | return nouveau_i2c_find(dev, i2c_index); | 825 | return nouveau_i2c_find(dev, i2c_index); |
| 738 | } | 826 | } |
| 739 | 827 | ||
| @@ -5090,83 +5178,6 @@ static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len) | |||
| 5090 | return 0; | 5178 | return 0; |
| 5091 | } | 5179 | } |
| 5092 | 5180 | ||
| 5093 | static int | ||
| 5094 | read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, int index, struct dcb_i2c_entry *i2c) | ||
| 5095 | { | ||
| 5096 | uint8_t dcb_i2c_ver = dcb_version, headerlen = 0, entry_len = 4; | ||
| 5097 | int i2c_entries = DCB_MAX_NUM_I2C_ENTRIES; | ||
| 5098 | int recordoffset = 0, rdofs = 1, wrofs = 0; | ||
| 5099 | uint8_t port_type = 0; | ||
| 5100 | |||
| 5101 | if (!i2ctable) | ||
| 5102 | return -EINVAL; | ||
| 5103 | |||
| 5104 | if (dcb_version >= 0x30) { | ||
| 5105 | if (i2ctable[0] != dcb_version) /* necessary? */ | ||
| 5106 | NV_WARN(dev, | ||
| 5107 | "DCB I2C table version mismatch (%02X vs %02X)\n", | ||
| 5108 | i2ctable[0], dcb_version); | ||
| 5109 | dcb_i2c_ver = i2ctable[0]; | ||
| 5110 | headerlen = i2ctable[1]; | ||
| 5111 | if (i2ctable[2] <= DCB_MAX_NUM_I2C_ENTRIES) | ||
| 5112 | i2c_entries = i2ctable[2]; | ||
| 5113 | else | ||
| 5114 | NV_WARN(dev, | ||
| 5115 | "DCB I2C table has more entries than indexable " | ||
| 5116 | "(%d entries, max %d)\n", i2ctable[2], | ||
| 5117 | DCB_MAX_NUM_I2C_ENTRIES); | ||
| 5118 | entry_len = i2ctable[3]; | ||
| 5119 | /* [4] is i2c_default_indices, read in parse_dcb_table() */ | ||
| 5120 | } | ||
| 5121 | /* | ||
| 5122 | * It's your own fault if you call this function on a DCB 1.1 BIOS -- | ||
| 5123 | * the test below is for DCB 1.2 | ||
| 5124 | */ | ||
| 5125 | if (dcb_version < 0x14) { | ||
| 5126 | recordoffset = 2; | ||
| 5127 | rdofs = 0; | ||
| 5128 | wrofs = 1; | ||
| 5129 | } | ||
| 5130 | |||
| 5131 | if (index == 0xf) | ||
| 5132 | return 0; | ||
| 5133 | if (index >= i2c_entries) { | ||
| 5134 | NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n", | ||
| 5135 | index, i2ctable[2]); | ||
| 5136 | return -ENOENT; | ||
| 5137 | } | ||
| 5138 | if (i2ctable[headerlen + entry_len * index + 3] == 0xff) { | ||
| 5139 | NV_ERROR(dev, "DCB I2C entry invalid\n"); | ||
| 5140 | return -EINVAL; | ||
| 5141 | } | ||
| 5142 | |||
| 5143 | if (dcb_i2c_ver >= 0x30) { | ||
| 5144 | port_type = i2ctable[headerlen + recordoffset + 3 + entry_len * index]; | ||
| 5145 | |||
| 5146 | /* | ||
| 5147 | * Fixup for chips using same address offset for read and | ||
| 5148 | * write. | ||
| 5149 | */ | ||
| 5150 | if (port_type == 4) /* seen on C51 */ | ||
| 5151 | rdofs = wrofs = 1; | ||
| 5152 | if (port_type >= 5) /* G80+ */ | ||
| 5153 | rdofs = wrofs = 0; | ||
| 5154 | } | ||
| 5155 | |||
| 5156 | if (dcb_i2c_ver >= 0x40) { | ||
| 5157 | if (port_type != 5 && port_type != 6) | ||
| 5158 | NV_WARN(dev, "DCB I2C table has port type %d\n", port_type); | ||
| 5159 | |||
| 5160 | i2c->entry = ROM32(i2ctable[headerlen + recordoffset + entry_len * index]); | ||
| 5161 | } | ||
| 5162 | |||
| 5163 | i2c->port_type = port_type; | ||
| 5164 | i2c->read = i2ctable[headerlen + recordoffset + rdofs + entry_len * index]; | ||
| 5165 | i2c->write = i2ctable[headerlen + recordoffset + wrofs + entry_len * index]; | ||
| 5166 | |||
| 5167 | return 0; | ||
| 5168 | } | ||
| 5169 | |||
| 5170 | static struct dcb_gpio_entry * | 5181 | static struct dcb_gpio_entry * |
| 5171 | new_gpio_entry(struct nvbios *bios) | 5182 | new_gpio_entry(struct nvbios *bios) |
| 5172 | { | 5183 | { |
