diff options
Diffstat (limited to 'drivers/gpu/drm/xlnx/zynqmp_dp.c')
-rw-r--r-- | drivers/gpu/drm/xlnx/zynqmp_dp.c | 85 |
1 files changed, 67 insertions, 18 deletions
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 1846c4971fd8..8c2d24809014 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/io.h> +#include <linux/media-bus-format.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -1276,28 +1277,45 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, * DISP Configuration */ +/** + * zynqmp_dp_disp_connected_live_layer - Return the first connected live layer + * @dp: DisplayPort IP core structure + * + * Return: The first connected live display layer or NULL if none of the live + * layers are connected. + */ +static struct zynqmp_disp_layer * +zynqmp_dp_disp_connected_live_layer(struct zynqmp_dp *dp) +{ + if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) + return dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID]; + else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX)) + return dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX]; + else + return NULL; +} + static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp, struct drm_bridge_state *old_bridge_state) { - enum zynqmp_dpsub_layer_id layer_id; struct zynqmp_disp_layer *layer; - const struct drm_format_info *info; + struct drm_bridge_state *bridge_state; + u32 bus_fmt; - if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) - layer_id = ZYNQMP_DPSUB_LAYER_VID; - else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX)) - layer_id = ZYNQMP_DPSUB_LAYER_GFX; - else + layer = zynqmp_dp_disp_connected_live_layer(dp); + if (!layer) return; - layer = dp->dpsub->layers[layer_id]; + bridge_state = drm_atomic_get_new_bridge_state(old_bridge_state->base.state, + old_bridge_state->bridge); + if (WARN_ON(!bridge_state)) + return; - /* TODO: Make the format configurable. */ - info = drm_format_info(DRM_FORMAT_YUV422); - zynqmp_disp_layer_set_format(layer, info); - zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_LIVE); + bus_fmt = bridge_state->input_bus_cfg.format; + zynqmp_disp_layer_set_live_format(layer, bus_fmt); + zynqmp_disp_layer_enable(layer); - if (layer_id == ZYNQMP_DPSUB_LAYER_GFX) + if (layer == dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX]) zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255); else zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, false, 0); @@ -1310,11 +1328,8 @@ static void zynqmp_dp_disp_disable(struct zynqmp_dp *dp, { struct zynqmp_disp_layer *layer; - if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) - layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID]; - else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX)) - layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX]; - else + layer = zynqmp_dp_disp_connected_live_layer(dp); + if (!layer) return; zynqmp_disp_disable(dp->dpsub->disp); @@ -1568,6 +1583,35 @@ static const struct drm_edid *zynqmp_dp_bridge_edid_read(struct drm_bridge *brid return drm_edid_read_ddc(connector, &dp->aux.ddc); } +static u32 *zynqmp_dp_bridge_default_bus_fmts(unsigned int *num_input_fmts) +{ + u32 *formats = kzalloc(sizeof(*formats), GFP_KERNEL); + + if (formats) + *formats = MEDIA_BUS_FMT_FIXED; + *num_input_fmts = !!formats; + + return formats; +} + +static u32 * +zynqmp_dp_bridge_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + struct zynqmp_disp_layer *layer; + + layer = zynqmp_dp_disp_connected_live_layer(dp); + if (layer) + return zynqmp_disp_live_layer_formats(layer, num_input_fmts); + else + return zynqmp_dp_bridge_default_bus_fmts(num_input_fmts); +} + static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { .attach = zynqmp_dp_bridge_attach, .detach = zynqmp_dp_bridge_detach, @@ -1580,6 +1624,7 @@ static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { .atomic_check = zynqmp_dp_bridge_atomic_check, .detect = zynqmp_dp_bridge_detect, .edid_read = zynqmp_dp_bridge_edid_read, + .atomic_get_input_bus_fmts = zynqmp_dp_bridge_get_input_bus_fmts, }; /* ----------------------------------------------------------------------------- @@ -1714,6 +1759,10 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) goto err_free; } + ret = zynqmp_dp_reset(dp, true); + if (ret < 0) + goto err_free; + ret = zynqmp_dp_reset(dp, false); if (ret < 0) goto err_free; |