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

simple-bridge.c (8573B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2015-2016 Free Electrons
      4 * Copyright (C) 2015-2016 NextThing Co
      5 *
      6 * Maxime Ripard <maxime.ripard@free-electrons.com>
      7 */
      8
      9#include <linux/gpio/consumer.h>
     10#include <linux/module.h>
     11#include <linux/of_device.h>
     12#include <linux/of_graph.h>
     13#include <linux/regulator/consumer.h>
     14
     15#include <drm/drm_atomic_helper.h>
     16#include <drm/drm_bridge.h>
     17#include <drm/drm_crtc.h>
     18#include <drm/drm_print.h>
     19#include <drm/drm_probe_helper.h>
     20
     21struct simple_bridge_info {
     22	const struct drm_bridge_timings *timings;
     23	unsigned int connector_type;
     24};
     25
     26struct simple_bridge {
     27	struct drm_bridge	bridge;
     28	struct drm_connector	connector;
     29
     30	const struct simple_bridge_info *info;
     31
     32	struct drm_bridge	*next_bridge;
     33	struct regulator	*vdd;
     34	struct gpio_desc	*enable;
     35};
     36
     37static inline struct simple_bridge *
     38drm_bridge_to_simple_bridge(struct drm_bridge *bridge)
     39{
     40	return container_of(bridge, struct simple_bridge, bridge);
     41}
     42
     43static inline struct simple_bridge *
     44drm_connector_to_simple_bridge(struct drm_connector *connector)
     45{
     46	return container_of(connector, struct simple_bridge, connector);
     47}
     48
     49static int simple_bridge_get_modes(struct drm_connector *connector)
     50{
     51	struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector);
     52	struct edid *edid;
     53	int ret;
     54
     55	if (sbridge->next_bridge->ops & DRM_BRIDGE_OP_EDID) {
     56		edid = drm_bridge_get_edid(sbridge->next_bridge, connector);
     57		if (!edid)
     58			DRM_INFO("EDID read failed. Fallback to standard modes\n");
     59	} else {
     60		edid = NULL;
     61	}
     62
     63	if (!edid) {
     64		/*
     65		 * In case we cannot retrieve the EDIDs (missing or broken DDC
     66		 * bus from the next bridge), fallback on the XGA standards and
     67		 * prefer a mode pretty much anyone can handle.
     68		 */
     69		ret = drm_add_modes_noedid(connector, 1920, 1200);
     70		drm_set_preferred_mode(connector, 1024, 768);
     71		return ret;
     72	}
     73
     74	drm_connector_update_edid_property(connector, edid);
     75	ret = drm_add_edid_modes(connector, edid);
     76	kfree(edid);
     77
     78	return ret;
     79}
     80
     81static const struct drm_connector_helper_funcs simple_bridge_con_helper_funcs = {
     82	.get_modes	= simple_bridge_get_modes,
     83};
     84
     85static enum drm_connector_status
     86simple_bridge_connector_detect(struct drm_connector *connector, bool force)
     87{
     88	struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector);
     89
     90	return drm_bridge_detect(sbridge->next_bridge);
     91}
     92
     93static const struct drm_connector_funcs simple_bridge_con_funcs = {
     94	.detect			= simple_bridge_connector_detect,
     95	.fill_modes		= drm_helper_probe_single_connector_modes,
     96	.destroy		= drm_connector_cleanup,
     97	.reset			= drm_atomic_helper_connector_reset,
     98	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
     99	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
    100};
    101
    102static int simple_bridge_attach(struct drm_bridge *bridge,
    103				enum drm_bridge_attach_flags flags)
    104{
    105	struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
    106	int ret;
    107
    108	ret = drm_bridge_attach(bridge->encoder, sbridge->next_bridge, bridge,
    109				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
    110	if (ret < 0)
    111		return ret;
    112
    113	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
    114		return 0;
    115
    116	if (!bridge->encoder) {
    117		DRM_ERROR("Missing encoder\n");
    118		return -ENODEV;
    119	}
    120
    121	drm_connector_helper_add(&sbridge->connector,
    122				 &simple_bridge_con_helper_funcs);
    123	ret = drm_connector_init_with_ddc(bridge->dev, &sbridge->connector,
    124					  &simple_bridge_con_funcs,
    125					  sbridge->info->connector_type,
    126					  sbridge->next_bridge->ddc);
    127	if (ret) {
    128		DRM_ERROR("Failed to initialize connector\n");
    129		return ret;
    130	}
    131
    132	drm_connector_attach_encoder(&sbridge->connector, bridge->encoder);
    133
    134	return 0;
    135}
    136
    137static void simple_bridge_enable(struct drm_bridge *bridge)
    138{
    139	struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
    140	int ret;
    141
    142	if (sbridge->vdd) {
    143		ret = regulator_enable(sbridge->vdd);
    144		if (ret)
    145			DRM_ERROR("Failed to enable vdd regulator: %d\n", ret);
    146	}
    147
    148	gpiod_set_value_cansleep(sbridge->enable, 1);
    149}
    150
    151static void simple_bridge_disable(struct drm_bridge *bridge)
    152{
    153	struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
    154
    155	gpiod_set_value_cansleep(sbridge->enable, 0);
    156
    157	if (sbridge->vdd)
    158		regulator_disable(sbridge->vdd);
    159}
    160
    161static const struct drm_bridge_funcs simple_bridge_bridge_funcs = {
    162	.attach		= simple_bridge_attach,
    163	.enable		= simple_bridge_enable,
    164	.disable	= simple_bridge_disable,
    165};
    166
    167static int simple_bridge_probe(struct platform_device *pdev)
    168{
    169	struct simple_bridge *sbridge;
    170	struct device_node *remote;
    171
    172	sbridge = devm_kzalloc(&pdev->dev, sizeof(*sbridge), GFP_KERNEL);
    173	if (!sbridge)
    174		return -ENOMEM;
    175	platform_set_drvdata(pdev, sbridge);
    176
    177	sbridge->info = of_device_get_match_data(&pdev->dev);
    178
    179	/* Get the next bridge in the pipeline. */
    180	remote = of_graph_get_remote_node(pdev->dev.of_node, 1, -1);
    181	if (!remote)
    182		return -EINVAL;
    183
    184	sbridge->next_bridge = of_drm_find_bridge(remote);
    185	of_node_put(remote);
    186
    187	if (!sbridge->next_bridge) {
    188		dev_dbg(&pdev->dev, "Next bridge not found, deferring probe\n");
    189		return -EPROBE_DEFER;
    190	}
    191
    192	/* Get the regulator and GPIO resources. */
    193	sbridge->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
    194	if (IS_ERR(sbridge->vdd)) {
    195		int ret = PTR_ERR(sbridge->vdd);
    196		if (ret == -EPROBE_DEFER)
    197			return -EPROBE_DEFER;
    198		sbridge->vdd = NULL;
    199		dev_dbg(&pdev->dev, "No vdd regulator found: %d\n", ret);
    200	}
    201
    202	sbridge->enable = devm_gpiod_get_optional(&pdev->dev, "enable",
    203						  GPIOD_OUT_LOW);
    204	if (IS_ERR(sbridge->enable)) {
    205		if (PTR_ERR(sbridge->enable) != -EPROBE_DEFER)
    206			dev_err(&pdev->dev, "Unable to retrieve enable GPIO\n");
    207		return PTR_ERR(sbridge->enable);
    208	}
    209
    210	/* Register the bridge. */
    211	sbridge->bridge.funcs = &simple_bridge_bridge_funcs;
    212	sbridge->bridge.of_node = pdev->dev.of_node;
    213	sbridge->bridge.timings = sbridge->info->timings;
    214
    215	drm_bridge_add(&sbridge->bridge);
    216
    217	return 0;
    218}
    219
    220static int simple_bridge_remove(struct platform_device *pdev)
    221{
    222	struct simple_bridge *sbridge = platform_get_drvdata(pdev);
    223
    224	drm_bridge_remove(&sbridge->bridge);
    225
    226	return 0;
    227}
    228
    229/*
    230 * We assume the ADV7123 DAC is the "default" for historical reasons
    231 * Information taken from the ADV7123 datasheet, revision D.
    232 * NOTE: the ADV7123EP seems to have other timings and need a new timings
    233 * set if used.
    234 */
    235static const struct drm_bridge_timings default_bridge_timings = {
    236	/* Timing specifications, datasheet page 7 */
    237	.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
    238	.setup_time_ps = 500,
    239	.hold_time_ps = 1500,
    240};
    241
    242/*
    243 * Information taken from the THS8134, THS8134A, THS8134B datasheet named
    244 * "SLVS205D", dated May 1990, revised March 2000.
    245 */
    246static const struct drm_bridge_timings ti_ths8134_bridge_timings = {
    247	/* From timing diagram, datasheet page 9 */
    248	.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
    249	/* From datasheet, page 12 */
    250	.setup_time_ps = 3000,
    251	/* I guess this means latched input */
    252	.hold_time_ps = 0,
    253};
    254
    255/*
    256 * Information taken from the THS8135 datasheet named "SLAS343B", dated
    257 * May 2001, revised April 2013.
    258 */
    259static const struct drm_bridge_timings ti_ths8135_bridge_timings = {
    260	/* From timing diagram, datasheet page 14 */
    261	.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
    262	/* From datasheet, page 16 */
    263	.setup_time_ps = 2000,
    264	.hold_time_ps = 500,
    265};
    266
    267static const struct of_device_id simple_bridge_match[] = {
    268	{
    269		.compatible = "dumb-vga-dac",
    270		.data = &(const struct simple_bridge_info) {
    271			.connector_type = DRM_MODE_CONNECTOR_VGA,
    272		},
    273	}, {
    274		.compatible = "adi,adv7123",
    275		.data = &(const struct simple_bridge_info) {
    276			.timings = &default_bridge_timings,
    277			.connector_type = DRM_MODE_CONNECTOR_VGA,
    278		},
    279	}, {
    280		.compatible = "ti,opa362",
    281		.data = &(const struct simple_bridge_info) {
    282			.connector_type = DRM_MODE_CONNECTOR_Composite,
    283		},
    284	}, {
    285		.compatible = "ti,ths8135",
    286		.data = &(const struct simple_bridge_info) {
    287			.timings = &ti_ths8135_bridge_timings,
    288			.connector_type = DRM_MODE_CONNECTOR_VGA,
    289		},
    290	}, {
    291		.compatible = "ti,ths8134",
    292		.data = &(const struct simple_bridge_info) {
    293			.timings = &ti_ths8134_bridge_timings,
    294			.connector_type = DRM_MODE_CONNECTOR_VGA,
    295		},
    296	},
    297	{},
    298};
    299MODULE_DEVICE_TABLE(of, simple_bridge_match);
    300
    301static struct platform_driver simple_bridge_driver = {
    302	.probe	= simple_bridge_probe,
    303	.remove	= simple_bridge_remove,
    304	.driver		= {
    305		.name		= "simple-bridge",
    306		.of_match_table	= simple_bridge_match,
    307	},
    308};
    309module_platform_driver(simple_bridge_driver);
    310
    311MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
    312MODULE_DESCRIPTION("Simple DRM bridge driver");
    313MODULE_LICENSE("GPL");