2 * R-Car Display Unit HDMI Encoder
4 * Copyright (C) 2014 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
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.
14 #include <linux/slab.h>
17 #include <drm/drm_crtc.h>
18 #include <drm/drm_crtc_helper.h>
19 #include <drm/drm_encoder_slave.h>
21 #include "rcar_du_drv.h"
22 #include "rcar_du_encoder.h"
23 #include "rcar_du_hdmienc.h"
24 #include "rcar_du_lvdsenc.h"
26 struct rcar_du_hdmienc
{
27 struct rcar_du_encoder
*renc
;
32 #define to_rcar_hdmienc(e) (to_rcar_encoder(e)->hdmi)
33 #define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs)
35 static void rcar_du_hdmienc_disable(struct drm_encoder
*encoder
)
37 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
38 struct drm_encoder_slave_funcs
*sfuncs
= to_slave_funcs(encoder
);
41 sfuncs
->dpms(encoder
, DRM_MODE_DPMS_OFF
);
43 if (hdmienc
->renc
->lvds
)
44 rcar_du_lvdsenc_enable(hdmienc
->renc
->lvds
, encoder
->crtc
,
47 hdmienc
->enabled
= false;
50 static void rcar_du_hdmienc_enable(struct drm_encoder
*encoder
)
52 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
53 struct drm_encoder_slave_funcs
*sfuncs
= to_slave_funcs(encoder
);
55 if (hdmienc
->renc
->lvds
)
56 rcar_du_lvdsenc_enable(hdmienc
->renc
->lvds
, encoder
->crtc
,
60 sfuncs
->dpms(encoder
, DRM_MODE_DPMS_ON
);
62 hdmienc
->enabled
= true;
65 static int rcar_du_hdmienc_atomic_check(struct drm_encoder
*encoder
,
66 struct drm_crtc_state
*crtc_state
,
67 struct drm_connector_state
*conn_state
)
69 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
70 struct drm_encoder_slave_funcs
*sfuncs
= to_slave_funcs(encoder
);
71 struct drm_display_mode
*adjusted_mode
= &crtc_state
->adjusted_mode
;
72 const struct drm_display_mode
*mode
= &crtc_state
->mode
;
74 /* The internal LVDS encoder has a clock frequency operating range of
75 * 30MHz to 150MHz. Clamp the clock accordingly.
77 if (hdmienc
->renc
->lvds
)
78 adjusted_mode
->clock
= clamp(adjusted_mode
->clock
,
81 if (sfuncs
->mode_fixup
== NULL
)
84 return sfuncs
->mode_fixup(encoder
, mode
, adjusted_mode
) ? 0 : -EINVAL
;
87 static void rcar_du_hdmienc_mode_set(struct drm_encoder
*encoder
,
88 struct drm_display_mode
*mode
,
89 struct drm_display_mode
*adjusted_mode
)
91 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
92 struct drm_encoder_slave_funcs
*sfuncs
= to_slave_funcs(encoder
);
95 sfuncs
->mode_set(encoder
, mode
, adjusted_mode
);
97 rcar_du_crtc_route_output(encoder
->crtc
, hdmienc
->renc
->output
);
100 static const struct drm_encoder_helper_funcs encoder_helper_funcs
= {
101 .mode_set
= rcar_du_hdmienc_mode_set
,
102 .disable
= rcar_du_hdmienc_disable
,
103 .enable
= rcar_du_hdmienc_enable
,
104 .atomic_check
= rcar_du_hdmienc_atomic_check
,
107 static void rcar_du_hdmienc_cleanup(struct drm_encoder
*encoder
)
109 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
111 if (hdmienc
->enabled
)
112 rcar_du_hdmienc_disable(encoder
);
114 drm_encoder_cleanup(encoder
);
115 put_device(hdmienc
->dev
);
118 static const struct drm_encoder_funcs encoder_funcs
= {
119 .destroy
= rcar_du_hdmienc_cleanup
,
122 int rcar_du_hdmienc_init(struct rcar_du_device
*rcdu
,
123 struct rcar_du_encoder
*renc
, struct device_node
*np
)
125 struct drm_encoder
*encoder
= rcar_encoder_to_drm_encoder(renc
);
126 struct drm_i2c_encoder_driver
*driver
;
127 struct i2c_client
*i2c_slave
;
128 struct rcar_du_hdmienc
*hdmienc
;
131 hdmienc
= devm_kzalloc(rcdu
->dev
, sizeof(*hdmienc
), GFP_KERNEL
);
135 /* Locate the slave I2C device and driver. */
136 i2c_slave
= of_find_i2c_device_by_node(np
);
137 if (!i2c_slave
|| !i2c_get_clientdata(i2c_slave
))
138 return -EPROBE_DEFER
;
140 hdmienc
->dev
= &i2c_slave
->dev
;
142 if (hdmienc
->dev
->driver
== NULL
) {
147 /* Initialize the slave encoder. */
148 driver
= to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc
->dev
->driver
));
149 ret
= driver
->encoder_init(i2c_slave
, rcdu
->ddev
, &renc
->slave
);
153 ret
= drm_encoder_init(rcdu
->ddev
, encoder
, &encoder_funcs
,
154 DRM_MODE_ENCODER_TMDS
);
158 drm_encoder_helper_add(encoder
, &encoder_helper_funcs
);
160 renc
->hdmi
= hdmienc
;
161 hdmienc
->renc
= renc
;
166 put_device(hdmienc
->dev
);