cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel.c (11818B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
      4 * Copyright (C) 2017 Broadcom
      5 */
      6
      7#include <drm/drm_atomic_helper.h>
      8#include <drm/drm_bridge.h>
      9#include <drm/drm_connector.h>
     10#include <drm/drm_encoder.h>
     11#include <drm/drm_modeset_helper_vtables.h>
     12#include <drm/drm_of.h>
     13#include <drm/drm_panel.h>
     14#include <drm/drm_print.h>
     15#include <drm/drm_probe_helper.h>
     16
     17struct panel_bridge {
     18	struct drm_bridge bridge;
     19	struct drm_connector connector;
     20	struct drm_panel *panel;
     21	u32 connector_type;
     22};
     23
     24static inline struct panel_bridge *
     25drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
     26{
     27	return container_of(bridge, struct panel_bridge, bridge);
     28}
     29
     30static inline struct panel_bridge *
     31drm_connector_to_panel_bridge(struct drm_connector *connector)
     32{
     33	return container_of(connector, struct panel_bridge, connector);
     34}
     35
     36static int panel_bridge_connector_get_modes(struct drm_connector *connector)
     37{
     38	struct panel_bridge *panel_bridge =
     39		drm_connector_to_panel_bridge(connector);
     40
     41	return drm_panel_get_modes(panel_bridge->panel, connector);
     42}
     43
     44static const struct drm_connector_helper_funcs
     45panel_bridge_connector_helper_funcs = {
     46	.get_modes = panel_bridge_connector_get_modes,
     47};
     48
     49static const struct drm_connector_funcs panel_bridge_connector_funcs = {
     50	.reset = drm_atomic_helper_connector_reset,
     51	.fill_modes = drm_helper_probe_single_connector_modes,
     52	.destroy = drm_connector_cleanup,
     53	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
     54	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
     55};
     56
     57static int panel_bridge_attach(struct drm_bridge *bridge,
     58			       enum drm_bridge_attach_flags flags)
     59{
     60	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     61	struct drm_connector *connector = &panel_bridge->connector;
     62	int ret;
     63
     64	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
     65		return 0;
     66
     67	if (!bridge->encoder) {
     68		DRM_ERROR("Missing encoder\n");
     69		return -ENODEV;
     70	}
     71
     72	drm_connector_helper_add(connector,
     73				 &panel_bridge_connector_helper_funcs);
     74
     75	ret = drm_connector_init(bridge->dev, connector,
     76				 &panel_bridge_connector_funcs,
     77				 panel_bridge->connector_type);
     78	if (ret) {
     79		DRM_ERROR("Failed to initialize connector\n");
     80		return ret;
     81	}
     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 was
    104	 * allocated with drmm_kzalloc(). This might be tricky since the
    105	 * 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_pre_enable(struct drm_bridge *bridge)
    112{
    113	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
    114
    115	drm_panel_prepare(panel_bridge->panel);
    116}
    117
    118static void panel_bridge_enable(struct drm_bridge *bridge)
    119{
    120	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
    121
    122	drm_panel_enable(panel_bridge->panel);
    123}
    124
    125static void panel_bridge_disable(struct drm_bridge *bridge)
    126{
    127	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
    128
    129	drm_panel_disable(panel_bridge->panel);
    130}
    131
    132static void panel_bridge_post_disable(struct drm_bridge *bridge)
    133{
    134	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
    135
    136	drm_panel_unprepare(panel_bridge->panel);
    137}
    138
    139static int panel_bridge_get_modes(struct drm_bridge *bridge,
    140				  struct drm_connector *connector)
    141{
    142	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
    143
    144	return drm_panel_get_modes(panel_bridge->panel, connector);
    145}
    146
    147static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
    148				      struct dentry *root)
    149{
    150	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
    151	struct drm_panel *panel = panel_bridge->panel;
    152
    153	root = debugfs_create_dir("panel", root);
    154	if (panel->funcs->debugfs_init)
    155		panel->funcs->debugfs_init(panel, root);
    156}
    157
    158static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
    159	.attach = panel_bridge_attach,
    160	.detach = panel_bridge_detach,
    161	.pre_enable = panel_bridge_pre_enable,
    162	.enable = panel_bridge_enable,
    163	.disable = panel_bridge_disable,
    164	.post_disable = panel_bridge_post_disable,
    165	.get_modes = panel_bridge_get_modes,
    166	.atomic_reset = drm_atomic_helper_bridge_reset,
    167	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
    168	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
    169	.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
    170	.debugfs_init = panel_bridge_debugfs_init,
    171};
    172
    173/**
    174 * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
    175 * just calls the appropriate functions from &drm_panel.
    176 *
    177 * @panel: The drm_panel being wrapped.  Must be non-NULL.
    178 *
    179 * For drivers converting from directly using drm_panel: The expected
    180 * usage pattern is that during either encoder module probe or DSI
    181 * host attach, a drm_panel will be looked up through
    182 * drm_of_find_panel_or_bridge().  drm_panel_bridge_add() is used to
    183 * wrap that panel in the new bridge, and the result can then be
    184 * passed to drm_bridge_attach().  The drm_panel_prepare() and related
    185 * functions can be dropped from the encoder driver (they're now
    186 * called by the KMS helpers before calling into the encoder), along
    187 * with connector creation.  When done with the bridge (after
    188 * drm_mode_config_cleanup() if the bridge has already been attached), then
    189 * drm_panel_bridge_remove() to free it.
    190 *
    191 * The connector type is set to @panel->connector_type, which must be set to a
    192 * known type. Calling this function with a panel whose connector type is
    193 * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
    194 *
    195 * See devm_drm_panel_bridge_add() for an automatically managed version of this
    196 * function.
    197 */
    198struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
    199{
    200	if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
    201		return ERR_PTR(-EINVAL);
    202
    203	return drm_panel_bridge_add_typed(panel, panel->connector_type);
    204}
    205EXPORT_SYMBOL(drm_panel_bridge_add);
    206
    207/**
    208 * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
    209 * an explicit connector type.
    210 * @panel: The drm_panel being wrapped.  Must be non-NULL.
    211 * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
    212 *
    213 * This is just like drm_panel_bridge_add(), but forces the connector type to
    214 * @connector_type instead of infering it from the panel.
    215 *
    216 * This function is deprecated and should not be used in new drivers. Use
    217 * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
    218 * don't report a connector type.
    219 */
    220struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
    221					      u32 connector_type)
    222{
    223	struct panel_bridge *panel_bridge;
    224
    225	if (!panel)
    226		return ERR_PTR(-EINVAL);
    227
    228	panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),
    229				    GFP_KERNEL);
    230	if (!panel_bridge)
    231		return ERR_PTR(-ENOMEM);
    232
    233	panel_bridge->connector_type = connector_type;
    234	panel_bridge->panel = panel;
    235
    236	panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs;
    237#ifdef CONFIG_OF
    238	panel_bridge->bridge.of_node = panel->dev->of_node;
    239#endif
    240	panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
    241	panel_bridge->bridge.type = connector_type;
    242
    243	drm_bridge_add(&panel_bridge->bridge);
    244
    245	return &panel_bridge->bridge;
    246}
    247EXPORT_SYMBOL(drm_panel_bridge_add_typed);
    248
    249/**
    250 * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
    251 * created by drm_panel_bridge_add().
    252 *
    253 * @bridge: The drm_bridge being freed.
    254 */
    255void drm_panel_bridge_remove(struct drm_bridge *bridge)
    256{
    257	struct panel_bridge *panel_bridge;
    258
    259	if (!bridge)
    260		return;
    261
    262	if (bridge->funcs != &panel_bridge_bridge_funcs)
    263		return;
    264
    265	panel_bridge = drm_bridge_to_panel_bridge(bridge);
    266
    267	drm_bridge_remove(bridge);
    268	devm_kfree(panel_bridge->panel->dev, bridge);
    269}
    270EXPORT_SYMBOL(drm_panel_bridge_remove);
    271
    272static void devm_drm_panel_bridge_release(struct device *dev, void *res)
    273{
    274	struct drm_bridge **bridge = res;
    275
    276	drm_panel_bridge_remove(*bridge);
    277}
    278
    279/**
    280 * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
    281 * that just calls the appropriate functions from &drm_panel.
    282 * @dev: device to tie the bridge lifetime to
    283 * @panel: The drm_panel being wrapped.  Must be non-NULL.
    284 *
    285 * This is the managed version of drm_panel_bridge_add() which automatically
    286 * calls drm_panel_bridge_remove() when @dev is unbound.
    287 */
    288struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
    289					     struct drm_panel *panel)
    290{
    291	if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
    292		return ERR_PTR(-EINVAL);
    293
    294	return devm_drm_panel_bridge_add_typed(dev, panel,
    295					       panel->connector_type);
    296}
    297EXPORT_SYMBOL(devm_drm_panel_bridge_add);
    298
    299/**
    300 * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
    301 * &drm_connector with an explicit connector type.
    302 * @dev: device to tie the bridge lifetime to
    303 * @panel: The drm_panel being wrapped.  Must be non-NULL.
    304 * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
    305 *
    306 * This is just like devm_drm_panel_bridge_add(), but forces the connector type
    307 * to @connector_type instead of infering it from the panel.
    308 *
    309 * This function is deprecated and should not be used in new drivers. Use
    310 * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
    311 * they don't report a connector type.
    312 */
    313struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
    314						   struct drm_panel *panel,
    315						   u32 connector_type)
    316{
    317	struct drm_bridge **ptr, *bridge;
    318
    319	ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
    320			   GFP_KERNEL);
    321	if (!ptr)
    322		return ERR_PTR(-ENOMEM);
    323
    324	bridge = drm_panel_bridge_add_typed(panel, connector_type);
    325	if (!IS_ERR(bridge)) {
    326		*ptr = bridge;
    327		devres_add(dev, ptr);
    328	} else {
    329		devres_free(ptr);
    330	}
    331
    332	return bridge;
    333}
    334EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
    335
    336/**
    337 * drm_panel_bridge_connector - return the connector for the panel bridge
    338 * @bridge: The drm_bridge.
    339 *
    340 * drm_panel_bridge creates the connector.
    341 * This function gives external access to the connector.
    342 *
    343 * Returns: Pointer to drm_connector
    344 */
    345struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
    346{
    347	struct panel_bridge *panel_bridge;
    348
    349	panel_bridge = drm_bridge_to_panel_bridge(bridge);
    350
    351	return &panel_bridge->connector;
    352}
    353EXPORT_SYMBOL(drm_panel_bridge_connector);
    354
    355#ifdef CONFIG_OF
    356/**
    357 * devm_drm_of_get_bridge - Return next bridge in the chain
    358 * @dev: device to tie the bridge lifetime to
    359 * @np: device tree node containing encoder output ports
    360 * @port: port in the device tree node
    361 * @endpoint: endpoint in the device tree node
    362 *
    363 * Given a DT node's port and endpoint number, finds the connected node
    364 * and returns the associated bridge if any, or creates and returns a
    365 * drm panel bridge instance if a panel is connected.
    366 *
    367 * Returns a pointer to the bridge if successful, or an error pointer
    368 * otherwise.
    369 */
    370struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
    371					  struct device_node *np,
    372					  u32 port, u32 endpoint)
    373{
    374	struct drm_bridge *bridge;
    375	struct drm_panel *panel;
    376	int ret;
    377
    378	ret = drm_of_find_panel_or_bridge(np, port, endpoint,
    379					  &panel, &bridge);
    380	if (ret)
    381		return ERR_PTR(ret);
    382
    383	if (panel)
    384		bridge = devm_drm_panel_bridge_add(dev, panel);
    385
    386	return bridge;
    387}
    388EXPORT_SYMBOL(devm_drm_of_get_bridge);
    389#endif