.. | .. |
---|
26 | 26 | #include <drm/drm_dp_helper.h> |
---|
27 | 27 | #include <drm/drm_atomic.h> |
---|
28 | 28 | |
---|
| 29 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
---|
| 30 | +#include <linux/stackdepot.h> |
---|
| 31 | +#include <linux/timekeeping.h> |
---|
| 32 | + |
---|
| 33 | +enum drm_dp_mst_topology_ref_type { |
---|
| 34 | + DRM_DP_MST_TOPOLOGY_REF_GET, |
---|
| 35 | + DRM_DP_MST_TOPOLOGY_REF_PUT, |
---|
| 36 | +}; |
---|
| 37 | + |
---|
| 38 | +struct drm_dp_mst_topology_ref_history { |
---|
| 39 | + struct drm_dp_mst_topology_ref_entry { |
---|
| 40 | + enum drm_dp_mst_topology_ref_type type; |
---|
| 41 | + int count; |
---|
| 42 | + ktime_t ts_nsec; |
---|
| 43 | + depot_stack_handle_t backtrace; |
---|
| 44 | + } *entries; |
---|
| 45 | + int len; |
---|
| 46 | +}; |
---|
| 47 | +#endif /* IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) */ |
---|
| 48 | + |
---|
29 | 49 | struct drm_dp_mst_branch; |
---|
30 | | -struct drm_dp_mst_port; |
---|
31 | 50 | |
---|
32 | 51 | /** |
---|
33 | 52 | * struct drm_dp_vcpi - Virtual Channel Payload Identifier |
---|
.. | .. |
---|
43 | 62 | int num_slots; |
---|
44 | 63 | }; |
---|
45 | 64 | |
---|
46 | | -struct drm_dp_mst_dsc_dpcd_cache { |
---|
47 | | - bool valid; |
---|
48 | | - bool use_parent_dpcd; |
---|
49 | | - u8 dsc_dpcd[16]; |
---|
50 | | -}; |
---|
51 | | - |
---|
52 | | -struct drm_dp_mst_dsc_info { |
---|
53 | | - bool dsc_support; |
---|
54 | | - struct drm_dp_mst_port *dsc_port; |
---|
55 | | - struct drm_dp_mst_dsc_dpcd_cache dsc_dpcd_cache; |
---|
56 | | -}; |
---|
57 | | - |
---|
58 | 65 | /** |
---|
59 | 66 | * struct drm_dp_mst_port - MST port |
---|
60 | | - * @kref: reference count for this port. |
---|
61 | 67 | * @port_num: port number |
---|
62 | | - * @input: if this port is an input port. |
---|
63 | | - * @mcs: message capability status - DP 1.2 spec. |
---|
64 | | - * @ddps: DisplayPort Device Plug Status - DP 1.2 |
---|
65 | | - * @pdt: Peer Device Type |
---|
66 | | - * @ldps: Legacy Device Plug Status |
---|
67 | | - * @dpcd_rev: DPCD revision of device on this port |
---|
68 | | - * @num_sdp_streams: Number of simultaneous streams |
---|
69 | | - * @num_sdp_stream_sinks: Number of stream sinks |
---|
70 | | - * @available_pbn: Available bandwidth for this port. |
---|
| 68 | + * @input: if this port is an input port. Protected by |
---|
| 69 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 70 | + * @mcs: message capability status - DP 1.2 spec. Protected by |
---|
| 71 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 72 | + * @ddps: DisplayPort Device Plug Status - DP 1.2. Protected by |
---|
| 73 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 74 | + * @pdt: Peer Device Type. Protected by |
---|
| 75 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 76 | + * @ldps: Legacy Device Plug Status. Protected by |
---|
| 77 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 78 | + * @dpcd_rev: DPCD revision of device on this port. Protected by |
---|
| 79 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 80 | + * @num_sdp_streams: Number of simultaneous streams. Protected by |
---|
| 81 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 82 | + * @num_sdp_stream_sinks: Number of stream sinks. Protected by |
---|
| 83 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
| 84 | + * @full_pbn: Max possible bandwidth for this port. Protected by |
---|
| 85 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
71 | 86 | * @next: link to next port on this branch device |
---|
72 | | - * @mstb: branch device attach below this port |
---|
73 | | - * @aux: i2c aux transport to talk to device connected to this port. |
---|
| 87 | + * @aux: i2c aux transport to talk to device connected to this port, protected |
---|
| 88 | + * by &drm_dp_mst_topology_mgr.base.lock. |
---|
74 | 89 | * @parent: branch device parent of this port |
---|
75 | 90 | * @vcpi: Virtual Channel Payload info for this port. |
---|
76 | | - * @connector: DRM connector this port is connected to. |
---|
| 91 | + * @connector: DRM connector this port is connected to. Protected by |
---|
| 92 | + * &drm_dp_mst_topology_mgr.base.lock. |
---|
77 | 93 | * @mgr: topology manager this port lives under. |
---|
78 | 94 | * |
---|
79 | 95 | * This structure represents an MST port endpoint on a device somewhere |
---|
80 | 96 | * in the MST topology. |
---|
81 | 97 | */ |
---|
82 | 98 | struct drm_dp_mst_port { |
---|
83 | | - struct kref kref; |
---|
| 99 | + /** |
---|
| 100 | + * @topology_kref: refcount for this port's lifetime in the topology, |
---|
| 101 | + * only the DP MST helpers should need to touch this |
---|
| 102 | + */ |
---|
| 103 | + struct kref topology_kref; |
---|
| 104 | + |
---|
| 105 | + /** |
---|
| 106 | + * @malloc_kref: refcount for the memory allocation containing this |
---|
| 107 | + * structure. See drm_dp_mst_get_port_malloc() and |
---|
| 108 | + * drm_dp_mst_put_port_malloc(). |
---|
| 109 | + */ |
---|
| 110 | + struct kref malloc_kref; |
---|
| 111 | + |
---|
| 112 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
---|
| 113 | + /** |
---|
| 114 | + * @topology_ref_history: A history of each topology |
---|
| 115 | + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. |
---|
| 116 | + */ |
---|
| 117 | + struct drm_dp_mst_topology_ref_history topology_ref_history; |
---|
| 118 | +#endif |
---|
84 | 119 | |
---|
85 | 120 | u8 port_num; |
---|
86 | 121 | bool input; |
---|
.. | .. |
---|
91 | 126 | u8 dpcd_rev; |
---|
92 | 127 | u8 num_sdp_streams; |
---|
93 | 128 | u8 num_sdp_stream_sinks; |
---|
94 | | - uint16_t available_pbn; |
---|
| 129 | + uint16_t full_pbn; |
---|
95 | 130 | struct list_head next; |
---|
96 | | - struct drm_dp_mst_branch *mstb; /* pointer to an mstb if this port has one */ |
---|
| 131 | + /** |
---|
| 132 | + * @mstb: the branch device connected to this port, if there is one. |
---|
| 133 | + * This should be considered protected for reading by |
---|
| 134 | + * &drm_dp_mst_topology_mgr.lock. There are two exceptions to this: |
---|
| 135 | + * &drm_dp_mst_topology_mgr.up_req_work and |
---|
| 136 | + * &drm_dp_mst_topology_mgr.work, which do not grab |
---|
| 137 | + * &drm_dp_mst_topology_mgr.lock during reads but are the only |
---|
| 138 | + * updaters of this list and are protected from writing concurrently |
---|
| 139 | + * by &drm_dp_mst_topology_mgr.probe_lock. |
---|
| 140 | + */ |
---|
| 141 | + struct drm_dp_mst_branch *mstb; |
---|
97 | 142 | struct drm_dp_aux aux; /* i2c bus for this port? */ |
---|
98 | 143 | struct drm_dp_mst_branch *parent; |
---|
99 | 144 | |
---|
.. | .. |
---|
112 | 157 | */ |
---|
113 | 158 | bool has_audio; |
---|
114 | 159 | |
---|
| 160 | + /** |
---|
| 161 | + * @fec_capable: bool indicating if FEC can be supported up to that |
---|
| 162 | + * point in the MST topology. |
---|
| 163 | + */ |
---|
115 | 164 | bool fec_capable; |
---|
116 | | - |
---|
117 | | - struct drm_dp_mst_dsc_info dsc_info; |
---|
118 | 165 | }; |
---|
119 | | - |
---|
120 | | -/** |
---|
121 | | - * struct drm_dp_mst_branch - MST branch device. |
---|
122 | | - * @kref: reference count for this port. |
---|
123 | | - * @rad: Relative Address to talk to this branch device. |
---|
124 | | - * @lct: Link count total to talk to this branch device. |
---|
125 | | - * @num_ports: number of ports on the branch. |
---|
126 | | - * @msg_slots: one bit per transmitted msg slot. |
---|
127 | | - * @ports: linked list of ports on this branch. |
---|
128 | | - * @port_parent: pointer to the port parent, NULL if toplevel. |
---|
129 | | - * @mgr: topology manager for this branch device. |
---|
130 | | - * @tx_slots: transmission slots for this device. |
---|
131 | | - * @last_seqno: last sequence number used to talk to this. |
---|
132 | | - * @link_address_sent: if a link address message has been sent to this device yet. |
---|
133 | | - * @guid: guid for DP 1.2 branch device. port under this branch can be |
---|
134 | | - * identified by port #. |
---|
135 | | - * |
---|
136 | | - * This structure represents an MST branch device, there is one |
---|
137 | | - * primary branch device at the root, along with any other branches connected |
---|
138 | | - * to downstream port of parent branches. |
---|
139 | | - */ |
---|
140 | | -struct drm_dp_mst_branch { |
---|
141 | | - struct kref kref; |
---|
142 | | - u8 rad[8]; |
---|
143 | | - u8 lct; |
---|
144 | | - int num_ports; |
---|
145 | | - |
---|
146 | | - int msg_slots; |
---|
147 | | - struct list_head ports; |
---|
148 | | - |
---|
149 | | - /* list of tx ops queue for this port */ |
---|
150 | | - struct drm_dp_mst_port *port_parent; |
---|
151 | | - struct drm_dp_mst_topology_mgr *mgr; |
---|
152 | | - |
---|
153 | | - /* slots are protected by mstb->mgr->qlock */ |
---|
154 | | - struct drm_dp_sideband_msg_tx *tx_slots[2]; |
---|
155 | | - int last_seqno; |
---|
156 | | - bool link_address_sent; |
---|
157 | | - |
---|
158 | | - /* global unique identifier to identify branch devices */ |
---|
159 | | - u8 guid[16]; |
---|
160 | | -}; |
---|
161 | | - |
---|
162 | 166 | |
---|
163 | 167 | /* sideband msg header - not bit struct */ |
---|
164 | 168 | struct drm_dp_sideband_msg_hdr { |
---|
.. | .. |
---|
172 | 176 | bool eomt; |
---|
173 | 177 | bool seqno; |
---|
174 | 178 | }; |
---|
| 179 | + |
---|
| 180 | +struct drm_dp_sideband_msg_rx { |
---|
| 181 | + u8 chunk[48]; |
---|
| 182 | + u8 msg[256]; |
---|
| 183 | + u8 curchunk_len; |
---|
| 184 | + u8 curchunk_idx; /* chunk we are parsing now */ |
---|
| 185 | + u8 curchunk_hdrlen; |
---|
| 186 | + u8 curlen; /* total length of the msg */ |
---|
| 187 | + bool have_somt; |
---|
| 188 | + bool have_eomt; |
---|
| 189 | + struct drm_dp_sideband_msg_hdr initial_hdr; |
---|
| 190 | +}; |
---|
| 191 | + |
---|
| 192 | +/** |
---|
| 193 | + * struct drm_dp_mst_branch - MST branch device. |
---|
| 194 | + * @rad: Relative Address to talk to this branch device. |
---|
| 195 | + * @lct: Link count total to talk to this branch device. |
---|
| 196 | + * @num_ports: number of ports on the branch. |
---|
| 197 | + * @port_parent: pointer to the port parent, NULL if toplevel. |
---|
| 198 | + * @mgr: topology manager for this branch device. |
---|
| 199 | + * @link_address_sent: if a link address message has been sent to this device yet. |
---|
| 200 | + * @guid: guid for DP 1.2 branch device. port under this branch can be |
---|
| 201 | + * identified by port #. |
---|
| 202 | + * |
---|
| 203 | + * This structure represents an MST branch device, there is one |
---|
| 204 | + * primary branch device at the root, along with any other branches connected |
---|
| 205 | + * to downstream port of parent branches. |
---|
| 206 | + */ |
---|
| 207 | +struct drm_dp_mst_branch { |
---|
| 208 | + /** |
---|
| 209 | + * @topology_kref: refcount for this branch device's lifetime in the |
---|
| 210 | + * topology, only the DP MST helpers should need to touch this |
---|
| 211 | + */ |
---|
| 212 | + struct kref topology_kref; |
---|
| 213 | + |
---|
| 214 | + /** |
---|
| 215 | + * @malloc_kref: refcount for the memory allocation containing this |
---|
| 216 | + * structure. See drm_dp_mst_get_mstb_malloc() and |
---|
| 217 | + * drm_dp_mst_put_mstb_malloc(). |
---|
| 218 | + */ |
---|
| 219 | + struct kref malloc_kref; |
---|
| 220 | + |
---|
| 221 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
---|
| 222 | + /** |
---|
| 223 | + * @topology_ref_history: A history of each topology |
---|
| 224 | + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. |
---|
| 225 | + */ |
---|
| 226 | + struct drm_dp_mst_topology_ref_history topology_ref_history; |
---|
| 227 | +#endif |
---|
| 228 | + |
---|
| 229 | + /** |
---|
| 230 | + * @destroy_next: linked-list entry used by |
---|
| 231 | + * drm_dp_delayed_destroy_work() |
---|
| 232 | + */ |
---|
| 233 | + struct list_head destroy_next; |
---|
| 234 | + |
---|
| 235 | + u8 rad[8]; |
---|
| 236 | + u8 lct; |
---|
| 237 | + int num_ports; |
---|
| 238 | + |
---|
| 239 | + /** |
---|
| 240 | + * @ports: the list of ports on this branch device. This should be |
---|
| 241 | + * considered protected for reading by &drm_dp_mst_topology_mgr.lock. |
---|
| 242 | + * There are two exceptions to this: |
---|
| 243 | + * &drm_dp_mst_topology_mgr.up_req_work and |
---|
| 244 | + * &drm_dp_mst_topology_mgr.work, which do not grab |
---|
| 245 | + * &drm_dp_mst_topology_mgr.lock during reads but are the only |
---|
| 246 | + * updaters of this list and are protected from updating the list |
---|
| 247 | + * concurrently by @drm_dp_mst_topology_mgr.probe_lock |
---|
| 248 | + */ |
---|
| 249 | + struct list_head ports; |
---|
| 250 | + |
---|
| 251 | + struct drm_dp_mst_port *port_parent; |
---|
| 252 | + struct drm_dp_mst_topology_mgr *mgr; |
---|
| 253 | + |
---|
| 254 | + bool link_address_sent; |
---|
| 255 | + |
---|
| 256 | + /* global unique identifier to identify branch devices */ |
---|
| 257 | + u8 guid[16]; |
---|
| 258 | +}; |
---|
| 259 | + |
---|
175 | 260 | |
---|
176 | 261 | struct drm_dp_nak_reply { |
---|
177 | 262 | u8 guid[16]; |
---|
.. | .. |
---|
228 | 313 | u8 port_number; |
---|
229 | 314 | }; |
---|
230 | 315 | |
---|
| 316 | +struct drm_dp_query_stream_enc_status_ack_reply { |
---|
| 317 | + /* Bit[23:16]- Stream Id */ |
---|
| 318 | + u8 stream_id; |
---|
231 | 319 | |
---|
232 | | -struct drm_dp_sideband_msg_rx { |
---|
233 | | - u8 chunk[48]; |
---|
234 | | - u8 msg[256]; |
---|
235 | | - u8 curchunk_len; |
---|
236 | | - u8 curchunk_idx; /* chunk we are parsing now */ |
---|
237 | | - u8 curchunk_hdrlen; |
---|
238 | | - u8 curlen; /* total length of the msg */ |
---|
239 | | - bool have_somt; |
---|
240 | | - bool have_eomt; |
---|
241 | | - struct drm_dp_sideband_msg_hdr initial_hdr; |
---|
| 320 | + /* Bit[15]- Signed */ |
---|
| 321 | + bool reply_signed; |
---|
| 322 | + |
---|
| 323 | + /* Bit[10:8]- Stream Output Sink Type */ |
---|
| 324 | + bool unauthorizable_device_present; |
---|
| 325 | + bool legacy_device_present; |
---|
| 326 | + bool query_capable_device_present; |
---|
| 327 | + |
---|
| 328 | + /* Bit[12:11]- Stream Output CP Type */ |
---|
| 329 | + bool hdcp_1x_device_present; |
---|
| 330 | + bool hdcp_2x_device_present; |
---|
| 331 | + |
---|
| 332 | + /* Bit[4]- Stream Authentication */ |
---|
| 333 | + bool auth_completed; |
---|
| 334 | + |
---|
| 335 | + /* Bit[3]- Stream Encryption */ |
---|
| 336 | + bool encryption_enabled; |
---|
| 337 | + |
---|
| 338 | + /* Bit[2]- Stream Repeater Function Present */ |
---|
| 339 | + bool repeater_present; |
---|
| 340 | + |
---|
| 341 | + /* Bit[1:0]- Stream State */ |
---|
| 342 | + u8 state; |
---|
242 | 343 | }; |
---|
243 | 344 | |
---|
244 | 345 | #define DRM_DP_MAX_SDP_STREAMS 16 |
---|
.. | .. |
---|
283 | 384 | struct drm_dp_remote_i2c_read { |
---|
284 | 385 | u8 num_transactions; |
---|
285 | 386 | u8 port_number; |
---|
286 | | - struct { |
---|
| 387 | + struct drm_dp_remote_i2c_read_tx { |
---|
287 | 388 | u8 i2c_dev_id; |
---|
288 | 389 | u8 num_bytes; |
---|
289 | 390 | u8 *bytes; |
---|
.. | .. |
---|
299 | 400 | u8 write_i2c_device_id; |
---|
300 | 401 | u8 num_bytes; |
---|
301 | 402 | u8 *bytes; |
---|
| 403 | +}; |
---|
| 404 | + |
---|
| 405 | +struct drm_dp_query_stream_enc_status { |
---|
| 406 | + u8 stream_id; |
---|
| 407 | + u8 client_id[7]; /* 56-bit nonce */ |
---|
| 408 | + u8 stream_event; |
---|
| 409 | + bool valid_stream_event; |
---|
| 410 | + u8 stream_behavior; |
---|
| 411 | + u8 valid_stream_behavior; |
---|
302 | 412 | }; |
---|
303 | 413 | |
---|
304 | 414 | /* this covers ENUM_RESOURCES, POWER_DOWN_PHY, POWER_UP_PHY */ |
---|
.. | .. |
---|
349 | 459 | |
---|
350 | 460 | struct drm_dp_remote_i2c_read i2c_read; |
---|
351 | 461 | struct drm_dp_remote_i2c_write i2c_write; |
---|
| 462 | + |
---|
| 463 | + struct drm_dp_query_stream_enc_status enc_status; |
---|
352 | 464 | } u; |
---|
353 | 465 | }; |
---|
354 | 466 | |
---|
.. | .. |
---|
371 | 483 | struct drm_dp_remote_i2c_read_ack_reply remote_i2c_read_ack; |
---|
372 | 484 | struct drm_dp_remote_i2c_read_nak_reply remote_i2c_read_nack; |
---|
373 | 485 | struct drm_dp_remote_i2c_write_ack_reply remote_i2c_write_ack; |
---|
| 486 | + |
---|
| 487 | + struct drm_dp_query_stream_enc_status_ack_reply enc_status; |
---|
374 | 488 | } u; |
---|
375 | 489 | }; |
---|
376 | 490 | |
---|
.. | .. |
---|
402 | 516 | struct drm_dp_mst_topology_cbs { |
---|
403 | 517 | /* create a connector for a port */ |
---|
404 | 518 | struct drm_connector *(*add_connector)(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *path); |
---|
405 | | - void (*register_connector)(struct drm_connector *connector); |
---|
406 | | - void (*destroy_connector)(struct drm_dp_mst_topology_mgr *mgr, |
---|
407 | | - struct drm_connector *connector); |
---|
408 | | - void (*hotplug)(struct drm_dp_mst_topology_mgr *mgr); |
---|
409 | | - |
---|
| 519 | + /* |
---|
| 520 | + * Checks for any pending MST interrupts, passing them to MST core for |
---|
| 521 | + * processing, the same way an HPD IRQ pulse handler would do this. |
---|
| 522 | + * If provided MST core calls this callback from a poll-waiting loop |
---|
| 523 | + * when waiting for MST down message replies. The driver is expected |
---|
| 524 | + * to guard against a race between this callback and the driver's HPD |
---|
| 525 | + * IRQ pulse handler. |
---|
| 526 | + */ |
---|
| 527 | + void (*poll_hpd_irq)(struct drm_dp_mst_topology_mgr *mgr); |
---|
410 | 528 | }; |
---|
411 | 529 | |
---|
412 | 530 | #define DP_MAX_PAYLOAD (sizeof(unsigned long) * 8) |
---|
.. | .. |
---|
424 | 542 | |
---|
425 | 543 | #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) |
---|
426 | 544 | |
---|
| 545 | +struct drm_dp_vcpi_allocation { |
---|
| 546 | + struct drm_dp_mst_port *port; |
---|
| 547 | + int vcpi; |
---|
| 548 | + int pbn; |
---|
| 549 | + bool dsc_enabled; |
---|
| 550 | + struct list_head next; |
---|
| 551 | +}; |
---|
| 552 | + |
---|
427 | 553 | struct drm_dp_mst_topology_state { |
---|
428 | 554 | struct drm_private_state base; |
---|
429 | | - int avail_slots; |
---|
430 | | - struct drm_atomic_state *state; |
---|
| 555 | + struct list_head vcpis; |
---|
431 | 556 | struct drm_dp_mst_topology_mgr *mgr; |
---|
432 | 557 | }; |
---|
433 | 558 | |
---|
.. | .. |
---|
475 | 600 | int conn_base_id; |
---|
476 | 601 | |
---|
477 | 602 | /** |
---|
478 | | - * @down_rep_recv: Message receiver state for down replies. This and |
---|
479 | | - * @up_req_recv are only ever access from the work item, which is |
---|
480 | | - * serialised. |
---|
481 | | - */ |
---|
482 | | - struct drm_dp_sideband_msg_rx down_rep_recv; |
---|
483 | | - /** |
---|
484 | | - * @up_req_recv: Message receiver state for up requests. This and |
---|
485 | | - * @down_rep_recv are only ever access from the work item, which is |
---|
486 | | - * serialised. |
---|
| 603 | + * @up_req_recv: Message receiver state for up requests. |
---|
487 | 604 | */ |
---|
488 | 605 | struct drm_dp_sideband_msg_rx up_req_recv; |
---|
489 | 606 | |
---|
490 | 607 | /** |
---|
491 | | - * @lock: protects mst state, primary, dpcd. |
---|
| 608 | + * @down_rep_recv: Message receiver state for replies to down |
---|
| 609 | + * requests. |
---|
| 610 | + */ |
---|
| 611 | + struct drm_dp_sideband_msg_rx down_rep_recv; |
---|
| 612 | + |
---|
| 613 | + /** |
---|
| 614 | + * @lock: protects @mst_state, @mst_primary, @dpcd, and |
---|
| 615 | + * @payload_id_table_cleared. |
---|
492 | 616 | */ |
---|
493 | 617 | struct mutex lock; |
---|
| 618 | + |
---|
| 619 | + /** |
---|
| 620 | + * @probe_lock: Prevents @work and @up_req_work, the only writers of |
---|
| 621 | + * &drm_dp_mst_port.mstb and &drm_dp_mst_branch.ports, from racing |
---|
| 622 | + * while they update the topology. |
---|
| 623 | + */ |
---|
| 624 | + struct mutex probe_lock; |
---|
494 | 625 | |
---|
495 | 626 | /** |
---|
496 | 627 | * @mst_state: If this manager is enabled for an MST capable port. False |
---|
497 | 628 | * if no MST sink/branch devices is connected. |
---|
498 | 629 | */ |
---|
499 | | - bool mst_state; |
---|
| 630 | + bool mst_state : 1; |
---|
| 631 | + |
---|
| 632 | + /** |
---|
| 633 | + * @payload_id_table_cleared: Whether or not we've cleared the payload |
---|
| 634 | + * ID table for @mst_primary. Protected by @lock. |
---|
| 635 | + */ |
---|
| 636 | + bool payload_id_table_cleared : 1; |
---|
| 637 | + |
---|
500 | 638 | /** |
---|
501 | 639 | * @mst_primary: Pointer to the primary/first branch device. |
---|
502 | 640 | */ |
---|
.. | .. |
---|
516 | 654 | int pbn_div; |
---|
517 | 655 | |
---|
518 | 656 | /** |
---|
519 | | - * @state: State information for topology manager |
---|
520 | | - */ |
---|
521 | | - struct drm_dp_mst_topology_state *state; |
---|
522 | | - |
---|
523 | | - /** |
---|
524 | 657 | * @funcs: Atomic helper callbacks |
---|
525 | 658 | */ |
---|
526 | 659 | const struct drm_private_state_funcs *funcs; |
---|
527 | 660 | |
---|
528 | 661 | /** |
---|
529 | | - * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and |
---|
530 | | - * &drm_dp_sideband_msg_tx.state once they are queued |
---|
| 662 | + * @qlock: protects @tx_msg_downq and &drm_dp_sideband_msg_tx.state |
---|
531 | 663 | */ |
---|
532 | 664 | struct mutex qlock; |
---|
| 665 | + |
---|
533 | 666 | /** |
---|
534 | | - * @tx_msg_downq: List of pending down replies. |
---|
| 667 | + * @tx_msg_downq: List of pending down requests |
---|
535 | 668 | */ |
---|
536 | 669 | struct list_head tx_msg_downq; |
---|
537 | 670 | |
---|
.. | .. |
---|
541 | 674 | struct mutex payload_lock; |
---|
542 | 675 | /** |
---|
543 | 676 | * @proposed_vcpis: Array of pointers for the new VCPI allocation. The |
---|
544 | | - * VCPI structure itself is &drm_dp_mst_port.vcpi. |
---|
| 677 | + * VCPI structure itself is &drm_dp_mst_port.vcpi, and the size of |
---|
| 678 | + * this array is determined by @max_payloads. |
---|
545 | 679 | */ |
---|
546 | 680 | struct drm_dp_vcpi **proposed_vcpis; |
---|
547 | 681 | /** |
---|
548 | | - * @payloads: Array of payloads. |
---|
| 682 | + * @payloads: Array of payloads. The size of this array is determined |
---|
| 683 | + * by @max_payloads. |
---|
549 | 684 | */ |
---|
550 | 685 | struct drm_dp_payload *payloads; |
---|
551 | 686 | /** |
---|
.. | .. |
---|
574 | 709 | struct work_struct tx_work; |
---|
575 | 710 | |
---|
576 | 711 | /** |
---|
577 | | - * @destroy_connector_list: List of to be destroyed connectors. |
---|
| 712 | + * @destroy_port_list: List of to be destroyed connectors. |
---|
578 | 713 | */ |
---|
579 | | - struct list_head destroy_connector_list; |
---|
| 714 | + struct list_head destroy_port_list; |
---|
580 | 715 | /** |
---|
581 | | - * @destroy_connector_lock: Protects @connector_list. |
---|
| 716 | + * @destroy_branch_device_list: List of to be destroyed branch |
---|
| 717 | + * devices. |
---|
582 | 718 | */ |
---|
583 | | - struct mutex destroy_connector_lock; |
---|
| 719 | + struct list_head destroy_branch_device_list; |
---|
584 | 720 | /** |
---|
585 | | - * @destroy_connector_work: Work item to destroy connectors. Needed to |
---|
586 | | - * avoid locking inversion. |
---|
| 721 | + * @delayed_destroy_lock: Protects @destroy_port_list and |
---|
| 722 | + * @destroy_branch_device_list. |
---|
587 | 723 | */ |
---|
588 | | - struct work_struct destroy_connector_work; |
---|
| 724 | + struct mutex delayed_destroy_lock; |
---|
| 725 | + |
---|
| 726 | + /** |
---|
| 727 | + * @delayed_destroy_wq: Workqueue used for delayed_destroy_work items. |
---|
| 728 | + * A dedicated WQ makes it possible to drain any requeued work items |
---|
| 729 | + * on it. |
---|
| 730 | + */ |
---|
| 731 | + struct workqueue_struct *delayed_destroy_wq; |
---|
| 732 | + |
---|
| 733 | + /** |
---|
| 734 | + * @delayed_destroy_work: Work item to destroy MST port and branch |
---|
| 735 | + * devices, needed to avoid locking inversion. |
---|
| 736 | + */ |
---|
| 737 | + struct work_struct delayed_destroy_work; |
---|
| 738 | + |
---|
| 739 | + /** |
---|
| 740 | + * @up_req_list: List of pending up requests from the topology that |
---|
| 741 | + * need to be processed, in chronological order. |
---|
| 742 | + */ |
---|
| 743 | + struct list_head up_req_list; |
---|
| 744 | + /** |
---|
| 745 | + * @up_req_lock: Protects @up_req_list |
---|
| 746 | + */ |
---|
| 747 | + struct mutex up_req_lock; |
---|
| 748 | + /** |
---|
| 749 | + * @up_req_work: Work item to process up requests received from the |
---|
| 750 | + * topology. Needed to avoid blocking hotplug handling and sideband |
---|
| 751 | + * transmissions. |
---|
| 752 | + */ |
---|
| 753 | + struct work_struct up_req_work; |
---|
| 754 | + |
---|
| 755 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
---|
| 756 | + /** |
---|
| 757 | + * @topology_ref_history_lock: protects |
---|
| 758 | + * &drm_dp_mst_port.topology_ref_history and |
---|
| 759 | + * &drm_dp_mst_branch.topology_ref_history. |
---|
| 760 | + */ |
---|
| 761 | + struct mutex topology_ref_history_lock; |
---|
| 762 | +#endif |
---|
589 | 763 | }; |
---|
590 | 764 | |
---|
591 | 765 | int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, |
---|
.. | .. |
---|
595 | 769 | |
---|
596 | 770 | void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr); |
---|
597 | 771 | |
---|
598 | | - |
---|
| 772 | +bool drm_dp_read_mst_cap(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE]); |
---|
599 | 773 | int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state); |
---|
600 | | - |
---|
601 | 774 | |
---|
602 | 775 | int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); |
---|
603 | 776 | |
---|
604 | 777 | |
---|
605 | | -enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); |
---|
606 | | - |
---|
607 | | -bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, |
---|
608 | | - struct drm_dp_mst_port *port); |
---|
609 | | - |
---|
610 | | -bool drm_dp_mst_has_fec(struct drm_dp_mst_topology_mgr *mgr, |
---|
611 | | - struct drm_dp_mst_port *port); |
---|
| 778 | +int |
---|
| 779 | +drm_dp_mst_detect_port(struct drm_connector *connector, |
---|
| 780 | + struct drm_modeset_acquire_ctx *ctx, |
---|
| 781 | + struct drm_dp_mst_topology_mgr *mgr, |
---|
| 782 | + struct drm_dp_mst_port *port); |
---|
612 | 783 | |
---|
613 | 784 | struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); |
---|
614 | 785 | |
---|
| 786 | +int drm_dp_get_vc_payload_bw(int link_rate, int link_lane_count); |
---|
615 | 787 | |
---|
616 | | -int drm_dp_calc_pbn_mode(int clock, int bpp); |
---|
617 | | - |
---|
| 788 | +int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc); |
---|
618 | 789 | |
---|
619 | 790 | bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, |
---|
620 | 791 | struct drm_dp_mst_port *port, int pbn, int slots); |
---|
.. | .. |
---|
644 | 815 | struct drm_dp_mst_topology_mgr *mgr); |
---|
645 | 816 | |
---|
646 | 817 | void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); |
---|
647 | | -int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); |
---|
| 818 | +int __must_check |
---|
| 819 | +drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, |
---|
| 820 | + bool sync); |
---|
| 821 | + |
---|
| 822 | +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, |
---|
| 823 | + unsigned int offset, void *buffer, size_t size); |
---|
| 824 | +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, |
---|
| 825 | + unsigned int offset, void *buffer, size_t size); |
---|
| 826 | + |
---|
| 827 | +int drm_dp_mst_connector_late_register(struct drm_connector *connector, |
---|
| 828 | + struct drm_dp_mst_port *port); |
---|
| 829 | +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, |
---|
| 830 | + struct drm_dp_mst_port *port); |
---|
| 831 | + |
---|
648 | 832 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, |
---|
649 | 833 | struct drm_dp_mst_topology_mgr *mgr); |
---|
650 | | -int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
---|
651 | | - struct drm_dp_mst_topology_mgr *mgr, |
---|
652 | | - struct drm_dp_mst_port *port, int pbn); |
---|
653 | | -int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
---|
654 | | - struct drm_dp_mst_topology_mgr *mgr, |
---|
655 | | - int slots); |
---|
| 834 | +int __must_check |
---|
| 835 | +drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
---|
| 836 | + struct drm_dp_mst_topology_mgr *mgr, |
---|
| 837 | + struct drm_dp_mst_port *port, int pbn, |
---|
| 838 | + int pbn_div); |
---|
| 839 | +int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, |
---|
| 840 | + struct drm_dp_mst_port *port, |
---|
| 841 | + int pbn, int pbn_div, |
---|
| 842 | + bool enable); |
---|
| 843 | +int __must_check |
---|
| 844 | +drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, |
---|
| 845 | + struct drm_dp_mst_topology_mgr *mgr); |
---|
| 846 | +int __must_check |
---|
| 847 | +drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
---|
| 848 | + struct drm_dp_mst_topology_mgr *mgr, |
---|
| 849 | + struct drm_dp_mst_port *port); |
---|
656 | 850 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, |
---|
657 | 851 | struct drm_dp_mst_port *port, bool power_up); |
---|
| 852 | +int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, |
---|
| 853 | + struct drm_dp_mst_port *port, |
---|
| 854 | + struct drm_dp_query_stream_enc_status_ack_reply *status); |
---|
| 855 | +int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); |
---|
658 | 856 | |
---|
659 | | -int drm_dp_mst_get_dsc_info(struct drm_dp_mst_topology_mgr *mgr, |
---|
660 | | - struct drm_dp_mst_port *port, |
---|
661 | | - struct drm_dp_mst_dsc_info *dsc_info); |
---|
| 857 | +void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); |
---|
| 858 | +void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); |
---|
662 | 859 | |
---|
663 | | -int drm_dp_mst_update_dsc_info(struct drm_dp_mst_topology_mgr *mgr, |
---|
664 | | - struct drm_dp_mst_port *port, |
---|
665 | | - struct drm_dp_mst_dsc_info *dsc_info); |
---|
| 860 | +struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port); |
---|
666 | 861 | |
---|
667 | | -int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, |
---|
668 | | - struct drm_dp_mst_port *port, |
---|
669 | | - int offset, int size, u8 *bytes); |
---|
| 862 | +extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; |
---|
670 | 863 | |
---|
671 | | -int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, |
---|
672 | | - struct drm_dp_mst_port *port, |
---|
673 | | - int offset, int size, u8 *bytes); |
---|
| 864 | +/** |
---|
| 865 | + * __drm_dp_mst_state_iter_get - private atomic state iterator function for |
---|
| 866 | + * macro-internal use |
---|
| 867 | + * @state: &struct drm_atomic_state pointer |
---|
| 868 | + * @mgr: pointer to the &struct drm_dp_mst_topology_mgr iteration cursor |
---|
| 869 | + * @old_state: optional pointer to the old &struct drm_dp_mst_topology_state |
---|
| 870 | + * iteration cursor |
---|
| 871 | + * @new_state: optional pointer to the new &struct drm_dp_mst_topology_state |
---|
| 872 | + * iteration cursor |
---|
| 873 | + * @i: int iteration cursor, for macro-internal use |
---|
| 874 | + * |
---|
| 875 | + * Used by for_each_oldnew_mst_mgr_in_state(), |
---|
| 876 | + * for_each_old_mst_mgr_in_state(), and for_each_new_mst_mgr_in_state(). Don't |
---|
| 877 | + * call this directly. |
---|
| 878 | + * |
---|
| 879 | + * Returns: |
---|
| 880 | + * True if the current &struct drm_private_obj is a &struct |
---|
| 881 | + * drm_dp_mst_topology_mgr, false otherwise. |
---|
| 882 | + */ |
---|
| 883 | +static inline bool |
---|
| 884 | +__drm_dp_mst_state_iter_get(struct drm_atomic_state *state, |
---|
| 885 | + struct drm_dp_mst_topology_mgr **mgr, |
---|
| 886 | + struct drm_dp_mst_topology_state **old_state, |
---|
| 887 | + struct drm_dp_mst_topology_state **new_state, |
---|
| 888 | + int i) |
---|
| 889 | +{ |
---|
| 890 | + struct __drm_private_objs_state *objs_state = &state->private_objs[i]; |
---|
674 | 891 | |
---|
675 | | -int drm_dp_mst_get_max_sdp_streams_supported( |
---|
676 | | - struct drm_dp_mst_topology_mgr *mgr, |
---|
677 | | - struct drm_dp_mst_port *port); |
---|
| 892 | + if (objs_state->ptr->funcs != &drm_dp_mst_topology_state_funcs) |
---|
| 893 | + return false; |
---|
| 894 | + |
---|
| 895 | + *mgr = to_dp_mst_topology_mgr(objs_state->ptr); |
---|
| 896 | + if (old_state) |
---|
| 897 | + *old_state = to_dp_mst_topology_state(objs_state->old_state); |
---|
| 898 | + if (new_state) |
---|
| 899 | + *new_state = to_dp_mst_topology_state(objs_state->new_state); |
---|
| 900 | + |
---|
| 901 | + return true; |
---|
| 902 | +} |
---|
| 903 | + |
---|
| 904 | +/** |
---|
| 905 | + * for_each_oldnew_mst_mgr_in_state - iterate over all DP MST topology |
---|
| 906 | + * managers in an atomic update |
---|
| 907 | + * @__state: &struct drm_atomic_state pointer |
---|
| 908 | + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor |
---|
| 909 | + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old |
---|
| 910 | + * state |
---|
| 911 | + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new |
---|
| 912 | + * state |
---|
| 913 | + * @__i: int iteration cursor, for macro-internal use |
---|
| 914 | + * |
---|
| 915 | + * This iterates over all DRM DP MST topology managers in an atomic update, |
---|
| 916 | + * tracking both old and new state. This is useful in places where the state |
---|
| 917 | + * delta needs to be considered, for example in atomic check functions. |
---|
| 918 | + */ |
---|
| 919 | +#define for_each_oldnew_mst_mgr_in_state(__state, mgr, old_state, new_state, __i) \ |
---|
| 920 | + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ |
---|
| 921 | + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), &(new_state), (__i))) |
---|
| 922 | + |
---|
| 923 | +/** |
---|
| 924 | + * for_each_old_mst_mgr_in_state - iterate over all DP MST topology managers |
---|
| 925 | + * in an atomic update |
---|
| 926 | + * @__state: &struct drm_atomic_state pointer |
---|
| 927 | + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor |
---|
| 928 | + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old |
---|
| 929 | + * state |
---|
| 930 | + * @__i: int iteration cursor, for macro-internal use |
---|
| 931 | + * |
---|
| 932 | + * This iterates over all DRM DP MST topology managers in an atomic update, |
---|
| 933 | + * tracking only the old state. This is useful in disable functions, where we |
---|
| 934 | + * need the old state the hardware is still in. |
---|
| 935 | + */ |
---|
| 936 | +#define for_each_old_mst_mgr_in_state(__state, mgr, old_state, __i) \ |
---|
| 937 | + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ |
---|
| 938 | + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), NULL, (__i))) |
---|
| 939 | + |
---|
| 940 | +/** |
---|
| 941 | + * for_each_new_mst_mgr_in_state - iterate over all DP MST topology managers |
---|
| 942 | + * in an atomic update |
---|
| 943 | + * @__state: &struct drm_atomic_state pointer |
---|
| 944 | + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor |
---|
| 945 | + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new |
---|
| 946 | + * state |
---|
| 947 | + * @__i: int iteration cursor, for macro-internal use |
---|
| 948 | + * |
---|
| 949 | + * This iterates over all DRM DP MST topology managers in an atomic update, |
---|
| 950 | + * tracking only the new state. This is useful in enable functions, where we |
---|
| 951 | + * need the new state the hardware should be in when the atomic commit |
---|
| 952 | + * operation has completed. |
---|
| 953 | + */ |
---|
| 954 | +#define for_each_new_mst_mgr_in_state(__state, mgr, new_state, __i) \ |
---|
| 955 | + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ |
---|
| 956 | + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), NULL, &(new_state), (__i))) |
---|
678 | 957 | |
---|
679 | 958 | #endif |
---|