diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip')
-rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_gem.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 152 |
6 files changed, 158 insertions, 65 deletions
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index d236faa05b19..80d6fc8a5cee 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -133,12 +133,12 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { } }; -static const struct dw_hdmi_sym_term rockchip_sym_term[] = { - /*pixelclk symbol term*/ - { 74250000, 0x8009, 0x0004 }, - { 148500000, 0x8029, 0x0004 }, - { 297000000, 0x8039, 0x0005 }, - { ~0UL, 0x0000, 0x0000 } +static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + /*pixelclk symbol term vlev*/ + { 74250000, 0x8009, 0x0004, 0x0272}, + { 148500000, 0x802b, 0x0004, 0x028d}, + { 297000000, 0x8039, 0x0005, 0x028d}, + { ~0UL, 0x0000, 0x0000, 0x0000} }; static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) @@ -230,7 +230,7 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = { .mode_valid = dw_hdmi_rockchip_mode_valid, .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, - .sym_term = rockchip_sym_term, + .phy_config = rockchip_phy_config, .dev_type = RK3288_HDMI, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 21a481b224eb..3962176ee713 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -129,6 +129,7 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags) struct rockchip_drm_private *private; struct dma_iommu_mapping *mapping; struct device *dev = drm_dev->dev; + struct drm_connector *connector; int ret; private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); @@ -171,6 +172,23 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags) if (ret) goto err_detach_device; + /* + * All components are now added, we can publish the connector sysfs + * entries to userspace. This will generate hotplug events and so + * userspace will expect to be able to access DRM at this point. + */ + list_for_each_entry(connector, &drm_dev->mode_config.connector_list, + head) { + ret = drm_connector_register(connector); + if (ret) { + dev_err(drm_dev->dev, + "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n", + connector->base.id, + connector->name, ret); + goto err_unbind; + } + } + /* init kms poll for handling hpd */ drm_kms_helper_poll_init(drm_dev); @@ -200,6 +218,7 @@ err_vblank_cleanup: drm_vblank_cleanup(drm_dev); err_kms_helper_poll_fini: drm_kms_helper_poll_fini(drm_dev); +err_unbind: component_unbind_all(dev, drm_dev); err_detach_device: arm_iommu_detach_device(dev); @@ -366,7 +385,7 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = { int rockchip_drm_encoder_get_mux_id(struct device_node *node, struct drm_encoder *encoder) { - struct device_node *ep = NULL; + struct device_node *ep; struct drm_crtc *crtc = encoder->crtc; struct of_endpoint endpoint; struct device_node *port; @@ -375,18 +394,15 @@ int rockchip_drm_encoder_get_mux_id(struct device_node *node, if (!node || !crtc) return -EINVAL; - do { - ep = of_graph_get_next_endpoint(node, ep); - if (!ep) - break; - + for_each_endpoint_of_node(node, ep) { port = of_graph_get_remote_port(ep); of_node_put(port); if (port == crtc->port) { ret = of_graph_parse_endpoint(ep, &endpoint); + of_node_put(ep); return ret ?: endpoint.id; } - } while (ep); + } return -EINVAL; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index a5d889a8716b..5b0dc0f6fd94 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c @@ -71,7 +71,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, size = mode_cmd.pitches[0] * mode_cmd.height; - rk_obj = rockchip_gem_create_object(dev, size); + rk_obj = rockchip_gem_create_object(dev, size, true); if (IS_ERR(rk_obj)) return -ENOMEM; @@ -106,7 +106,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, fb = helper->fb; drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); - drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); + drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); offset = fbi->var.xoffset * bytes_per_pixel; offset += fbi->var.yoffset * fb->pitches[0]; @@ -119,6 +119,9 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, DRM_DEBUG_KMS("FB [%dx%d]-%d kvaddr=%p offset=%ld size=%d\n", fb->width, fb->height, fb->depth, rk_obj->kvaddr, offset, size); + + fbi->skip_vt_switch = true; + return 0; err_drm_framebuffer_unref: diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 7ca8799ef784..eb2282cc4a56 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -22,7 +22,8 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" -static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj) +static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj, + bool alloc_kmap) { struct drm_gem_object *obj = &rk_obj->base; struct drm_device *drm = obj->dev; @@ -30,7 +31,9 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj) init_dma_attrs(&rk_obj->dma_attrs); dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs); - /* TODO(djkurtz): Use DMA_ATTR_NO_KERNEL_MAPPING except for fbdev */ + if (!alloc_kmap) + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs); + rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size, &rk_obj->dma_addr, GFP_KERNEL, &rk_obj->dma_attrs); @@ -103,7 +106,8 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma) } struct rockchip_gem_object * - rockchip_gem_create_object(struct drm_device *drm, unsigned int size) + rockchip_gem_create_object(struct drm_device *drm, unsigned int size, + bool alloc_kmap) { struct rockchip_gem_object *rk_obj; struct drm_gem_object *obj; @@ -119,7 +123,7 @@ struct rockchip_gem_object * drm_gem_private_object_init(drm, obj, size); - ret = rockchip_gem_alloc_buf(rk_obj); + ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap); if (ret) goto err_free_rk_obj; @@ -163,7 +167,7 @@ rockchip_gem_create_with_handle(struct drm_file *file_priv, struct drm_gem_object *obj; int ret; - rk_obj = rockchip_gem_create_object(drm, size); + rk_obj = rockchip_gem_create_object(drm, size, false); if (IS_ERR(rk_obj)) return ERR_CAST(rk_obj); @@ -282,6 +286,9 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj) { struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); + if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs)) + return NULL; + return rk_obj->kvaddr; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h index 67bcebe90003..ad22618473a4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h @@ -41,7 +41,8 @@ int rockchip_gem_mmap_buf(struct drm_gem_object *obj, struct vm_area_struct *vma); struct rockchip_gem_object * - rockchip_gem_create_object(struct drm_device *drm, unsigned int size); + rockchip_gem_create_object(struct drm_device *drm, unsigned int size, + bool alloc_kmap); void rockchip_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 9a5c571b95fc..4557f335a8a5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -81,7 +81,7 @@ struct vop { struct drm_crtc crtc; struct device *dev; struct drm_device *drm_dev; - unsigned int dpms; + bool is_enabled; int connector_type; int connector_out_mode; @@ -89,6 +89,7 @@ struct vop { /* mutex vsync_ work */ struct mutex vsync_mutex; bool vsync_work_pending; + struct completion dsp_hold_completion; const struct vop_data *data; @@ -382,11 +383,50 @@ static bool is_alpha_support(uint32_t format) } } +static void vop_dsp_hold_valid_irq_enable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(&vop->irq_lock, flags); + + vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK, + DSP_HOLD_VALID_INTR_EN(1)); + + spin_unlock_irqrestore(&vop->irq_lock, flags); +} + +static void vop_dsp_hold_valid_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(&vop->irq_lock, flags); + + vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK, + DSP_HOLD_VALID_INTR_EN(0)); + + spin_unlock_irqrestore(&vop->irq_lock, flags); +} + static void vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); int ret; + if (vop->is_enabled) + return; + + ret = pm_runtime_get_sync(vop->dev); + if (ret < 0) { + dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); + return; + } + ret = clk_enable(vop->hclk); if (ret < 0) { dev_err(vop->dev, "failed to enable hclk - %d\n", ret); @@ -417,6 +457,11 @@ static void vop_enable(struct drm_crtc *crtc) goto err_disable_aclk; } + /* + * At here, vop clock & iommu is enable, R/W vop regs would be safe. + */ + vop->is_enabled = true; + spin_lock(&vop->reg_lock); VOP_CTRL_SET(vop, standby, 0); @@ -441,28 +486,44 @@ static void vop_disable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); - drm_vblank_off(crtc->dev, vop->pipe); + if (!vop->is_enabled) + return; - disable_irq(vop->irq); + drm_vblank_off(crtc->dev, vop->pipe); /* - * TODO: Since standby doesn't take effect until the next vblank, - * when we turn off dclk below, the vop is probably still active. + * Vop standby will take effect at end of current frame, + * if dsp hold valid irq happen, it means standby complete. + * + * we must wait standby complete when we want to disable aclk, + * if not, memory bus maybe dead. */ + reinit_completion(&vop->dsp_hold_completion); + vop_dsp_hold_valid_irq_enable(vop); + spin_lock(&vop->reg_lock); VOP_CTRL_SET(vop, standby, 1); spin_unlock(&vop->reg_lock); + + wait_for_completion(&vop->dsp_hold_completion); + + vop_dsp_hold_valid_irq_disable(vop); + + disable_irq(vop->irq); + + vop->is_enabled = false; + /* - * disable dclk to stop frame scan, so we can safely detach iommu, + * vop standby complete, so iommu detach is safe. */ - clk_disable(vop->dclk); - rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); + clk_disable(vop->dclk); clk_disable(vop->aclk); clk_disable(vop->hclk); + pm_runtime_put(vop->dev); } /* @@ -742,7 +803,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc) struct vop *vop = to_vop(crtc); unsigned long flags; - if (vop->dpms != DRM_MODE_DPMS_ON) + if (!vop->is_enabled) return -EPERM; spin_lock_irqsave(&vop->irq_lock, flags); @@ -759,8 +820,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) struct vop *vop = to_vop(crtc); unsigned long flags; - if (vop->dpms != DRM_MODE_DPMS_ON) + if (!vop->is_enabled) return; + spin_lock_irqsave(&vop->irq_lock, flags); vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0)); spin_unlock_irqrestore(&vop->irq_lock, flags); @@ -773,15 +835,8 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = { static void vop_crtc_dpms(struct drm_crtc *crtc, int mode) { - struct vop *vop = to_vop(crtc); - DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); - if (vop->dpms == mode) { - DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); - return; - } - switch (mode) { case DRM_MODE_DPMS_ON: vop_enable(crtc); @@ -795,8 +850,6 @@ static void vop_crtc_dpms(struct drm_crtc *crtc, int mode) DRM_DEBUG_KMS("unspecified mode %d\n", mode); break; } - - vop->dpms = mode; } static void vop_crtc_prepare(struct drm_crtc *crtc) @@ -847,7 +900,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc, u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start; u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start; u16 vact_end = vact_st + vdisplay; - int ret; + int ret, ret_clk; uint32_t val; /* @@ -869,13 +922,14 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc, default: DRM_ERROR("unsupport connector_type[%d]\n", vop->connector_type); - return -EINVAL; + ret = -EINVAL; + goto out; }; VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode); val = 0x8; - val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0; - val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? (1 << 1) : 0; + val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1; + val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1); VOP_CTRL_SET(vop, pin_pol, val); VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len); @@ -892,7 +946,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc, ret = vop_crtc_mode_set_base(crtc, x, y, fb); if (ret) - return ret; + goto out; /* * reset dclk, take all mode config affect, so the clk would run in @@ -903,13 +957,14 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc, reset_control_deassert(vop->dclk_rst); clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); - ret = clk_enable(vop->dclk); - if (ret < 0) { - dev_err(vop->dev, "failed to enable dclk - %d\n", ret); - return ret; +out: + ret_clk = clk_enable(vop->dclk); + if (ret_clk < 0) { + dev_err(vop->dev, "failed to enable dclk - %d\n", ret_clk); + return ret_clk; } - return 0; + return ret; } static void vop_crtc_commit(struct drm_crtc *crtc) @@ -934,9 +989,9 @@ static int vop_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *old_fb = crtc->primary->fb; int ret; - /* when the page flip is requested, crtc's dpms should be on */ - if (vop->dpms > DRM_MODE_DPMS_ON) { - DRM_DEBUG("failed page flip request at dpms[%d].\n", vop->dpms); + /* when the page flip is requested, crtc should be on */ + if (!vop->is_enabled) { + DRM_DEBUG("page flip request rejected because crtc is off.\n"); return 0; } @@ -1081,6 +1136,7 @@ static irqreturn_t vop_isr(int irq, void *data) struct vop *vop = data; uint32_t intr0_reg, active_irqs; unsigned long flags; + int ret = IRQ_NONE; /* * INTR_CTRL0 register has interrupt status, enable and clear bits, we @@ -1099,15 +1155,23 @@ static irqreturn_t vop_isr(int irq, void *data) if (!active_irqs) return IRQ_NONE; - /* Only Frame Start Interrupt is enabled; other irqs are spurious. */ - if (!(active_irqs & FS_INTR)) { - DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs); - return IRQ_NONE; + if (active_irqs & DSP_HOLD_VALID_INTR) { + complete(&vop->dsp_hold_completion); + active_irqs &= ~DSP_HOLD_VALID_INTR; + ret = IRQ_HANDLED; + } + + if (active_irqs & FS_INTR) { + drm_handle_vblank(vop->drm_dev, vop->pipe); + active_irqs &= ~FS_INTR; + ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED; } - drm_handle_vblank(vop->drm_dev, vop->pipe); + /* Unhandled irqs are spurious. */ + if (active_irqs) + DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs); - return (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED; + return ret; } static int vop_create_crtc(struct vop *vop) @@ -1189,6 +1253,7 @@ static int vop_create_crtc(struct vop *vop) goto err_cleanup_crtc; } + init_completion(&vop->dsp_hold_completion); crtc->port = port; vop->pipe = drm_crtc_index(crtc); rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe); @@ -1302,7 +1367,7 @@ static int vop_initial(struct vop *vop) clk_disable(vop->hclk); - vop->dpms = DRM_MODE_DPMS_OFF; + vop->is_enabled = false; return 0; @@ -1344,7 +1409,7 @@ static int vop_bind(struct device *dev, struct device *master, void *data) struct vop *vop; struct resource *res; size_t alloc_size; - int ret; + int ret, irq; of_id = of_match_device(vop_driver_dt_match, dev); vop_data = of_id->data; @@ -1380,11 +1445,12 @@ static int vop_bind(struct device *dev, struct device *master, void *data) return ret; } - vop->irq = platform_get_irq(pdev, 0); - if (vop->irq < 0) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) { dev_err(dev, "cannot find irq for vop\n"); - return vop->irq; + return irq; } + vop->irq = (unsigned int)irq; spin_lock_init(&vop->reg_lock); spin_lock_init(&vop->irq_lock); |