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 /drivers/gpu/drm | |
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>
Diffstat (limited to 'drivers/gpu/drm')
-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 | { |