|
@@ -235,6 +235,47 @@ static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
|
|
|
drm_panel_unprepare(output->panel);
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+tegra_rgb_encoder_atomic_check(struct drm_encoder *encoder,
|
|
|
+ struct drm_crtc_state *crtc_state,
|
|
|
+ struct drm_connector_state *conn_state)
|
|
|
+{
|
|
|
+ struct tegra_output *output = encoder_to_output(encoder);
|
|
|
+ struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
|
|
|
+ unsigned long pclk = crtc_state->mode.clock * 1000;
|
|
|
+ struct tegra_rgb *rgb = to_rgb(output);
|
|
|
+ unsigned int div;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We may not want to change the frequency of the parent clock, since
|
|
|
+ * it may be a parent for other peripherals. This is due to the fact
|
|
|
+ * that on Tegra20 there's only a single clock dedicated to display
|
|
|
+ * (pll_d_out0), whereas later generations have a second one that can
|
|
|
+ * be used to independently drive a second output (pll_d2_out0).
|
|
|
+ *
|
|
|
+ * As a way to support multiple outputs on Tegra20 as well, pll_p is
|
|
|
+ * typically used as the parent clock for the display controllers.
|
|
|
+ * But this comes at a cost: pll_p is the parent of several other
|
|
|
+ * peripherals, so its frequency shouldn't change out of the blue.
|
|
|
+ *
|
|
|
+ * The best we can do at this point is to use the shift clock divider
|
|
|
+ * and hope that the desired frequency can be matched (or at least
|
|
|
+ * matched sufficiently close that the panel will still work).
|
|
|
+ */
|
|
|
+ div = ((clk_get_rate(rgb->clk) * 2) / pclk) - 2;
|
|
|
+ pclk = 0;
|
|
|
+
|
|
|
+ err = tegra_dc_state_setup_clock(dc, crtc_state, rgb->clk_parent,
|
|
|
+ pclk, div);
|
|
|
+ if (err < 0) {
|
|
|
+ dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
|
|
|
.dpms = tegra_rgb_encoder_dpms,
|
|
|
.mode_fixup = tegra_rgb_encoder_mode_fixup,
|
|
@@ -242,6 +283,7 @@ static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
|
|
|
.commit = tegra_rgb_encoder_commit,
|
|
|
.mode_set = tegra_rgb_encoder_mode_set,
|
|
|
.disable = tegra_rgb_encoder_disable,
|
|
|
+ .atomic_check = tegra_rgb_encoder_atomic_check,
|
|
|
};
|
|
|
|
|
|
int tegra_dc_rgb_probe(struct tegra_dc *dc)
|