Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/tidss: Update encoder/bridge chain connect model

With the new encoder/bridge chain model, the display controller driver
is required to create a drm_connector entity instead of asking the
bridge to do so during drm_bridge_attach. Moreover, the controller
driver should create a drm_bridge entity to negotiate bus formats and a
'simple' drm_encoder entity to expose it to userspace.

Update the encoder/bridge initialization sequence in tidss as per the
new model.

Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230606082142.23760-8-a-bhatia1@ti.com

authored by

Aradhya Bhatia and committed by
Javier Martinez Canillas
c932ced6 b1c08ffc

+93 -62
+86 -52
drivers/gpu/drm/tidss/tidss_encoder.c
··· 6 6 7 7 #include <linux/export.h> 8 8 9 + #include <drm/drm_atomic_helper.h> 10 + #include <drm/drm_bridge.h> 11 + #include <drm/drm_bridge_connector.h> 9 12 #include <drm/drm_crtc.h> 10 13 #include <drm/drm_modeset_helper_vtables.h> 11 14 #include <drm/drm_panel.h> 12 15 #include <drm/drm_of.h> 16 + #include <drm/drm_simple_kms_helper.h> 13 17 14 18 #include "tidss_crtc.h" 15 19 #include "tidss_drv.h" 16 20 #include "tidss_encoder.h" 17 21 18 - static int tidss_encoder_atomic_check(struct drm_encoder *encoder, 19 - struct drm_crtc_state *crtc_state, 20 - struct drm_connector_state *conn_state) 22 + struct tidss_encoder { 23 + struct drm_bridge bridge; 24 + struct drm_encoder encoder; 25 + struct drm_connector *connector; 26 + struct drm_bridge *next_bridge; 27 + struct tidss_device *tidss; 28 + }; 29 + 30 + static inline struct tidss_encoder 31 + *bridge_to_tidss_encoder(struct drm_bridge *b) 21 32 { 22 - struct drm_device *ddev = encoder->dev; 33 + return container_of(b, struct tidss_encoder, bridge); 34 + } 35 + 36 + static int tidss_bridge_attach(struct drm_bridge *bridge, 37 + enum drm_bridge_attach_flags flags) 38 + { 39 + struct tidss_encoder *t_enc = bridge_to_tidss_encoder(bridge); 40 + 41 + return drm_bridge_attach(bridge->encoder, t_enc->next_bridge, 42 + bridge, flags); 43 + } 44 + 45 + static int tidss_bridge_atomic_check(struct drm_bridge *bridge, 46 + struct drm_bridge_state *bridge_state, 47 + struct drm_crtc_state *crtc_state, 48 + struct drm_connector_state *conn_state) 49 + { 50 + struct tidss_encoder *t_enc = bridge_to_tidss_encoder(bridge); 51 + struct tidss_device *tidss = t_enc->tidss; 23 52 struct tidss_crtc_state *tcrtc_state = to_tidss_crtc_state(crtc_state); 24 53 struct drm_display_info *di = &conn_state->connector->display_info; 25 - struct drm_bridge *bridge; 26 - bool bus_flags_set = false; 54 + struct drm_bridge_state *next_bridge_state = NULL; 27 55 28 - dev_dbg(ddev->dev, "%s\n", __func__); 56 + if (t_enc->next_bridge) 57 + next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, 58 + t_enc->next_bridge); 29 59 30 - /* 31 - * Take the bus_flags from the first bridge that defines 32 - * bridge timings, or from the connector's display_info if no 33 - * bridge defines the timings. 34 - */ 35 - drm_for_each_bridge_in_chain(encoder, bridge) { 36 - if (!bridge->timings) 37 - continue; 38 - 39 - tcrtc_state->bus_flags = bridge->timings->input_bus_flags; 40 - bus_flags_set = true; 41 - break; 42 - } 43 - 44 - if (!di->bus_formats || di->num_bus_formats == 0) { 45 - dev_err(ddev->dev, "%s: No bus_formats in connected display\n", 60 + if (next_bridge_state) { 61 + tcrtc_state->bus_flags = next_bridge_state->input_bus_cfg.flags; 62 + tcrtc_state->bus_format = next_bridge_state->input_bus_cfg.format; 63 + } else if (di->num_bus_formats) { 64 + tcrtc_state->bus_format = di->bus_formats[0]; 65 + tcrtc_state->bus_flags = di->bus_flags; 66 + } else { 67 + dev_err(tidss->dev, "%s: No bus_formats in connected display\n", 46 68 __func__); 47 69 return -EINVAL; 48 70 } 49 71 50 - // XXX any cleaner way to set bus format and flags? 51 - tcrtc_state->bus_format = di->bus_formats[0]; 52 - if (!bus_flags_set) 53 - tcrtc_state->bus_flags = di->bus_flags; 54 - 55 72 return 0; 56 73 } 57 74 58 - static void tidss_encoder_destroy(struct drm_encoder *encoder) 59 - { 60 - drm_encoder_cleanup(encoder); 61 - kfree(encoder); 62 - } 63 - 64 - static const struct drm_encoder_helper_funcs encoder_helper_funcs = { 65 - .atomic_check = tidss_encoder_atomic_check, 75 + static const struct drm_bridge_funcs tidss_bridge_funcs = { 76 + .attach = tidss_bridge_attach, 77 + .atomic_check = tidss_bridge_atomic_check, 78 + .atomic_reset = drm_atomic_helper_bridge_reset, 79 + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 80 + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 66 81 }; 67 82 68 - static const struct drm_encoder_funcs encoder_funcs = { 69 - .destroy = tidss_encoder_destroy, 70 - }; 71 - 72 - struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss, 73 - u32 encoder_type, u32 possible_crtcs) 83 + int tidss_encoder_create(struct tidss_device *tidss, 84 + struct drm_bridge *next_bridge, 85 + u32 encoder_type, u32 possible_crtcs) 74 86 { 87 + struct tidss_encoder *t_enc; 75 88 struct drm_encoder *enc; 89 + struct drm_connector *connector; 76 90 int ret; 77 91 78 - enc = kzalloc(sizeof(*enc), GFP_KERNEL); 79 - if (!enc) 80 - return ERR_PTR(-ENOMEM); 92 + t_enc = drmm_simple_encoder_alloc(&tidss->ddev, struct tidss_encoder, 93 + encoder, encoder_type); 94 + if (IS_ERR(t_enc)) 95 + return PTR_ERR(t_enc); 81 96 97 + t_enc->tidss = tidss; 98 + t_enc->next_bridge = next_bridge; 99 + t_enc->bridge.funcs = &tidss_bridge_funcs; 100 + 101 + enc = &t_enc->encoder; 82 102 enc->possible_crtcs = possible_crtcs; 83 103 84 - ret = drm_encoder_init(&tidss->ddev, enc, &encoder_funcs, 85 - encoder_type, NULL); 86 - if (ret < 0) { 87 - kfree(enc); 88 - return ERR_PTR(ret); 104 + /* Attaching first bridge to the encoder */ 105 + ret = drm_bridge_attach(enc, &t_enc->bridge, NULL, 106 + DRM_BRIDGE_ATTACH_NO_CONNECTOR); 107 + if (ret) { 108 + dev_err(tidss->dev, "bridge attach failed: %d\n", ret); 109 + return ret; 89 110 } 90 111 91 - drm_encoder_helper_add(enc, &encoder_helper_funcs); 112 + /* Initializing the connector at the end of bridge-chain */ 113 + connector = drm_bridge_connector_init(&tidss->ddev, enc); 114 + if (IS_ERR(connector)) { 115 + dev_err(tidss->dev, "bridge_connector create failed\n"); 116 + return PTR_ERR(connector); 117 + } 118 + 119 + ret = drm_connector_attach_encoder(connector, enc); 120 + if (ret) { 121 + dev_err(tidss->dev, "attaching encoder to connector failed\n"); 122 + return ret; 123 + } 124 + 125 + t_enc->connector = connector; 92 126 93 127 dev_dbg(tidss->dev, "Encoder create done\n"); 94 128 95 - return enc; 129 + return ret; 96 130 }
+3 -2
drivers/gpu/drm/tidss/tidss_encoder.h
··· 11 11 12 12 struct tidss_device; 13 13 14 - struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss, 15 - u32 encoder_type, u32 possible_crtcs); 14 + int tidss_encoder_create(struct tidss_device *tidss, 15 + struct drm_bridge *next_bridge, 16 + u32 encoder_type, u32 possible_crtcs); 16 17 17 18 #endif
+4 -8
drivers/gpu/drm/tidss/tidss_kms.c
··· 193 193 for (i = 0; i < num_pipes; ++i) { 194 194 struct tidss_plane *tplane; 195 195 struct tidss_crtc *tcrtc; 196 - struct drm_encoder *enc; 197 196 u32 hw_plane_id = feat->vid_order[tidss->num_planes]; 198 197 int ret; 199 198 ··· 215 216 216 217 tidss->crtcs[tidss->num_crtcs++] = &tcrtc->crtc; 217 218 218 - enc = tidss_encoder_create(tidss, pipes[i].enc_type, 219 + ret = tidss_encoder_create(tidss, pipes[i].bridge, 220 + pipes[i].enc_type, 219 221 1 << tcrtc->crtc.index); 220 - if (IS_ERR(enc)) { 222 + if (ret) { 221 223 dev_err(tidss->dev, "encoder create failed\n"); 222 - return PTR_ERR(enc); 223 - } 224 - 225 - ret = drm_bridge_attach(enc, pipes[i].bridge, NULL, 0); 226 - if (ret) 227 224 return ret; 225 + } 228 226 } 229 227 230 228 /* create overlay planes of the leftover planes */