brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · 0dc36df Raw
250 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Exynos DRM Parallel output support.4 *5 * Copyright (c) 2014 Samsung Electronics Co., Ltd6 *7 * Contacts: Andrzej Hajda <a.hajda@samsung.com>8*/9 10#include <linux/of.h>11#include <linux/of_graph.h>12#include <linux/regulator/consumer.h>13 14#include <drm/drm_atomic_helper.h>15#include <drm/drm_panel.h>16#include <drm/drm_print.h>17#include <drm/drm_probe_helper.h>18#include <drm/drm_simple_kms_helper.h>19 20#include <video/of_videomode.h>21#include <video/videomode.h>22 23#include "exynos_drm_crtc.h"24 25struct exynos_dpi {26	struct drm_encoder encoder;27	struct device *dev;28	struct device_node *panel_node;29 30	struct drm_panel *panel;31	struct drm_connector connector;32 33	struct videomode *vm;34};35 36#define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)37 38static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)39{40	return container_of(e, struct exynos_dpi, encoder);41}42 43static enum drm_connector_status44exynos_dpi_detect(struct drm_connector *connector, bool force)45{46	return connector_status_connected;47}48 49static void exynos_dpi_connector_destroy(struct drm_connector *connector)50{51	drm_connector_unregister(connector);52	drm_connector_cleanup(connector);53}54 55static const struct drm_connector_funcs exynos_dpi_connector_funcs = {56	.detect = exynos_dpi_detect,57	.fill_modes = drm_helper_probe_single_connector_modes,58	.destroy = exynos_dpi_connector_destroy,59	.reset = drm_atomic_helper_connector_reset,60	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,61	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,62};63 64static int exynos_dpi_get_modes(struct drm_connector *connector)65{66	struct exynos_dpi *ctx = connector_to_dpi(connector);67 68	/* fimd timings gets precedence over panel modes */69	if (ctx->vm) {70		struct drm_display_mode *mode;71 72		mode = drm_mode_create(connector->dev);73		if (!mode) {74			DRM_DEV_ERROR(ctx->dev,75				      "failed to create a new display mode\n");76			return 0;77		}78		drm_display_mode_from_videomode(ctx->vm, mode);79		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;80		drm_mode_probed_add(connector, mode);81		return 1;82	}83 84	if (ctx->panel)85		return drm_panel_get_modes(ctx->panel, connector);86 87	return 0;88}89 90static const struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {91	.get_modes = exynos_dpi_get_modes,92};93 94static int exynos_dpi_create_connector(struct drm_encoder *encoder)95{96	struct exynos_dpi *ctx = encoder_to_dpi(encoder);97	struct drm_connector *connector = &ctx->connector;98	int ret;99 100	connector->polled = DRM_CONNECTOR_POLL_HPD;101 102	ret = drm_connector_init(encoder->dev, connector,103				 &exynos_dpi_connector_funcs,104				 DRM_MODE_CONNECTOR_DPI);105	if (ret) {106		DRM_DEV_ERROR(ctx->dev,107			      "failed to initialize connector with drm\n");108		return ret;109	}110 111	drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs);112	drm_connector_attach_encoder(connector, encoder);113 114	return 0;115}116 117static void exynos_dpi_mode_set(struct drm_encoder *encoder,118				struct drm_display_mode *mode,119				struct drm_display_mode *adjusted_mode)120{121}122 123static void exynos_dpi_enable(struct drm_encoder *encoder)124{125	struct exynos_dpi *ctx = encoder_to_dpi(encoder);126 127	if (ctx->panel) {128		drm_panel_prepare(ctx->panel);129		drm_panel_enable(ctx->panel);130	}131}132 133static void exynos_dpi_disable(struct drm_encoder *encoder)134{135	struct exynos_dpi *ctx = encoder_to_dpi(encoder);136 137	if (ctx->panel) {138		drm_panel_disable(ctx->panel);139		drm_panel_unprepare(ctx->panel);140	}141}142 143static const struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {144	.mode_set = exynos_dpi_mode_set,145	.enable = exynos_dpi_enable,146	.disable = exynos_dpi_disable,147};148 149enum {150	FIMD_PORT_IN0,151	FIMD_PORT_IN1,152	FIMD_PORT_IN2,153	FIMD_PORT_RGB,154	FIMD_PORT_WRB,155};156 157static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)158{159	struct device *dev = ctx->dev;160	struct device_node *dn = dev->of_node;161	struct device_node *np;162 163	ctx->panel_node = of_graph_get_remote_node(dn, FIMD_PORT_RGB, 0);164 165	np = of_get_child_by_name(dn, "display-timings");166	if (np) {167		struct videomode *vm;168		int ret;169 170		of_node_put(np);171 172		vm = devm_kzalloc(dev, sizeof(*ctx->vm), GFP_KERNEL);173		if (!vm)174			return -ENOMEM;175 176		ret = of_get_videomode(dn, vm, 0);177		if (ret < 0) {178			devm_kfree(dev, vm);179			return ret;180		}181 182		ctx->vm = vm;183 184		return 0;185	}186 187	if (!ctx->panel_node)188		return -EINVAL;189 190	return 0;191}192 193int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)194{195	int ret;196 197	drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS);198 199	drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);200 201	ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);202	if (ret < 0)203		return ret;204 205	ret = exynos_dpi_create_connector(encoder);206	if (ret) {207		DRM_DEV_ERROR(encoder_to_dpi(encoder)->dev,208			      "failed to create connector ret = %d\n", ret);209		drm_encoder_cleanup(encoder);210		return ret;211	}212 213	return 0;214}215 216struct drm_encoder *exynos_dpi_probe(struct device *dev)217{218	struct exynos_dpi *ctx;219	int ret;220 221	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);222	if (!ctx)223		return ERR_PTR(-ENOMEM);224 225	ctx->dev = dev;226 227	ret = exynos_dpi_parse_dt(ctx);228	if (ret < 0) {229		devm_kfree(dev, ctx);230		return NULL;231	}232 233	if (ctx->panel_node) {234		ctx->panel = of_drm_find_panel(ctx->panel_node);235		if (IS_ERR(ctx->panel))236			return ERR_CAST(ctx->panel);237	}238 239	return &ctx->encoder;240}241 242int exynos_dpi_remove(struct drm_encoder *encoder)243{244	struct exynos_dpi *ctx = encoder_to_dpi(encoder);245 246	exynos_dpi_disable(&ctx->encoder);247 248	return 0;249}250