Loading drivers/gpu/drm/msm/dsi-staging/dsi_display.c +187 −59 Original line number Diff line number Diff line Loading @@ -3498,8 +3498,15 @@ static int dsi_display_parse_dt(struct dsi_display *display) /* Parse TE data */ dsi_display_parse_te_data(display); /* Parse external bridge from port 0, reg 0 */ display->ext_bridge_of = of_graph_get_remote_node(of_node, 0, 0); /* Parse all external bridges from port 0 */ display_for_each_ctrl(i, display) { display->ext_bridge[i].node_of = of_graph_get_remote_node(of_node, 0, i); if (display->ext_bridge[i].node_of) display->ext_bridge_cnt++; else break; } pr_debug("success\n"); error: Loading Loading @@ -5112,6 +5119,102 @@ static int dsi_display_ext_get_mode_info(struct drm_connector *connector, return 0; } static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge( struct drm_bridge *bridge) { struct msm_drm_private *priv; struct sde_kms *sde_kms; struct list_head *connector_list; struct drm_connector *conn_iter; struct sde_connector *sde_conn; struct dsi_display *display; int i; if (!bridge || !bridge->encoder) { SDE_ERROR("invalid argument\n"); return NULL; } priv = bridge->dev->dev_private; sde_kms = to_sde_kms(priv->kms); connector_list = &sde_kms->dev->mode_config.connector_list; list_for_each_entry(conn_iter, connector_list, head) { sde_conn = to_sde_connector(conn_iter); if (sde_conn->encoder == bridge->encoder) { display = sde_conn->display; for (i = 0; i < display->ctrl_count; i++) { if (display->ext_bridge[i].bridge == bridge) return &display->ext_bridge[i]; } } } return NULL; } static void dsi_display_drm_ext_adjust_timing( const struct dsi_display *display, struct drm_display_mode *mode) { mode->hdisplay /= display->ctrl_count; mode->hsync_start /= display->ctrl_count; mode->hsync_end /= display->ctrl_count; mode->htotal /= display->ctrl_count; mode->hskew /= display->ctrl_count; mode->clock /= display->ctrl_count; } static enum drm_mode_status dsi_display_drm_ext_bridge_mode_valid( struct drm_bridge *bridge, const struct drm_display_mode *mode) { struct dsi_display_ext_bridge *ext_bridge; struct drm_display_mode tmp; ext_bridge = dsi_display_ext_get_bridge(bridge); if (!ext_bridge) return MODE_ERROR; tmp = *mode; dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); return ext_bridge->orig_funcs->mode_valid(bridge, &tmp); } static bool dsi_display_drm_ext_bridge_mode_fixup( struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct dsi_display_ext_bridge *ext_bridge; struct drm_display_mode tmp; ext_bridge = dsi_display_ext_get_bridge(bridge); if (!ext_bridge) return false; tmp = *mode; dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); return ext_bridge->orig_funcs->mode_fixup(bridge, &tmp, &tmp); } static void dsi_display_drm_ext_bridge_mode_set( struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct dsi_display_ext_bridge *ext_bridge; struct drm_display_mode tmp; ext_bridge = dsi_display_ext_get_bridge(bridge); if (!ext_bridge) return; tmp = *mode; dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); ext_bridge->orig_funcs->mode_set(bridge, &tmp, &tmp); } static int dsi_host_ext_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi) { Loading Loading @@ -5204,31 +5307,50 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, struct drm_bridge *ext_bridge; struct drm_connector *ext_conn; struct sde_connector *sde_conn = to_sde_connector(connector); int rc; struct drm_bridge *prev_bridge = bridge; int rc = 0, i; /* check if ext_bridge is already attached */ if (display->ext_bridge) return 0; for (i = 0; i < display->ext_bridge_cnt; i++) { struct dsi_display_ext_bridge *ext_bridge_info = &display->ext_bridge[i]; /* check if there is no external bridge defined */ if (!display->ext_bridge_of) /* return if ext bridge is already initialized */ if (ext_bridge_info->bridge) return 0; ext_bridge = of_drm_find_bridge(display->ext_bridge_of); ext_bridge = of_drm_find_bridge(ext_bridge_info->node_of); if (IS_ERR_OR_NULL(ext_bridge)) { rc = PTR_ERR(ext_bridge); pr_err("failed to find ext bridge\n"); goto error; } rc = drm_bridge_attach(bridge->encoder, ext_bridge, bridge); /* override functions for mode adjustment */ if (display->ext_bridge_cnt > 1) { ext_bridge_info->bridge_funcs = *ext_bridge->funcs; if (ext_bridge->funcs->mode_fixup) ext_bridge_info->bridge_funcs.mode_fixup = dsi_display_drm_ext_bridge_mode_fixup; if (ext_bridge->funcs->mode_valid) ext_bridge_info->bridge_funcs.mode_valid = dsi_display_drm_ext_bridge_mode_valid; if (ext_bridge->funcs->mode_set) ext_bridge_info->bridge_funcs.mode_set = dsi_display_drm_ext_bridge_mode_set; ext_bridge_info->orig_funcs = ext_bridge->funcs; ext_bridge->funcs = &ext_bridge_info->bridge_funcs; } rc = drm_bridge_attach(encoder, ext_bridge, prev_bridge); if (rc) { pr_err("[%s] ext brige attach failed, %d\n", display->name, rc); goto error; } display->ext_bridge = ext_bridge; ext_bridge_info->display = display; ext_bridge_info->bridge = ext_bridge; prev_bridge = ext_bridge; /* ext bridge will init its own connector during attach, * we need to extract it out of the connector list Loading @@ -5243,14 +5365,15 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, } spin_unlock_irq(&drm->mode_config.connector_list_lock); /* if there is no valid external connector created, we'll use default * setting from panel defined in DT file. /* if there is no valid external connector created, or in split * mode, default setting is used from panel defined in DT file. */ if (!display->ext_conn || !display->ext_conn->funcs || !display->ext_conn->helper_private) { !display->ext_conn->helper_private || display->ext_bridge_cnt > 1) { display->ext_conn = NULL; return 0; continue; } /* otherwise, hook up the functions to use external connector */ Loading @@ -5258,13 +5381,16 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, sde_conn->ops.detect = dsi_display_drm_ext_detect; if (display->ext_conn->helper_private->get_modes) sde_conn->ops.get_modes = dsi_display_drm_ext_get_modes; sde_conn->ops.get_modes = dsi_display_drm_ext_get_modes; if (display->ext_conn->helper_private->mode_valid) sde_conn->ops.mode_valid = dsi_display_drm_ext_mode_valid; sde_conn->ops.mode_valid = dsi_display_drm_ext_mode_valid; if (display->ext_conn->helper_private->atomic_check) sde_conn->ops.atomic_check = dsi_display_drm_ext_atomic_check; sde_conn->ops.atomic_check = dsi_display_drm_ext_atomic_check; sde_conn->ops.get_info = dsi_display_ext_get_info; Loading @@ -5273,6 +5399,8 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, /* add support to attach/detach */ display->host.ops = &dsi_host_ext_ops; } return 0; error: return rc; Loading drivers/gpu/drm/msm/dsi-staging/dsi_display.h +22 −4 Original line number Diff line number Diff line Loading @@ -123,6 +123,22 @@ struct dsi_display_clk_info { struct dsi_clk_link_set shadow_clks; }; /** * struct dsi_display_ext_bridge - dsi display external bridge information * @display: Pointer of DSI display. * @node_of: Bridge node created from bridge driver. * @bridge: Bridge created from bridge driver * @orig_funcs: Bridge function from bridge driver (split mode only) * @bridge_funcs: Overridden function from bridge driver (split mode only) */ struct dsi_display_ext_bridge { void *display; struct device_node *node_of; struct drm_bridge *bridge; const struct drm_bridge_funcs *orig_funcs; struct drm_bridge_funcs bridge_funcs; }; /** * struct dsi_display - dsi display information * @pdev: Pointer to platform device. Loading @@ -143,7 +159,8 @@ struct dsi_display_clk_info { * @ctrl: Controller information for DSI display. * @panel: Handle to DSI panel. * @panel_of: pHandle to DSI panel. * @ext_bridge_of: pHandle to external DSI bridge. * @ext_bridge: External bridge information for DSI display. * @ext_bridge_cnt: Number of external bridges * @modes: Array of probed DSI modes * @type: DSI display type. * @clk_master_idx: The master controller for controlling clocks. This is an Loading @@ -163,7 +180,6 @@ struct dsi_display_clk_info { * @phy_idle_power_off: PHY power state. * @host: DRM MIPI DSI Host. * @bridge: Pointer to DRM bridge object. * @ext_bridge: Pointer to external bridge object attached to DSI bridge. * @cmd_engine_refcount: Reference count enforcing single instance of cmd eng * @clk_mngr: DSI clock manager. * @dsi_clk_handle: DSI clock handle. Loading Loading @@ -198,7 +214,10 @@ struct dsi_display { struct device_node *disp_node; struct device_node *panel_of; struct device_node *parser_node; struct device_node *ext_bridge_of; /* external bridge */ struct dsi_display_ext_bridge ext_bridge[MAX_DSI_CTRLS_PER_DISPLAY]; u32 ext_bridge_cnt; struct dsi_display_mode *modes; Loading Loading @@ -228,7 +247,6 @@ struct dsi_display { struct mipi_dsi_host host; struct dsi_bridge *bridge; struct drm_bridge *ext_bridge; u32 cmd_engine_refcount; struct sde_power_handle *phandle; Loading Loading
drivers/gpu/drm/msm/dsi-staging/dsi_display.c +187 −59 Original line number Diff line number Diff line Loading @@ -3498,8 +3498,15 @@ static int dsi_display_parse_dt(struct dsi_display *display) /* Parse TE data */ dsi_display_parse_te_data(display); /* Parse external bridge from port 0, reg 0 */ display->ext_bridge_of = of_graph_get_remote_node(of_node, 0, 0); /* Parse all external bridges from port 0 */ display_for_each_ctrl(i, display) { display->ext_bridge[i].node_of = of_graph_get_remote_node(of_node, 0, i); if (display->ext_bridge[i].node_of) display->ext_bridge_cnt++; else break; } pr_debug("success\n"); error: Loading Loading @@ -5112,6 +5119,102 @@ static int dsi_display_ext_get_mode_info(struct drm_connector *connector, return 0; } static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge( struct drm_bridge *bridge) { struct msm_drm_private *priv; struct sde_kms *sde_kms; struct list_head *connector_list; struct drm_connector *conn_iter; struct sde_connector *sde_conn; struct dsi_display *display; int i; if (!bridge || !bridge->encoder) { SDE_ERROR("invalid argument\n"); return NULL; } priv = bridge->dev->dev_private; sde_kms = to_sde_kms(priv->kms); connector_list = &sde_kms->dev->mode_config.connector_list; list_for_each_entry(conn_iter, connector_list, head) { sde_conn = to_sde_connector(conn_iter); if (sde_conn->encoder == bridge->encoder) { display = sde_conn->display; for (i = 0; i < display->ctrl_count; i++) { if (display->ext_bridge[i].bridge == bridge) return &display->ext_bridge[i]; } } } return NULL; } static void dsi_display_drm_ext_adjust_timing( const struct dsi_display *display, struct drm_display_mode *mode) { mode->hdisplay /= display->ctrl_count; mode->hsync_start /= display->ctrl_count; mode->hsync_end /= display->ctrl_count; mode->htotal /= display->ctrl_count; mode->hskew /= display->ctrl_count; mode->clock /= display->ctrl_count; } static enum drm_mode_status dsi_display_drm_ext_bridge_mode_valid( struct drm_bridge *bridge, const struct drm_display_mode *mode) { struct dsi_display_ext_bridge *ext_bridge; struct drm_display_mode tmp; ext_bridge = dsi_display_ext_get_bridge(bridge); if (!ext_bridge) return MODE_ERROR; tmp = *mode; dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); return ext_bridge->orig_funcs->mode_valid(bridge, &tmp); } static bool dsi_display_drm_ext_bridge_mode_fixup( struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct dsi_display_ext_bridge *ext_bridge; struct drm_display_mode tmp; ext_bridge = dsi_display_ext_get_bridge(bridge); if (!ext_bridge) return false; tmp = *mode; dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); return ext_bridge->orig_funcs->mode_fixup(bridge, &tmp, &tmp); } static void dsi_display_drm_ext_bridge_mode_set( struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct dsi_display_ext_bridge *ext_bridge; struct drm_display_mode tmp; ext_bridge = dsi_display_ext_get_bridge(bridge); if (!ext_bridge) return; tmp = *mode; dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); ext_bridge->orig_funcs->mode_set(bridge, &tmp, &tmp); } static int dsi_host_ext_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi) { Loading Loading @@ -5204,31 +5307,50 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, struct drm_bridge *ext_bridge; struct drm_connector *ext_conn; struct sde_connector *sde_conn = to_sde_connector(connector); int rc; struct drm_bridge *prev_bridge = bridge; int rc = 0, i; /* check if ext_bridge is already attached */ if (display->ext_bridge) return 0; for (i = 0; i < display->ext_bridge_cnt; i++) { struct dsi_display_ext_bridge *ext_bridge_info = &display->ext_bridge[i]; /* check if there is no external bridge defined */ if (!display->ext_bridge_of) /* return if ext bridge is already initialized */ if (ext_bridge_info->bridge) return 0; ext_bridge = of_drm_find_bridge(display->ext_bridge_of); ext_bridge = of_drm_find_bridge(ext_bridge_info->node_of); if (IS_ERR_OR_NULL(ext_bridge)) { rc = PTR_ERR(ext_bridge); pr_err("failed to find ext bridge\n"); goto error; } rc = drm_bridge_attach(bridge->encoder, ext_bridge, bridge); /* override functions for mode adjustment */ if (display->ext_bridge_cnt > 1) { ext_bridge_info->bridge_funcs = *ext_bridge->funcs; if (ext_bridge->funcs->mode_fixup) ext_bridge_info->bridge_funcs.mode_fixup = dsi_display_drm_ext_bridge_mode_fixup; if (ext_bridge->funcs->mode_valid) ext_bridge_info->bridge_funcs.mode_valid = dsi_display_drm_ext_bridge_mode_valid; if (ext_bridge->funcs->mode_set) ext_bridge_info->bridge_funcs.mode_set = dsi_display_drm_ext_bridge_mode_set; ext_bridge_info->orig_funcs = ext_bridge->funcs; ext_bridge->funcs = &ext_bridge_info->bridge_funcs; } rc = drm_bridge_attach(encoder, ext_bridge, prev_bridge); if (rc) { pr_err("[%s] ext brige attach failed, %d\n", display->name, rc); goto error; } display->ext_bridge = ext_bridge; ext_bridge_info->display = display; ext_bridge_info->bridge = ext_bridge; prev_bridge = ext_bridge; /* ext bridge will init its own connector during attach, * we need to extract it out of the connector list Loading @@ -5243,14 +5365,15 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, } spin_unlock_irq(&drm->mode_config.connector_list_lock); /* if there is no valid external connector created, we'll use default * setting from panel defined in DT file. /* if there is no valid external connector created, or in split * mode, default setting is used from panel defined in DT file. */ if (!display->ext_conn || !display->ext_conn->funcs || !display->ext_conn->helper_private) { !display->ext_conn->helper_private || display->ext_bridge_cnt > 1) { display->ext_conn = NULL; return 0; continue; } /* otherwise, hook up the functions to use external connector */ Loading @@ -5258,13 +5381,16 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, sde_conn->ops.detect = dsi_display_drm_ext_detect; if (display->ext_conn->helper_private->get_modes) sde_conn->ops.get_modes = dsi_display_drm_ext_get_modes; sde_conn->ops.get_modes = dsi_display_drm_ext_get_modes; if (display->ext_conn->helper_private->mode_valid) sde_conn->ops.mode_valid = dsi_display_drm_ext_mode_valid; sde_conn->ops.mode_valid = dsi_display_drm_ext_mode_valid; if (display->ext_conn->helper_private->atomic_check) sde_conn->ops.atomic_check = dsi_display_drm_ext_atomic_check; sde_conn->ops.atomic_check = dsi_display_drm_ext_atomic_check; sde_conn->ops.get_info = dsi_display_ext_get_info; Loading @@ -5273,6 +5399,8 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, /* add support to attach/detach */ display->host.ops = &dsi_host_ext_ops; } return 0; error: return rc; Loading
drivers/gpu/drm/msm/dsi-staging/dsi_display.h +22 −4 Original line number Diff line number Diff line Loading @@ -123,6 +123,22 @@ struct dsi_display_clk_info { struct dsi_clk_link_set shadow_clks; }; /** * struct dsi_display_ext_bridge - dsi display external bridge information * @display: Pointer of DSI display. * @node_of: Bridge node created from bridge driver. * @bridge: Bridge created from bridge driver * @orig_funcs: Bridge function from bridge driver (split mode only) * @bridge_funcs: Overridden function from bridge driver (split mode only) */ struct dsi_display_ext_bridge { void *display; struct device_node *node_of; struct drm_bridge *bridge; const struct drm_bridge_funcs *orig_funcs; struct drm_bridge_funcs bridge_funcs; }; /** * struct dsi_display - dsi display information * @pdev: Pointer to platform device. Loading @@ -143,7 +159,8 @@ struct dsi_display_clk_info { * @ctrl: Controller information for DSI display. * @panel: Handle to DSI panel. * @panel_of: pHandle to DSI panel. * @ext_bridge_of: pHandle to external DSI bridge. * @ext_bridge: External bridge information for DSI display. * @ext_bridge_cnt: Number of external bridges * @modes: Array of probed DSI modes * @type: DSI display type. * @clk_master_idx: The master controller for controlling clocks. This is an Loading @@ -163,7 +180,6 @@ struct dsi_display_clk_info { * @phy_idle_power_off: PHY power state. * @host: DRM MIPI DSI Host. * @bridge: Pointer to DRM bridge object. * @ext_bridge: Pointer to external bridge object attached to DSI bridge. * @cmd_engine_refcount: Reference count enforcing single instance of cmd eng * @clk_mngr: DSI clock manager. * @dsi_clk_handle: DSI clock handle. Loading Loading @@ -198,7 +214,10 @@ struct dsi_display { struct device_node *disp_node; struct device_node *panel_of; struct device_node *parser_node; struct device_node *ext_bridge_of; /* external bridge */ struct dsi_display_ext_bridge ext_bridge[MAX_DSI_CTRLS_PER_DISPLAY]; u32 ext_bridge_cnt; struct dsi_display_mode *modes; Loading Loading @@ -228,7 +247,6 @@ struct dsi_display { struct mipi_dsi_host host; struct dsi_bridge *bridge; struct drm_bridge *ext_bridge; u32 cmd_engine_refcount; struct sde_power_handle *phandle; Loading