aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-12-17 11:04:36 -0500
committerThierry Reding <treding@nvidia.com>2015-01-27 04:14:53 -0500
commit3cebae6737b100323baca21de6bce6647249e778 (patch)
tree3943710d02b6366dcd66535dcbee33becd534168
parentca915b108a39081edff1206ec00ecdb4136408ac (diff)
drm/tegra: rgb: Implement ->atomic_check()
The implementation of the ->atomic_check() callback precomputes all parameters to check if the given configuration can be applied. If so the precomputed values are stored in the atomic state object for the encoder and applied during modeset. In that way the modeset no longer needs to perform any checking but simply program values into registers. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/rgb.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index 78e3cb1529d0..be1b38936dbe 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -235,6 +235,47 @@ static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
235 drm_panel_unprepare(output->panel); 235 drm_panel_unprepare(output->panel);
236} 236}
237 237
238static int
239tegra_rgb_encoder_atomic_check(struct drm_encoder *encoder,
240 struct drm_crtc_state *crtc_state,
241 struct drm_connector_state *conn_state)
242{
243 struct tegra_output *output = encoder_to_output(encoder);
244 struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
245 unsigned long pclk = crtc_state->mode.clock * 1000;
246 struct tegra_rgb *rgb = to_rgb(output);
247 unsigned int div;
248 int err;
249
250 /*
251 * We may not want to change the frequency of the parent clock, since
252 * it may be a parent for other peripherals. This is due to the fact
253 * that on Tegra20 there's only a single clock dedicated to display
254 * (pll_d_out0), whereas later generations have a second one that can
255 * be used to independently drive a second output (pll_d2_out0).
256 *
257 * As a way to support multiple outputs on Tegra20 as well, pll_p is
258 * typically used as the parent clock for the display controllers.
259 * But this comes at a cost: pll_p is the parent of several other
260 * peripherals, so its frequency shouldn't change out of the blue.
261 *
262 * The best we can do at this point is to use the shift clock divider
263 * and hope that the desired frequency can be matched (or at least
264 * matched sufficiently close that the panel will still work).
265 */
266 div = ((clk_get_rate(rgb->clk) * 2) / pclk) - 2;
267 pclk = 0;
268
269 err = tegra_dc_state_setup_clock(dc, crtc_state, rgb->clk_parent,
270 pclk, div);
271 if (err < 0) {
272 dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
273 return err;
274 }
275
276 return err;
277}
278
238static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = { 279static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
239 .dpms = tegra_rgb_encoder_dpms, 280 .dpms = tegra_rgb_encoder_dpms,
240 .mode_fixup = tegra_rgb_encoder_mode_fixup, 281 .mode_fixup = tegra_rgb_encoder_mode_fixup,
@@ -242,6 +283,7 @@ static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
242 .commit = tegra_rgb_encoder_commit, 283 .commit = tegra_rgb_encoder_commit,
243 .mode_set = tegra_rgb_encoder_mode_set, 284 .mode_set = tegra_rgb_encoder_mode_set,
244 .disable = tegra_rgb_encoder_disable, 285 .disable = tegra_rgb_encoder_disable,
286 .atomic_check = tegra_rgb_encoder_atomic_check,
245}; 287};
246 288
247int tegra_dc_rgb_probe(struct tegra_dc *dc) 289int tegra_dc_rgb_probe(struct tegra_dc *dc)