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_dpms(struct drm_encoder
*encoder
, int mode
)
37 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
38 struct drm_encoder_slave_funcs
*sfuncs
= to_slave_funcs(encoder
);
40 if (mode
!= DRM_MODE_DPMS_ON
)
41 mode
= DRM_MODE_DPMS_OFF
;
43 if (hdmienc
->dpms
== mode
)
46 if (mode
== DRM_MODE_DPMS_ON
&& hdmienc
->renc
->lvds
)
47 rcar_du_lvdsenc_dpms(hdmienc
->renc
->lvds
, encoder
->crtc
, mode
);
50 sfuncs
->dpms(encoder
, mode
);
52 if (mode
!= DRM_MODE_DPMS_ON
&& hdmienc
->renc
->lvds
)
53 rcar_du_lvdsenc_dpms(hdmienc
->renc
->lvds
, encoder
->crtc
, mode
);
58 static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder
*encoder
,
59 const struct drm_display_mode
*mode
,
60 struct drm_display_mode
*adjusted_mode
)
62 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
63 struct drm_encoder_slave_funcs
*sfuncs
= to_slave_funcs(encoder
);
65 /* The internal LVDS encoder has a clock frequency operating range of
66 * 30MHz to 150MHz. Clamp the clock accordingly.
68 if (hdmienc
->renc
->lvds
)
69 adjusted_mode
->clock
= clamp(adjusted_mode
->clock
,
72 if (sfuncs
->mode_fixup
== NULL
)
75 return sfuncs
->mode_fixup(encoder
, mode
, adjusted_mode
);
78 static void rcar_du_hdmienc_mode_prepare(struct drm_encoder
*encoder
)
80 rcar_du_hdmienc_dpms(encoder
, DRM_MODE_DPMS_OFF
);
83 static void rcar_du_hdmienc_mode_commit(struct drm_encoder
*encoder
)
85 rcar_du_hdmienc_dpms(encoder
, DRM_MODE_DPMS_ON
);
88 static void rcar_du_hdmienc_mode_set(struct drm_encoder
*encoder
,
89 struct drm_display_mode
*mode
,
90 struct drm_display_mode
*adjusted_mode
)
92 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
93 struct drm_encoder_slave_funcs
*sfuncs
= to_slave_funcs(encoder
);
96 sfuncs
->mode_set(encoder
, mode
, adjusted_mode
);
98 rcar_du_crtc_route_output(encoder
->crtc
, hdmienc
->renc
->output
);
101 static const struct drm_encoder_helper_funcs encoder_helper_funcs
= {
102 .dpms
= rcar_du_hdmienc_dpms
,
103 .mode_fixup
= rcar_du_hdmienc_mode_fixup
,
104 .prepare
= rcar_du_hdmienc_mode_prepare
,
105 .commit
= rcar_du_hdmienc_mode_commit
,
106 .mode_set
= rcar_du_hdmienc_mode_set
,
109 static void rcar_du_hdmienc_cleanup(struct drm_encoder
*encoder
)
111 struct rcar_du_hdmienc
*hdmienc
= to_rcar_hdmienc(encoder
);
113 rcar_du_hdmienc_dpms(encoder
, DRM_MODE_DPMS_OFF
);
115 drm_encoder_cleanup(encoder
);
116 put_device(hdmienc
->dev
);
119 static const struct drm_encoder_funcs encoder_funcs
= {
120 .destroy
= rcar_du_hdmienc_cleanup
,
123 int rcar_du_hdmienc_init(struct rcar_du_device
*rcdu
,
124 struct rcar_du_encoder
*renc
, struct device_node
*np
)
126 struct drm_encoder
*encoder
= rcar_encoder_to_drm_encoder(renc
);
127 struct drm_i2c_encoder_driver
*driver
;
128 struct i2c_client
*i2c_slave
;
129 struct rcar_du_hdmienc
*hdmienc
;
132 hdmienc
= devm_kzalloc(rcdu
->dev
, sizeof(*hdmienc
), GFP_KERNEL
);
136 /* Locate the slave I2C device and driver. */
137 i2c_slave
= of_find_i2c_device_by_node(np
);
138 if (!i2c_slave
|| !i2c_get_clientdata(i2c_slave
))
139 return -EPROBE_DEFER
;
141 hdmienc
->dev
= &i2c_slave
->dev
;
143 if (hdmienc
->dev
->driver
== NULL
) {
148 /* Initialize the slave encoder. */
149 driver
= to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc
->dev
->driver
));
150 ret
= driver
->encoder_init(i2c_slave
, rcdu
->ddev
, &renc
->slave
);
154 ret
= drm_encoder_init(rcdu
->ddev
, encoder
, &encoder_funcs
,
155 DRM_MODE_ENCODER_TMDS
);
159 drm_encoder_helper_add(encoder
, &encoder_helper_funcs
);
161 renc
->hdmi
= hdmienc
;
162 hdmienc
->renc
= renc
;
167 put_device(hdmienc
->dev
);