intel_extreme: parse VBT device configs, use this to skip unused ports
* BDB version from 111 * for DDI from Gen9 * for HDMI and DisplayPort from Gen6 * use the first port to create the mode list * also probe DDI Port A * the aux channel helps to select the correct dp aux registers. Change-Id: I80549a6ec0477bed768cc5f388959b606d50c1b7 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5286 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
parent
2aac05508f
commit
46bbf334f6
@ -285,7 +285,104 @@ struct ring_buffer {
|
||||
uint8* base;
|
||||
};
|
||||
|
||||
struct overlay_registers;
|
||||
|
||||
struct child_device_config {
|
||||
uint16 handle;
|
||||
uint16 device_type;
|
||||
uint8 device_id[10];
|
||||
uint16 addin_offset;
|
||||
uint8 dvo_port;
|
||||
uint8 i2c_pin;
|
||||
uint8 slave_addr;
|
||||
uint8 ddc_pin;
|
||||
uint16 edid_ptr;
|
||||
uint8 dvo_cfg;
|
||||
|
||||
struct {
|
||||
bool efp_routed:1;
|
||||
bool lane_reversal:1;
|
||||
bool lspcon:1;
|
||||
bool iboost:1;
|
||||
bool hpd_invert:1;
|
||||
bool use_vbt_vswing:1;
|
||||
uint8 reserved:2;
|
||||
bool hdmi_support:1;
|
||||
bool dp_support:1;
|
||||
bool tmds_support:1;
|
||||
uint8 reserved2:5;
|
||||
uint8 aux_channel;
|
||||
uint8 dongle_detect;
|
||||
} __attribute__((packed));
|
||||
|
||||
uint8 caps;
|
||||
uint8 dvo_wiring;
|
||||
uint8 dvo2_wiring;
|
||||
uint16 extended_type;
|
||||
uint8 dvo_function;
|
||||
|
||||
bool dp_usb_type_c:1;
|
||||
bool tbt:1;
|
||||
uint8 reserved3:2;
|
||||
uint8 dp_port_trace_length:4;
|
||||
uint8 dp_gpio_index;
|
||||
uint8 dp_gpio_pin_num;
|
||||
uint8 dp_iboost_level:4;
|
||||
uint8 hdmi_iboost_level:4;
|
||||
uint8 dp_max_link_rate:3;
|
||||
uint8 dp_max_link_rate_reserved:5;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
enum dvo_port {
|
||||
DVO_PORT_HDMIA,
|
||||
DVO_PORT_HDMIB,
|
||||
DVO_PORT_HDMIC,
|
||||
DVO_PORT_HDMID,
|
||||
DVO_PORT_LVDS,
|
||||
DVO_PORT_TV,
|
||||
DVO_PORT_CRT,
|
||||
DVO_PORT_DPB,
|
||||
DVO_PORT_DPC,
|
||||
DVO_PORT_DPD,
|
||||
DVO_PORT_DPA,
|
||||
DVO_PORT_DPE,
|
||||
DVO_PORT_HDMIE,
|
||||
DVO_PORT_DPF,
|
||||
DVO_PORT_HDMIF,
|
||||
DVO_PORT_DPG,
|
||||
DVO_PORT_HDMIG,
|
||||
DVO_PORT_DPH,
|
||||
DVO_PORT_HDMIH,
|
||||
DVO_PORT_DPI,
|
||||
DVO_PORT_HDMII,
|
||||
};
|
||||
|
||||
|
||||
enum dp_aux_channel {
|
||||
DP_AUX_A = 0x40,
|
||||
DP_AUX_B = 0x10,
|
||||
DP_AUX_C = 0x20,
|
||||
DP_AUX_D = 0x30,
|
||||
DP_AUX_E = 0x50,
|
||||
DP_AUX_F = 0x60,
|
||||
DP_AUX_G = 0x70,
|
||||
DP_AUX_H = 0x80,
|
||||
DP_AUX_I = 0x90
|
||||
};
|
||||
|
||||
|
||||
enum aux_channel {
|
||||
AUX_CH_A,
|
||||
AUX_CH_B,
|
||||
AUX_CH_C,
|
||||
AUX_CH_D,
|
||||
AUX_CH_E,
|
||||
AUX_CH_F,
|
||||
AUX_CH_G,
|
||||
AUX_CH_H,
|
||||
AUX_CH_I,
|
||||
};
|
||||
|
||||
|
||||
struct intel_shared_info {
|
||||
area_id mode_list_area; // area containing display mode list
|
||||
@ -345,6 +442,9 @@ struct intel_shared_info {
|
||||
|
||||
edid1_info vesa_edid_info;
|
||||
bool has_vesa_edid_info;
|
||||
|
||||
uint32 device_config_count;
|
||||
child_device_config device_configs[10];
|
||||
};
|
||||
|
||||
enum pipe_index {
|
||||
|
@ -400,6 +400,63 @@ Port::_SetI2CSignals(void* cookie, int clock, int data)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Port::_IsPortInVBT(uint32* foundIndex)
|
||||
{
|
||||
// check VBT mapping
|
||||
bool found = false;
|
||||
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
|
||||
for (uint32 i = 0; i < deviceConfigCount; i++) {
|
||||
child_device_config& config = gInfo->shared_info->device_configs[i];
|
||||
if (config.dvo_port > DVO_PORT_HDMII) {
|
||||
ERROR("%s: DVO port unknown\n", __func__);
|
||||
continue;
|
||||
}
|
||||
dvo_port port = (dvo_port)config.dvo_port;
|
||||
switch (PortIndex()) {
|
||||
case INTEL_PORT_A:
|
||||
found = port == DVO_PORT_HDMIA || port == DVO_PORT_DPA;
|
||||
break;
|
||||
case INTEL_PORT_B:
|
||||
found = port == DVO_PORT_HDMIB || port == DVO_PORT_DPB;
|
||||
break;
|
||||
case INTEL_PORT_C:
|
||||
found = port == DVO_PORT_HDMIC || port == DVO_PORT_DPC;
|
||||
break;
|
||||
case INTEL_PORT_D:
|
||||
found = port == DVO_PORT_HDMID || port == DVO_PORT_DPD;
|
||||
break;
|
||||
case INTEL_PORT_E:
|
||||
found = port == DVO_PORT_HDMIE || port == DVO_PORT_DPE || port == DVO_PORT_CRT;
|
||||
break;
|
||||
case INTEL_PORT_F:
|
||||
found = port == DVO_PORT_HDMIF || port == DVO_PORT_DPF;
|
||||
break;
|
||||
default:
|
||||
ERROR("%s: DDI port unknown\n", __func__);
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
if (foundIndex != NULL)
|
||||
*foundIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Port::_IsDisplayPortInVBT()
|
||||
{
|
||||
uint32 foundIndex = 0;
|
||||
if (!_IsPortInVBT(&foundIndex))
|
||||
return false;
|
||||
child_device_config& config = gInfo->shared_info->device_configs[foundIndex];
|
||||
return config.aux_channel > 0;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Analog Port
|
||||
|
||||
|
||||
@ -956,6 +1013,16 @@ HDMIPort::IsConnected()
|
||||
if (portRegister == 0)
|
||||
return false;
|
||||
|
||||
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 6 && deviceConfigCount > 0) {
|
||||
// check VBT mapping
|
||||
if (!_IsPortInVBT()) {
|
||||
TRACE("%s: %s: port not found in VBT\n", __func__, PortName());
|
||||
return false;
|
||||
} else
|
||||
TRACE("%s: %s: port found in VBT\n", __func__, PortName());
|
||||
}
|
||||
|
||||
//Notes:
|
||||
//- DISPLAY_MONITOR_PORT_DETECTED does only tell you *some* sort of digital display is
|
||||
// connected to the port *if* you have the AUX channel stuff under power. It does not
|
||||
@ -1128,6 +1195,16 @@ DisplayPort::IsConnected()
|
||||
if (portRegister == 0)
|
||||
return false;
|
||||
|
||||
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 6 && deviceConfigCount > 0) {
|
||||
// check VBT mapping
|
||||
if (!_IsPortInVBT()) {
|
||||
TRACE("%s: %s: port not found in VBT\n", __func__, PortName());
|
||||
return false;
|
||||
} else
|
||||
TRACE("%s: %s: port found in VBT\n", __func__, PortName());
|
||||
}
|
||||
|
||||
//Notes:
|
||||
//- DISPLAY_MONITOR_PORT_DETECTED does only tell you *some* sort of digital display is
|
||||
// connected to the port *if* you have the AUX channel stuff under power. It does not
|
||||
@ -1181,6 +1258,13 @@ status_t
|
||||
DigitalDisplayInterface::SetupI2c(i2c_bus *bus)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 9 && deviceConfigCount > 0) {
|
||||
if (!_IsDisplayPortInVBT())
|
||||
return Port::SetupI2c(bus);
|
||||
}
|
||||
|
||||
ddc2_init_timing(bus);
|
||||
bus->cookie = this;
|
||||
bus->send_receive = &_DpAuxSendReceiveHook;
|
||||
@ -1428,9 +1512,9 @@ DigitalDisplayInterface::_DpAuxTransfer(uint8* transmitBuffer, uint8 transmitSiz
|
||||
addr_t channelData[5];
|
||||
if (gInfo->shared_info->device_type.Generation() >= 9) {
|
||||
// assume AUX channel 0
|
||||
channelControl = DP_AUX_CH_CTL(0);
|
||||
channelControl = DP_AUX_CH_CTL(_DpAuxChannel());
|
||||
for (int i = 0; i < 5; i++)
|
||||
channelData[i] = DP_AUX_CH_DATA(0, i);
|
||||
channelData[i] = DP_AUX_CH_DATA(_DpAuxChannel(), i);
|
||||
} else {
|
||||
ERROR("DigitalDisplayInterface::_DpAuxTransfer() unknown register config\n");
|
||||
return B_BUSY;
|
||||
@ -1521,6 +1605,30 @@ done:
|
||||
}
|
||||
|
||||
|
||||
aux_channel
|
||||
DigitalDisplayInterface::_DpAuxChannel()
|
||||
{
|
||||
uint32 foundIndex = 0;
|
||||
if (!_IsPortInVBT(&foundIndex))
|
||||
return AUX_CH_A;
|
||||
child_device_config& config = gInfo->shared_info->device_configs[foundIndex];
|
||||
switch (config.aux_channel) {
|
||||
case DP_AUX_B:
|
||||
return AUX_CH_B;
|
||||
case DP_AUX_C:
|
||||
return AUX_CH_C;
|
||||
case DP_AUX_D:
|
||||
return AUX_CH_D;
|
||||
case DP_AUX_E:
|
||||
return AUX_CH_E;
|
||||
case DP_AUX_F:
|
||||
return AUX_CH_F;
|
||||
default:
|
||||
return AUX_CH_A;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addr_t
|
||||
DisplayPort::_PortRegister()
|
||||
{
|
||||
@ -2066,6 +2174,16 @@ DigitalDisplayInterface::IsConnected()
|
||||
}
|
||||
}
|
||||
|
||||
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 9 && deviceConfigCount > 0) {
|
||||
// check VBT mapping
|
||||
if (!_IsPortInVBT()) {
|
||||
TRACE("%s: %s: port not found in VBT\n", __func__, PortName());
|
||||
return false;
|
||||
} else
|
||||
TRACE("%s: %s: port found in VBT\n", __func__, PortName());
|
||||
}
|
||||
|
||||
TRACE("%s: %s Maximum Lanes: %" B_PRId8 "\n", __func__,
|
||||
PortName(), fMaxLanes);
|
||||
|
||||
|
@ -75,6 +75,8 @@ static status_t _GetI2CSignals(void* cookie, int* _clock,
|
||||
int* _data);
|
||||
static status_t _SetI2CSignals(void* cookie, int clock,
|
||||
int data);
|
||||
bool _IsPortInVBT(uint32* foundIndex = NULL);
|
||||
bool _IsDisplayPortInVBT();
|
||||
|
||||
display_mode fCurrentMode;
|
||||
Pipe* fPipe;
|
||||
@ -239,6 +241,7 @@ static status_t _DpAuxSendReceiveHook(const struct i2c_bus *bus,
|
||||
uint32 slave_address, const uint8 *writeBuffer,
|
||||
size_t writeLength, uint8 *readBuffer,
|
||||
size_t readLength);
|
||||
aux_channel _DpAuxChannel();
|
||||
};
|
||||
|
||||
|
||||
|
@ -301,7 +301,7 @@ probe_ports()
|
||||
|
||||
// Digital Display Interface (for DP, HDMI, DVI and eDP)
|
||||
if (gInfo->shared_info->device_type.HasDDI()) {
|
||||
for (int i = INTEL_PORT_B; i <= INTEL_PORT_F; i++) {
|
||||
for (int i = INTEL_PORT_A; i <= INTEL_PORT_F; i++) {
|
||||
TRACE("Probing DDI %d\n", i);
|
||||
|
||||
Port* ddiPort
|
||||
|
@ -201,8 +201,10 @@ create_mode_list(void)
|
||||
continue;
|
||||
|
||||
status_t status = gInfo->ports[i]->GetEDID(&gInfo->edid_info);
|
||||
if (status == B_OK)
|
||||
if (status == B_OK) {
|
||||
gInfo->has_edid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// use EDID found at boot time if there since we don't have any ourselves
|
||||
if (!gInfo->has_edid && gInfo->shared_info->has_vesa_edid_info) {
|
||||
|
@ -44,6 +44,7 @@ struct bdb_header {
|
||||
|
||||
|
||||
enum bdb_block_id {
|
||||
BDB_GENERAL_DEFINITIONS = 2,
|
||||
BDB_LVDS_OPTIONS = 40,
|
||||
BDB_LVDS_LFP_DATA_PTRS = 41,
|
||||
BDB_LVDS_BACKLIGHT = 43,
|
||||
@ -51,6 +52,17 @@ enum bdb_block_id {
|
||||
};
|
||||
|
||||
|
||||
struct bdb_general_definitions {
|
||||
uint8 id;
|
||||
uint16 size;
|
||||
uint8 crt_ddc_gmbus_pin;
|
||||
uint8 dpms_bits;
|
||||
uint8 boot_display[2];
|
||||
uint8 child_device_size;
|
||||
uint8 devices[];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
// FIXME the struct definition for the bdb_header is not complete, so we rely
|
||||
// on direct access with hardcoded offsets to get the timings out of it.
|
||||
#define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000
|
||||
@ -422,8 +434,11 @@ sanitize_panel_timing(display_timing& timing)
|
||||
|
||||
|
||||
bool
|
||||
get_lvds_mode_from_bios(display_timing* panelTiming, uint16* minBrightness)
|
||||
parse_vbt_from_bios(struct intel_shared_info* info)
|
||||
{
|
||||
display_timing* panelTiming = &info->panel_timing;
|
||||
uint16* minBrightness = &info->min_brightness;
|
||||
|
||||
int vbtOffset = 0;
|
||||
if (!get_bios(&vbtOffset))
|
||||
return false;
|
||||
@ -450,6 +465,29 @@ get_lvds_mode_from_bios(display_timing* panelTiming, uint16* minBrightness)
|
||||
int id = vbios.memory[start];
|
||||
blockSize = vbios.ReadWord(start + 1) + 3;
|
||||
switch (id) {
|
||||
case BDB_GENERAL_DEFINITIONS:
|
||||
{
|
||||
info->device_config_count = 0;
|
||||
struct bdb_general_definitions* defs;
|
||||
if (bdb->version < 111)
|
||||
break;
|
||||
defs = (struct bdb_general_definitions*)(vbios.memory + start);
|
||||
uint8 childDeviceSize = defs->child_device_size;
|
||||
uint32 device_config_count = (blockSize - sizeof(*defs)) / childDeviceSize;
|
||||
for (uint32 i = 0; i < device_config_count; i++) {
|
||||
child_device_config* config =
|
||||
(child_device_config*)(&defs->devices[i * childDeviceSize]);
|
||||
if (config->device_type == 0)
|
||||
continue;
|
||||
memcpy(&info->device_configs[info->device_config_count], config,
|
||||
min_c(sizeof(child_device_config), childDeviceSize));
|
||||
TRACE((DEVICE_NAME ": found child device type: 0x%x\n", config->device_type));
|
||||
info->device_config_count++;
|
||||
if (info->device_config_count > 10)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BDB_LVDS_OPTIONS:
|
||||
{
|
||||
struct lvds_bdb1 *lvds1;
|
||||
|
@ -679,9 +679,8 @@ intel_extreme_init(intel_info &info)
|
||||
info.shared_info->dpms_mode = B_DPMS_ON;
|
||||
info.shared_info->min_brightness = 2;
|
||||
|
||||
// Pull VBIOS panel mode for later use
|
||||
info.shared_info->got_vbt = get_lvds_mode_from_bios(
|
||||
&info.shared_info->panel_timing, &info.shared_info->min_brightness);
|
||||
// Pull VBIOS info for later use
|
||||
info.shared_info->got_vbt = parse_vbt_from_bios(info.shared_info);
|
||||
|
||||
/* at least 855gm can't drive more than one head at time */
|
||||
if (info.device_type.InFamily(INTEL_FAMILY_8xx))
|
||||
|
@ -72,7 +72,7 @@ find_reg(const intel_info& info, uint32 target)
|
||||
}
|
||||
|
||||
|
||||
extern bool get_lvds_mode_from_bios(display_timing *timing, uint16 *minBrightness);
|
||||
extern bool parse_vbt_from_bios(struct intel_shared_info* info);
|
||||
extern status_t intel_free_memory(intel_info& info, addr_t offset);
|
||||
extern status_t intel_allocate_memory(intel_info& info, size_t size,
|
||||
size_t alignment, uint32 flags, addr_t* _offset,
|
||||
|
Loading…
Reference in New Issue
Block a user