drm/radeon/kms: add support for clock/data path routers
This is a follow on to:
26b5bc9864
(drm/radeon/kms: add support for router objects)
That patch added support for systems that use a mux to control
the ddc line routing between the connectors. This patch adds
support for systems that use a mux to control the encoder
clock and data path routing to the connectors.
Should fix:
https://bugs.freedesktop.org/show_bug.cgi?id=31339
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Родитель
dccb2a952b
Коммит
fb939dfcf2
|
@ -526,7 +526,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
||||||
if (crev < 2)
|
if (crev < 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
router.valid = false;
|
router.ddc_valid = false;
|
||||||
|
router.cd_valid = false;
|
||||||
|
|
||||||
obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
|
obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
|
||||||
path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
|
path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
|
||||||
|
@ -647,7 +648,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
||||||
usDeviceTag));
|
usDeviceTag));
|
||||||
|
|
||||||
} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
|
} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
|
||||||
router.valid = false;
|
router.ddc_valid = false;
|
||||||
|
router.cd_valid = false;
|
||||||
for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
|
for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
|
||||||
u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
|
u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
|
||||||
if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
|
if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
|
||||||
|
@ -657,6 +659,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
||||||
ATOM_I2C_RECORD *i2c_record;
|
ATOM_I2C_RECORD *i2c_record;
|
||||||
ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
|
ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
|
||||||
ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
|
ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
|
||||||
|
ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
|
||||||
ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
|
ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
|
||||||
(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
|
(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
|
||||||
(ctx->bios + data_offset +
|
(ctx->bios + data_offset +
|
||||||
|
@ -690,10 +693,18 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
||||||
case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
|
case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
|
||||||
ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
|
ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
|
||||||
record;
|
record;
|
||||||
router.valid = true;
|
router.ddc_valid = true;
|
||||||
router.mux_type = ddc_path->ucMuxType;
|
router.ddc_mux_type = ddc_path->ucMuxType;
|
||||||
router.mux_control_pin = ddc_path->ucMuxControlPin;
|
router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
|
||||||
router.mux_state = ddc_path->ucMuxState[enum_id];
|
router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
|
||||||
|
break;
|
||||||
|
case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
|
||||||
|
cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
|
||||||
|
record;
|
||||||
|
router.cd_valid = true;
|
||||||
|
router.cd_mux_type = cd_path->ucMuxType;
|
||||||
|
router.cd_mux_control_pin = cd_path->ucMuxControlPin;
|
||||||
|
router.cd_mux_state = cd_path->ucMuxState[enum_id];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
record = (ATOM_COMMON_RECORD_HEADER *)
|
record = (ATOM_COMMON_RECORD_HEADER *)
|
||||||
|
@ -860,7 +871,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
|
||||||
size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
|
size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
|
||||||
struct radeon_router router;
|
struct radeon_router router;
|
||||||
|
|
||||||
router.valid = false;
|
router.ddc_valid = false;
|
||||||
|
router.cd_valid = false;
|
||||||
|
|
||||||
bios_connectors = kzalloc(bc_size, GFP_KERNEL);
|
bios_connectors = kzalloc(bc_size, GFP_KERNEL);
|
||||||
if (!bios_connectors)
|
if (!bios_connectors)
|
||||||
|
|
|
@ -1116,7 +1116,7 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||||
radeon_connector->shared_ddc = true;
|
radeon_connector->shared_ddc = true;
|
||||||
shared_ddc = true;
|
shared_ddc = true;
|
||||||
}
|
}
|
||||||
if (radeon_connector->router_bus && router->valid &&
|
if (radeon_connector->router_bus && router->ddc_valid &&
|
||||||
(radeon_connector->router.router_id == router->router_id)) {
|
(radeon_connector->router.router_id == router->router_id)) {
|
||||||
radeon_connector->shared_ddc = false;
|
radeon_connector->shared_ddc = false;
|
||||||
shared_ddc = false;
|
shared_ddc = false;
|
||||||
|
@ -1136,7 +1136,7 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||||
radeon_connector->connector_object_id = connector_object_id;
|
radeon_connector->connector_object_id = connector_object_id;
|
||||||
radeon_connector->hpd = *hpd;
|
radeon_connector->hpd = *hpd;
|
||||||
radeon_connector->router = *router;
|
radeon_connector->router = *router;
|
||||||
if (router->valid) {
|
if (router->ddc_valid || router->cd_valid) {
|
||||||
radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
|
radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
|
||||||
if (!radeon_connector->router_bus)
|
if (!radeon_connector->router_bus)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
|
@ -315,10 +315,14 @@ static void radeon_print_display_setup(struct drm_device *dev)
|
||||||
radeon_connector->ddc_bus->rec.en_data_reg,
|
radeon_connector->ddc_bus->rec.en_data_reg,
|
||||||
radeon_connector->ddc_bus->rec.y_clk_reg,
|
radeon_connector->ddc_bus->rec.y_clk_reg,
|
||||||
radeon_connector->ddc_bus->rec.y_data_reg);
|
radeon_connector->ddc_bus->rec.y_data_reg);
|
||||||
if (radeon_connector->router_bus)
|
if (radeon_connector->router.ddc_valid)
|
||||||
DRM_INFO(" DDC Router 0x%x/0x%x\n",
|
DRM_INFO(" DDC Router 0x%x/0x%x\n",
|
||||||
radeon_connector->router.mux_control_pin,
|
radeon_connector->router.ddc_mux_control_pin,
|
||||||
radeon_connector->router.mux_state);
|
radeon_connector->router.ddc_mux_state);
|
||||||
|
if (radeon_connector->router.cd_valid)
|
||||||
|
DRM_INFO(" Clock/Data Router 0x%x/0x%x\n",
|
||||||
|
radeon_connector->router.cd_mux_control_pin,
|
||||||
|
radeon_connector->router.cd_mux_state);
|
||||||
} else {
|
} else {
|
||||||
if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
|
if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
|
||||||
connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
|
connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
|
||||||
|
@ -398,8 +402,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* on hw with routers, select right port */
|
/* on hw with routers, select right port */
|
||||||
if (radeon_connector->router.valid)
|
if (radeon_connector->router.ddc_valid)
|
||||||
radeon_router_select_port(radeon_connector);
|
radeon_router_select_ddc_port(radeon_connector);
|
||||||
|
|
||||||
if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
|
if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
|
||||||
(radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
|
(radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
|
||||||
|
@ -432,8 +436,8 @@ static int radeon_ddc_dump(struct drm_connector *connector)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* on hw with routers, select right port */
|
/* on hw with routers, select right port */
|
||||||
if (radeon_connector->router.valid)
|
if (radeon_connector->router.ddc_valid)
|
||||||
radeon_router_select_port(radeon_connector);
|
radeon_router_select_ddc_port(radeon_connector);
|
||||||
|
|
||||||
if (!radeon_connector->ddc_bus)
|
if (!radeon_connector->ddc_bus)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1520,6 +1520,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
|
||||||
static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
|
static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||||
|
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
|
||||||
|
|
||||||
if (radeon_encoder->active_device &
|
if (radeon_encoder->active_device &
|
||||||
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
|
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
|
||||||
|
@ -1531,6 +1532,13 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
|
||||||
radeon_atom_output_lock(encoder, true);
|
radeon_atom_output_lock(encoder, true);
|
||||||
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||||
|
|
||||||
|
/* select the clock/data port if it uses a router */
|
||||||
|
if (connector) {
|
||||||
|
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||||
|
if (radeon_connector->router.cd_valid)
|
||||||
|
radeon_router_select_cd_port(radeon_connector);
|
||||||
|
}
|
||||||
|
|
||||||
/* this is needed for the pll/ss setup to work correctly in some cases */
|
/* this is needed for the pll/ss setup to work correctly in some cases */
|
||||||
atombios_set_encoder_crtc_source(encoder);
|
atombios_set_encoder_crtc_source(encoder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,8 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* on hw with routers, select right port */
|
/* on hw with routers, select right port */
|
||||||
if (radeon_connector->router.valid)
|
if (radeon_connector->router.ddc_valid)
|
||||||
radeon_router_select_port(radeon_connector);
|
radeon_router_select_ddc_port(radeon_connector);
|
||||||
|
|
||||||
ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
|
ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
|
||||||
if (ret == 2)
|
if (ret == 2)
|
||||||
|
@ -1084,26 +1084,51 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
|
||||||
addr, val);
|
addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* router switching */
|
/* ddc router switching */
|
||||||
void radeon_router_select_port(struct radeon_connector *radeon_connector)
|
void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector)
|
||||||
{
|
{
|
||||||
u8 val;
|
u8 val;
|
||||||
|
|
||||||
if (!radeon_connector->router.valid)
|
if (!radeon_connector->router.ddc_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
radeon_i2c_get_byte(radeon_connector->router_bus,
|
radeon_i2c_get_byte(radeon_connector->router_bus,
|
||||||
radeon_connector->router.i2c_addr,
|
radeon_connector->router.i2c_addr,
|
||||||
0x3, &val);
|
0x3, &val);
|
||||||
val &= radeon_connector->router.mux_control_pin;
|
val &= radeon_connector->router.ddc_mux_control_pin;
|
||||||
radeon_i2c_put_byte(radeon_connector->router_bus,
|
radeon_i2c_put_byte(radeon_connector->router_bus,
|
||||||
radeon_connector->router.i2c_addr,
|
radeon_connector->router.i2c_addr,
|
||||||
0x3, val);
|
0x3, val);
|
||||||
radeon_i2c_get_byte(radeon_connector->router_bus,
|
radeon_i2c_get_byte(radeon_connector->router_bus,
|
||||||
radeon_connector->router.i2c_addr,
|
radeon_connector->router.i2c_addr,
|
||||||
0x1, &val);
|
0x1, &val);
|
||||||
val &= radeon_connector->router.mux_control_pin;
|
val &= radeon_connector->router.ddc_mux_control_pin;
|
||||||
val |= radeon_connector->router.mux_state;
|
val |= radeon_connector->router.ddc_mux_state;
|
||||||
|
radeon_i2c_put_byte(radeon_connector->router_bus,
|
||||||
|
radeon_connector->router.i2c_addr,
|
||||||
|
0x1, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clock/data router switching */
|
||||||
|
void radeon_router_select_cd_port(struct radeon_connector *radeon_connector)
|
||||||
|
{
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
if (!radeon_connector->router.cd_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
radeon_i2c_get_byte(radeon_connector->router_bus,
|
||||||
|
radeon_connector->router.i2c_addr,
|
||||||
|
0x3, &val);
|
||||||
|
val &= radeon_connector->router.cd_mux_control_pin;
|
||||||
|
radeon_i2c_put_byte(radeon_connector->router_bus,
|
||||||
|
radeon_connector->router.i2c_addr,
|
||||||
|
0x3, val);
|
||||||
|
radeon_i2c_get_byte(radeon_connector->router_bus,
|
||||||
|
radeon_connector->router.i2c_addr,
|
||||||
|
0x1, &val);
|
||||||
|
val &= radeon_connector->router.cd_mux_control_pin;
|
||||||
|
val |= radeon_connector->router.cd_mux_state;
|
||||||
radeon_i2c_put_byte(radeon_connector->router_bus,
|
radeon_i2c_put_byte(radeon_connector->router_bus,
|
||||||
radeon_connector->router.i2c_addr,
|
radeon_connector->router.i2c_addr,
|
||||||
0x1, val);
|
0x1, val);
|
||||||
|
|
|
@ -401,13 +401,19 @@ struct radeon_hpd {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radeon_router {
|
struct radeon_router {
|
||||||
bool valid;
|
|
||||||
u32 router_id;
|
u32 router_id;
|
||||||
struct radeon_i2c_bus_rec i2c_info;
|
struct radeon_i2c_bus_rec i2c_info;
|
||||||
u8 i2c_addr;
|
u8 i2c_addr;
|
||||||
u8 mux_type;
|
/* i2c mux */
|
||||||
u8 mux_control_pin;
|
bool ddc_valid;
|
||||||
u8 mux_state;
|
u8 ddc_mux_type;
|
||||||
|
u8 ddc_mux_control_pin;
|
||||||
|
u8 ddc_mux_state;
|
||||||
|
/* clock/data mux */
|
||||||
|
bool cd_valid;
|
||||||
|
u8 cd_mux_type;
|
||||||
|
u8 cd_mux_control_pin;
|
||||||
|
u8 cd_mux_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radeon_connector {
|
struct radeon_connector {
|
||||||
|
@ -488,7 +494,8 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
|
||||||
u8 slave_addr,
|
u8 slave_addr,
|
||||||
u8 addr,
|
u8 addr,
|
||||||
u8 val);
|
u8 val);
|
||||||
extern void radeon_router_select_port(struct radeon_connector *radeon_connector);
|
extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
|
||||||
|
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
|
||||||
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
|
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
|
||||||
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
|
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче