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

atmel_hlcdc_output.c (3185B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Traphandler
      4 * Copyright (C) 2014 Free Electrons
      5 * Copyright (C) 2014 Atmel
      6 *
      7 * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
      8 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
      9 */
     10
     11#include <linux/media-bus-format.h>
     12#include <linux/of_graph.h>
     13
     14#include <drm/drm_bridge.h>
     15#include <drm/drm_encoder.h>
     16#include <drm/drm_of.h>
     17#include <drm/drm_simple_kms_helper.h>
     18
     19#include "atmel_hlcdc_dc.h"
     20
     21struct atmel_hlcdc_rgb_output {
     22	struct drm_encoder encoder;
     23	int bus_fmt;
     24};
     25
     26static struct atmel_hlcdc_rgb_output *
     27atmel_hlcdc_encoder_to_rgb_output(struct drm_encoder *encoder)
     28{
     29	return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder);
     30}
     31
     32int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder)
     33{
     34	struct atmel_hlcdc_rgb_output *output;
     35
     36	output = atmel_hlcdc_encoder_to_rgb_output(encoder);
     37
     38	return output->bus_fmt;
     39}
     40
     41static int atmel_hlcdc_of_bus_fmt(const struct device_node *ep)
     42{
     43	u32 bus_width;
     44	int ret;
     45
     46	ret = of_property_read_u32(ep, "bus-width", &bus_width);
     47	if (ret == -EINVAL)
     48		return 0;
     49	if (ret)
     50		return ret;
     51
     52	switch (bus_width) {
     53	case 12:
     54		return MEDIA_BUS_FMT_RGB444_1X12;
     55	case 16:
     56		return MEDIA_BUS_FMT_RGB565_1X16;
     57	case 18:
     58		return MEDIA_BUS_FMT_RGB666_1X18;
     59	case 24:
     60		return MEDIA_BUS_FMT_RGB888_1X24;
     61	default:
     62		return -EINVAL;
     63	}
     64}
     65
     66static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
     67{
     68	struct atmel_hlcdc_rgb_output *output;
     69	struct device_node *ep;
     70	struct drm_panel *panel;
     71	struct drm_bridge *bridge;
     72	int ret;
     73
     74	ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0, endpoint);
     75	if (!ep)
     76		return -ENODEV;
     77
     78	ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint,
     79					  &panel, &bridge);
     80	if (ret) {
     81		of_node_put(ep);
     82		return ret;
     83	}
     84
     85	output = devm_kzalloc(dev->dev, sizeof(*output), GFP_KERNEL);
     86	if (!output) {
     87		of_node_put(ep);
     88		return -ENOMEM;
     89	}
     90
     91	output->bus_fmt = atmel_hlcdc_of_bus_fmt(ep);
     92	of_node_put(ep);
     93	if (output->bus_fmt < 0) {
     94		dev_err(dev->dev, "endpoint %d: invalid bus width\n", endpoint);
     95		return -EINVAL;
     96	}
     97
     98	ret = drm_simple_encoder_init(dev, &output->encoder,
     99				      DRM_MODE_ENCODER_NONE);
    100	if (ret)
    101		return ret;
    102
    103	output->encoder.possible_crtcs = 0x1;
    104
    105	if (panel) {
    106		bridge = drm_panel_bridge_add_typed(panel,
    107						    DRM_MODE_CONNECTOR_Unknown);
    108		if (IS_ERR(bridge))
    109			return PTR_ERR(bridge);
    110	}
    111
    112	if (bridge) {
    113		ret = drm_bridge_attach(&output->encoder, bridge, NULL, 0);
    114		if (!ret)
    115			return 0;
    116
    117		if (panel)
    118			drm_panel_bridge_remove(bridge);
    119	}
    120
    121	drm_encoder_cleanup(&output->encoder);
    122
    123	return ret;
    124}
    125
    126int atmel_hlcdc_create_outputs(struct drm_device *dev)
    127{
    128	int endpoint, ret = 0;
    129	int attached = 0;
    130
    131	/*
    132	 * Always scan the first few endpoints even if we get -ENODEV,
    133	 * but keep going after that as long as we keep getting hits.
    134	 */
    135	for (endpoint = 0; !ret || endpoint < 4; endpoint++) {
    136		ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
    137		if (ret == -ENODEV)
    138			continue;
    139		if (ret)
    140			break;
    141		attached++;
    142	}
    143
    144	/* At least one device was successfully attached.*/
    145	if (ret == -ENODEV && attached)
    146		return 0;
    147
    148	return ret;
    149}