mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-26 14:14:01 +08:00
drm/radeon/kms: add support for router objects
router objects are found on systems that use a mux to control ddc line to connector routing or to control the actual clock and data routing from the chip to the connectors. This patch implements ddc line routing. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
179e8078a7
commit
26b5bc9864
@ -48,7 +48,8 @@ radeon_add_atom_connector(struct drm_device *dev,
|
|||||||
struct radeon_i2c_bus_rec *i2c_bus,
|
struct radeon_i2c_bus_rec *i2c_bus,
|
||||||
bool linkb, uint32_t igp_lane_info,
|
bool linkb, uint32_t igp_lane_info,
|
||||||
uint16_t connector_object_id,
|
uint16_t connector_object_id,
|
||||||
struct radeon_hpd *hpd);
|
struct radeon_hpd *hpd,
|
||||||
|
struct radeon_router *router);
|
||||||
|
|
||||||
/* from radeon_legacy_encoder.c */
|
/* from radeon_legacy_encoder.c */
|
||||||
extern void
|
extern void
|
||||||
@ -460,13 +461,15 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
|||||||
u16 size, data_offset;
|
u16 size, data_offset;
|
||||||
u8 frev, crev;
|
u8 frev, crev;
|
||||||
ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
|
ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
|
||||||
|
ATOM_OBJECT_TABLE *router_obj;
|
||||||
ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
|
ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
|
||||||
ATOM_OBJECT_HEADER *obj_header;
|
ATOM_OBJECT_HEADER *obj_header;
|
||||||
int i, j, path_size, device_support;
|
int i, j, k, path_size, device_support;
|
||||||
int connector_type;
|
int connector_type;
|
||||||
u16 igp_lane_info, conn_id, connector_object_id;
|
u16 igp_lane_info, conn_id, connector_object_id;
|
||||||
bool linkb;
|
bool linkb;
|
||||||
struct radeon_i2c_bus_rec ddc_bus;
|
struct radeon_i2c_bus_rec ddc_bus;
|
||||||
|
struct radeon_router router;
|
||||||
struct radeon_gpio_rec gpio;
|
struct radeon_gpio_rec gpio;
|
||||||
struct radeon_hpd hpd;
|
struct radeon_hpd hpd;
|
||||||
|
|
||||||
@ -476,6 +479,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;
|
||||||
|
|
||||||
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 *)
|
||||||
(ctx->bios + data_offset +
|
(ctx->bios + data_offset +
|
||||||
@ -483,6 +488,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
|||||||
con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
|
con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
|
||||||
(ctx->bios + data_offset +
|
(ctx->bios + data_offset +
|
||||||
le16_to_cpu(obj_header->usConnectorObjectTableOffset));
|
le16_to_cpu(obj_header->usConnectorObjectTableOffset));
|
||||||
|
router_obj = (ATOM_OBJECT_TABLE *)
|
||||||
|
(ctx->bios + data_offset +
|
||||||
|
le16_to_cpu(obj_header->usRouterObjectTableOffset));
|
||||||
device_support = le16_to_cpu(obj_header->usDeviceSupport);
|
device_support = le16_to_cpu(obj_header->usDeviceSupport);
|
||||||
|
|
||||||
path_size = 0;
|
path_size = 0;
|
||||||
@ -569,33 +577,86 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
|||||||
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
|
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2);
|
for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
|
||||||
j++) {
|
uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
|
||||||
uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
|
|
||||||
|
|
||||||
enc_obj_id =
|
grph_obj_id =
|
||||||
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
||||||
OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
|
OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
|
||||||
enc_obj_num =
|
grph_obj_num =
|
||||||
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
||||||
ENUM_ID_MASK) >> ENUM_ID_SHIFT;
|
ENUM_ID_MASK) >> ENUM_ID_SHIFT;
|
||||||
enc_obj_type =
|
grph_obj_type =
|
||||||
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
||||||
OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
|
OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
|
||||||
|
|
||||||
/* FIXME: add support for router objects */
|
if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
|
||||||
if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
|
if (grph_obj_num == 2)
|
||||||
if (enc_obj_num == 2)
|
|
||||||
linkb = true;
|
linkb = true;
|
||||||
else
|
else
|
||||||
linkb = false;
|
linkb = false;
|
||||||
|
|
||||||
radeon_add_atom_encoder(dev,
|
radeon_add_atom_encoder(dev,
|
||||||
enc_obj_id,
|
grph_obj_id,
|
||||||
le16_to_cpu
|
le16_to_cpu
|
||||||
(path->
|
(path->
|
||||||
usDeviceTag));
|
usDeviceTag));
|
||||||
|
|
||||||
|
} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
|
||||||
|
router.valid = false;
|
||||||
|
for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
|
||||||
|
u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
|
||||||
|
if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
|
||||||
|
ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
|
||||||
|
(ctx->bios + data_offset +
|
||||||
|
le16_to_cpu(router_obj->asObjects[k].usRecordOffset));
|
||||||
|
ATOM_I2C_RECORD *i2c_record;
|
||||||
|
ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
|
||||||
|
ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
|
||||||
|
ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
|
||||||
|
(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
|
||||||
|
(ctx->bios + data_offset +
|
||||||
|
le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));
|
||||||
|
int enum_id;
|
||||||
|
|
||||||
|
router.router_id = router_obj_id;
|
||||||
|
for (enum_id = 0; enum_id < router_src_dst_table->ucNumberOfDst;
|
||||||
|
enum_id++) {
|
||||||
|
if (le16_to_cpu(path->usConnObjectId) ==
|
||||||
|
le16_to_cpu(router_src_dst_table->usDstObjectID[enum_id]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (record->ucRecordType > 0 &&
|
||||||
|
record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
|
||||||
|
switch (record->ucRecordType) {
|
||||||
|
case ATOM_I2C_RECORD_TYPE:
|
||||||
|
i2c_record =
|
||||||
|
(ATOM_I2C_RECORD *)
|
||||||
|
record;
|
||||||
|
i2c_config =
|
||||||
|
(ATOM_I2C_ID_CONFIG_ACCESS *)
|
||||||
|
&i2c_record->sucI2cId;
|
||||||
|
router.i2c_info =
|
||||||
|
radeon_lookup_i2c_gpio(rdev,
|
||||||
|
i2c_config->
|
||||||
|
ucAccess);
|
||||||
|
router.i2c_addr = i2c_record->ucI2CAddr >> 1;
|
||||||
|
break;
|
||||||
|
case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
|
||||||
|
ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
|
||||||
|
record;
|
||||||
|
router.valid = true;
|
||||||
|
router.mux_type = ddc_path->ucMuxType;
|
||||||
|
router.mux_control_pin = ddc_path->ucMuxControlPin;
|
||||||
|
router.mux_state = ddc_path->ucMuxState[enum_id];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
record = (ATOM_COMMON_RECORD_HEADER *)
|
||||||
|
((char *)record + record->ucRecordSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,7 +736,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
|
|||||||
connector_type, &ddc_bus,
|
connector_type, &ddc_bus,
|
||||||
linkb, igp_lane_info,
|
linkb, igp_lane_info,
|
||||||
connector_object_id,
|
connector_object_id,
|
||||||
&hpd);
|
&hpd,
|
||||||
|
&router);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -752,6 +814,9 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
|
|||||||
int i, j, max_device;
|
int i, j, max_device;
|
||||||
struct bios_connector *bios_connectors;
|
struct bios_connector *bios_connectors;
|
||||||
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;
|
||||||
|
|
||||||
|
router.valid = false;
|
||||||
|
|
||||||
bios_connectors = kzalloc(bc_size, GFP_KERNEL);
|
bios_connectors = kzalloc(bc_size, GFP_KERNEL);
|
||||||
if (!bios_connectors)
|
if (!bios_connectors)
|
||||||
@ -923,7 +988,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
|
|||||||
&bios_connectors[i].ddc_bus,
|
&bios_connectors[i].ddc_bus,
|
||||||
false, 0,
|
false, 0,
|
||||||
connector_object_id,
|
connector_object_id,
|
||||||
&bios_connectors[i].hpd);
|
&bios_connectors[i].hpd,
|
||||||
|
&router);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,7 +1040,8 @@ radeon_add_atom_connector(struct drm_device *dev,
|
|||||||
bool linkb,
|
bool linkb,
|
||||||
uint32_t igp_lane_info,
|
uint32_t igp_lane_info,
|
||||||
uint16_t connector_object_id,
|
uint16_t connector_object_id,
|
||||||
struct radeon_hpd *hpd)
|
struct radeon_hpd *hpd,
|
||||||
|
struct radeon_router *router)
|
||||||
{
|
{
|
||||||
struct radeon_device *rdev = dev->dev_private;
|
struct radeon_device *rdev = dev->dev_private;
|
||||||
struct drm_connector *connector;
|
struct drm_connector *connector;
|
||||||
@ -1065,6 +1066,11 @@ 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 &&
|
||||||
|
(radeon_connector->router.router_id == router->router_id)) {
|
||||||
|
radeon_connector->shared_ddc = false;
|
||||||
|
shared_ddc = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1079,6 +1085,12 @@ radeon_add_atom_connector(struct drm_device *dev,
|
|||||||
radeon_connector->shared_ddc = shared_ddc;
|
radeon_connector->shared_ddc = shared_ddc;
|
||||||
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;
|
||||||
|
if (router->valid) {
|
||||||
|
radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
|
||||||
|
if (!radeon_connector->router_bus)
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
switch (connector_type) {
|
switch (connector_type) {
|
||||||
case DRM_MODE_CONNECTOR_VGA:
|
case DRM_MODE_CONNECTOR_VGA:
|
||||||
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
|
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
|
||||||
|
@ -319,6 +319,10 @@ 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)
|
||||||
|
DRM_INFO(" DDC Router 0x%x/0x%x\n",
|
||||||
|
radeon_connector->router.mux_control_pin,
|
||||||
|
radeon_connector->router.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 ||
|
||||||
@ -395,6 +399,10 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
|
|||||||
struct radeon_device *rdev = dev->dev_private;
|
struct radeon_device *rdev = dev->dev_private;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
/* on hw with routers, select right port */
|
||||||
|
if (radeon_connector->router.valid)
|
||||||
|
radeon_router_select_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)) {
|
||||||
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
|
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
|
||||||
@ -425,6 +433,10 @@ static int radeon_ddc_dump(struct drm_connector *connector)
|
|||||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
/* on hw with routers, select right port */
|
||||||
|
if (radeon_connector->router.valid)
|
||||||
|
radeon_router_select_port(radeon_connector);
|
||||||
|
|
||||||
if (!radeon_connector->ddc_bus)
|
if (!radeon_connector->ddc_bus)
|
||||||
return -1;
|
return -1;
|
||||||
edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
|
edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
|
||||||
|
@ -52,6 +52,10 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* on hw with routers, select right port */
|
||||||
|
if (radeon_connector->router.valid)
|
||||||
|
radeon_router_select_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)
|
||||||
return true;
|
return true;
|
||||||
@ -1073,3 +1077,28 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
|
|||||||
addr, val);
|
addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* router switching */
|
||||||
|
void radeon_router_select_port(struct radeon_connector *radeon_connector)
|
||||||
|
{
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
if (!radeon_connector->router.valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
radeon_i2c_get_byte(radeon_connector->router_bus,
|
||||||
|
radeon_connector->router.i2c_addr,
|
||||||
|
0x3, &val);
|
||||||
|
val &= radeon_connector->router.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.mux_control_pin;
|
||||||
|
val |= radeon_connector->router.mux_state;
|
||||||
|
radeon_i2c_put_byte(radeon_connector->router_bus,
|
||||||
|
radeon_connector->router.i2c_addr,
|
||||||
|
0x1, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -400,6 +400,16 @@ struct radeon_hpd {
|
|||||||
struct radeon_gpio_rec gpio;
|
struct radeon_gpio_rec gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct radeon_router {
|
||||||
|
bool valid;
|
||||||
|
u32 router_id;
|
||||||
|
struct radeon_i2c_bus_rec i2c_info;
|
||||||
|
u8 i2c_addr;
|
||||||
|
u8 mux_type;
|
||||||
|
u8 mux_control_pin;
|
||||||
|
u8 mux_state;
|
||||||
|
};
|
||||||
|
|
||||||
struct radeon_connector {
|
struct radeon_connector {
|
||||||
struct drm_connector base;
|
struct drm_connector base;
|
||||||
uint32_t connector_id;
|
uint32_t connector_id;
|
||||||
@ -415,6 +425,8 @@ struct radeon_connector {
|
|||||||
bool dac_load_detect;
|
bool dac_load_detect;
|
||||||
uint16_t connector_object_id;
|
uint16_t connector_object_id;
|
||||||
struct radeon_hpd hpd;
|
struct radeon_hpd hpd;
|
||||||
|
struct radeon_router router;
|
||||||
|
struct radeon_i2c_chan *router_bus;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radeon_framebuffer {
|
struct radeon_framebuffer {
|
||||||
@ -471,6 +483,7 @@ 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 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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user