Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1/*
  2 * R-Car Display Unit HDMI Encoder
  3 *
  4 * Copyright (C) 2014 Renesas Electronics Corporation
  5 *
  6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  7 *
  8 * This program is free software; you can redistribute it and/or modify
  9 * it under the terms of the GNU General Public License as published by
 10 * the Free Software Foundation; either version 2 of the License, or
 11 * (at your option) any later version.
 12 */
 13
 14#include <linux/slab.h>
 15
 16#include <drm/drmP.h>
 17#include <drm/drm_crtc.h>
 18#include <drm/drm_crtc_helper.h>
 19
 20#include "rcar_du_drv.h"
 21#include "rcar_du_encoder.h"
 22#include "rcar_du_hdmienc.h"
 23#include "rcar_du_lvdsenc.h"
 24
 25struct rcar_du_hdmienc {
 26	struct rcar_du_encoder *renc;
 27	bool enabled;
 28};
 29
 30#define to_rcar_hdmienc(e)	(to_rcar_encoder(e)->hdmi)
 31
 32static void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
 33{
 34	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 35
 36	if (hdmienc->renc->lvds)
 37		rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
 38				       false);
 39
 40	hdmienc->enabled = false;
 41}
 42
 43static void rcar_du_hdmienc_enable(struct drm_encoder *encoder)
 44{
 45	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 46
 47	if (hdmienc->renc->lvds)
 48		rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
 49				       true);
 50
 51	hdmienc->enabled = true;
 52}
 53
 54static int rcar_du_hdmienc_atomic_check(struct drm_encoder *encoder,
 55					struct drm_crtc_state *crtc_state,
 56					struct drm_connector_state *conn_state)
 57{
 58	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 59	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
 60
 61	if (hdmienc->renc->lvds)
 62		rcar_du_lvdsenc_atomic_check(hdmienc->renc->lvds,
 63					     adjusted_mode);
 64
 65	return 0;
 66}
 67
 68
 69static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
 70				     struct drm_display_mode *mode,
 71				     struct drm_display_mode *adjusted_mode)
 72{
 73	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 74
 75	rcar_du_crtc_route_output(encoder->crtc, hdmienc->renc->output);
 76}
 77
 78static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
 79	.mode_set = rcar_du_hdmienc_mode_set,
 80	.disable = rcar_du_hdmienc_disable,
 81	.enable = rcar_du_hdmienc_enable,
 82	.atomic_check = rcar_du_hdmienc_atomic_check,
 83};
 84
 85static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder)
 86{
 87	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 88
 89	if (hdmienc->enabled)
 90		rcar_du_hdmienc_disable(encoder);
 91
 92	drm_encoder_cleanup(encoder);
 93}
 94
 95static const struct drm_encoder_funcs encoder_funcs = {
 96	.destroy = rcar_du_hdmienc_cleanup,
 97};
 98
 99int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
100			 struct rcar_du_encoder *renc, struct device_node *np)
101{
102	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
103	struct drm_bridge *bridge;
104	struct rcar_du_hdmienc *hdmienc;
105	int ret;
106
107	hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL);
108	if (hdmienc == NULL)
109		return -ENOMEM;
110
111	/* Locate the DRM bridge from the HDMI encoder DT node. */
112	bridge = of_drm_find_bridge(np);
113	if (!bridge)
114		return -EPROBE_DEFER;
115
116	ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
117			       DRM_MODE_ENCODER_TMDS, NULL);
118	if (ret < 0)
119		return ret;
120
121	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
122
123	renc->hdmi = hdmienc;
124	hdmienc->renc = renc;
125
126	/* Link the bridge to the encoder. */
127	bridge->encoder = encoder;
128	encoder->bridge = bridge;
129
130	ret = drm_bridge_attach(rcdu->ddev, bridge);
131	if (ret) {
132		drm_encoder_cleanup(encoder);
133		return ret;
134	}
135
136	return 0;
137}