#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
+#include <linux/clk.h>
#include <linux/component.h>
#include <linux/fence.h>
#include <linux/console.h>
drm_dev->dev_private = private;
+ private->hdmi_pll.pll = devm_clk_get(dev, "hdmi-tmds-pll");
+ if (PTR_ERR(private->hdmi_pll.pll) == -ENOENT) {
+ private->hdmi_pll.pll = NULL;
+ } else if (PTR_ERR(private->hdmi_pll.pll) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_free;
+ } else if (IS_ERR(private->hdmi_pll.pll)) {
+ dev_err(dev, "failed to get hdmi-tmds-pll\n");
+ ret = PTR_ERR(private->hdmi_pll.pll);
+ goto err_free;
+ }
+
+ private->default_pll.pll = devm_clk_get(dev, "default-vop-pll");
+ if (PTR_ERR(private->default_pll.pll) == -ENOENT) {
+ private->default_pll.pll = NULL;
+ } else if (PTR_ERR(private->default_pll.pll) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_free;
+ } else if (IS_ERR(private->default_pll.pll)) {
+ dev_err(dev, "failed to get default vop pll\n");
+ ret = PTR_ERR(private->default_pll.pll);
+ goto err_free;
+ }
+
#ifdef CONFIG_DRM_DMA_SYNC
private->cpu_fence_context = fence_context_alloc(1);
atomic_set(&private->cpu_fence_seqno, 0);
struct clk *dclk;
/* vop share memory frequency */
struct clk *aclk;
+ /* vop source handling, optional */
+ struct clk *dclk_source;
/* vop dclk reset */
struct reset_control *dclk_rst;
val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ?
0 : BIT(VSYNC_POSITIVE);
VOP_CTRL_SET(vop, pin_pol, val);
+
+ if (vop->dclk_source && s->pll && s->pll->pll) {
+ if (!clk_set_parent(vop->dclk_source, s->pll->pll))
+ DRM_DEV_ERROR(vop->dev,
+ "failed to set dclk's parents\n");
+ }
+
switch (s->output_type) {
case DRM_MODE_CONNECTOR_LVDS:
VOP_CTRL_SET(vop, rgb_en, 1);
return 0;
}
+static void vop_dclk_source_generate(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ struct rockchip_drm_private *private = crtc->dev->dev_private;
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+ struct rockchip_crtc_state *old_s = to_rockchip_crtc_state(crtc->state);
+ struct vop *vop = to_vop(crtc);
+
+ if (!vop->dclk_source)
+ return;
+
+ if (crtc_state->active) {
+ WARN_ON(s->pll && !s->pll->use_count);
+ if (!s->pll || s->pll->use_count > 1 ||
+ s->output_type != old_s->output_type) {
+ if (s->pll)
+ s->pll->use_count--;
+
+ if (s->output_type != DRM_MODE_CONNECTOR_HDMIA &&
+ !private->default_pll.use_count)
+ s->pll = &private->default_pll;
+ else
+ s->pll = &private->hdmi_pll;
+
+ s->pll->use_count++;
+ }
+ } else if (s->pll) {
+ s->pll->use_count--;
+ s->pll = NULL;
+ }
+ if (s->pll && s->pll != old_s->pll)
+ crtc_state->mode_changed = true;
+}
+
static int vop_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *crtc_state)
{
s->dsp_layer_sel = dsp_layer_sel;
+ vop_dclk_source_generate(crtc, crtc_state);
+
err_free_pzpos:
kfree(pzpos);
return ret;
return PTR_ERR(vop->dclk);
}
+ vop->dclk_source = devm_clk_get(vop->dev, "dclk_source");
+ if (PTR_ERR(vop->dclk_source) == -ENOENT) {
+ vop->dclk_source = NULL;
+ } else if (PTR_ERR(vop->dclk_source) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
+ } else if (IS_ERR(vop->dclk_source)) {
+ dev_err(vop->dev, "failed to get dclk source parent\n");
+ return PTR_ERR(vop->dclk_source);
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "cannot find irq for vop\n");