2 * Copyright 2007 Jérôme Glisse
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
26 * Jérôme Glisse <glisse@freedesktop.org>
28 #include "radeon_ms.h"
30 extern struct radeon_ms_output radeon_ms_dac1;
31 extern struct radeon_ms_output radeon_ms_dac2;
32 extern const struct drm_output_funcs radeon_ms_output_funcs;
34 static struct combios_connector_chip_info *
35 radeon_ms_combios_get_connector_chip_info(struct drm_device *dev, int chip_num)
37 struct drm_radeon_private *dev_priv = dev->dev_private;
38 struct radeon_ms_rom *rom = &dev_priv->rom;
39 struct combios_header *header;
40 struct combios_connector_table *connector_table;
41 struct combios_connector_chip_info *connector_chip_info;
45 if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) {
48 header = rom->rom.combios_header;
49 offset = header->usPointerToExtendedInitTable2;
50 if ((offset + sizeof(struct combios_connector_table)) > rom->rom_size) {
51 DRM_INFO("[radeon_ms] wrong COMBIOS connector offset\n");
57 connector_table = (struct combios_connector_table *)
58 &rom->rom_image[offset];
59 numof_chips = (connector_table->ucConnectorHeader &
60 BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK) >>
61 BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT;
62 DRM_INFO("[radeon_ms] COMBIOS number of chip: %d (table rev: %d)\n",
64 (connector_table->ucConnectorHeader &
65 BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK) >>
66 BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT);
67 for (i = 0; i < numof_chips; i++) {
70 connector_chip_info = &connector_table->sChipConnectorInfo[i];
71 chip = (connector_chip_info->ucChipHeader &
72 BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK) >>
73 BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT;
74 DRM_INFO("[radeon_ms] COMBIOS chip: %d (asked for: %d)\n",
76 if (chip == chip_num) {
77 return connector_chip_info;
83 static int radeon_combios_get_connector_infos(struct drm_device *dev,
90 struct drm_radeon_private *dev_priv = dev->dev_private;
92 *connector_type = (connector_info & BIOS_CONNECTOR_INFO__TYPE__MASK) >>
93 BIOS_CONNECTOR_INFO__TYPE__SHIFT;
94 *ddc_line = (connector_info & BIOS_CONNECTOR_INFO__DDC_LINE__MASK) >>
95 BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT;
96 *tmds_type = (connector_info & BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK) >>
97 BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT;
98 *dac_type = (connector_info & BIOS_CONNECTOR_INFO__DAC_TYPE__MASK) >>
99 BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT;
101 /* most XPRESS chips seem to specify DDC_CRT2 for their
102 * VGA DDC port, however DDC never seems to work on that
103 * port. Some have reported success on DDC_MONID, so
104 * lets see what happens with that.
106 if (dev_priv->family == CHIP_RS400 &&
107 *connector_type == BIOS_CONNECTOR_TYPE__CRT &&
108 *ddc_line == BIOS_DDC_LINE__CRT2) {
109 *ddc_line = BIOS_DDC_LINE__MONID01;
111 /* XPRESS desktop chips seem to have a proprietary
112 * connector listed for DVI-D, try and do the right
115 if (dev_priv->family == CHIP_RS400 &&
116 *connector_type == BIOS_CONNECTOR_TYPE__PROPRIETARY) {
117 DRM_INFO("[radeon_ms] COMBIOS Proprietary connector "
118 "found, assuming DVI-D\n");
120 *tmds_type = BIOS_TMDS_TYPE__EXTERNAL;
121 *connector_type = BIOS_CONNECTOR_TYPE__DVI_D;
126 static int radeon_ms_combios_connector_add(struct drm_device *dev,
127 int connector_number,
131 struct drm_radeon_private *dev_priv = dev->dev_private;
132 struct radeon_ms_connector *connector = NULL;
133 struct drm_output *output = NULL;
135 connector = drm_alloc(sizeof(struct radeon_ms_connector),
137 if (connector == NULL) {
138 radeon_ms_connectors_destroy(dev);
141 memset(connector, 0, sizeof(struct radeon_ms_connector));
142 connector->monitor_type = MT_NONE;
143 connector->type = connector_type;
144 connector->i2c_reg = i2c_reg;
146 switch (connector->type) {
148 sprintf(connector->name, "VGA");
150 case CONNECTOR_DVI_I:
151 sprintf(connector->name, "DVI-I");
153 case CONNECTOR_DVI_D:
154 sprintf(connector->name, "DVI-D");
157 sprintf(connector->name, "UNKNOWN-CONNECTOR");
162 connector->i2c = radeon_ms_i2c_create(dev,
165 if (connector->i2c == NULL) {
166 radeon_ms_connectors_destroy(dev);
170 connector->i2c = NULL;
173 output = drm_output_create(dev, &radeon_ms_output_funcs,
175 if (output == NULL) {
176 radeon_ms_connectors_destroy(dev);
179 connector->output = output;
180 output->driver_private = connector;
181 output->possible_crtcs = 0x3;
182 dev_priv->connectors[connector_number] = connector;
186 int radeon_ms_combios_get_properties(struct drm_device *dev)
188 struct drm_radeon_private *dev_priv = dev->dev_private;
189 struct radeon_ms_rom *rom = &dev_priv->rom;
190 struct combios_pll_block *pll_block;
191 struct combios_header *header;
194 if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) {
197 header = rom->rom.combios_header;
198 offset = header->usPointerToPllInfoBlock;
199 if ((offset + sizeof(struct combios_pll_block)) > rom->rom_size) {
200 DRM_INFO("[radeon_ms] wrong COMBIOS pll block offset\n");
206 pll_block = (struct combios_pll_block *)&rom->rom_image[offset];
207 dev_priv->properties.pll_reference_freq = pll_block->usDotClockRefFreq;
208 dev_priv->properties.pll_reference_div = pll_block->usDotClockRefDiv;
209 dev_priv->properties.pll_min_pll_freq = pll_block->ulDotClockMinFreq;
210 dev_priv->properties.pll_max_pll_freq = pll_block->ulDotClockMaxFreq;
211 dev_priv->properties.pll_reference_freq *= 10;
212 dev_priv->properties.pll_min_pll_freq *= 10;
213 dev_priv->properties.pll_max_pll_freq *= 10;
214 DRM_INFO("[radeon_ms] COMBIOS pll reference frequency : %d\n",
215 dev_priv->properties.pll_reference_freq);
216 DRM_INFO("[radeon_ms] COMBIOS pll reference divider : %d\n",
217 dev_priv->properties.pll_reference_div);
218 DRM_INFO("[radeon_ms] COMBIOS pll minimum frequency : %d\n",
219 dev_priv->properties.pll_min_pll_freq);
220 DRM_INFO("[radeon_ms] COMBIOS pll maximum frequency : %d\n",
221 dev_priv->properties.pll_max_pll_freq);
225 int radeon_ms_connectors_from_combios(struct drm_device *dev)
227 struct drm_radeon_private *dev_priv = dev->dev_private;
228 struct combios_connector_chip_info *connector_chip_info;
229 int connector_type, ddc_line, tmds_type, dac_type;
230 int dac1, dac2, tmdsint, tmdsext;
231 int numof_connector, i, c = 0, added, j;
235 dac1 = dac2 = tmdsint = tmdsext = -1;
236 connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1);
237 if (connector_chip_info == NULL) {
240 numof_connector = (connector_chip_info->ucChipHeader &
241 BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >>
242 BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT;
243 DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n",
245 for (i = 0; i < numof_connector; i++) {
246 int connector_info = connector_chip_info->sConnectorInfo[i];
248 ret = radeon_combios_get_connector_infos(dev,
256 case BIOS_DDC_LINE__MONID01:
257 i2c_reg = GPIO_MONID;
259 case BIOS_DDC_LINE__DVI:
260 i2c_reg = GPIO_DVI_DDC;
262 case BIOS_DDC_LINE__VGA:
265 case BIOS_DDC_LINE__CRT2:
266 i2c_reg = GPIO_CRT2_DDC;
268 case BIOS_DDC_LINE__GPIOPAD:
271 case BIOS_DDC_LINE__ZV_LCDPAD:
272 i2c_reg = VIPPAD1_EN;
279 switch (connector_type) {
280 case BIOS_CONNECTOR_TYPE__CRT:
281 ret = radeon_ms_combios_connector_add(dev, c,
289 case BIOS_CONNECTOR_TYPE__DVI_I:
290 ret = radeon_ms_combios_connector_add(dev, c,
298 case BIOS_CONNECTOR_TYPE__DVI_D:
299 ret = radeon_ms_combios_connector_add(dev, c,
312 /* find to which output this connector is associated
313 * by following same algo as in:
314 * radeon_ms_outputs_from_combios*/
316 case BIOS_DAC_TYPE__CRT:
320 dev_priv->connectors[c]->outputs[j++] = dac1;
322 case BIOS_DAC_TYPE__NON_CRT:
326 dev_priv->connectors[c]->outputs[j++] = dac2;
331 case BIOS_TMDS_TYPE__INTERNAL:
335 dev_priv->connectors[c]->outputs[j++] = tmdsint;
337 case BIOS_TMDS_TYPE__EXTERNAL:
341 dev_priv->connectors[c]->outputs[j++] = tmdsext;
351 int radeon_ms_outputs_from_combios(struct drm_device *dev)
353 struct drm_radeon_private *dev_priv = dev->dev_private;
354 struct combios_connector_chip_info *connector_chip_info;
355 int connector_type, ddc_line, tmds_type, dac_type;
356 int numof_connector, i, dac1_present, dac2_present, c = 0;
359 dac1_present = dac2_present = 0;
360 connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1);
361 if (connector_chip_info == NULL) {
364 numof_connector = (connector_chip_info->ucChipHeader &
365 BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >>
366 BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT;
367 DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n",
369 for (i = 0; i < numof_connector; i++) {
370 int connector_info = connector_chip_info->sConnectorInfo[i];
372 ret = radeon_combios_get_connector_infos(dev,
379 if (!dac1_present && dac_type == BIOS_DAC_TYPE__CRT) {
380 dev_priv->outputs[c] =
381 drm_alloc(sizeof(struct radeon_ms_output),
383 if (dev_priv->outputs[c] == NULL) {
384 radeon_ms_outputs_destroy(dev);
387 memcpy(dev_priv->outputs[c], &radeon_ms_dac1,
388 sizeof(struct radeon_ms_output));
389 dev_priv->outputs[c]->dev = dev;
390 dev_priv->outputs[c]->initialize(dev_priv->outputs[c]);
394 if (!dac2_present && dac_type == BIOS_DAC_TYPE__NON_CRT) {
395 dev_priv->outputs[c] =
396 drm_alloc(sizeof(struct radeon_ms_output),
398 if (dev_priv->outputs[c] == NULL) {
399 radeon_ms_outputs_destroy(dev);
402 memcpy(dev_priv->outputs[c], &radeon_ms_dac2,
403 sizeof(struct radeon_ms_output));
404 dev_priv->outputs[c]->dev = dev;
405 dev_priv->outputs[c]->initialize(dev_priv->outputs[c]);