提交 cfcfb65a 编写于 作者: D Dave Airlie

Merge tag 'drm-msm-next-2017-08-22' of git://people.freedesktop.org/~robclark/linux into drm-next

Updates for 4.14..  I have some further patches from Jordan to add
multiple priority levels and pre-emption, but those will probably be
for 4.15 to give me time for the mesa parts.

* tag 'drm-msm-next-2017-08-22' of git://people.freedesktop.org/~robclark/linux:
  drm/msm/mdp5: mark runtime_pm functions as __maybe_unused
  drm/msm: remove unused variable
  drm/msm/mdp5: make helper function static
  drm/msm: make msm_framebuffer_init() static
  drm/msm: add helper to allocate stolen fb
  drm/msm: don't track fbdev's gem object separately
  drm/msm: add modeset module param
  drm/msm/mdp5: add tracking for clk enable-count
  drm/msm: remove unused define
  drm/msm: Add a helper function for in-kernel buffer allocations
  drm/msm: Attach the GPU MMU when it is created
  drm/msm: Add A5XX hardware fault detection
  drm/msm: Remove uneeded platform dev members
  drm/msm/mdp5: Set up runtime PM for MDSS
  drm/msm/mdp5: Write to SMP registers even if allocations don't change
  drm/msm/mdp5: Don't use mode_set helper funcs for encoders and CRTCs
  drm/msm/dsi: Implement RPM suspend/resume callbacks
  drm/msm/dsi: Set up runtime PM for DSI
  drm/msm/hdmi: Set up runtime PM for HDMI
  drm/msm/mdp5: Use runtime PM get/put API instead of toggling clocks
...@@ -486,8 +486,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) ...@@ -486,8 +486,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
adreno_gpu = &a3xx_gpu->base; adreno_gpu = &a3xx_gpu->base;
gpu = &adreno_gpu->base; gpu = &adreno_gpu->base;
a3xx_gpu->pdev = pdev;
gpu->perfcntrs = perfcntrs; gpu->perfcntrs = perfcntrs;
gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs); gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
struct a3xx_gpu { struct a3xx_gpu {
struct adreno_gpu base; struct adreno_gpu base;
struct platform_device *pdev;
/* if OCMEM is used for GMEM: */ /* if OCMEM is used for GMEM: */
uint32_t ocmem_base; uint32_t ocmem_base;
......
...@@ -568,8 +568,6 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) ...@@ -568,8 +568,6 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
adreno_gpu = &a4xx_gpu->base; adreno_gpu = &a4xx_gpu->base;
gpu = &adreno_gpu->base; gpu = &adreno_gpu->base;
a4xx_gpu->pdev = pdev;
gpu->perfcntrs = NULL; gpu->perfcntrs = NULL;
gpu->num_perfcntrs = 0; gpu->num_perfcntrs = 0;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
struct a4xx_gpu { struct a4xx_gpu {
struct adreno_gpu base; struct adreno_gpu base;
struct platform_device *pdev;
/* if OCMEM is used for GMEM: */ /* if OCMEM is used for GMEM: */
uint32_t ocmem_base; uint32_t ocmem_base;
......
...@@ -284,28 +284,14 @@ static int a5xx_me_init(struct msm_gpu *gpu) ...@@ -284,28 +284,14 @@ static int a5xx_me_init(struct msm_gpu *gpu)
static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu, static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu,
const struct firmware *fw, u64 *iova) const struct firmware *fw, u64 *iova)
{ {
struct drm_device *drm = gpu->dev;
struct drm_gem_object *bo; struct drm_gem_object *bo;
void *ptr; void *ptr;
bo = msm_gem_new_locked(drm, fw->size - 4, MSM_BO_UNCACHED); ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4,
if (IS_ERR(bo)) MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova);
return bo;
ptr = msm_gem_get_vaddr(bo); if (IS_ERR(ptr))
if (!ptr) { return ERR_CAST(ptr);
drm_gem_object_unreference(bo);
return ERR_PTR(-ENOMEM);
}
if (iova) {
int ret = msm_gem_get_iova(bo, gpu->aspace, iova);
if (ret) {
drm_gem_object_unreference(bo);
return ERR_PTR(ret);
}
}
memcpy(ptr, &fw->data[4], fw->size - 4); memcpy(ptr, &fw->data[4], fw->size - 4);
...@@ -372,8 +358,7 @@ static int a5xx_zap_shader_init(struct msm_gpu *gpu) ...@@ -372,8 +358,7 @@ static int a5xx_zap_shader_init(struct msm_gpu *gpu)
{ {
static bool loaded; static bool loaded;
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); struct platform_device *pdev = gpu->pdev;
struct platform_device *pdev = a5xx_gpu->pdev;
int ret; int ret;
/* /*
...@@ -410,6 +395,7 @@ static int a5xx_zap_shader_init(struct msm_gpu *gpu) ...@@ -410,6 +395,7 @@ static int a5xx_zap_shader_init(struct msm_gpu *gpu)
A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \ A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \
A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW | \ A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW | \
A5XX_RBBM_INT_0_MASK_CP_HW_ERROR | \ A5XX_RBBM_INT_0_MASK_CP_HW_ERROR | \
A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT | \
A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | \ A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | \
A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \ A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \
A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP) A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP)
...@@ -812,6 +798,27 @@ static void a5xx_gpmu_err_irq(struct msm_gpu *gpu) ...@@ -812,6 +798,27 @@ static void a5xx_gpmu_err_irq(struct msm_gpu *gpu)
dev_err_ratelimited(gpu->dev->dev, "GPMU | voltage droop\n"); dev_err_ratelimited(gpu->dev->dev, "GPMU | voltage droop\n");
} }
static void a5xx_fault_detect_irq(struct msm_gpu *gpu)
{
struct drm_device *dev = gpu->dev;
struct msm_drm_private *priv = dev->dev_private;
dev_err(dev->dev, "gpu fault fence %x status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n",
gpu->funcs->last_fence(gpu),
gpu_read(gpu, REG_A5XX_RBBM_STATUS),
gpu_read(gpu, REG_A5XX_CP_RB_RPTR),
gpu_read(gpu, REG_A5XX_CP_RB_WPTR),
gpu_read64(gpu, REG_A5XX_CP_IB1_BASE, REG_A5XX_CP_IB1_BASE_HI),
gpu_read(gpu, REG_A5XX_CP_IB1_BUFSZ),
gpu_read64(gpu, REG_A5XX_CP_IB2_BASE, REG_A5XX_CP_IB2_BASE_HI),
gpu_read(gpu, REG_A5XX_CP_IB2_BUFSZ));
/* Turn off the hangcheck timer to keep it from bothering us */
del_timer(&gpu->hangcheck_timer);
queue_work(priv->wq, &gpu->recover_work);
}
#define RBBM_ERROR_MASK \ #define RBBM_ERROR_MASK \
(A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \
A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \
...@@ -838,6 +845,9 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu) ...@@ -838,6 +845,9 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu)
if (status & A5XX_RBBM_INT_0_MASK_CP_HW_ERROR) if (status & A5XX_RBBM_INT_0_MASK_CP_HW_ERROR)
a5xx_cp_err_irq(gpu); a5xx_cp_err_irq(gpu);
if (status & A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT)
a5xx_fault_detect_irq(gpu);
if (status & A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS) if (status & A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS)
a5xx_uche_err_irq(gpu); a5xx_uche_err_irq(gpu);
...@@ -1015,7 +1025,6 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) ...@@ -1015,7 +1025,6 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
adreno_gpu = &a5xx_gpu->base; adreno_gpu = &a5xx_gpu->base;
gpu = &adreno_gpu->base; gpu = &adreno_gpu->base;
a5xx_gpu->pdev = pdev;
adreno_gpu->registers = a5xx_registers; adreno_gpu->registers = a5xx_registers;
adreno_gpu->reg_offsets = a5xx_register_offsets; adreno_gpu->reg_offsets = a5xx_register_offsets;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
struct a5xx_gpu { struct a5xx_gpu {
struct adreno_gpu base; struct adreno_gpu base;
struct platform_device *pdev;
struct drm_gem_object *pm4_bo; struct drm_gem_object *pm4_bo;
uint64_t pm4_iova; uint64_t pm4_iova;
......
...@@ -294,16 +294,10 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) ...@@ -294,16 +294,10 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
*/ */
bosize = (cmds_size + (cmds_size / TYPE4_MAX_PAYLOAD) + 1) << 2; bosize = (cmds_size + (cmds_size / TYPE4_MAX_PAYLOAD) + 1) << 2;
a5xx_gpu->gpmu_bo = msm_gem_new_locked(drm, bosize, MSM_BO_UNCACHED); ptr = msm_gem_kernel_new_locked(drm, bosize,
if (IS_ERR(a5xx_gpu->gpmu_bo)) MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace,
goto err; &a5xx_gpu->gpmu_bo, &a5xx_gpu->gpmu_iova);
if (IS_ERR(ptr))
if (msm_gem_get_iova(a5xx_gpu->gpmu_bo, gpu->aspace,
&a5xx_gpu->gpmu_iova))
goto err;
ptr = msm_gem_get_vaddr(a5xx_gpu->gpmu_bo);
if (!ptr)
goto err; goto err;
while (cmds_size > 0) { while (cmds_size > 0) {
......
...@@ -337,11 +337,6 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords) ...@@ -337,11 +337,6 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name); DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
} }
static const char *iommu_ports[] = {
"gfx3d_user", "gfx3d_priv",
"gfx3d1_user", "gfx3d1_priv",
};
int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct adreno_gpu *adreno_gpu, const struct adreno_gpu_funcs *funcs) struct adreno_gpu *adreno_gpu, const struct adreno_gpu_funcs *funcs)
{ {
...@@ -373,15 +368,15 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, ...@@ -373,15 +368,15 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
adreno_gpu_config.ringsz = RB_SIZE; adreno_gpu_config.ringsz = RB_SIZE;
pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base, ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
adreno_gpu->info->name, &adreno_gpu_config); adreno_gpu->info->name, &adreno_gpu_config);
if (ret) if (ret)
return ret; return ret;
pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev); ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev);
if (ret) { if (ret) {
dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n", dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
...@@ -396,37 +391,17 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, ...@@ -396,37 +391,17 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
return ret; return ret;
} }
if (gpu->aspace && gpu->aspace->mmu) { adreno_gpu->memptrs = msm_gem_kernel_new(drm,
struct msm_mmu *mmu = gpu->aspace->mmu; sizeof(*adreno_gpu->memptrs), MSM_BO_UNCACHED, gpu->aspace,
ret = mmu->funcs->attach(mmu, iommu_ports, &adreno_gpu->memptrs_bo, &adreno_gpu->memptrs_iova);
ARRAY_SIZE(iommu_ports));
if (ret)
return ret;
}
adreno_gpu->memptrs_bo = msm_gem_new(drm, sizeof(*adreno_gpu->memptrs),
MSM_BO_UNCACHED);
if (IS_ERR(adreno_gpu->memptrs_bo)) {
ret = PTR_ERR(adreno_gpu->memptrs_bo);
adreno_gpu->memptrs_bo = NULL;
dev_err(drm->dev, "could not allocate memptrs: %d\n", ret);
return ret;
}
adreno_gpu->memptrs = msm_gem_get_vaddr(adreno_gpu->memptrs_bo);
if (IS_ERR(adreno_gpu->memptrs)) { if (IS_ERR(adreno_gpu->memptrs)) {
dev_err(drm->dev, "could not vmap memptrs\n"); ret = PTR_ERR(adreno_gpu->memptrs);
return -ENOMEM; adreno_gpu->memptrs = NULL;
} dev_err(drm->dev, "could not allocate memptrs: %d\n", ret);
ret = msm_gem_get_iova(adreno_gpu->memptrs_bo, gpu->aspace,
&adreno_gpu->memptrs_iova);
if (ret) {
dev_err(drm->dev, "could not map memptrs: %d\n", ret);
return ret;
} }
return 0; return ret;
} }
void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu)
...@@ -446,10 +421,4 @@ void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) ...@@ -446,10 +421,4 @@ void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu)
release_firmware(adreno_gpu->pfp); release_firmware(adreno_gpu->pfp);
msm_gpu_cleanup(gpu); msm_gpu_cleanup(gpu);
if (gpu->aspace) {
gpu->aspace->mmu->funcs->detach(gpu->aspace->mmu,
iommu_ports, ARRAY_SIZE(iommu_ports));
msm_gem_address_space_put(gpu->aspace);
}
} }
...@@ -161,12 +161,17 @@ static const struct of_device_id dt_match[] = { ...@@ -161,12 +161,17 @@ static const struct of_device_id dt_match[] = {
{} {}
}; };
static const struct dev_pm_ops dsi_pm_ops = {
SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL)
};
static struct platform_driver dsi_driver = { static struct platform_driver dsi_driver = {
.probe = dsi_dev_probe, .probe = dsi_dev_probe,
.remove = dsi_dev_remove, .remove = dsi_dev_remove,
.driver = { .driver = {
.name = "msm_dsi", .name = "msm_dsi",
.of_match_table = dt_match, .of_match_table = dt_match,
.pm = &dsi_pm_ops,
}, },
}; };
......
...@@ -179,6 +179,8 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host); ...@@ -179,6 +179,8 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host);
int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
struct drm_device *dev); struct drm_device *dev);
int msm_dsi_host_init(struct msm_dsi *msm_dsi); int msm_dsi_host_init(struct msm_dsi *msm_dsi);
int msm_dsi_runtime_suspend(struct device *dev);
int msm_dsi_runtime_resume(struct device *dev);
/* dsi phy */ /* dsi phy */
struct msm_dsi_phy; struct msm_dsi_phy;
......
...@@ -135,7 +135,6 @@ struct msm_dsi_host { ...@@ -135,7 +135,6 @@ struct msm_dsi_host {
struct completion video_comp; struct completion video_comp;
struct mutex dev_mutex; struct mutex dev_mutex;
struct mutex cmd_mutex; struct mutex cmd_mutex;
struct mutex clk_mutex;
spinlock_t intr_lock; /* Protect interrupt ctrl register */ spinlock_t intr_lock; /* Protect interrupt ctrl register */
u32 err_work_state; u32 err_work_state;
...@@ -221,6 +220,8 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( ...@@ -221,6 +220,8 @@ static const struct msm_dsi_cfg_handler *dsi_get_config(
goto put_gdsc; goto put_gdsc;
} }
pm_runtime_get_sync(dev);
ret = regulator_enable(gdsc_reg); ret = regulator_enable(gdsc_reg);
if (ret) { if (ret) {
pr_err("%s: unable to enable gdsc\n", __func__); pr_err("%s: unable to enable gdsc\n", __func__);
...@@ -247,6 +248,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( ...@@ -247,6 +248,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config(
clk_disable_unprepare(ahb_clk); clk_disable_unprepare(ahb_clk);
disable_gdsc: disable_gdsc:
regulator_disable(gdsc_reg); regulator_disable(gdsc_reg);
pm_runtime_put_autosuspend(dev);
put_clk: put_clk:
clk_put(ahb_clk); clk_put(ahb_clk);
put_gdsc: put_gdsc:
...@@ -455,6 +457,34 @@ static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host) ...@@ -455,6 +457,34 @@ static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host)
clk_disable_unprepare(msm_host->bus_clks[i]); clk_disable_unprepare(msm_host->bus_clks[i]);
} }
int msm_dsi_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct msm_dsi *msm_dsi = platform_get_drvdata(pdev);
struct mipi_dsi_host *host = msm_dsi->host;
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
if (!msm_host->cfg_hnd)
return 0;
dsi_bus_clk_disable(msm_host);
return 0;
}
int msm_dsi_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct msm_dsi *msm_dsi = platform_get_drvdata(pdev);
struct mipi_dsi_host *host = msm_dsi->host;
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
if (!msm_host->cfg_hnd)
return 0;
return dsi_bus_clk_enable(msm_host);
}
static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host)
{ {
int ret; int ret;
...@@ -596,35 +626,6 @@ static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) ...@@ -596,35 +626,6 @@ static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
} }
} }
static int dsi_clk_ctrl(struct msm_dsi_host *msm_host, bool enable)
{
int ret = 0;
mutex_lock(&msm_host->clk_mutex);
if (enable) {
ret = dsi_bus_clk_enable(msm_host);
if (ret) {
pr_err("%s: Can not enable bus clk, %d\n",
__func__, ret);
goto unlock_ret;
}
ret = dsi_link_clk_enable(msm_host);
if (ret) {
pr_err("%s: Can not enable link clk, %d\n",
__func__, ret);
dsi_bus_clk_disable(msm_host);
goto unlock_ret;
}
} else {
dsi_link_clk_disable(msm_host);
dsi_bus_clk_disable(msm_host);
}
unlock_ret:
mutex_unlock(&msm_host->clk_mutex);
return ret;
}
static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host) static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host)
{ {
struct drm_display_mode *mode = msm_host->mode; struct drm_display_mode *mode = msm_host->mode;
...@@ -1699,6 +1700,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) ...@@ -1699,6 +1700,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
} }
msm_host->pdev = pdev; msm_host->pdev = pdev;
msm_dsi->host = &msm_host->base;
ret = dsi_host_parse_dt(msm_host); ret = dsi_host_parse_dt(msm_host);
if (ret) { if (ret) {
...@@ -1713,6 +1715,8 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) ...@@ -1713,6 +1715,8 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
goto fail; goto fail;
} }
pm_runtime_enable(&pdev->dev);
msm_host->cfg_hnd = dsi_get_config(msm_host); msm_host->cfg_hnd = dsi_get_config(msm_host);
if (!msm_host->cfg_hnd) { if (!msm_host->cfg_hnd) {
ret = -EINVAL; ret = -EINVAL;
...@@ -1753,7 +1757,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) ...@@ -1753,7 +1757,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
init_completion(&msm_host->video_comp); init_completion(&msm_host->video_comp);
mutex_init(&msm_host->dev_mutex); mutex_init(&msm_host->dev_mutex);
mutex_init(&msm_host->cmd_mutex); mutex_init(&msm_host->cmd_mutex);
mutex_init(&msm_host->clk_mutex);
spin_lock_init(&msm_host->intr_lock); spin_lock_init(&msm_host->intr_lock);
/* setup workqueue */ /* setup workqueue */
...@@ -1761,7 +1764,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) ...@@ -1761,7 +1764,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
INIT_WORK(&msm_host->err_work, dsi_err_worker); INIT_WORK(&msm_host->err_work, dsi_err_worker);
INIT_WORK(&msm_host->hpd_work, dsi_hpd_worker); INIT_WORK(&msm_host->hpd_work, dsi_hpd_worker);
msm_dsi->host = &msm_host->base;
msm_dsi->id = msm_host->id; msm_dsi->id = msm_host->id;
DBG("Dsi Host %d initialized", msm_host->id); DBG("Dsi Host %d initialized", msm_host->id);
...@@ -1783,9 +1785,10 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host) ...@@ -1783,9 +1785,10 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host)
msm_host->workqueue = NULL; msm_host->workqueue = NULL;
} }
mutex_destroy(&msm_host->clk_mutex);
mutex_destroy(&msm_host->cmd_mutex); mutex_destroy(&msm_host->cmd_mutex);
mutex_destroy(&msm_host->dev_mutex); mutex_destroy(&msm_host->dev_mutex);
pm_runtime_disable(&msm_host->pdev->dev);
} }
int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
...@@ -1881,7 +1884,8 @@ int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, ...@@ -1881,7 +1884,8 @@ int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
* mdss interrupt is generated in mdp core clock domain * mdss interrupt is generated in mdp core clock domain
* mdp clock need to be enabled to receive dsi interrupt * mdp clock need to be enabled to receive dsi interrupt
*/ */
dsi_clk_ctrl(msm_host, 1); pm_runtime_get_sync(&msm_host->pdev->dev);
dsi_link_clk_enable(msm_host);
/* TODO: vote for bus bandwidth */ /* TODO: vote for bus bandwidth */
...@@ -1911,7 +1915,8 @@ void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, ...@@ -1911,7 +1915,8 @@ void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host,
/* TODO: unvote for bus bandwidth */ /* TODO: unvote for bus bandwidth */
dsi_clk_ctrl(msm_host, 0); dsi_link_clk_disable(msm_host);
pm_runtime_put_autosuspend(&msm_host->pdev->dev);
} }
int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host, int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
...@@ -2160,8 +2165,11 @@ int msm_dsi_host_enable(struct mipi_dsi_host *host) ...@@ -2160,8 +2165,11 @@ int msm_dsi_host_enable(struct mipi_dsi_host *host)
* and only turned on before MDP START. * and only turned on before MDP START.
* This part of code should be enabled once mdp driver support it. * This part of code should be enabled once mdp driver support it.
*/ */
/* if (msm_panel->mode == MSM_DSI_CMD_MODE) /* if (msm_panel->mode == MSM_DSI_CMD_MODE) {
dsi_clk_ctrl(msm_host, 0); */ * dsi_link_clk_disable(msm_host);
* pm_runtime_put_autosuspend(&msm_host->pdev->dev);
* }
*/
return 0; return 0;
} }
...@@ -2217,9 +2225,11 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, ...@@ -2217,9 +2225,11 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host,
goto unlock_ret; goto unlock_ret;
} }
ret = dsi_clk_ctrl(msm_host, 1); pm_runtime_get_sync(&msm_host->pdev->dev);
ret = dsi_link_clk_enable(msm_host);
if (ret) { if (ret) {
pr_err("%s: failed to enable clocks. ret=%d\n", __func__, ret); pr_err("%s: failed to enable link clocks. ret=%d\n",
__func__, ret);
goto fail_disable_reg; goto fail_disable_reg;
} }
...@@ -2243,7 +2253,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, ...@@ -2243,7 +2253,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host,
return 0; return 0;
fail_disable_clk: fail_disable_clk:
dsi_clk_ctrl(msm_host, 0); dsi_link_clk_disable(msm_host);
pm_runtime_put_autosuspend(&msm_host->pdev->dev);
fail_disable_reg: fail_disable_reg:
dsi_host_regulator_disable(msm_host); dsi_host_regulator_disable(msm_host);
unlock_ret: unlock_ret:
...@@ -2268,7 +2279,8 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host) ...@@ -2268,7 +2279,8 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host)
pinctrl_pm_select_sleep_state(&msm_host->pdev->dev); pinctrl_pm_select_sleep_state(&msm_host->pdev->dev);
dsi_clk_ctrl(msm_host, 0); dsi_link_clk_disable(msm_host);
pm_runtime_put_autosuspend(&msm_host->pdev->dev);
dsi_host_regulator_disable(msm_host); dsi_host_regulator_disable(msm_host);
......
...@@ -373,7 +373,7 @@ static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) ...@@ -373,7 +373,7 @@ static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
static void dsi_phy_disable_resource(struct msm_dsi_phy *phy) static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
{ {
clk_disable_unprepare(phy->ahb_clk); clk_disable_unprepare(phy->ahb_clk);
pm_runtime_put_sync(&phy->pdev->dev); pm_runtime_put_autosuspend(&phy->pdev->dev);
} }
static const struct of_device_id dsi_phy_dt_match[] = { static const struct of_device_id dsi_phy_dt_match[] = {
......
...@@ -239,6 +239,8 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) ...@@ -239,6 +239,8 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
hdmi->pwr_clks[i] = clk; hdmi->pwr_clks[i] = clk;
} }
pm_runtime_enable(&pdev->dev);
hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0); hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
hdmi->i2c = msm_hdmi_i2c_init(hdmi); hdmi->i2c = msm_hdmi_i2c_init(hdmi);
......
...@@ -35,6 +35,8 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge) ...@@ -35,6 +35,8 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge)
const struct hdmi_platform_config *config = hdmi->config; const struct hdmi_platform_config *config = hdmi->config;
int i, ret; int i, ret;
pm_runtime_get_sync(&hdmi->pdev->dev);
for (i = 0; i < config->pwr_reg_cnt; i++) { for (i = 0; i < config->pwr_reg_cnt; i++) {
ret = regulator_enable(hdmi->pwr_regs[i]); ret = regulator_enable(hdmi->pwr_regs[i]);
if (ret) { if (ret) {
...@@ -84,6 +86,8 @@ static void power_off(struct drm_bridge *bridge) ...@@ -84,6 +86,8 @@ static void power_off(struct drm_bridge *bridge)
config->pwr_reg_names[i], ret); config->pwr_reg_names[i], ret);
} }
} }
pm_runtime_put_autosuspend(&hdmi->pdev->dev);
} }
#define AVI_IFRAME_LINE_NUMBER 1 #define AVI_IFRAME_LINE_NUMBER 1
......
...@@ -137,6 +137,36 @@ static int gpio_config(struct hdmi *hdmi, bool on) ...@@ -137,6 +137,36 @@ static int gpio_config(struct hdmi *hdmi, bool on)
return ret; return ret;
} }
static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
{
const struct hdmi_platform_config *config = hdmi->config;
struct device *dev = &hdmi->pdev->dev;
int i, ret;
if (enable) {
for (i = 0; i < config->hpd_clk_cnt; i++) {
if (config->hpd_freq && config->hpd_freq[i]) {
ret = clk_set_rate(hdmi->hpd_clks[i],
config->hpd_freq[i]);
if (ret)
dev_warn(dev,
"failed to set clk %s (%d)\n",
config->hpd_clk_names[i], ret);
}
ret = clk_prepare_enable(hdmi->hpd_clks[i]);
if (ret) {
dev_err(dev,
"failed to enable hpd clk: %s (%d)\n",
config->hpd_clk_names[i], ret);
}
}
} else {
for (i = config->hpd_clk_cnt - 1; i >= 0; i--)
clk_disable_unprepare(hdmi->hpd_clks[i]);
}
}
static int hpd_enable(struct hdmi_connector *hdmi_connector) static int hpd_enable(struct hdmi_connector *hdmi_connector)
{ {
struct hdmi *hdmi = hdmi_connector->hdmi; struct hdmi *hdmi = hdmi_connector->hdmi;
...@@ -167,22 +197,8 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) ...@@ -167,22 +197,8 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
goto fail; goto fail;
} }
for (i = 0; i < config->hpd_clk_cnt; i++) { pm_runtime_get_sync(dev);
if (config->hpd_freq && config->hpd_freq[i]) { enable_hpd_clocks(hdmi, true);
ret = clk_set_rate(hdmi->hpd_clks[i],
config->hpd_freq[i]);
if (ret)
dev_warn(dev, "failed to set clk %s (%d)\n",
config->hpd_clk_names[i], ret);
}
ret = clk_prepare_enable(hdmi->hpd_clks[i]);
if (ret) {
dev_err(dev, "failed to enable hpd clk: %s (%d)\n",
config->hpd_clk_names[i], ret);
goto fail;
}
}
msm_hdmi_set_mode(hdmi, false); msm_hdmi_set_mode(hdmi, false);
msm_hdmi_phy_reset(hdmi); msm_hdmi_phy_reset(hdmi);
...@@ -225,8 +241,8 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector) ...@@ -225,8 +241,8 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector)
msm_hdmi_set_mode(hdmi, false); msm_hdmi_set_mode(hdmi, false);
for (i = 0; i < config->hpd_clk_cnt; i++) enable_hpd_clocks(hdmi, false);
clk_disable_unprepare(hdmi->hpd_clks[i]); pm_runtime_put_autosuspend(dev);
ret = gpio_config(hdmi, false); ret = gpio_config(hdmi, false);
if (ret) if (ret)
...@@ -285,7 +301,16 @@ void msm_hdmi_connector_irq(struct drm_connector *connector) ...@@ -285,7 +301,16 @@ void msm_hdmi_connector_irq(struct drm_connector *connector)
static enum drm_connector_status detect_reg(struct hdmi *hdmi) static enum drm_connector_status detect_reg(struct hdmi *hdmi)
{ {
uint32_t hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); uint32_t hpd_int_status;
pm_runtime_get_sync(&hdmi->pdev->dev);
enable_hpd_clocks(hdmi, true);
hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
enable_hpd_clocks(hdmi, false);
pm_runtime_put_autosuspend(&hdmi->pdev->dev);
return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ? return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
connector_status_connected : connector_status_disconnected; connector_status_connected : connector_status_disconnected;
} }
......
...@@ -192,6 +192,7 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder, ...@@ -192,6 +192,7 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
{ {
struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder); struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms; struct mdp5_kms *mdp5_kms;
struct device *dev;
int intf_num; int intf_num;
u32 data = 0; u32 data = 0;
...@@ -214,14 +215,16 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder, ...@@ -214,14 +215,16 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
/* Smart Panel, Sync mode */ /* Smart Panel, Sync mode */
data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL; data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
dev = &mdp5_kms->pdev->dev;
/* Make sure clocks are on when connectors calling this function. */ /* Make sure clocks are on when connectors calling this function. */
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data); mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
MDP5_SPLIT_DPL_LOWER_SMART_PANEL); MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
return 0; return 0;
} }
...@@ -415,6 +415,7 @@ static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc, ...@@ -415,6 +415,7 @@ static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc,
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
struct mdp5_kms *mdp5_kms = get_kms(crtc); struct mdp5_kms *mdp5_kms = get_kms(crtc);
struct device *dev = &mdp5_kms->pdev->dev;
DBG("%s", crtc->name); DBG("%s", crtc->name);
...@@ -425,7 +426,7 @@ static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc, ...@@ -425,7 +426,7 @@ static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc,
mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done); mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done);
mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
mdp5_crtc->enabled = false; mdp5_crtc->enabled = false;
} }
...@@ -436,13 +437,17 @@ static void mdp5_crtc_atomic_enable(struct drm_crtc *crtc, ...@@ -436,13 +437,17 @@ static void mdp5_crtc_atomic_enable(struct drm_crtc *crtc,
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
struct mdp5_kms *mdp5_kms = get_kms(crtc); struct mdp5_kms *mdp5_kms = get_kms(crtc);
struct device *dev = &mdp5_kms->pdev->dev;
DBG("%s", crtc->name); DBG("%s", crtc->name);
if (WARN_ON(mdp5_crtc->enabled)) if (WARN_ON(mdp5_crtc->enabled))
return; return;
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
mdp5_crtc_mode_set_nofb(crtc);
mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
if (mdp5_cstate->cmd_mode) if (mdp5_cstate->cmd_mode)
...@@ -533,7 +538,7 @@ static bool is_fullscreen(struct drm_crtc_state *cstate, ...@@ -533,7 +538,7 @@ static bool is_fullscreen(struct drm_crtc_state *cstate,
((pstate->crtc_y + pstate->crtc_h) >= cstate->mode.vdisplay); ((pstate->crtc_y + pstate->crtc_h) >= cstate->mode.vdisplay);
} }
enum mdp_mixer_stage_id get_start_stage(struct drm_crtc *crtc, static enum mdp_mixer_stage_id get_start_stage(struct drm_crtc *crtc,
struct drm_crtc_state *new_crtc_state, struct drm_crtc_state *new_crtc_state,
struct drm_plane_state *bpstate) struct drm_plane_state *bpstate)
{ {
...@@ -727,6 +732,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -727,6 +732,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline; struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct mdp5_kms *mdp5_kms = get_kms(crtc); struct mdp5_kms *mdp5_kms = get_kms(crtc);
struct platform_device *pdev = mdp5_kms->pdev;
struct msm_kms *kms = &mdp5_kms->base.base; struct msm_kms *kms = &mdp5_kms->base.base;
struct drm_gem_object *cursor_bo, *old_bo = NULL; struct drm_gem_object *cursor_bo, *old_bo = NULL;
uint32_t blendcfg, stride; uint32_t blendcfg, stride;
...@@ -755,7 +761,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -755,7 +761,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
if (!handle) { if (!handle) {
DBG("Cursor off"); DBG("Cursor off");
cursor_enable = false; cursor_enable = false;
mdp5_enable(mdp5_kms); pm_runtime_get_sync(&pdev->dev);
goto set_cursor; goto set_cursor;
} }
...@@ -770,6 +776,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -770,6 +776,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
lm = mdp5_cstate->pipeline.mixer->lm; lm = mdp5_cstate->pipeline.mixer->lm;
stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0); stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0);
pm_runtime_get_sync(&pdev->dev);
spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags); spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
old_bo = mdp5_crtc->cursor.scanout_bo; old_bo = mdp5_crtc->cursor.scanout_bo;
...@@ -779,8 +787,6 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -779,8 +787,6 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
get_roi(crtc, &roi_w, &roi_h); get_roi(crtc, &roi_w, &roi_h);
mdp5_enable(mdp5_kms);
mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride); mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm), mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888)); MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
...@@ -798,6 +804,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -798,6 +804,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags); spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
pm_runtime_put_autosuspend(&pdev->dev);
set_cursor: set_cursor:
ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable); ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable);
if (ret) { if (ret) {
...@@ -809,7 +817,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -809,7 +817,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
crtc_flush(crtc, flush_mask); crtc_flush(crtc, flush_mask);
end: end:
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(&pdev->dev);
if (old_bo) { if (old_bo) {
drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo); drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo);
/* enable vblank to complete cursor work: */ /* enable vblank to complete cursor work: */
...@@ -842,7 +850,7 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) ...@@ -842,7 +850,7 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
get_roi(crtc, &roi_w, &roi_h); get_roi(crtc, &roi_w, &roi_h);
mdp5_enable(mdp5_kms); pm_runtime_get_sync(&mdp5_kms->pdev->dev);
spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags); spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm), mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
...@@ -855,7 +863,7 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) ...@@ -855,7 +863,7 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
crtc_flush(crtc, flush_mask); crtc_flush(crtc, flush_mask);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(&mdp5_kms->pdev->dev);
return 0; return 0;
} }
......
...@@ -297,6 +297,10 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder) ...@@ -297,6 +297,10 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
{ {
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_interface *intf = mdp5_encoder->intf; struct mdp5_interface *intf = mdp5_encoder->intf;
/* this isn't right I think */
struct drm_crtc_state *cstate = encoder->crtc->state;
mdp5_encoder_mode_set(encoder, &cstate->mode, &cstate->adjusted_mode);
if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND) if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
mdp5_cmd_encoder_enable(encoder); mdp5_cmd_encoder_enable(encoder);
...@@ -320,7 +324,6 @@ static int mdp5_encoder_atomic_check(struct drm_encoder *encoder, ...@@ -320,7 +324,6 @@ static int mdp5_encoder_atomic_check(struct drm_encoder *encoder,
} }
static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
.mode_set = mdp5_encoder_mode_set,
.disable = mdp5_encoder_disable, .disable = mdp5_encoder_disable,
.enable = mdp5_encoder_enable, .enable = mdp5_encoder_enable,
.atomic_check = mdp5_encoder_atomic_check, .atomic_check = mdp5_encoder_atomic_check,
...@@ -350,6 +353,7 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder, ...@@ -350,6 +353,7 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder); struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
struct mdp5_kms *mdp5_kms; struct mdp5_kms *mdp5_kms;
struct device *dev;
int intf_num; int intf_num;
u32 data = 0; u32 data = 0;
...@@ -369,8 +373,10 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder, ...@@ -369,8 +373,10 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
else else
return -EINVAL; return -EINVAL;
dev = &mdp5_kms->pdev->dev;
/* Make sure clocks are on when connectors calling this function. */ /* Make sure clocks are on when connectors calling this function. */
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
/* Dumb Panel, Sync mode */ /* Dumb Panel, Sync mode */
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0); mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data); mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
...@@ -378,7 +384,7 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder, ...@@ -378,7 +384,7 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true); mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
return 0; return 0;
} }
......
...@@ -49,16 +49,19 @@ static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) ...@@ -49,16 +49,19 @@ static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
void mdp5_irq_preinstall(struct msm_kms *kms) void mdp5_irq_preinstall(struct msm_kms *kms)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
mdp5_enable(mdp5_kms); struct device *dev = &mdp5_kms->pdev->dev;
pm_runtime_get_sync(dev);
mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff); mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
} }
int mdp5_irq_postinstall(struct msm_kms *kms) int mdp5_irq_postinstall(struct msm_kms *kms)
{ {
struct mdp_kms *mdp_kms = to_mdp_kms(kms); struct mdp_kms *mdp_kms = to_mdp_kms(kms);
struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
struct device *dev = &mdp5_kms->pdev->dev;
struct mdp_irq *error_handler = &mdp5_kms->error_handler; struct mdp_irq *error_handler = &mdp5_kms->error_handler;
error_handler->irq = mdp5_irq_error_handler; error_handler->irq = mdp5_irq_error_handler;
...@@ -67,9 +70,9 @@ int mdp5_irq_postinstall(struct msm_kms *kms) ...@@ -67,9 +70,9 @@ int mdp5_irq_postinstall(struct msm_kms *kms)
MDP5_IRQ_INTF2_UNDER_RUN | MDP5_IRQ_INTF2_UNDER_RUN |
MDP5_IRQ_INTF3_UNDER_RUN; MDP5_IRQ_INTF3_UNDER_RUN;
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
mdp_irq_register(mdp_kms, error_handler); mdp_irq_register(mdp_kms, error_handler);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
return 0; return 0;
} }
...@@ -77,9 +80,11 @@ int mdp5_irq_postinstall(struct msm_kms *kms) ...@@ -77,9 +80,11 @@ int mdp5_irq_postinstall(struct msm_kms *kms)
void mdp5_irq_uninstall(struct msm_kms *kms) void mdp5_irq_uninstall(struct msm_kms *kms)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
mdp5_enable(mdp5_kms); struct device *dev = &mdp5_kms->pdev->dev;
pm_runtime_get_sync(dev);
mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
} }
irqreturn_t mdp5_irq(struct msm_kms *kms) irqreturn_t mdp5_irq(struct msm_kms *kms)
...@@ -109,11 +114,12 @@ irqreturn_t mdp5_irq(struct msm_kms *kms) ...@@ -109,11 +114,12 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
struct device *dev = &mdp5_kms->pdev->dev;
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
mdp_update_vblank_mask(to_mdp_kms(kms), mdp_update_vblank_mask(to_mdp_kms(kms),
mdp5_crtc_vblank(crtc), true); mdp5_crtc_vblank(crtc), true);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
return 0; return 0;
} }
...@@ -121,9 +127,10 @@ int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) ...@@ -121,9 +127,10 @@ int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
struct device *dev = &mdp5_kms->pdev->dev;
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
mdp_update_vblank_mask(to_mdp_kms(kms), mdp_update_vblank_mask(to_mdp_kms(kms),
mdp5_crtc_vblank(crtc), false); mdp5_crtc_vblank(crtc), false);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
} }
...@@ -30,11 +30,10 @@ static const char *iommu_ports[] = { ...@@ -30,11 +30,10 @@ static const char *iommu_ports[] = {
static int mdp5_hw_init(struct msm_kms *kms) static int mdp5_hw_init(struct msm_kms *kms)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
struct platform_device *pdev = mdp5_kms->pdev; struct device *dev = &mdp5_kms->pdev->dev;
unsigned long flags; unsigned long flags;
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(dev);
mdp5_enable(mdp5_kms);
/* Magic unknown register writes: /* Magic unknown register writes:
* *
...@@ -66,8 +65,7 @@ static int mdp5_hw_init(struct msm_kms *kms) ...@@ -66,8 +65,7 @@ static int mdp5_hw_init(struct msm_kms *kms)
mdp5_ctlm_hw_reset(mdp5_kms->ctlm); mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
mdp5_disable(mdp5_kms); pm_runtime_put_sync(dev);
pm_runtime_put_sync(&pdev->dev);
return 0; return 0;
} }
...@@ -111,8 +109,9 @@ static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state) ...@@ -111,8 +109,9 @@ static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state)
static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
struct device *dev = &mdp5_kms->pdev->dev;
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
if (mdp5_kms->smp) if (mdp5_kms->smp)
mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp); mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
...@@ -121,11 +120,12 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st ...@@ -121,11 +120,12 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st
static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
struct device *dev = &mdp5_kms->pdev->dev;
if (mdp5_kms->smp) if (mdp5_kms->smp)
mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp); mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
} }
static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms, static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms,
...@@ -249,6 +249,9 @@ int mdp5_disable(struct mdp5_kms *mdp5_kms) ...@@ -249,6 +249,9 @@ int mdp5_disable(struct mdp5_kms *mdp5_kms)
{ {
DBG(""); DBG("");
mdp5_kms->enable_count--;
WARN_ON(mdp5_kms->enable_count < 0);
clk_disable_unprepare(mdp5_kms->ahb_clk); clk_disable_unprepare(mdp5_kms->ahb_clk);
clk_disable_unprepare(mdp5_kms->axi_clk); clk_disable_unprepare(mdp5_kms->axi_clk);
clk_disable_unprepare(mdp5_kms->core_clk); clk_disable_unprepare(mdp5_kms->core_clk);
...@@ -262,6 +265,8 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms) ...@@ -262,6 +265,8 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms)
{ {
DBG(""); DBG("");
mdp5_kms->enable_count++;
clk_prepare_enable(mdp5_kms->ahb_clk); clk_prepare_enable(mdp5_kms->ahb_clk);
clk_prepare_enable(mdp5_kms->axi_clk); clk_prepare_enable(mdp5_kms->axi_clk);
clk_prepare_enable(mdp5_kms->core_clk); clk_prepare_enable(mdp5_kms->core_clk);
...@@ -486,11 +491,12 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) ...@@ -486,11 +491,12 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms,
u32 *major, u32 *minor) u32 *major, u32 *minor)
{ {
struct device *dev = &mdp5_kms->pdev->dev;
u32 version; u32 version;
mdp5_enable(mdp5_kms); pm_runtime_get_sync(dev);
version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION); version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION);
mdp5_disable(mdp5_kms); pm_runtime_put_autosuspend(dev);
*major = FIELD(version, MDP5_HW_VERSION_MAJOR); *major = FIELD(version, MDP5_HW_VERSION_MAJOR);
*minor = FIELD(version, MDP5_HW_VERSION_MINOR); *minor = FIELD(version, MDP5_HW_VERSION_MINOR);
...@@ -643,7 +649,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) ...@@ -643,7 +649,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
* have left things on, in which case we'll start getting faults if * have left things on, in which case we'll start getting faults if
* we don't disable): * we don't disable):
*/ */
mdp5_enable(mdp5_kms); pm_runtime_get_sync(&pdev->dev);
for (i = 0; i < MDP5_INTF_NUM_MAX; i++) { for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) || if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||
!config->hw->intf.base[i]) !config->hw->intf.base[i])
...@@ -652,7 +658,6 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) ...@@ -652,7 +658,6 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3); mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
} }
mdp5_disable(mdp5_kms);
mdelay(16); mdelay(16);
if (config->platform.iommu) { if (config->platform.iommu) {
...@@ -678,6 +683,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) ...@@ -678,6 +683,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
aspace = NULL;; aspace = NULL;;
} }
pm_runtime_put_autosuspend(&pdev->dev);
ret = modeset_init(mdp5_kms); ret = modeset_init(mdp5_kms);
if (ret) { if (ret) {
dev_err(&pdev->dev, "modeset_init failed: %d\n", ret); dev_err(&pdev->dev, "modeset_init failed: %d\n", ret);
...@@ -1005,6 +1012,30 @@ static int mdp5_dev_remove(struct platform_device *pdev) ...@@ -1005,6 +1012,30 @@ static int mdp5_dev_remove(struct platform_device *pdev)
return 0; return 0;
} }
static __maybe_unused int mdp5_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
DBG("");
return mdp5_disable(mdp5_kms);
}
static __maybe_unused int mdp5_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
DBG("");
return mdp5_enable(mdp5_kms);
}
static const struct dev_pm_ops mdp5_pm_ops = {
SET_RUNTIME_PM_OPS(mdp5_runtime_suspend, mdp5_runtime_resume, NULL)
};
static const struct of_device_id mdp5_dt_match[] = { static const struct of_device_id mdp5_dt_match[] = {
{ .compatible = "qcom,mdp5", }, { .compatible = "qcom,mdp5", },
/* to support downstream DT files */ /* to support downstream DT files */
...@@ -1019,6 +1050,7 @@ static struct platform_driver mdp5_driver = { ...@@ -1019,6 +1050,7 @@ static struct platform_driver mdp5_driver = {
.driver = { .driver = {
.name = "msm_mdp", .name = "msm_mdp",
.of_match_table = mdp5_dt_match, .of_match_table = mdp5_dt_match,
.pm = &mdp5_pm_ops,
}, },
}; };
......
...@@ -76,6 +76,8 @@ struct mdp5_kms { ...@@ -76,6 +76,8 @@ struct mdp5_kms {
bool rpm_enabled; bool rpm_enabled;
struct mdp_irq error_handler; struct mdp_irq error_handler;
int enable_count;
}; };
#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base)
...@@ -167,11 +169,13 @@ struct mdp5_encoder { ...@@ -167,11 +169,13 @@ struct mdp5_encoder {
static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data) static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
{ {
WARN_ON(mdp5_kms->enable_count <= 0);
msm_writel(data, mdp5_kms->mmio + reg); msm_writel(data, mdp5_kms->mmio + reg);
} }
static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg) static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg)
{ {
WARN_ON(mdp5_kms->enable_count <= 0);
return msm_readl(mdp5_kms->mmio + reg); return msm_readl(mdp5_kms->mmio + reg);
} }
...@@ -255,9 +259,6 @@ static inline uint32_t lm2ppdone(struct mdp5_hw_mixer *mixer) ...@@ -255,9 +259,6 @@ static inline uint32_t lm2ppdone(struct mdp5_hw_mixer *mixer)
return MDP5_IRQ_PING_PONG_0_DONE << mixer->pp; return MDP5_IRQ_PING_PONG_0_DONE << mixer->pp;
} }
int mdp5_disable(struct mdp5_kms *mdp5_kms);
int mdp5_enable(struct mdp5_kms *mdp5_kms);
void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
uint32_t old_irqmask); uint32_t old_irqmask);
void mdp5_irq_preinstall(struct msm_kms *kms); void mdp5_irq_preinstall(struct msm_kms *kms);
......
...@@ -31,6 +31,10 @@ struct msm_mdss { ...@@ -31,6 +31,10 @@ struct msm_mdss {
struct regulator *vdd; struct regulator *vdd;
struct clk *ahb_clk;
struct clk *axi_clk;
struct clk *vsync_clk;
struct { struct {
volatile unsigned long enabled_mask; volatile unsigned long enabled_mask;
struct irq_domain *domain; struct irq_domain *domain;
...@@ -140,6 +144,51 @@ static int mdss_irq_domain_init(struct msm_mdss *mdss) ...@@ -140,6 +144,51 @@ static int mdss_irq_domain_init(struct msm_mdss *mdss)
return 0; return 0;
} }
int msm_mdss_enable(struct msm_mdss *mdss)
{
DBG("");
clk_prepare_enable(mdss->ahb_clk);
if (mdss->axi_clk)
clk_prepare_enable(mdss->axi_clk);
if (mdss->vsync_clk)
clk_prepare_enable(mdss->vsync_clk);
return 0;
}
int msm_mdss_disable(struct msm_mdss *mdss)
{
DBG("");
if (mdss->vsync_clk)
clk_disable_unprepare(mdss->vsync_clk);
if (mdss->axi_clk)
clk_disable_unprepare(mdss->axi_clk);
clk_disable_unprepare(mdss->ahb_clk);
return 0;
}
static int msm_mdss_get_clocks(struct msm_mdss *mdss)
{
struct platform_device *pdev = to_platform_device(mdss->dev->dev);
mdss->ahb_clk = msm_clk_get(pdev, "iface");
if (IS_ERR(mdss->ahb_clk))
mdss->ahb_clk = NULL;
mdss->axi_clk = msm_clk_get(pdev, "bus");
if (IS_ERR(mdss->axi_clk))
mdss->axi_clk = NULL;
mdss->vsync_clk = msm_clk_get(pdev, "vsync");
if (IS_ERR(mdss->vsync_clk))
mdss->vsync_clk = NULL;
return 0;
}
void msm_mdss_destroy(struct drm_device *dev) void msm_mdss_destroy(struct drm_device *dev)
{ {
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
...@@ -153,8 +202,6 @@ void msm_mdss_destroy(struct drm_device *dev) ...@@ -153,8 +202,6 @@ void msm_mdss_destroy(struct drm_device *dev)
regulator_disable(mdss->vdd); regulator_disable(mdss->vdd);
pm_runtime_put_sync(dev->dev);
pm_runtime_disable(dev->dev); pm_runtime_disable(dev->dev);
} }
...@@ -190,6 +237,12 @@ int msm_mdss_init(struct drm_device *dev) ...@@ -190,6 +237,12 @@ int msm_mdss_init(struct drm_device *dev)
goto fail; goto fail;
} }
ret = msm_mdss_get_clocks(mdss);
if (ret) {
dev_err(dev->dev, "failed to get clocks: %d\n", ret);
goto fail;
}
/* Regulator to enable GDSCs in downstream kernels */ /* Regulator to enable GDSCs in downstream kernels */
mdss->vdd = devm_regulator_get(dev->dev, "vdd"); mdss->vdd = devm_regulator_get(dev->dev, "vdd");
if (IS_ERR(mdss->vdd)) { if (IS_ERR(mdss->vdd)) {
...@@ -221,12 +274,6 @@ int msm_mdss_init(struct drm_device *dev) ...@@ -221,12 +274,6 @@ int msm_mdss_init(struct drm_device *dev)
pm_runtime_enable(dev->dev); pm_runtime_enable(dev->dev);
/*
* TODO: This is needed as the MDSS GDSC is only tied to MDSS's power
* domain. Remove this once runtime PM is adapted for all the devices.
*/
pm_runtime_get_sync(dev->dev);
return 0; return 0;
fail_irq: fail_irq:
regulator_disable(mdss->vdd); regulator_disable(mdss->vdd);
......
...@@ -28,6 +28,13 @@ struct mdp5_smp { ...@@ -28,6 +28,13 @@ struct mdp5_smp {
int blk_cnt; int blk_cnt;
int blk_size; int blk_size;
/* register cache */
u32 alloc_w[22];
u32 alloc_r[22];
u32 pipe_reqprio_fifo_wm0[SSPP_MAX];
u32 pipe_reqprio_fifo_wm1[SSPP_MAX];
u32 pipe_reqprio_fifo_wm2[SSPP_MAX];
}; };
static inline static inline
...@@ -98,16 +105,15 @@ static int smp_request_block(struct mdp5_smp *smp, ...@@ -98,16 +105,15 @@ static int smp_request_block(struct mdp5_smp *smp,
static void set_fifo_thresholds(struct mdp5_smp *smp, static void set_fifo_thresholds(struct mdp5_smp *smp,
enum mdp5_pipe pipe, int nblks) enum mdp5_pipe pipe, int nblks)
{ {
struct mdp5_kms *mdp5_kms = get_kms(smp);
u32 smp_entries_per_blk = smp->blk_size / (128 / BITS_PER_BYTE); u32 smp_entries_per_blk = smp->blk_size / (128 / BITS_PER_BYTE);
u32 val; u32 val;
/* 1/4 of SMP pool that is being fetched */ /* 1/4 of SMP pool that is being fetched */
val = (nblks * smp_entries_per_blk) / 4; val = (nblks * smp_entries_per_blk) / 4;
mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe), val * 1); smp->pipe_reqprio_fifo_wm0[pipe] = val * 1;
mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe), val * 2); smp->pipe_reqprio_fifo_wm1[pipe] = val * 2;
mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe), val * 3); smp->pipe_reqprio_fifo_wm2[pipe] = val * 3;
} }
/* /*
...@@ -222,7 +228,6 @@ void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state, ...@@ -222,7 +228,6 @@ void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state,
static unsigned update_smp_state(struct mdp5_smp *smp, static unsigned update_smp_state(struct mdp5_smp *smp,
u32 cid, mdp5_smp_state_t *assigned) u32 cid, mdp5_smp_state_t *assigned)
{ {
struct mdp5_kms *mdp5_kms = get_kms(smp);
int cnt = smp->blk_cnt; int cnt = smp->blk_cnt;
unsigned nblks = 0; unsigned nblks = 0;
u32 blk, val; u32 blk, val;
...@@ -231,7 +236,7 @@ static unsigned update_smp_state(struct mdp5_smp *smp, ...@@ -231,7 +236,7 @@ static unsigned update_smp_state(struct mdp5_smp *smp,
int idx = blk / 3; int idx = blk / 3;
int fld = blk % 3; int fld = blk % 3;
val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx)); val = smp->alloc_w[idx];
switch (fld) { switch (fld) {
case 0: case 0:
...@@ -248,8 +253,8 @@ static unsigned update_smp_state(struct mdp5_smp *smp, ...@@ -248,8 +253,8 @@ static unsigned update_smp_state(struct mdp5_smp *smp,
break; break;
} }
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val); smp->alloc_w[idx] = val;
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val); smp->alloc_r[idx] = val;
nblks++; nblks++;
} }
...@@ -257,6 +262,39 @@ static unsigned update_smp_state(struct mdp5_smp *smp, ...@@ -257,6 +262,39 @@ static unsigned update_smp_state(struct mdp5_smp *smp,
return nblks; return nblks;
} }
static void write_smp_alloc_regs(struct mdp5_smp *smp)
{
struct mdp5_kms *mdp5_kms = get_kms(smp);
int i, num_regs;
num_regs = smp->blk_cnt / 3 + 1;
for (i = 0; i < num_regs; i++) {
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(i),
smp->alloc_w[i]);
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(i),
smp->alloc_r[i]);
}
}
static void write_smp_fifo_regs(struct mdp5_smp *smp)
{
struct mdp5_kms *mdp5_kms = get_kms(smp);
int i;
for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
enum mdp5_pipe pipe = hwpipe->pipe;
mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe),
smp->pipe_reqprio_fifo_wm0[pipe]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe),
smp->pipe_reqprio_fifo_wm1[pipe]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe),
smp->pipe_reqprio_fifo_wm2[pipe]);
}
}
void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state) void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
{ {
enum mdp5_pipe pipe; enum mdp5_pipe pipe;
...@@ -277,6 +315,9 @@ void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state) ...@@ -277,6 +315,9 @@ void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
set_fifo_thresholds(smp, pipe, nblks); set_fifo_thresholds(smp, pipe, nblks);
} }
write_smp_alloc_regs(smp);
write_smp_fifo_regs(smp);
state->assigned = 0; state->assigned = 0;
} }
...@@ -289,6 +330,8 @@ void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state ...@@ -289,6 +330,8 @@ void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state
set_fifo_thresholds(smp, pipe, 0); set_fifo_thresholds(smp, pipe, 0);
} }
write_smp_fifo_regs(smp);
state->released = 0; state->released = 0;
} }
......
...@@ -73,6 +73,10 @@ bool dumpstate = false; ...@@ -73,6 +73,10 @@ bool dumpstate = false;
MODULE_PARM_DESC(dumpstate, "Dump KMS state on errors"); MODULE_PARM_DESC(dumpstate, "Dump KMS state on errors");
module_param(dumpstate, bool, 0600); module_param(dumpstate, bool, 0600);
static bool modeset = true;
MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (1=on (default), 0=disable)");
module_param(modeset, bool, 0600);
/* /*
* Util/helpers: * Util/helpers:
*/ */
...@@ -878,8 +882,37 @@ static int msm_pm_resume(struct device *dev) ...@@ -878,8 +882,37 @@ static int msm_pm_resume(struct device *dev)
} }
#endif #endif
#ifdef CONFIG_PM
static int msm_runtime_suspend(struct device *dev)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct msm_drm_private *priv = ddev->dev_private;
DBG("");
if (priv->mdss)
return msm_mdss_disable(priv->mdss);
return 0;
}
static int msm_runtime_resume(struct device *dev)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct msm_drm_private *priv = ddev->dev_private;
DBG("");
if (priv->mdss)
return msm_mdss_enable(priv->mdss);
return 0;
}
#endif
static const struct dev_pm_ops msm_pm_ops = { static const struct dev_pm_ops msm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume) SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume)
SET_RUNTIME_PM_OPS(msm_runtime_suspend, msm_runtime_resume, NULL)
}; };
/* /*
...@@ -1103,6 +1136,9 @@ static struct platform_driver msm_platform_driver = { ...@@ -1103,6 +1136,9 @@ static struct platform_driver msm_platform_driver = {
static int __init msm_drm_register(void) static int __init msm_drm_register(void)
{ {
if (!modeset)
return -EINVAL;
DBG("init"); DBG("init");
msm_mdp_register(); msm_mdp_register();
msm_dsi_register(); msm_dsi_register();
......
...@@ -55,8 +55,6 @@ struct msm_fence_cb; ...@@ -55,8 +55,6 @@ struct msm_fence_cb;
struct msm_gem_address_space; struct msm_gem_address_space;
struct msm_gem_vma; struct msm_gem_vma;
#define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */
struct msm_file_private { struct msm_file_private {
/* currently we don't do anything useful with this.. but when /* currently we don't do anything useful with this.. but when
* per-context address spaces are supported we'd keep track of * per-context address spaces are supported we'd keep track of
...@@ -237,6 +235,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, ...@@ -237,6 +235,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
uint32_t size, uint32_t flags); uint32_t size, uint32_t flags);
struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev, struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev,
uint32_t size, uint32_t flags); uint32_t size, uint32_t flags);
void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
uint32_t flags, struct msm_gem_address_space *aspace,
struct drm_gem_object **bo, uint64_t *iova);
void *msm_gem_kernel_new_locked(struct drm_device *dev, uint32_t size,
uint32_t flags, struct msm_gem_address_space *aspace,
struct drm_gem_object **bo, uint64_t *iova);
struct drm_gem_object *msm_gem_import(struct drm_device *dev, struct drm_gem_object *msm_gem_import(struct drm_device *dev,
struct dma_buf *dmabuf, struct sg_table *sgt); struct dma_buf *dmabuf, struct sg_table *sgt);
...@@ -248,10 +252,10 @@ uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, ...@@ -248,10 +252,10 @@ uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,
struct msm_gem_address_space *aspace, int plane); struct msm_gem_address_space *aspace, int plane);
struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane); struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb); const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev,
int w, int h, int p, uint32_t format);
struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
void msm_fbdev_free(struct drm_device *dev); void msm_fbdev_free(struct drm_device *dev);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "msm_drv.h" #include "msm_drv.h"
#include "msm_kms.h" #include "msm_kms.h"
#include "msm_gem.h"
struct msm_framebuffer { struct msm_framebuffer {
struct drm_framebuffer base; struct drm_framebuffer base;
...@@ -28,6 +29,8 @@ struct msm_framebuffer { ...@@ -28,6 +29,8 @@ struct msm_framebuffer {
}; };
#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base) #define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
static int msm_framebuffer_create_handle(struct drm_framebuffer *fb, static int msm_framebuffer_create_handle(struct drm_framebuffer *fb,
struct drm_file *file_priv, struct drm_file *file_priv,
...@@ -161,7 +164,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, ...@@ -161,7 +164,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
{ {
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
...@@ -237,3 +240,43 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, ...@@ -237,3 +240,43 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
struct drm_framebuffer *
msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format)
{
struct drm_mode_fb_cmd2 mode_cmd = {
.pixel_format = format,
.width = w,
.height = h,
.pitches = { p },
};
struct drm_gem_object *bo;
struct drm_framebuffer *fb;
int size;
/* allocate backing bo */
size = mode_cmd.pitches[0] * mode_cmd.height;
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN);
if (IS_ERR(bo)) {
dev_warn(dev->dev, "could not allocate stolen bo\n");
/* try regular bo: */
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
}
if (IS_ERR(bo)) {
dev_err(dev->dev, "failed to allocate buffer object\n");
return ERR_CAST(bo);
}
fb = msm_framebuffer_init(dev, &mode_cmd, &bo);
if (IS_ERR(fb)) {
dev_err(dev->dev, "failed to allocate fb\n");
/* note: if fb creation failed, we can't rely on fb destroy
* to unref the bo:
*/
drm_gem_object_unreference_unlocked(bo);
return ERR_CAST(fb);
}
return fb;
}
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include "msm_drv.h" #include "msm_drv.h"
#include "msm_gem.h"
#include "msm_kms.h" #include "msm_kms.h"
extern int msm_gem_mmap_obj(struct drm_gem_object *obj, extern int msm_gem_mmap_obj(struct drm_gem_object *obj,
...@@ -35,7 +34,6 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma); ...@@ -35,7 +34,6 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma);
struct msm_fbdev { struct msm_fbdev {
struct drm_fb_helper base; struct drm_fb_helper base;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct drm_gem_object *bo;
}; };
static struct fb_ops msm_fb_ops = { static struct fb_ops msm_fb_ops = {
...@@ -57,16 +55,16 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) ...@@ -57,16 +55,16 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
{ {
struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par; struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par;
struct msm_fbdev *fbdev = to_msm_fbdev(helper); struct msm_fbdev *fbdev = to_msm_fbdev(helper);
struct drm_gem_object *drm_obj = fbdev->bo; struct drm_gem_object *bo = msm_framebuffer_bo(fbdev->fb, 0);
int ret = 0; int ret = 0;
ret = drm_gem_mmap_obj(drm_obj, drm_obj->size, vma); ret = drm_gem_mmap_obj(bo, bo->size, vma);
if (ret) { if (ret) {
pr_err("%s:drm_gem_mmap_obj fail\n", __func__); pr_err("%s:drm_gem_mmap_obj fail\n", __func__);
return ret; return ret;
} }
return msm_gem_mmap_obj(drm_obj, vma); return msm_gem_mmap_obj(bo, vma);
} }
static int msm_fbdev_create(struct drm_fb_helper *helper, static int msm_fbdev_create(struct drm_fb_helper *helper,
...@@ -76,47 +74,30 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, ...@@ -76,47 +74,30 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
struct drm_device *dev = helper->dev; struct drm_device *dev = helper->dev;
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fb = NULL;
struct drm_gem_object *bo;
struct fb_info *fbi = NULL; struct fb_info *fbi = NULL;
struct drm_mode_fb_cmd2 mode_cmd = {0};
uint64_t paddr; uint64_t paddr;
int ret, size; uint32_t format;
int ret, pitch;
format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width, DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
sizes->surface_height, sizes->surface_bpp, sizes->surface_height, sizes->surface_bpp,
sizes->fb_width, sizes->fb_height); sizes->fb_width, sizes->fb_height);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, pitch = align_pitch(sizes->surface_width, sizes->surface_bpp);
sizes->surface_depth); fb = msm_alloc_stolen_fb(dev, sizes->surface_width,
sizes->surface_height, pitch, format);
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
mode_cmd.pitches[0] = align_pitch(
mode_cmd.width, sizes->surface_bpp);
/* allocate backing bo */
size = mode_cmd.pitches[0] * mode_cmd.height;
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT |
MSM_BO_WC | MSM_BO_STOLEN);
if (IS_ERR(fbdev->bo)) {
ret = PTR_ERR(fbdev->bo);
fbdev->bo = NULL;
dev_err(dev->dev, "failed to allocate buffer object: %d\n", ret);
goto fail;
}
fb = msm_framebuffer_init(dev, &mode_cmd, &fbdev->bo);
if (IS_ERR(fb)) { if (IS_ERR(fb)) {
dev_err(dev->dev, "failed to allocate fb\n"); dev_err(dev->dev, "failed to allocate fb\n");
/* note: if fb creation failed, we can't rely on fb destroy
* to unref the bo:
*/
drm_gem_object_unreference_unlocked(fbdev->bo);
ret = PTR_ERR(fb); ret = PTR_ERR(fb);
goto fail; goto fail;
} }
bo = msm_framebuffer_bo(fb, 0);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
/* /*
...@@ -124,7 +105,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, ...@@ -124,7 +105,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
* in panic (ie. lock-safe, etc) we could avoid pinning the * in panic (ie. lock-safe, etc) we could avoid pinning the
* buffer now: * buffer now:
*/ */
ret = msm_gem_get_iova(fbdev->bo, priv->kms->aspace, &paddr); ret = msm_gem_get_iova(bo, priv->kms->aspace, &paddr);
if (ret) { if (ret) {
dev_err(dev->dev, "failed to get buffer obj iova: %d\n", ret); dev_err(dev->dev, "failed to get buffer obj iova: %d\n", ret);
goto fail_unlock; goto fail_unlock;
...@@ -152,14 +133,14 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, ...@@ -152,14 +133,14 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
dev->mode_config.fb_base = paddr; dev->mode_config.fb_base = paddr;
fbi->screen_base = msm_gem_get_vaddr(fbdev->bo); fbi->screen_base = msm_gem_get_vaddr(bo);
if (IS_ERR(fbi->screen_base)) { if (IS_ERR(fbi->screen_base)) {
ret = PTR_ERR(fbi->screen_base); ret = PTR_ERR(fbi->screen_base);
goto fail_unlock; goto fail_unlock;
} }
fbi->screen_size = fbdev->bo->size; fbi->screen_size = bo->size;
fbi->fix.smem_start = paddr; fbi->fix.smem_start = paddr;
fbi->fix.smem_len = fbdev->bo->size; fbi->fix.smem_len = bo->size;
DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height);
...@@ -241,7 +222,9 @@ void msm_fbdev_free(struct drm_device *dev) ...@@ -241,7 +222,9 @@ void msm_fbdev_free(struct drm_device *dev)
/* this will free the backing object */ /* this will free the backing object */
if (fbdev->fb) { if (fbdev->fb) {
msm_gem_put_vaddr(fbdev->bo); struct drm_gem_object *bo =
msm_framebuffer_bo(fbdev->fb, 0);
msm_gem_put_vaddr(bo);
drm_framebuffer_remove(fbdev->fb); drm_framebuffer_remove(fbdev->fb);
} }
......
...@@ -1024,3 +1024,49 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, ...@@ -1024,3 +1024,49 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
drm_gem_object_unreference_unlocked(obj); drm_gem_object_unreference_unlocked(obj);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
uint32_t flags, struct msm_gem_address_space *aspace,
struct drm_gem_object **bo, uint64_t *iova, bool locked)
{
void *vaddr;
struct drm_gem_object *obj = _msm_gem_new(dev, size, flags, locked);
int ret;
if (IS_ERR(obj))
return ERR_CAST(obj);
if (iova) {
ret = msm_gem_get_iova(obj, aspace, iova);
if (ret) {
drm_gem_object_unreference(obj);
return ERR_PTR(ret);
}
}
vaddr = msm_gem_get_vaddr(obj);
if (!vaddr) {
msm_gem_put_iova(obj, aspace);
drm_gem_object_unreference(obj);
return ERR_PTR(-ENOMEM);
}
if (bo)
*bo = obj;
return vaddr;
}
void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
uint32_t flags, struct msm_gem_address_space *aspace,
struct drm_gem_object **bo, uint64_t *iova)
{
return _msm_gem_kernel_new(dev, size, flags, aspace, bo, iova, false);
}
void *msm_gem_kernel_new_locked(struct drm_device *dev, uint32_t size,
uint32_t flags, struct msm_gem_address_space *aspace,
struct drm_gem_object **bo, uint64_t *iova)
{
return _msm_gem_kernel_new(dev, size, flags, aspace, bo, iova, true);
}
...@@ -562,11 +562,49 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) ...@@ -562,11 +562,49 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu)
return 0; return 0;
} }
static struct msm_gem_address_space *
msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev,
uint64_t va_start, uint64_t va_end)
{
struct iommu_domain *iommu;
struct msm_gem_address_space *aspace;
int ret;
/*
* Setup IOMMU.. eventually we will (I think) do this once per context
* and have separate page tables per context. For now, to keep things
* simple and to get something working, just use a single address space:
*/
iommu = iommu_domain_alloc(&platform_bus_type);
if (!iommu)
return NULL;
iommu->geometry.aperture_start = va_start;
iommu->geometry.aperture_end = va_end;
dev_info(gpu->dev->dev, "%s: using IOMMU\n", gpu->name);
aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu");
if (IS_ERR(aspace)) {
dev_err(gpu->dev->dev, "failed to init iommu: %ld\n",
PTR_ERR(aspace));
iommu_domain_free(iommu);
return ERR_CAST(aspace);
}
ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0);
if (ret) {
msm_gem_address_space_put(aspace);
return ERR_PTR(ret);
}
return aspace;
}
int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs,
const char *name, struct msm_gpu_config *config) const char *name, struct msm_gpu_config *config)
{ {
struct iommu_domain *iommu;
int ret; int ret;
if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs))) if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs)))
...@@ -636,28 +674,19 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, ...@@ -636,28 +674,19 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
if (IS_ERR(gpu->gpu_cx)) if (IS_ERR(gpu->gpu_cx))
gpu->gpu_cx = NULL; gpu->gpu_cx = NULL;
/* Setup IOMMU.. eventually we will (I think) do this once per context gpu->pdev = pdev;
* and have separate page tables per context. For now, to keep things platform_set_drvdata(pdev, gpu);
* simple and to get something working, just use a single address space:
*/ bs_init(gpu);
iommu = iommu_domain_alloc(&platform_bus_type);
if (iommu) {
iommu->geometry.aperture_start = config->va_start;
iommu->geometry.aperture_end = config->va_end;
dev_info(drm->dev, "%s: using IOMMU\n", name);
gpu->aspace = msm_gem_address_space_create(&pdev->dev,
iommu, "gpu");
if (IS_ERR(gpu->aspace)) {
ret = PTR_ERR(gpu->aspace);
dev_err(drm->dev, "failed to init iommu: %d\n", ret);
gpu->aspace = NULL;
iommu_domain_free(iommu);
goto fail;
}
} else { gpu->aspace = msm_gpu_create_address_space(gpu, pdev,
config->va_start, config->va_end);
if (gpu->aspace == NULL)
dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name);
else if (IS_ERR(gpu->aspace)) {
ret = PTR_ERR(gpu->aspace);
goto fail;
} }
/* Create ringbuffer: */ /* Create ringbuffer: */
...@@ -669,14 +698,10 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, ...@@ -669,14 +698,10 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
goto fail; goto fail;
} }
gpu->pdev = pdev;
platform_set_drvdata(pdev, gpu);
bs_init(gpu);
return 0; return 0;
fail: fail:
platform_set_drvdata(pdev, NULL);
return ret; return ret;
} }
...@@ -693,7 +718,9 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) ...@@ -693,7 +718,9 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)
msm_gem_put_iova(gpu->rb->bo, gpu->aspace); msm_gem_put_iova(gpu->rb->bo, gpu->aspace);
msm_ringbuffer_destroy(gpu->rb); msm_ringbuffer_destroy(gpu->rb);
} }
if (gpu->aspace) {
if (gpu->fctx) gpu->aspace->mmu->funcs->detach(gpu->aspace->mmu,
msm_fence_context_free(gpu->fctx); NULL, 0);
msm_gem_address_space_put(gpu->aspace);
}
} }
...@@ -99,5 +99,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev); ...@@ -99,5 +99,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev);
struct msm_kms *mdp5_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev);
int msm_mdss_init(struct drm_device *dev); int msm_mdss_init(struct drm_device *dev);
void msm_mdss_destroy(struct drm_device *dev); void msm_mdss_destroy(struct drm_device *dev);
int msm_mdss_enable(struct msm_mdss *mdss);
int msm_mdss_disable(struct msm_mdss *mdss);
#endif /* __MSM_KMS_H__ */ #endif /* __MSM_KMS_H__ */
...@@ -33,16 +33,14 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) ...@@ -33,16 +33,14 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size)
} }
ring->gpu = gpu; ring->gpu = gpu;
ring->bo = msm_gem_new(gpu->dev, size, MSM_BO_WC);
if (IS_ERR(ring->bo)) {
ret = PTR_ERR(ring->bo);
ring->bo = NULL;
goto fail;
}
ring->start = msm_gem_get_vaddr(ring->bo); /* Pass NULL for the iova pointer - we will map it later */
ring->start = msm_gem_kernel_new(gpu->dev, size, MSM_BO_WC,
gpu->aspace, &ring->bo, NULL);
if (IS_ERR(ring->start)) { if (IS_ERR(ring->start)) {
ret = PTR_ERR(ring->start); ret = PTR_ERR(ring->start);
ring->start = 0;
goto fail; goto fail;
} }
ring->end = ring->start + (size / 4); ring->end = ring->start + (size / 4);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册