brintos

brintos / linux-shallow public Read only

0
0
Text · 16.5 KiB · 6e88339 Raw
555 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>4 * Copyright (C) 2017 Broadcom5 */6 7#include <linux/debugfs.h>8 9#include <drm/drm_atomic_helper.h>10#include <drm/drm_bridge.h>11#include <drm/drm_connector.h>12#include <drm/drm_encoder.h>13#include <drm/drm_managed.h>14#include <drm/drm_modeset_helper_vtables.h>15#include <drm/drm_of.h>16#include <drm/drm_panel.h>17#include <drm/drm_print.h>18#include <drm/drm_probe_helper.h>19 20struct panel_bridge {21	struct drm_bridge bridge;22	struct drm_connector connector;23	struct drm_panel *panel;24	u32 connector_type;25};26 27static inline struct panel_bridge *28drm_bridge_to_panel_bridge(struct drm_bridge *bridge)29{30	return container_of(bridge, struct panel_bridge, bridge);31}32 33static inline struct panel_bridge *34drm_connector_to_panel_bridge(struct drm_connector *connector)35{36	return container_of(connector, struct panel_bridge, connector);37}38 39static int panel_bridge_connector_get_modes(struct drm_connector *connector)40{41	struct panel_bridge *panel_bridge =42		drm_connector_to_panel_bridge(connector);43 44	return drm_panel_get_modes(panel_bridge->panel, connector);45}46 47static const struct drm_connector_helper_funcs48panel_bridge_connector_helper_funcs = {49	.get_modes = panel_bridge_connector_get_modes,50};51 52static const struct drm_connector_funcs panel_bridge_connector_funcs = {53	.reset = drm_atomic_helper_connector_reset,54	.fill_modes = drm_helper_probe_single_connector_modes,55	.destroy = drm_connector_cleanup,56	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,57	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,58};59 60static int panel_bridge_attach(struct drm_bridge *bridge,61			       enum drm_bridge_attach_flags flags)62{63	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);64	struct drm_connector *connector = &panel_bridge->connector;65	int ret;66 67	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)68		return 0;69 70	drm_connector_helper_add(connector,71				 &panel_bridge_connector_helper_funcs);72 73	ret = drm_connector_init(bridge->dev, connector,74				 &panel_bridge_connector_funcs,75				 panel_bridge->connector_type);76	if (ret) {77		DRM_ERROR("Failed to initialize connector\n");78		return ret;79	}80 81	drm_panel_bridge_set_orientation(connector, bridge);82 83	drm_connector_attach_encoder(&panel_bridge->connector,84					  bridge->encoder);85 86	if (bridge->dev->registered) {87		if (connector->funcs->reset)88			connector->funcs->reset(connector);89		drm_connector_register(connector);90	}91 92	return 0;93}94 95static void panel_bridge_detach(struct drm_bridge *bridge)96{97	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);98	struct drm_connector *connector = &panel_bridge->connector;99 100	/*101	 * Cleanup the connector if we know it was initialized.102	 *103	 * FIXME: This wouldn't be needed if the panel_bridge structure was104	 * allocated with drmm_kzalloc(). This might be tricky since the105	 * drm_device pointer can only be retrieved when the bridge is attached.106	 */107	if (connector->dev)108		drm_connector_cleanup(connector);109}110 111static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,112				struct drm_bridge_state *old_bridge_state)113{114	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);115	struct drm_atomic_state *atomic_state = old_bridge_state->base.state;116	struct drm_encoder *encoder = bridge->encoder;117	struct drm_crtc *crtc;118	struct drm_crtc_state *old_crtc_state;119 120	crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);121	if (!crtc)122		return;123 124	old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);125	if (old_crtc_state && old_crtc_state->self_refresh_active)126		return;127 128	drm_panel_prepare(panel_bridge->panel);129}130 131static void panel_bridge_atomic_enable(struct drm_bridge *bridge,132				struct drm_bridge_state *old_bridge_state)133{134	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);135	struct drm_atomic_state *atomic_state = old_bridge_state->base.state;136	struct drm_encoder *encoder = bridge->encoder;137	struct drm_crtc *crtc;138	struct drm_crtc_state *old_crtc_state;139 140	crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);141	if (!crtc)142		return;143 144	old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);145	if (old_crtc_state && old_crtc_state->self_refresh_active)146		return;147 148	drm_panel_enable(panel_bridge->panel);149}150 151static void panel_bridge_atomic_disable(struct drm_bridge *bridge,152				struct drm_bridge_state *old_bridge_state)153{154	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);155	struct drm_atomic_state *atomic_state = old_bridge_state->base.state;156	struct drm_encoder *encoder = bridge->encoder;157	struct drm_crtc *crtc;158	struct drm_crtc_state *new_crtc_state;159 160	crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);161	if (!crtc)162		return;163 164	new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);165	if (new_crtc_state && new_crtc_state->self_refresh_active)166		return;167 168	drm_panel_disable(panel_bridge->panel);169}170 171static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,172				struct drm_bridge_state *old_bridge_state)173{174	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);175	struct drm_atomic_state *atomic_state = old_bridge_state->base.state;176	struct drm_encoder *encoder = bridge->encoder;177	struct drm_crtc *crtc;178	struct drm_crtc_state *new_crtc_state;179 180	crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);181	if (!crtc)182		return;183 184	new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);185	if (new_crtc_state && new_crtc_state->self_refresh_active)186		return;187 188	drm_panel_unprepare(panel_bridge->panel);189}190 191static int panel_bridge_get_modes(struct drm_bridge *bridge,192				  struct drm_connector *connector)193{194	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);195 196	return drm_panel_get_modes(panel_bridge->panel, connector);197}198 199static void panel_bridge_debugfs_init(struct drm_bridge *bridge,200				      struct dentry *root)201{202	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);203	struct drm_panel *panel = panel_bridge->panel;204 205	root = debugfs_create_dir("panel", root);206	if (panel->funcs->debugfs_init)207		panel->funcs->debugfs_init(panel, root);208}209 210static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {211	.attach = panel_bridge_attach,212	.detach = panel_bridge_detach,213	.atomic_pre_enable = panel_bridge_atomic_pre_enable,214	.atomic_enable = panel_bridge_atomic_enable,215	.atomic_disable = panel_bridge_atomic_disable,216	.atomic_post_disable = panel_bridge_atomic_post_disable,217	.get_modes = panel_bridge_get_modes,218	.atomic_reset = drm_atomic_helper_bridge_reset,219	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,220	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,221	.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,222	.debugfs_init = panel_bridge_debugfs_init,223};224 225/**226 * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.227 *228 * @bridge: The drm_bridge to be checked.229 *230 * Returns true if the bridge is a panel bridge, or false otherwise.231 */232bool drm_bridge_is_panel(const struct drm_bridge *bridge)233{234	return bridge->funcs == &panel_bridge_bridge_funcs;235}236EXPORT_SYMBOL(drm_bridge_is_panel);237 238/**239 * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that240 * just calls the appropriate functions from &drm_panel.241 *242 * @panel: The drm_panel being wrapped.  Must be non-NULL.243 *244 * For drivers converting from directly using drm_panel: The expected245 * usage pattern is that during either encoder module probe or DSI246 * host attach, a drm_panel will be looked up through247 * drm_of_find_panel_or_bridge().  drm_panel_bridge_add() is used to248 * wrap that panel in the new bridge, and the result can then be249 * passed to drm_bridge_attach().  The drm_panel_prepare() and related250 * functions can be dropped from the encoder driver (they're now251 * called by the KMS helpers before calling into the encoder), along252 * with connector creation.  When done with the bridge (after253 * drm_mode_config_cleanup() if the bridge has already been attached), then254 * drm_panel_bridge_remove() to free it.255 *256 * The connector type is set to @panel->connector_type, which must be set to a257 * known type. Calling this function with a panel whose connector type is258 * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).259 *260 * See devm_drm_panel_bridge_add() for an automatically managed version of this261 * function.262 */263struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)264{265	if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))266		return ERR_PTR(-EINVAL);267 268	return drm_panel_bridge_add_typed(panel, panel->connector_type);269}270EXPORT_SYMBOL(drm_panel_bridge_add);271 272/**273 * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with274 * an explicit connector type.275 * @panel: The drm_panel being wrapped.  Must be non-NULL.276 * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)277 *278 * This is just like drm_panel_bridge_add(), but forces the connector type to279 * @connector_type instead of infering it from the panel.280 *281 * This function is deprecated and should not be used in new drivers. Use282 * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they283 * don't report a connector type.284 */285struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,286					      u32 connector_type)287{288	struct panel_bridge *panel_bridge;289 290	if (!panel)291		return ERR_PTR(-EINVAL);292 293	panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),294				    GFP_KERNEL);295	if (!panel_bridge)296		return ERR_PTR(-ENOMEM);297 298	panel_bridge->connector_type = connector_type;299	panel_bridge->panel = panel;300 301	panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs;302	panel_bridge->bridge.of_node = panel->dev->of_node;303	panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;304	panel_bridge->bridge.type = connector_type;305 306	drm_bridge_add(&panel_bridge->bridge);307 308	return &panel_bridge->bridge;309}310EXPORT_SYMBOL(drm_panel_bridge_add_typed);311 312/**313 * drm_panel_bridge_remove - Unregisters and frees a drm_bridge314 * created by drm_panel_bridge_add().315 *316 * @bridge: The drm_bridge being freed.317 */318void drm_panel_bridge_remove(struct drm_bridge *bridge)319{320	struct panel_bridge *panel_bridge;321 322	if (!bridge)323		return;324 325	if (bridge->funcs != &panel_bridge_bridge_funcs)326		return;327 328	panel_bridge = drm_bridge_to_panel_bridge(bridge);329 330	drm_bridge_remove(bridge);331	devm_kfree(panel_bridge->panel->dev, bridge);332}333EXPORT_SYMBOL(drm_panel_bridge_remove);334 335/**336 * drm_panel_bridge_set_orientation - Set the connector's panel orientation337 * from the bridge that can be transformed to panel bridge.338 *339 * @connector: The connector to be set panel orientation.340 * @bridge: The drm_bridge to be transformed to panel bridge.341 *342 * Returns 0 on success, negative errno on failure.343 */344int drm_panel_bridge_set_orientation(struct drm_connector *connector,345				     struct drm_bridge *bridge)346{347	struct panel_bridge *panel_bridge;348 349	panel_bridge = drm_bridge_to_panel_bridge(bridge);350 351	return drm_connector_set_orientation_from_panel(connector,352							panel_bridge->panel);353}354EXPORT_SYMBOL(drm_panel_bridge_set_orientation);355 356static void devm_drm_panel_bridge_release(struct device *dev, void *res)357{358	struct drm_bridge *bridge = *(struct drm_bridge **)res;359 360	if (!bridge)361		return;362 363	drm_bridge_remove(bridge);364}365 366/**367 * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector368 * that just calls the appropriate functions from &drm_panel.369 * @dev: device to tie the bridge lifetime to370 * @panel: The drm_panel being wrapped.  Must be non-NULL.371 *372 * This is the managed version of drm_panel_bridge_add() which automatically373 * calls drm_panel_bridge_remove() when @dev is unbound.374 */375struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,376					     struct drm_panel *panel)377{378	if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))379		return ERR_PTR(-EINVAL);380 381	return devm_drm_panel_bridge_add_typed(dev, panel,382					       panel->connector_type);383}384EXPORT_SYMBOL(devm_drm_panel_bridge_add);385 386/**387 * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and388 * &drm_connector with an explicit connector type.389 * @dev: device to tie the bridge lifetime to390 * @panel: The drm_panel being wrapped.  Must be non-NULL.391 * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)392 *393 * This is just like devm_drm_panel_bridge_add(), but forces the connector type394 * to @connector_type instead of infering it from the panel.395 *396 * This function is deprecated and should not be used in new drivers. Use397 * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if398 * they don't report a connector type.399 */400struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,401						   struct drm_panel *panel,402						   u32 connector_type)403{404	struct drm_bridge **ptr, *bridge;405 406	ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),407			   GFP_KERNEL);408	if (!ptr)409		return ERR_PTR(-ENOMEM);410 411	bridge = drm_panel_bridge_add_typed(panel, connector_type);412	if (IS_ERR(bridge)) {413		devres_free(ptr);414		return bridge;415	}416 417	bridge->pre_enable_prev_first = panel->prepare_prev_first;418 419	*ptr = bridge;420	devres_add(dev, ptr);421 422	return bridge;423}424EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);425 426static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)427{428	struct drm_bridge *bridge = ptr;429 430	drm_panel_bridge_remove(bridge);431}432 433/**434 * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and435 *                         &drm_connector that just calls the436 *                         appropriate functions from &drm_panel.437 *438 * @drm: DRM device to tie the bridge lifetime to439 * @panel: The drm_panel being wrapped.  Must be non-NULL.440 *441 * This is the DRM-managed version of drm_panel_bridge_add() which442 * automatically calls drm_panel_bridge_remove() when @dev is cleaned443 * up.444 */445struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,446					 struct drm_panel *panel)447{448	struct drm_bridge *bridge;449	int ret;450 451	bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);452	if (IS_ERR(bridge))453		return bridge;454 455	ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,456				       bridge);457	if (ret)458		return ERR_PTR(ret);459 460	bridge->pre_enable_prev_first = panel->prepare_prev_first;461 462	return bridge;463}464EXPORT_SYMBOL(drmm_panel_bridge_add);465 466/**467 * drm_panel_bridge_connector - return the connector for the panel bridge468 * @bridge: The drm_bridge.469 *470 * drm_panel_bridge creates the connector.471 * This function gives external access to the connector.472 *473 * Returns: Pointer to drm_connector474 */475struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)476{477	struct panel_bridge *panel_bridge;478 479	panel_bridge = drm_bridge_to_panel_bridge(bridge);480 481	return &panel_bridge->connector;482}483EXPORT_SYMBOL(drm_panel_bridge_connector);484 485#ifdef CONFIG_OF486/**487 * devm_drm_of_get_bridge - Return next bridge in the chain488 * @dev: device to tie the bridge lifetime to489 * @np: device tree node containing encoder output ports490 * @port: port in the device tree node491 * @endpoint: endpoint in the device tree node492 *493 * Given a DT node's port and endpoint number, finds the connected node494 * and returns the associated bridge if any, or creates and returns a495 * drm panel bridge instance if a panel is connected.496 *497 * Returns a pointer to the bridge if successful, or an error pointer498 * otherwise.499 */500struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,501					  struct device_node *np,502					  u32 port, u32 endpoint)503{504	struct drm_bridge *bridge;505	struct drm_panel *panel;506	int ret;507 508	ret = drm_of_find_panel_or_bridge(np, port, endpoint,509					  &panel, &bridge);510	if (ret)511		return ERR_PTR(ret);512 513	if (panel)514		bridge = devm_drm_panel_bridge_add(dev, panel);515 516	return bridge;517}518EXPORT_SYMBOL(devm_drm_of_get_bridge);519 520/**521 * drmm_of_get_bridge - Return next bridge in the chain522 * @drm: device to tie the bridge lifetime to523 * @np: device tree node containing encoder output ports524 * @port: port in the device tree node525 * @endpoint: endpoint in the device tree node526 *527 * Given a DT node's port and endpoint number, finds the connected node528 * and returns the associated bridge if any, or creates and returns a529 * drm panel bridge instance if a panel is connected.530 *531 * Returns a drmm managed pointer to the bridge if successful, or an error532 * pointer otherwise.533 */534struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,535				      struct device_node *np,536				      u32 port, u32 endpoint)537{538	struct drm_bridge *bridge;539	struct drm_panel *panel;540	int ret;541 542	ret = drm_of_find_panel_or_bridge(np, port, endpoint,543					  &panel, &bridge);544	if (ret)545		return ERR_PTR(ret);546 547	if (panel)548		bridge = drmm_panel_bridge_add(drm, panel);549 550	return bridge;551}552EXPORT_SYMBOL(drmm_of_get_bridge);553 554#endif555