|
13 | 13 | #include <linux/platform_device.h>
|
14 | 14 | #include <linux/regulator/consumer.h>
|
15 | 15 |
|
| 16 | +#include <drm/drm_atomic_helper.h> |
16 | 17 | #include <drm/drm_bridge.h>
|
17 | 18 | #include <drm/drm_edid.h>
|
18 | 19 |
|
@@ -87,10 +88,95 @@ static struct edid *display_connector_get_edid(struct drm_bridge *bridge,
|
87 | 88 | return drm_get_edid(connector, conn->bridge.ddc);
|
88 | 89 | }
|
89 | 90 |
|
| 91 | +/* |
| 92 | + * Since this bridge is tied to the connector, it acts like a passthrough, |
| 93 | + * so concerning the output bus formats, either pass the bus formats from the |
| 94 | + * previous bridge or return fallback data like done in the bridge function: |
| 95 | + * drm_atomic_bridge_chain_select_bus_fmts(). |
| 96 | + * This supports negotiation if the bridge chain has all bits in place. |
| 97 | + */ |
| 98 | +static u32 *display_connector_get_output_bus_fmts(struct drm_bridge *bridge, |
| 99 | + struct drm_bridge_state *bridge_state, |
| 100 | + struct drm_crtc_state *crtc_state, |
| 101 | + struct drm_connector_state *conn_state, |
| 102 | + unsigned int *num_output_fmts) |
| 103 | +{ |
| 104 | + struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); |
| 105 | + struct drm_bridge_state *prev_bridge_state; |
| 106 | + |
| 107 | + if (!prev_bridge || !prev_bridge->funcs->atomic_get_output_bus_fmts) { |
| 108 | + struct drm_connector *conn = conn_state->connector; |
| 109 | + u32 *out_bus_fmts; |
| 110 | + |
| 111 | + *num_output_fmts = 1; |
| 112 | + out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); |
| 113 | + if (!out_bus_fmts) |
| 114 | + return NULL; |
| 115 | + |
| 116 | + if (conn->display_info.num_bus_formats && |
| 117 | + conn->display_info.bus_formats) |
| 118 | + out_bus_fmts[0] = conn->display_info.bus_formats[0]; |
| 119 | + else |
| 120 | + out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; |
| 121 | + |
| 122 | + return out_bus_fmts; |
| 123 | + } |
| 124 | + |
| 125 | + prev_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, |
| 126 | + prev_bridge); |
| 127 | + |
| 128 | + return prev_bridge->funcs->atomic_get_output_bus_fmts(prev_bridge, prev_bridge_state, |
| 129 | + crtc_state, conn_state, |
| 130 | + num_output_fmts); |
| 131 | +} |
| 132 | + |
| 133 | +/* |
| 134 | + * Since this bridge is tied to the connector, it acts like a passthrough, |
| 135 | + * so concerning the input bus formats, either pass the bus formats from the |
| 136 | + * previous bridge or MEDIA_BUS_FMT_FIXED (like select_bus_fmt_recursive()) |
| 137 | + * when atomic_get_input_bus_fmts is not supported. |
| 138 | + * This supports negotiation if the bridge chain has all bits in place. |
| 139 | + */ |
| 140 | +static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, |
| 141 | + struct drm_bridge_state *bridge_state, |
| 142 | + struct drm_crtc_state *crtc_state, |
| 143 | + struct drm_connector_state *conn_state, |
| 144 | + u32 output_fmt, |
| 145 | + unsigned int *num_input_fmts) |
| 146 | +{ |
| 147 | + struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); |
| 148 | + struct drm_bridge_state *prev_bridge_state; |
| 149 | + |
| 150 | + if (!prev_bridge || !prev_bridge->funcs->atomic_get_input_bus_fmts) { |
| 151 | + u32 *in_bus_fmts; |
| 152 | + |
| 153 | + *num_input_fmts = 1; |
| 154 | + in_bus_fmts = kmalloc(sizeof(*in_bus_fmts), GFP_KERNEL); |
| 155 | + if (!in_bus_fmts) |
| 156 | + return NULL; |
| 157 | + |
| 158 | + in_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; |
| 159 | + |
| 160 | + return in_bus_fmts; |
| 161 | + } |
| 162 | + |
| 163 | + prev_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, |
| 164 | + prev_bridge); |
| 165 | + |
| 166 | + return prev_bridge->funcs->atomic_get_input_bus_fmts(prev_bridge, prev_bridge_state, |
| 167 | + crtc_state, conn_state, output_fmt, |
| 168 | + num_input_fmts); |
| 169 | +} |
| 170 | + |
90 | 171 | static const struct drm_bridge_funcs display_connector_bridge_funcs = {
|
91 | 172 | .attach = display_connector_attach,
|
92 | 173 | .detect = display_connector_detect,
|
93 | 174 | .get_edid = display_connector_get_edid,
|
| 175 | + .atomic_get_output_bus_fmts = display_connector_get_output_bus_fmts, |
| 176 | + .atomic_get_input_bus_fmts = display_connector_get_input_bus_fmts, |
| 177 | + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
| 178 | + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
| 179 | + .atomic_reset = drm_atomic_helper_bridge_reset, |
94 | 180 | };
|
95 | 181 |
|
96 | 182 | static irqreturn_t display_connector_hpd_irq(int irq, void *arg)
|
|
0 commit comments