intel_extreme: probe all GPIO pins

This commit is contained in:
Jessica Hamilton 2014-09-13 17:21:37 +12:00 committed by Adrien Destugues
parent 9965ac0677
commit cee64ce507

137
src/add-ons/accelerants/intel_extreme/mode.cpp Normal file → Executable file
View File

@ -73,6 +73,12 @@ struct pll_limits {
uint32 max_vco;
};
struct gpio_map {
const char* name;
uint32 pin;
uint32 validOn;
};
static void mode_fill_missing_bits(display_mode *, uint32);
@ -579,78 +585,87 @@ set_frame_buffer_base()
status_t
create_mode_list(void)
{
i2c_bus bus;
bus.cookie = (void*)(addr_t)INTEL_I2C_IO_A;
bus.set_signals = &set_i2c_signals;
bus.get_signals = &get_i2c_signals;
ddc2_init_timing(&bus);
// TODO: We may want to choose different GPIO pin maps
// for different generations of cards... not sure
const gpio_map gpioPinMap[] = {
{"ssc", INTEL_I2C_IO_B, 0},
{"vga", INTEL_I2C_IO_A, HEAD_MODE_A_ANALOG},
{"lvds", INTEL_I2C_IO_C, HEAD_MODE_LVDS_PANEL},
{"dpc", INTEL_I2C_IO_D, 0},
{"dpb", INTEL_I2C_IO_E, 0},
{"dpd", INTEL_I2C_IO_F, 0},
};
// TODO: We may want to do extra validation on gpio validOn
// vs the HEAD_MODE_ in head_mode
for (uint32 i = 0; i < sizeof(gpioPinMap) / sizeof(gpioPinMap[0]); i++) {
i2c_bus bus;
bus.cookie = (void*)gpioPinMap[i].pin;
bus.set_signals = &set_i2c_signals;
bus.get_signals = &get_i2c_signals;
ddc2_init_timing(&bus);
status_t result = ddc2_read_edid1(&bus, &gInfo->edid_info,
NULL, NULL);
if (result != B_OK)
continue;
TRACE("found edid data on gpio '%s'\n", gpioPinMap[i].name);
status_t error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL);
if (error == B_OK) {
edid_dump(&gInfo->edid_info);
gInfo->has_edid = true;
if (gInfo->shared_info->single_head_locked)
gInfo->head_mode = HEAD_MODE_A_ANALOG;
} else {
TRACE("getting EDID on port A (analog) failed: %s. "
"Trying on port C (lvds)\n", strerror(error));
bus.cookie = (void*)INTEL_I2C_IO_C;
error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL);
if (error == B_OK) {
edid_dump(&gInfo->edid_info);
gInfo->has_edid = true;
} else if (gInfo->shared_info->has_vesa_edid_info) {
TRACE("getting EDID on port C failed: %s. Use VESA EDID info\n",
strerror(error));
memcpy(&gInfo->edid_info, &gInfo->shared_info->vesa_edid_info,
sizeof(edid1_info));
gInfo->has_edid = true;
} else {
TRACE("getting EDID on port C failed: %s\n",
strerror(error));
// We could not read any EDID info. Fallback to creating a list with
// only the mode set up by the BIOS.
// TODO: support lower modes via scaling and windowing
if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0)
|| ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& gInfo->shared_info->got_vbt)) {
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
& ~(B_PAGE_SIZE - 1);
// TODO: We may want to probe multiple GPIO pins here
// someday and store valid ones for multi-head support.
// For now, we break on the first valid one.
break;
}
display_mode* list;
area_id area = create_area("intel extreme modes",
(void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (area < B_OK)
return area;
if (!gInfo->has_edid) {
// We could not read any EDID info. Fallback to creating a list with
// only the mode set up by the BIOS.
// TODO: support lower modes via scaling and windowing
if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0)
|| ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& gInfo->shared_info->got_vbt)) {
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
& ~(B_PAGE_SIZE - 1);
// Prefer information dumped directly from VBT, as the BIOS
// one may have display scaling, but only do this if the VBT
// resolution is higher than the BIOS one.
if (gInfo->shared_info->got_vbt
&& gInfo->shared_info->current_mode.virtual_width
>= gInfo->lvds_panel_mode.virtual_width
&& gInfo->shared_info->current_mode.virtual_height
>= gInfo->lvds_panel_mode.virtual_height) {
memcpy(list, &gInfo->shared_info->current_mode,
sizeof(display_mode));
mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL);
} else {
memcpy(list, &gInfo->lvds_panel_mode,
sizeof(display_mode));
display_mode* list;
area_id area = create_area("intel extreme modes",
(void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (area < B_OK)
return area;
if (gInfo->shared_info->got_vbt)
TRACE("intel_extreme: ignoring VBT mode.");
}
// Prefer information dumped directly from VBT, as the BIOS
// one may have display scaling, but only do this if the VBT
// resolution is higher than the BIOS one.
if (gInfo->shared_info->got_vbt
&& gInfo->shared_info->current_mode.virtual_width
>= gInfo->lvds_panel_mode.virtual_width
&& gInfo->shared_info->current_mode.virtual_height
>= gInfo->lvds_panel_mode.virtual_height) {
memcpy(list, &gInfo->shared_info->current_mode,
sizeof(display_mode));
mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL);
} else {
memcpy(list, &gInfo->lvds_panel_mode,
sizeof(display_mode));
gInfo->mode_list_area = area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = 1;
return B_OK;
if (gInfo->shared_info->got_vbt)
TRACE("intel_extreme: ignoring VBT mode.");
}
gInfo->mode_list_area = area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = 1;
return B_OK;
}
}