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

drm_of.c (11984B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/component.h>
      3#include <linux/export.h>
      4#include <linux/list.h>
      5#include <linux/of_graph.h>
      6
      7#include <drm/drm_bridge.h>
      8#include <drm/drm_crtc.h>
      9#include <drm/drm_device.h>
     10#include <drm/drm_encoder.h>
     11#include <drm/drm_of.h>
     12#include <drm/drm_panel.h>
     13
     14/**
     15 * DOC: overview
     16 *
     17 * A set of helper functions to aid DRM drivers in parsing standard DT
     18 * properties.
     19 */
     20
     21/**
     22 * drm_of_crtc_port_mask - find the mask of a registered CRTC by port OF node
     23 * @dev: DRM device
     24 * @port: port OF node
     25 *
     26 * Given a port OF node, return the possible mask of the corresponding
     27 * CRTC within a device's list of CRTCs.  Returns zero if not found.
     28 */
     29uint32_t drm_of_crtc_port_mask(struct drm_device *dev,
     30			    struct device_node *port)
     31{
     32	unsigned int index = 0;
     33	struct drm_crtc *tmp;
     34
     35	drm_for_each_crtc(tmp, dev) {
     36		if (tmp->port == port)
     37			return 1 << index;
     38
     39		index++;
     40	}
     41
     42	return 0;
     43}
     44EXPORT_SYMBOL(drm_of_crtc_port_mask);
     45
     46/**
     47 * drm_of_find_possible_crtcs - find the possible CRTCs for an encoder port
     48 * @dev: DRM device
     49 * @port: encoder port to scan for endpoints
     50 *
     51 * Scan all endpoints attached to a port, locate their attached CRTCs,
     52 * and generate the DRM mask of CRTCs which may be attached to this
     53 * encoder.
     54 *
     55 * See Documentation/devicetree/bindings/graph.txt for the bindings.
     56 */
     57uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
     58				    struct device_node *port)
     59{
     60	struct device_node *remote_port, *ep;
     61	uint32_t possible_crtcs = 0;
     62
     63	for_each_endpoint_of_node(port, ep) {
     64		remote_port = of_graph_get_remote_port(ep);
     65		if (!remote_port) {
     66			of_node_put(ep);
     67			return 0;
     68		}
     69
     70		possible_crtcs |= drm_of_crtc_port_mask(dev, remote_port);
     71
     72		of_node_put(remote_port);
     73	}
     74
     75	return possible_crtcs;
     76}
     77EXPORT_SYMBOL(drm_of_find_possible_crtcs);
     78
     79/**
     80 * drm_of_component_match_add - Add a component helper OF node match rule
     81 * @master: master device
     82 * @matchptr: component match pointer
     83 * @compare: compare function used for matching component
     84 * @node: of_node
     85 */
     86void drm_of_component_match_add(struct device *master,
     87				struct component_match **matchptr,
     88				int (*compare)(struct device *, void *),
     89				struct device_node *node)
     90{
     91	of_node_get(node);
     92	component_match_add_release(master, matchptr, component_release_of,
     93				    compare, node);
     94}
     95EXPORT_SYMBOL_GPL(drm_of_component_match_add);
     96
     97/**
     98 * drm_of_component_probe - Generic probe function for a component based master
     99 * @dev: master device containing the OF node
    100 * @compare_of: compare function used for matching components
    101 * @m_ops: component master ops to be used
    102 *
    103 * Parse the platform device OF node and bind all the components associated
    104 * with the master. Interface ports are added before the encoders in order to
    105 * satisfy their .bind requirements
    106 * See Documentation/devicetree/bindings/graph.txt for the bindings.
    107 *
    108 * Returns zero if successful, or one of the standard error codes if it fails.
    109 */
    110int drm_of_component_probe(struct device *dev,
    111			   int (*compare_of)(struct device *, void *),
    112			   const struct component_master_ops *m_ops)
    113{
    114	struct device_node *ep, *port, *remote;
    115	struct component_match *match = NULL;
    116	int i;
    117
    118	if (!dev->of_node)
    119		return -EINVAL;
    120
    121	/*
    122	 * Bind the crtc's ports first, so that drm_of_find_possible_crtcs()
    123	 * called from encoder's .bind callbacks works as expected
    124	 */
    125	for (i = 0; ; i++) {
    126		port = of_parse_phandle(dev->of_node, "ports", i);
    127		if (!port)
    128			break;
    129
    130		if (of_device_is_available(port->parent))
    131			drm_of_component_match_add(dev, &match, compare_of,
    132						   port);
    133
    134		of_node_put(port);
    135	}
    136
    137	if (i == 0) {
    138		dev_err(dev, "missing 'ports' property\n");
    139		return -ENODEV;
    140	}
    141
    142	if (!match) {
    143		dev_err(dev, "no available port\n");
    144		return -ENODEV;
    145	}
    146
    147	/*
    148	 * For bound crtcs, bind the encoders attached to their remote endpoint
    149	 */
    150	for (i = 0; ; i++) {
    151		port = of_parse_phandle(dev->of_node, "ports", i);
    152		if (!port)
    153			break;
    154
    155		if (!of_device_is_available(port->parent)) {
    156			of_node_put(port);
    157			continue;
    158		}
    159
    160		for_each_child_of_node(port, ep) {
    161			remote = of_graph_get_remote_port_parent(ep);
    162			if (!remote || !of_device_is_available(remote)) {
    163				of_node_put(remote);
    164				continue;
    165			} else if (!of_device_is_available(remote->parent)) {
    166				dev_warn(dev, "parent device of %pOF is not available\n",
    167					 remote);
    168				of_node_put(remote);
    169				continue;
    170			}
    171
    172			drm_of_component_match_add(dev, &match, compare_of,
    173						   remote);
    174			of_node_put(remote);
    175		}
    176		of_node_put(port);
    177	}
    178
    179	return component_master_add_with_match(dev, m_ops, match);
    180}
    181EXPORT_SYMBOL(drm_of_component_probe);
    182
    183/*
    184 * drm_of_encoder_active_endpoint - return the active encoder endpoint
    185 * @node: device tree node containing encoder input ports
    186 * @encoder: drm_encoder
    187 *
    188 * Given an encoder device node and a drm_encoder with a connected crtc,
    189 * parse the encoder endpoint connecting to the crtc port.
    190 */
    191int drm_of_encoder_active_endpoint(struct device_node *node,
    192				   struct drm_encoder *encoder,
    193				   struct of_endpoint *endpoint)
    194{
    195	struct device_node *ep;
    196	struct drm_crtc *crtc = encoder->crtc;
    197	struct device_node *port;
    198	int ret;
    199
    200	if (!node || !crtc)
    201		return -EINVAL;
    202
    203	for_each_endpoint_of_node(node, ep) {
    204		port = of_graph_get_remote_port(ep);
    205		of_node_put(port);
    206		if (port == crtc->port) {
    207			ret = of_graph_parse_endpoint(ep, endpoint);
    208			of_node_put(ep);
    209			return ret;
    210		}
    211	}
    212
    213	return -EINVAL;
    214}
    215EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
    216
    217/**
    218 * drm_of_find_panel_or_bridge - return connected panel or bridge device
    219 * @np: device tree node containing encoder output ports
    220 * @port: port in the device tree node
    221 * @endpoint: endpoint in the device tree node
    222 * @panel: pointer to hold returned drm_panel
    223 * @bridge: pointer to hold returned drm_bridge
    224 *
    225 * Given a DT node's port and endpoint number, find the connected node and
    226 * return either the associated struct drm_panel or drm_bridge device. Either
    227 * @panel or @bridge must not be NULL.
    228 *
    229 * This function is deprecated and should not be used in new drivers. Use
    230 * devm_drm_of_get_bridge() instead.
    231 *
    232 * Returns zero if successful, or one of the standard error codes if it fails.
    233 */
    234int drm_of_find_panel_or_bridge(const struct device_node *np,
    235				int port, int endpoint,
    236				struct drm_panel **panel,
    237				struct drm_bridge **bridge)
    238{
    239	int ret = -EPROBE_DEFER;
    240	struct device_node *remote;
    241
    242	if (!panel && !bridge)
    243		return -EINVAL;
    244	if (panel)
    245		*panel = NULL;
    246
    247	/*
    248	 * of_graph_get_remote_node() produces a noisy error message if port
    249	 * node isn't found and the absence of the port is a legit case here,
    250	 * so at first we silently check whether graph presents in the
    251	 * device-tree node.
    252	 */
    253	if (!of_graph_is_present(np))
    254		return -ENODEV;
    255
    256	remote = of_graph_get_remote_node(np, port, endpoint);
    257	if (!remote)
    258		return -ENODEV;
    259
    260	if (panel) {
    261		*panel = of_drm_find_panel(remote);
    262		if (!IS_ERR(*panel))
    263			ret = 0;
    264		else
    265			*panel = NULL;
    266	}
    267
    268	/* No panel found yet, check for a bridge next. */
    269	if (bridge) {
    270		if (ret) {
    271			*bridge = of_drm_find_bridge(remote);
    272			if (*bridge)
    273				ret = 0;
    274		} else {
    275			*bridge = NULL;
    276		}
    277
    278	}
    279
    280	of_node_put(remote);
    281	return ret;
    282}
    283EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
    284
    285enum drm_of_lvds_pixels {
    286	DRM_OF_LVDS_EVEN = BIT(0),
    287	DRM_OF_LVDS_ODD = BIT(1),
    288};
    289
    290static int drm_of_lvds_get_port_pixels_type(struct device_node *port_node)
    291{
    292	bool even_pixels =
    293		of_property_read_bool(port_node, "dual-lvds-even-pixels");
    294	bool odd_pixels =
    295		of_property_read_bool(port_node, "dual-lvds-odd-pixels");
    296
    297	return (even_pixels ? DRM_OF_LVDS_EVEN : 0) |
    298	       (odd_pixels ? DRM_OF_LVDS_ODD : 0);
    299}
    300
    301static int drm_of_lvds_get_remote_pixels_type(
    302			const struct device_node *port_node)
    303{
    304	struct device_node *endpoint = NULL;
    305	int pixels_type = -EPIPE;
    306
    307	for_each_child_of_node(port_node, endpoint) {
    308		struct device_node *remote_port;
    309		int current_pt;
    310
    311		if (!of_node_name_eq(endpoint, "endpoint"))
    312			continue;
    313
    314		remote_port = of_graph_get_remote_port(endpoint);
    315		if (!remote_port) {
    316			of_node_put(endpoint);
    317			return -EPIPE;
    318		}
    319
    320		current_pt = drm_of_lvds_get_port_pixels_type(remote_port);
    321		of_node_put(remote_port);
    322		if (pixels_type < 0)
    323			pixels_type = current_pt;
    324
    325		/*
    326		 * Sanity check, ensure that all remote endpoints have the same
    327		 * pixel type. We may lift this restriction later if we need to
    328		 * support multiple sinks with different dual-link
    329		 * configurations by passing the endpoints explicitly to
    330		 * drm_of_lvds_get_dual_link_pixel_order().
    331		 */
    332		if (!current_pt || pixels_type != current_pt) {
    333			of_node_put(endpoint);
    334			return -EINVAL;
    335		}
    336	}
    337
    338	return pixels_type;
    339}
    340
    341/**
    342 * drm_of_lvds_get_dual_link_pixel_order - Get LVDS dual-link pixel order
    343 * @port1: First DT port node of the Dual-link LVDS source
    344 * @port2: Second DT port node of the Dual-link LVDS source
    345 *
    346 * An LVDS dual-link connection is made of two links, with even pixels
    347 * transitting on one link, and odd pixels on the other link. This function
    348 * returns, for two ports of an LVDS dual-link source, which port shall transmit
    349 * the even and odd pixels, based on the requirements of the connected sink.
    350 *
    351 * The pixel order is determined from the dual-lvds-even-pixels and
    352 * dual-lvds-odd-pixels properties in the sink's DT port nodes. If those
    353 * properties are not present, or if their usage is not valid, this function
    354 * returns -EINVAL.
    355 *
    356 * If either port is not connected, this function returns -EPIPE.
    357 *
    358 * @port1 and @port2 are typically DT sibling nodes, but may have different
    359 * parents when, for instance, two separate LVDS encoders carry the even and odd
    360 * pixels.
    361 *
    362 * Return:
    363 * * DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS - @port1 carries even pixels and @port2
    364 *   carries odd pixels
    365 * * DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS - @port1 carries odd pixels and @port2
    366 *   carries even pixels
    367 * * -EINVAL - @port1 and @port2 are not connected to a dual-link LVDS sink, or
    368 *   the sink configuration is invalid
    369 * * -EPIPE - when @port1 or @port2 are not connected
    370 */
    371int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1,
    372					  const struct device_node *port2)
    373{
    374	int remote_p1_pt, remote_p2_pt;
    375
    376	if (!port1 || !port2)
    377		return -EINVAL;
    378
    379	remote_p1_pt = drm_of_lvds_get_remote_pixels_type(port1);
    380	if (remote_p1_pt < 0)
    381		return remote_p1_pt;
    382
    383	remote_p2_pt = drm_of_lvds_get_remote_pixels_type(port2);
    384	if (remote_p2_pt < 0)
    385		return remote_p2_pt;
    386
    387	/*
    388	 * A valid dual-lVDS bus is found when one remote port is marked with
    389	 * "dual-lvds-even-pixels", and the other remote port is marked with
    390	 * "dual-lvds-odd-pixels", bail out if the markers are not right.
    391	 */
    392	if (remote_p1_pt + remote_p2_pt != DRM_OF_LVDS_EVEN + DRM_OF_LVDS_ODD)
    393		return -EINVAL;
    394
    395	return remote_p1_pt == DRM_OF_LVDS_EVEN ?
    396		DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS :
    397		DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
    398}
    399EXPORT_SYMBOL_GPL(drm_of_lvds_get_dual_link_pixel_order);
    400
    401/**
    402 * drm_of_lvds_get_data_mapping - Get LVDS data mapping
    403 * @port: DT port node of the LVDS source or sink
    404 *
    405 * Convert DT "data-mapping" property string value into media bus format value.
    406 *
    407 * Return:
    408 * * MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - data-mapping is "jeida-18"
    409 * * MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA - data-mapping is "jeida-24"
    410 * * MEDIA_BUS_FMT_RGB888_1X7X4_SPWG - data-mapping is "vesa-24"
    411 * * -EINVAL - the "data-mapping" property is unsupported
    412 * * -ENODEV - the "data-mapping" property is missing
    413 */
    414int drm_of_lvds_get_data_mapping(const struct device_node *port)
    415{
    416	const char *mapping;
    417	int ret;
    418
    419	ret = of_property_read_string(port, "data-mapping", &mapping);
    420	if (ret < 0)
    421		return -ENODEV;
    422
    423	if (!strcmp(mapping, "jeida-18"))
    424		return MEDIA_BUS_FMT_RGB666_1X7X3_SPWG;
    425	if (!strcmp(mapping, "jeida-24"))
    426		return MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
    427	if (!strcmp(mapping, "vesa-24"))
    428		return MEDIA_BUS_FMT_RGB888_1X7X4_SPWG;
    429
    430	return -EINVAL;
    431}
    432EXPORT_SYMBOL_GPL(drm_of_lvds_get_data_mapping);