aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_crtc.c63
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.h18
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h3
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c15
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_plane.c84
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c10
-rw-r--r--drivers/gpu/drm/armada/armada_510.c130
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c214
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.h21
-rw-r--r--drivers/gpu/drm/armada/armada_debugfs.c98
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h1
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c38
-rw-r--r--drivers/gpu/drm/armada/armada_hw.h29
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c56
-rw-r--r--drivers/gpu/drm/armada/armada_plane.c124
-rw-r--r--drivers/gpu/drm/armada/armada_plane.h23
-rw-r--r--drivers/gpu/drm/bochs/bochs.h2
-rw-r--r--drivers/gpu/drm/bochs/bochs_hw.c14
-rw-r--r--drivers/gpu/drm/bochs/bochs_kms.c3
-rw-r--r--drivers/gpu/drm/bridge/ti-tfp410.c10
-rw-r--r--drivers/gpu/drm/drm_client_modeset.c3
-rw-r--r--drivers/gpu/drm/drm_connector.c2
-rw-r--r--drivers/gpu/drm/drm_modes.c14
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c12
-rw-r--r--drivers/gpu/drm/exynos/Kconfig6
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp.c13
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dma.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c21
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c15
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c14
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c13
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c22
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_scaler.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c9
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c41
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c31
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c1
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx_gpu.c24
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx.xml.h28
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_debugfs.c8
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c40
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_power.c76
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.c70
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.h1
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu.c16
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu.h2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c20
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c8
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h6
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c176
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h4
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c14
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c5
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c110
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c6
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c46
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h6
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c57
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c6
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h22
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c4
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c3
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c38
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c3
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.c2
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h7
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_cfg.c21
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_cfg.h1
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c19
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c149
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.c6
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.h5
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c30
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c106
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c34
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h1
-rw-r--r--drivers/gpu/drm/msm/msm_fb.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c6
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h1
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c5
-rw-r--r--drivers/gpu/drm/msm/msm_iommu.c2
-rw-r--r--drivers/gpu/drm/msm/msm_perf.c15
-rw-r--r--drivers/gpu/drm/msm/msm_rd.c16
-rw-r--r--drivers/gpu/drm/selftests/test-drm_cmdline_parser.c136
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c1
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c169
-rw-r--r--drivers/gpu/drm/vmwgfx/Kconfig1
-rw-r--r--drivers/gpu/drm/vmwgfx/Makefile2
-rw-r--r--drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h233
-rw-r--r--drivers/gpu/drm/vmwgfx/ttm_lock.c100
-rw-r--r--drivers/gpu/drm/vmwgfx/ttm_lock.h30
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.c12
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_context.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c167
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h139
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c23
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c472
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c245
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h15
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_shader.c8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c405
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_validation.c74
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_validation.h16
120 files changed, 1944 insertions, 2849 deletions
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index 3f222f464eb2..f4400788ab94 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -454,24 +454,6 @@ static void komeda_crtc_vblank_disable(struct drm_crtc *crtc)
mdev->funcs->on_off_vblank(mdev, kcrtc->master->id, false);
}
-static int
-komeda_crtc_atomic_get_property(struct drm_crtc *crtc,
- const struct drm_crtc_state *state,
- struct drm_property *property, uint64_t *val)
-{
- struct komeda_crtc *kcrtc = to_kcrtc(crtc);
- struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(state);
-
- if (property == kcrtc->clock_ratio_property) {
- *val = kcrtc_st->clock_ratio;
- } else {
- DRM_DEBUG_DRIVER("Unknown property %s\n", property->name);
- return -EINVAL;
- }
-
- return 0;
-}
-
static const struct drm_crtc_funcs komeda_crtc_funcs = {
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = drm_crtc_cleanup,
@@ -482,7 +464,6 @@ static const struct drm_crtc_funcs komeda_crtc_funcs = {
.atomic_destroy_state = komeda_crtc_atomic_destroy_state,
.enable_vblank = komeda_crtc_vblank_enable,
.disable_vblank = komeda_crtc_vblank_disable,
- .atomic_get_property = komeda_crtc_atomic_get_property,
};
int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
@@ -518,42 +499,6 @@ int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
return 0;
}
-static int komeda_crtc_create_clock_ratio_property(struct komeda_crtc *kcrtc)
-{
- struct drm_crtc *crtc = &kcrtc->base;
- struct drm_property *prop;
-
- prop = drm_property_create_range(crtc->dev, DRM_MODE_PROP_ATOMIC,
- "CLOCK_RATIO", 0, U64_MAX);
- if (!prop)
- return -ENOMEM;
-
- drm_object_attach_property(&crtc->base, prop, 0);
- kcrtc->clock_ratio_property = prop;
-
- return 0;
-}
-
-static int komeda_crtc_create_slave_planes_property(struct komeda_crtc *kcrtc)
-{
- struct drm_crtc *crtc = &kcrtc->base;
- struct drm_property *prop;
-
- if (kcrtc->slave_planes == 0)
- return 0;
-
- prop = drm_property_create_range(crtc->dev, DRM_MODE_PROP_IMMUTABLE,
- "slave_planes", 0, U32_MAX);
- if (!prop)
- return -ENOMEM;
-
- drm_object_attach_property(&crtc->base, prop, kcrtc->slave_planes);
-
- kcrtc->slave_planes_property = prop;
-
- return 0;
-}
-
static struct drm_plane *
get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
{
@@ -590,14 +535,6 @@ static int komeda_crtc_add(struct komeda_kms_dev *kms,
crtc->port = kcrtc->master->of_output_port;
- err = komeda_crtc_create_clock_ratio_property(kcrtc);
- if (err)
- return err;
-
- err = komeda_crtc_create_slave_planes_property(kcrtc);
- if (err)
- return err;
-
return err;
}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
index 219fa3f0c336..8c89fc245b83 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -33,11 +33,6 @@ struct komeda_plane {
* Layers with same capabilities.
*/
struct komeda_layer *layer;
-
- /** @prop_img_enhancement: for on/off image enhancement */
- struct drm_property *prop_img_enhancement;
- /** @prop_layer_split: for on/off layer_split */
- struct drm_property *prop_layer_split;
};
/**
@@ -52,11 +47,8 @@ struct komeda_plane_state {
/** @zlist_node: zorder list node */
struct list_head zlist_node;
- /* @img_enhancement: on/off image enhancement
- * @layer_split: on/off layer_split
- */
- u8 img_enhancement : 1,
- layer_split : 1;
+ /** @layer_split: on/off layer_split */
+ u8 layer_split : 1;
};
/**
@@ -94,12 +86,6 @@ struct komeda_crtc {
/** @disable_done: this flip_done is for tracing the disable */
struct completion *disable_done;
-
- /** @clock_ratio_property: property for ratio of (aclk << 32)/pxlclk */
- struct drm_property *clock_ratio_property;
-
- /** @slave_planes_property: property for slaves of the planes */
- struct drm_property *slave_planes_property;
};
/**
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index fc1b8613385e..a90bcbb3cb23 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -537,7 +537,8 @@ void komeda_pipeline_disable(struct komeda_pipeline *pipe,
void komeda_pipeline_update(struct komeda_pipeline *pipe,
struct drm_atomic_state *old_state);
-void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
+void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
+ struct komeda_data_flow_cfg *dflow,
struct drm_framebuffer *fb);
#endif /* _KOMEDA_PIPELINE_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
index 2b415ef2b7d3..950235af1e79 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -784,9 +784,11 @@ komeda_timing_ctrlr_validate(struct komeda_timing_ctrlr *ctrlr,
return 0;
}
-void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
+void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
+ struct komeda_data_flow_cfg *dflow,
struct drm_framebuffer *fb)
{
+ struct komeda_scaler *scaler = layer->base.pipeline->scalers[0];
u32 w = dflow->in_w;
u32 h = dflow->in_h;
@@ -803,6 +805,17 @@ void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
dflow->en_scaling = (w != dflow->out_w) || (h != dflow->out_h);
dflow->is_yuv = fb->format->is_yuv;
+
+ /* try to enable image enhancer if data flow is a 2x+ upscaling */
+ dflow->en_img_enhancement = dflow->out_w >= 2 * w ||
+ dflow->out_h >= 2 * h;
+
+ /* try to enable split if scaling exceed the scaler's acceptable
+ * input/output range.
+ */
+ if (dflow->en_scaling && scaler)
+ dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) ||
+ !in_range(&scaler->hsize, dflow->out_w);
}
static bool merger_is_available(struct komeda_pipeline *pipe,
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
index 04b122f28fb6..c095af154216 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -18,7 +18,6 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
struct komeda_data_flow_cfg *dflow)
{
struct komeda_plane *kplane = to_kplane(st->plane);
- struct komeda_plane_state *kplane_st = to_kplane_st(st);
struct drm_framebuffer *fb = st->fb;
const struct komeda_format_caps *caps = to_kfb(fb)->format_caps;
struct komeda_pipeline *pipe = kplane->layer->base.pipeline;
@@ -57,10 +56,7 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
return -EINVAL;
}
- dflow->en_img_enhancement = !!kplane_st->img_enhancement;
- dflow->en_split = !!kplane_st->layer_split;
-
- komeda_complete_data_flow_cfg(dflow, fb);
+ komeda_complete_data_flow_cfg(kplane->layer, dflow, fb);
return 0;
}
@@ -175,8 +171,6 @@ komeda_plane_atomic_duplicate_state(struct drm_plane *plane)
old = to_kplane_st(plane->state);
- new->img_enhancement = old->img_enhancement;
-
return &new->base;
}
@@ -188,44 +182,6 @@ komeda_plane_atomic_destroy_state(struct drm_plane *plane,
kfree(to_kplane_st(state));
}
-static int
-komeda_plane_atomic_get_property(struct drm_plane *plane,
- const struct drm_plane_state *state,
- struct drm_property *property,
- uint64_t *val)
-{
- struct komeda_plane *kplane = to_kplane(plane);
- struct komeda_plane_state *st = to_kplane_st(state);
-
- if (property == kplane->prop_img_enhancement)
- *val = st->img_enhancement;
- else if (property == kplane->prop_layer_split)
- *val = st->layer_split;
- else
- return -EINVAL;
-
- return 0;
-}
-
-static int
-komeda_plane_atomic_set_property(struct drm_plane *plane,
- struct drm_plane_state *state,
- struct drm_property *property,
- uint64_t val)
-{
- struct komeda_plane *kplane = to_kplane(plane);
- struct komeda_plane_state *st = to_kplane_st(state);
-
- if (property == kplane->prop_img_enhancement)
- st->img_enhancement = !!val;
- else if (property == kplane->prop_layer_split)
- st->layer_split = !!val;
- else
- return -EINVAL;
-
- return 0;
-}
-
static bool
komeda_plane_format_mod_supported(struct drm_plane *plane,
u32 format, u64 modifier)
@@ -245,43 +201,9 @@ static const struct drm_plane_funcs komeda_plane_funcs = {
.reset = komeda_plane_reset,
.atomic_duplicate_state = komeda_plane_atomic_duplicate_state,
.atomic_destroy_state = komeda_plane_atomic_destroy_state,
- .atomic_get_property = komeda_plane_atomic_get_property,
- .atomic_set_property = komeda_plane_atomic_set_property,
.format_mod_supported = komeda_plane_format_mod_supported,
};
-static int
-komeda_plane_create_layer_properties(struct komeda_plane *kplane,
- struct komeda_layer *layer)
-{
- struct drm_device *drm = kplane->base.dev;
- struct drm_plane *plane = &kplane->base;
- struct drm_property *prop = NULL;
-
- /* property: layer image_enhancement */
- if (layer->base.supported_outputs & KOMEDA_PIPELINE_SCALERS) {
- prop = drm_property_create_bool(drm, DRM_MODE_PROP_ATOMIC,
- "img_enhancement");
- if (!prop)
- return -ENOMEM;
-
- drm_object_attach_property(&plane->base, prop, 0);
- kplane->prop_img_enhancement = prop;
- }
-
- /* property: layer split */
- if (layer->right) {
- prop = drm_property_create_bool(drm, DRM_MODE_PROP_ATOMIC,
- "layer_split");
- if (!prop)
- return -ENOMEM;
- kplane->prop_layer_split = prop;
- drm_object_attach_property(&plane->base, prop, 0);
- }
-
- return 0;
-}
-
/* for komeda, which is pipeline can be share between crtcs */
static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
struct komeda_pipeline *pipe)
@@ -375,10 +297,6 @@ static int komeda_plane_add(struct komeda_kms_dev *kms,
if (err)
goto cleanup;
- err = komeda_plane_create_layer_properties(kplane, layer);
- if (err)
- goto cleanup;
-
err = drm_plane_create_color_properties(plane,
BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709) |
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
index bb8a61f6e9a4..617e1f7b8472 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
@@ -13,7 +13,6 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer,
struct komeda_crtc_state *kcrtc_st,
struct komeda_data_flow_cfg *dflow)
{
- struct komeda_scaler *scaler = wb_layer->base.pipeline->scalers[0];
struct drm_framebuffer *fb = conn_st->writeback_job->fb;
memset(dflow, 0, sizeof(*dflow));
@@ -28,14 +27,7 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer,
dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
dflow->rot = DRM_MODE_ROTATE_0;
- komeda_complete_data_flow_cfg(dflow, fb);
-
- /* if scaling exceed the acceptable scaler input/output range, try to
- * enable split.
- */
- if (dflow->en_scaling && scaler)
- dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) ||
- !in_range(&scaler->hsize, dflow->out_w);
+ komeda_complete_data_flow_cfg(wb_layer, dflow, fb);
return 0;
}
diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c
index 0e91d27921bd..6f8ad8fb19f1 100644
--- a/drivers/gpu/drm/armada/armada_510.c
+++ b/drivers/gpu/drm/armada/armada_510.c
@@ -14,18 +14,62 @@
#include "armada_drm.h"
#include "armada_hw.h"
+struct armada510_variant_data {
+ struct clk *clks[4];
+ struct clk *sel_clk;
+};
+
static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
{
+ struct armada510_variant_data *v;
struct clk *clk;
+ int idx;
+
+ v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL);
+ if (!v)
+ return -ENOMEM;
+
+ dcrtc->variant_data = v;
+
+ if (dev->of_node) {
+ struct property *prop;
+ const char *s;
+
+ of_property_for_each_string(dev->of_node, "clock-names", prop,
+ s) {
+ if (!strcmp(s, "ext_ref_clk0"))
+ idx = 0;
+ else if (!strcmp(s, "ext_ref_clk1"))
+ idx = 1;
+ else if (!strcmp(s, "plldivider"))
+ idx = 2;
+ else if (!strcmp(s, "axibus"))
+ idx = 3;
+ else
+ continue;
+
+ clk = devm_clk_get(dev, s);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
+ PTR_ERR(clk);
+ v->clks[idx] = clk;
+ }
+ } else {
+ clk = devm_clk_get(dev, "ext_ref_clk1");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
+ PTR_ERR(clk);
+
+ v->clks[1] = clk;
+ }
- clk = devm_clk_get(dev, "ext_ref_clk1");
- if (IS_ERR(clk))
- return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk);
-
- dcrtc->extclk[0] = clk;
-
- /* Lower the watermark so to eliminate jitter at higher bandwidths */
- armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F);
+ /*
+ * Lower the watermark so to eliminate jitter at higher bandwidths.
+ * Disable SRAM read wait state to avoid system hang with external
+ * clock.
+ */
+ armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK,
+ dcrtc->base + LCD_CFG_RDREG4F);
/* Initialise SPU register */
writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
@@ -34,65 +78,77 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
return 0;
}
+static const u32 armada510_clk_sels[] = {
+ SCLK_510_EXTCLK0,
+ SCLK_510_EXTCLK1,
+ SCLK_510_PLL,
+ SCLK_510_AXI,
+};
+
+static const struct armada_clocking_params armada510_clocking = {
+ /* HDMI requires -0.6%..+0.5% */
+ .permillage_min = 994,
+ .permillage_max = 1005,
+ .settable = BIT(0) | BIT(1),
+ .div_max = SCLK_510_INT_DIV_MASK,
+};
+
/*
* Armada510 specific SCLK register selection.
* This gets called with sclk = NULL to test whether the mode is
* supportable, and again with sclk != NULL to set the clocks up for
* that. The former can return an error, but the latter is expected
* not to.
- *
- * We currently are pretty rudimentary here, always selecting
- * EXT_REF_CLK_1 for LCD0 and erroring LCD1. This needs improvement!
*/
static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
const struct drm_display_mode *mode, uint32_t *sclk)
{
- struct clk *clk = dcrtc->extclk[0];
- int ret;
+ struct armada510_variant_data *v = dcrtc->variant_data;
+ unsigned long desired_khz = mode->crtc_clock;
+ struct armada_clk_result res;
+ int ret, idx;
- if (dcrtc->num == 1)
- return -EINVAL;
+ idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking,
+ v->clks, ARRAY_SIZE(v->clks),
+ desired_khz);
+ if (idx < 0)
+ return idx;
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- if (dcrtc->clk != clk) {
- ret = clk_prepare_enable(clk);
- if (ret)
- return ret;
- dcrtc->clk = clk;
- }
+ ret = clk_prepare_enable(res.clk);
+ if (ret)
+ return ret;
if (sclk) {
- uint32_t rate, ref, div;
+ clk_set_rate(res.clk, res.desired_clk_hz);
- rate = mode->clock * 1000;
- ref = clk_round_rate(clk, rate);
- div = DIV_ROUND_UP(ref, rate);
- if (div < 1)
- div = 1;
+ *sclk = res.div | armada510_clk_sels[idx];
- clk_set_rate(clk, ref);
- *sclk = div | SCLK_510_EXTCLK1;
+ /* We are now using this clock */
+ v->sel_clk = res.clk;
+ swap(dcrtc->clk, res.clk);
}
+ clk_disable_unprepare(res.clk);
+
return 0;
}
static void armada510_crtc_disable(struct armada_crtc *dcrtc)
{
- if (!IS_ERR(dcrtc->clk)) {
+ if (dcrtc->clk) {
clk_disable_unprepare(dcrtc->clk);
- dcrtc->clk = ERR_PTR(-EINVAL);
+ dcrtc->clk = NULL;
}
}
static void armada510_crtc_enable(struct armada_crtc *dcrtc,
const struct drm_display_mode *mode)
{
- if (IS_ERR(dcrtc->clk)) {
- dcrtc->clk = dcrtc->extclk[0];
- WARN_ON(clk_prepare_enable(dcrtc->clk));
+ struct armada510_variant_data *v = dcrtc->variant_data;
+
+ if (!dcrtc->clk && v->sel_clk) {
+ if (!WARN_ON(clk_prepare_enable(v->sel_clk)))
+ dcrtc->clk = v->sel_clk;
}
}
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index ba4a3fab7745..2e17d7e72eeb 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -130,6 +130,70 @@ static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc)
}
}
+static void armada_drm_update_gamma(struct drm_crtc *crtc)
+{
+ struct drm_property_blob *blob = crtc->state->gamma_lut;
+ void __iomem *base = drm_to_armada_crtc(crtc)->base;
+ int i;
+
+ if (blob) {
+ struct drm_color_lut *lut = blob->data;
+
+ armada_updatel(CFG_CSB_256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
+ base + LCD_SPU_SRAM_PARA1);
+
+ for (i = 0; i < 256; i++) {
+ writel_relaxed(drm_color_lut_extract(lut[i].red, 8),
+ base + LCD_SPU_SRAM_WRDAT);
+ writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_YR,
+ base + LCD_SPU_SRAM_CTRL);
+ readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
+ writel_relaxed(drm_color_lut_extract(lut[i].green, 8),
+ base + LCD_SPU_SRAM_WRDAT);
+ writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_UG,
+ base + LCD_SPU_SRAM_CTRL);
+ readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
+ writel_relaxed(drm_color_lut_extract(lut[i].blue, 8),
+ base + LCD_SPU_SRAM_WRDAT);
+ writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_VB,
+ base + LCD_SPU_SRAM_CTRL);
+ readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
+ }
+ armada_updatel(CFG_GAMMA_ENA, CFG_GAMMA_ENA,
+ base + LCD_SPU_DMA_CTRL0);
+ } else {
+ armada_updatel(0, CFG_GAMMA_ENA, base + LCD_SPU_DMA_CTRL0);
+ armada_updatel(CFG_PDWN256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
+ base + LCD_SPU_SRAM_PARA1);
+ }
+}
+
+static enum drm_mode_status armada_drm_crtc_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
+
+ if (mode->vscan > 1)
+ return MODE_NO_VSCAN;
+
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ return MODE_NO_DBLESCAN;
+
+ if (mode->flags & DRM_MODE_FLAG_HSKEW)
+ return MODE_H_ILLEGAL;
+
+ /* We can't do interlaced modes if we don't have the SPU_ADV_REG */
+ if (!dcrtc->variant->has_spu_adv_reg &&
+ mode->flags & DRM_MODE_FLAG_INTERLACE)
+ return MODE_NO_INTERLACE;
+
+ if (mode->flags & (DRM_MODE_FLAG_BCAST | DRM_MODE_FLAG_PIXMUX |
+ DRM_MODE_FLAG_CLKDIV2))
+ return MODE_BAD;
+
+ return MODE_OK;
+}
+
/* The mode_config.mutex will be held for this call */
static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode, struct drm_display_mode *adj)
@@ -137,9 +201,18 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
int ret;
- /* We can't do interlaced modes if we don't have the SPU_ADV_REG */
- if (!dcrtc->variant->has_spu_adv_reg &&
- adj->flags & DRM_MODE_FLAG_INTERLACE)
+ /*
+ * Set CRTC modesetting parameters for the adjusted mode. This is
+ * applied after the connectors, bridges, and encoders have fixed up
+ * this mode, as described above drm_atomic_helper_check_modeset().
+ */
+ drm_mode_set_crtcinfo(adj, CRTC_INTERLACE_HALVE_V);
+
+ /*
+ * Validate the adjusted mode in case an encoder/bridge has set
+ * something we don't support.
+ */
+ if (armada_drm_crtc_mode_valid(crtc, adj) != MODE_OK)
return false;
/* Check whether the display mode is possible */
@@ -278,16 +351,9 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV);
- if (interlaced ^ dcrtc->interlaced) {
- if (adj->flags & DRM_MODE_FLAG_INTERLACE)
- drm_crtc_vblank_get(&dcrtc->crtc);
- else
- drm_crtc_vblank_put(&dcrtc->crtc);
- dcrtc->interlaced = interlaced;
- }
-
spin_lock_irqsave(&dcrtc->irq_lock, flags);
+ dcrtc->interlaced = interlaced;
/* Even interlaced/progressive frame */
dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 |
adj->crtc_htotal;
@@ -345,6 +411,20 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
}
+static int armada_drm_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
+
+ if (state->gamma_lut && drm_color_lut_size(state->gamma_lut) != 256)
+ return -EINVAL;
+
+ if (state->color_mgmt_changed)
+ state->planes_changed = true;
+
+ return 0;
+}
+
static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
@@ -352,6 +432,9 @@ static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
+ if (crtc->state->color_mgmt_changed)
+ armada_drm_update_gamma(crtc);
+
dcrtc->regs_idx = 0;
dcrtc->regs = dcrtc->atomic_regs;
}
@@ -390,6 +473,9 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc,
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
+ if (old_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+ drm_crtc_vblank_put(crtc);
+
drm_crtc_vblank_off(crtc);
armada_drm_crtc_update(dcrtc, false);
@@ -434,12 +520,17 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc,
armada_drm_crtc_update(dcrtc, true);
drm_crtc_vblank_on(crtc);
+ if (crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+ WARN_ON(drm_crtc_vblank_get(crtc));
+
armada_drm_crtc_queue_state_event(crtc);
}
static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
+ .mode_valid = armada_drm_crtc_mode_valid,
.mode_fixup = armada_drm_crtc_mode_fixup,
.mode_set_nofb = armada_drm_crtc_mode_set_nofb,
+ .atomic_check = armada_drm_crtc_atomic_check,
.atomic_begin = armada_drm_crtc_atomic_begin,
.atomic_flush = armada_drm_crtc_atomic_flush,
.atomic_disable = armada_drm_crtc_atomic_disable,
@@ -460,6 +551,13 @@ static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
for (x = 0; x < width; x++, p++) {
uint32_t val = *p;
+ /*
+ * In "ARGB888" (HWC32) mode, writing to the SRAM
+ * requires these bits to contain:
+ * 31:24 = alpha 23:16 = blue 15:8 = green 7:0 = red
+ * So, it's actually ABGR8888. This is independent
+ * of the SWAPRB bits in DMA control register 0.
+ */
val = (val & 0xff00ff00) |
(val & 0x000000ff) << 16 |
(val & 0x00ff0000) >> 16;
@@ -676,6 +774,14 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
kfree(dcrtc);
}
+static int armada_drm_crtc_late_register(struct drm_crtc *crtc)
+{
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ armada_drm_crtc_debugfs_init(drm_to_armada_crtc(crtc));
+
+ return 0;
+}
+
/* These are called under the vbl_lock. */
static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc)
{
@@ -703,14 +809,93 @@ static const struct drm_crtc_funcs armada_crtc_funcs = {
.cursor_set = armada_drm_crtc_cursor_set,
.cursor_move = armada_drm_crtc_cursor_move,
.destroy = armada_drm_crtc_destroy,
+ .gamma_set = drm_atomic_helper_legacy_gamma_set,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .late_register = armada_drm_crtc_late_register,
.enable_vblank = armada_drm_crtc_enable_vblank,
.disable_vblank = armada_drm_crtc_disable_vblank,
};
+int armada_crtc_select_clock(struct armada_crtc *dcrtc,
+ struct armada_clk_result *res,
+ const struct armada_clocking_params *params,
+ struct clk *clks[], size_t num_clks,
+ unsigned long desired_khz)
+{
+ unsigned long desired_hz = desired_khz * 1000;
+ unsigned long desired_clk_hz; // requested clk input
+ unsigned long real_clk_hz; // actual clk input
+ unsigned long real_hz; // actual pixel clk
+ unsigned long permillage;
+ struct clk *clk;
+ u32 div;
+ int i;
+
+ DRM_DEBUG_KMS("[CRTC:%u:%s] desired clock=%luHz\n",
+ dcrtc->crtc.base.id, dcrtc->crtc.name, desired_hz);
+
+ for (i = 0; i < num_clks; i++) {
+ clk = clks[i];
+ if (!clk)
+ continue;
+
+ if (params->settable & BIT(i)) {
+ real_clk_hz = clk_round_rate(clk, desired_hz);
+ desired_clk_hz = desired_hz;
+ } else {
+ real_clk_hz = clk_get_rate(clk);
+ desired_clk_hz = real_clk_hz;
+ }
+
+ /* If the clock can do exactly the desired rate, we're done */
+ if (real_clk_hz == desired_hz) {
+ real_hz = real_clk_hz;
+ div = 1;
+ goto found;
+ }
+
+ /* Calculate the divider - if invalid, we can't do this rate */
+ div = DIV_ROUND_CLOSEST(real_clk_hz, desired_hz);
+ if (div == 0 || div > params->div_max)
+ continue;
+
+ /* Calculate the actual rate - HDMI requires -0.6%..+0.5% */
+ real_hz = DIV_ROUND_CLOSEST(real_clk_hz, div);
+
+ DRM_DEBUG_KMS("[CRTC:%u:%s] clk=%u %luHz div=%u real=%luHz\n",
+ dcrtc->crtc.base.id, dcrtc->crtc.name,
+ i, real_clk_hz, div, real_hz);
+
+ /* Avoid repeated division */
+ if (real_hz < desired_hz) {
+ permillage = real_hz / desired_khz;
+ if (permillage < params->permillage_min)
+ continue;
+ } else {
+ permillage = DIV_ROUND_UP(real_hz, desired_khz);
+ if (permillage > params->permillage_max)
+ continue;
+ }
+ goto found;
+ }
+
+ return -ERANGE;
+
+found:
+ DRM_DEBUG_KMS("[CRTC:%u:%s] selected clk=%u %luHz div=%u real=%luHz\n",
+ dcrtc->crtc.base.id, dcrtc->crtc.name,
+ i, real_clk_hz, div, real_hz);
+
+ res->desired_clk_hz = desired_clk_hz;
+ res->clk = clk;
+ res->div = div;
+
+ return i;
+}
+
static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
struct resource *res, int irq, const struct armada_variant *variant,
struct device_node *port)
@@ -737,7 +922,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
dcrtc->variant = variant;
dcrtc->base = base;
dcrtc->num = drm->mode_config.num_crtc;
- dcrtc->clk = ERR_PTR(-EINVAL);
dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0;
dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
spin_lock_init(&dcrtc->irq_lock);
@@ -794,6 +978,12 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
+ ret = drm_mode_crtc_set_gamma_size(&dcrtc->crtc, 256);
+ if (ret)
+ return ret;
+
+ drm_crtc_enable_color_mgmt(&dcrtc->crtc, 0, false, 256);
+
return armada_overlay_plane_create(drm, 1 << dcrtc->num);
err_crtc_init:
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index 08761ff01739..fb4aa48da60c 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -39,10 +39,10 @@ struct armada_variant;
struct armada_crtc {
struct drm_crtc crtc;
const struct armada_variant *variant;
+ void *variant_data;
unsigned num;
void __iomem *base;
struct clk *clk;
- struct clk *extclk[2];
struct {
uint32_t spu_v_h_total;
uint32_t spu_v_porch;
@@ -75,6 +75,25 @@ struct armada_crtc {
void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
+struct armada_clocking_params {
+ unsigned long permillage_min;
+ unsigned long permillage_max;
+ u32 settable;
+ u32 div_max;
+};
+
+struct armada_clk_result {
+ unsigned long desired_clk_hz;
+ struct clk *clk;
+ u32 div;
+};
+
+int armada_crtc_select_clock(struct armada_crtc *dcrtc,
+ struct armada_clk_result *res,
+ const struct armada_clocking_params *params,
+ struct clk *clks[], size_t num_clks,
+ unsigned long desired_khz);
+
extern struct platform_driver armada_lcd_platform_driver;
#endif
diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c
index 6758c3a83de2..4dcce002ea2a 100644
--- a/drivers/gpu/drm/armada/armada_debugfs.c
+++ b/drivers/gpu/drm/armada/armada_debugfs.c
@@ -28,50 +28,33 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data)
return 0;
}
-static int armada_debugfs_reg_show(struct seq_file *m, void *data)
+static int armada_debugfs_crtc_reg_show(struct seq_file *m, void *data)
{
- struct drm_device *dev = m->private;
- struct armada_private *priv = dev->dev_private;
- int n, i;
-
- if (priv) {
- for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) {
- struct armada_crtc *dcrtc = priv->dcrtc[n];
- if (!dcrtc)
- continue;
-
- for (i = 0x84; i <= 0x1c4; i += 4) {
- uint32_t v = readl_relaxed(dcrtc->base + i);
- seq_printf(m, "%u: 0x%04x: 0x%08x\n", n, i, v);
- }
- }
+ struct armada_crtc *dcrtc = m->private;
+ int i;
+
+ for (i = 0x84; i <= 0x1c4; i += 4) {
+ u32 v = readl_relaxed(dcrtc->base + i);
+ seq_printf(m, "0x%04x: 0x%08x\n", i, v);
}
return 0;
}
-static int armada_debugfs_reg_r_open(struct inode *inode, struct file *file)
+static int armada_debugfs_crtc_reg_open(struct inode *inode, struct file *file)
{
- return single_open(file, armada_debugfs_reg_show, inode->i_private);
+ return single_open(file, armada_debugfs_crtc_reg_show,
+ inode->i_private);
}
-static const struct file_operations fops_reg_r = {
- .owner = THIS_MODULE,
- .open = armada_debugfs_reg_r_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int armada_debugfs_write(struct file *file, const char __user *ptr,
- size_t len, loff_t *off)
+static int armada_debugfs_crtc_reg_write(struct file *file,
+ const char __user *ptr, size_t len, loff_t *off)
{
- struct drm_device *dev = file->private_data;
- struct armada_private *priv = dev->dev_private;
- struct armada_crtc *dcrtc = priv->dcrtc[0];
- char buf[32], *p;
- uint32_t reg, val;
+ struct armada_crtc *dcrtc;
+ unsigned long reg, mask, val;
+ char buf[32];
int ret;
+ u32 v;
if (*off != 0)
return 0;
@@ -84,24 +67,35 @@ static int armada_debugfs_write(struct file *file, const char __user *ptr,
return ret;
buf[len] = '\0';
- reg = simple_strtoul(buf, &p, 16);
- if (!isspace(*p))
+ if (sscanf(buf, "%lx %lx %lx", &reg, &mask, &val) != 3)
return -EINVAL;
- val = simple_strtoul(p + 1, NULL, 16);
+ if (reg < 0x84 || reg > 0x1c4 || reg & 3)
+ return -ERANGE;
- if (reg >= 0x84 && reg <= 0x1c4)
- writel(val, dcrtc->base + reg);
+ dcrtc = ((struct seq_file *)file->private_data)->private;
+ v = readl(dcrtc->base + reg);
+ v &= ~mask;
+ v |= val & mask;
+ writel(v, dcrtc->base + reg);
return len;
}
-static const struct file_operations fops_reg_w = {
+static const struct file_operations armada_debugfs_crtc_reg_fops = {
.owner = THIS_MODULE,
- .open = simple_open,
- .write = armada_debugfs_write,
- .llseek = noop_llseek,
+ .open = armada_debugfs_crtc_reg_open,
+ .read = seq_read,
+ .write = armada_debugfs_crtc_reg_write,
+ .llseek = seq_lseek,
+ .release = single_release,
};
+void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc)
+{
+ debugfs_create_file("armada-regs", 0600, dcrtc->crtc.debugfs_entry,
+ dcrtc, &armada_debugfs_crtc_reg_fops);
+}
+
static struct drm_info_list armada_debugfs_list[] = {
{ "gem_linear", armada_debugfs_gem_linear_show, 0 },
};
@@ -109,24 +103,8 @@ static struct drm_info_list armada_debugfs_list[] = {
int armada_drm_debugfs_init(struct drm_minor *minor)
{
- struct dentry *de;
- int ret;
-
- ret = drm_debugfs_create_files(armada_debugfs_list,
- ARMADA_DEBUGFS_ENTRIES,
- minor->debugfs_root, minor);
- if (ret)
- return ret;
-
- de = debugfs_create_file("reg", S_IFREG | S_IRUSR,
- minor->debugfs_root, minor->dev, &fops_reg_r);
- if (!de)
- return -ENOMEM;
-
- de = debugfs_create_file("reg_wr", S_IFREG | S_IWUSR,
- minor->debugfs_root, minor->dev, &fops_reg_w);
- if (!de)
- return -ENOMEM;
+ drm_debugfs_create_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES,
+ minor->debugfs_root, minor);
return 0;
}
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index f09083ff15d3..b6307235f320 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -78,6 +78,7 @@ void armada_fbdev_fini(struct drm_device *);
int armada_overlay_plane_create(struct drm_device *, unsigned long);
+void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc);
int armada_drm_debugfs_init(struct drm_minor *);
#endif
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index e660c5ca52ae..f1729398b1bd 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -100,6 +100,17 @@ static int armada_drm_bind(struct device *dev)
return ret;
}
+ /* Remove early framebuffers */
+ ret = drm_fb_helper_remove_conflicting_framebuffers(NULL,
+ "armada-drm-fb",
+ false);
+ if (ret) {
+ dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",
+ __func__, ret);
+ kfree(priv);
+ return ret;
+ }
+
priv->drm.dev_private = priv;
dev_set_drvdata(dev, &priv->drm);
@@ -171,6 +182,8 @@ static void armada_drm_unbind(struct device *dev)
drm_dev_unregister(&priv->drm);
+ drm_atomic_helper_shutdown(&priv->drm);
+
component_unbind_all(dev, &priv->drm);
drm_mode_config_cleanup(&priv->drm);
@@ -191,23 +204,15 @@ static int compare_dev_name(struct device *dev, void *data)
}
static void armada_add_endpoints(struct device *dev,
- struct component_match **match, struct device_node *port)
+ struct component_match **match, struct device_node *dev_node)
{
struct device_node *ep, *remote;
- for_each_child_of_node(port, ep) {
+ for_each_endpoint_of_node(dev_node, ep) {
remote = of_graph_get_remote_port_parent(ep);
- if (!remote || !of_device_is_available(remote)) {
- of_node_put(remote);
- continue;
- } else if (!of_device_is_available(remote->parent)) {
- dev_warn(dev, "parent device of %pOF is not available\n",
- remote);
- of_node_put(remote);
- continue;
- }
-
- drm_of_component_match_add(dev, match, compare_of, remote);
+ if (remote && of_device_is_available(remote))
+ drm_of_component_match_add(dev, match, compare_of,
+ remote);
of_node_put(remote);
}
}
@@ -229,7 +234,6 @@ static int armada_drm_probe(struct platform_device *pdev)
if (dev->platform_data) {
char **devices = dev->platform_data;
- struct device_node *port;
struct device *d;
int i;
@@ -245,10 +249,8 @@ static int armada_drm_probe(struct platform_device *pdev)
for (i = 0; devices[i]; i++) {
d = bus_find_device_by_name(&platform_bus_type, NULL,
devices[i]);
- if (d && d->of_node) {
- for_each_child_of_node(d->of_node, port)
- armada_add_endpoints(dev, &match, port);
- }
+ if (d && d->of_node)
+ armada_add_endpoints(dev, &match, d->of_node);
put_device(d);
}
}
diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h
index 277580b36758..5b1af0cc9f50 100644
--- a/drivers/gpu/drm/armada/armada_hw.h
+++ b/drivers/gpu/drm/armada/armada_hw.h
@@ -88,6 +88,16 @@ enum {
ADV_VSYNC_H_OFF = 0xfff << 0,
};
+/* LCD_CFG_RDREG4F - Armada 510 only */
+enum {
+ CFG_SRAM_WAIT = BIT(11),
+ CFG_SMPN_FASTTX = BIT(10),
+ CFG_DMA_ARB = BIT(9),
+ CFG_DMA_WM_EN = BIT(8),
+ CFG_DMA_WM_MASK = 0xff,
+#define CFG_DMA_WM(x) ((x) & CFG_DMA_WM_MASK)
+};
+
enum {
CFG_565 = 0,
CFG_1555 = 1,
@@ -169,6 +179,10 @@ enum {
SRAM_READ = 0 << 14,
SRAM_WRITE = 2 << 14,
SRAM_INIT = 3 << 14,
+ SRAM_GAMMA_YR = 0x0 << 8,
+ SRAM_GAMMA_UG = 0x1 << 8,
+ SRAM_GAMMA_VB = 0x2 << 8,
+ SRAM_PALETTE = 0x3 << 8,
SRAM_HWC32_RAM1 = 0xc << 8,
SRAM_HWC32_RAM2 = 0xd << 8,
SRAM_HWC32_RAMR = SRAM_HWC32_RAM1,
@@ -316,19 +330,4 @@ enum {
PWRDN_IRQ_LEVEL = 1 << 0,
};
-static inline u32 armada_rect_hw_fp(struct drm_rect *r)
-{
- return (drm_rect_height(r) & 0xffff0000) | drm_rect_width(r) >> 16;
-}
-
-static inline u32 armada_rect_hw(struct drm_rect *r)
-{
- return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff);
-}
-
-static inline u32 armada_rect_yx(struct drm_rect *r)
-{
- return (r)->y1 << 16 | ((r)->x1 & 0x0000ffff);
-}
-
#endif
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index 8d770641fcc4..a79d6e940435 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -27,7 +27,7 @@
#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601
struct armada_overlay_state {
- struct drm_plane_state base;
+ struct armada_plane_state base;
u32 colorkey_yr;
u32 colorkey_ug;
u32 colorkey_vb;
@@ -38,7 +38,7 @@ struct armada_overlay_state {
u16 saturation;
};
#define drm_to_overlay_state(s) \
- container_of(s, struct armada_overlay_state, base)
+ container_of(s, struct armada_overlay_state, base.base)
static inline u32 armada_spu_contrast(struct drm_plane_state *state)
{
@@ -94,41 +94,39 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
armada_reg_queue_mod(regs, idx,
0, CFG_PDWN16x66 | CFG_PDWN32x66,
LCD_SPU_SRAM_PARA1);
- val = armada_rect_hw_fp(&state->src);
- if (armada_rect_hw_fp(&old_state->src) != val)
+ val = armada_src_hw(state);
+ if (armada_src_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
- val = armada_rect_yx(&state->dst);
- if (armada_rect_yx(&old_state->dst) != val)
+ val = armada_dst_yx(state);
+ if (armada_dst_yx(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
- val = armada_rect_hw(&state->dst);
- if (armada_rect_hw(&old_state->dst) != val)
+ val = armada_dst_hw(state);
+ if (armada_dst_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
/* FIXME: overlay on an interlaced display */
if (old_state->src.x1 != state->src.x1 ||
old_state->src.y1 != state->src.y1 ||
- old_state->fb != state->fb) {
+ old_state->fb != state->fb ||
+ state->crtc->state->mode_changed) {
const struct drm_format_info *format;
- u16 src_x, pitches[3];
- u32 addrs[2][3];
+ u16 src_x;
- armada_drm_plane_calc(state, addrs, pitches, false);
-
- armada_reg_queue_set(regs, idx, addrs[0][0],
+ armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
LCD_SPU_DMA_START_ADDR_Y0);
- armada_reg_queue_set(regs, idx, addrs[0][1],
+ armada_reg_queue_set(regs, idx, armada_addr(state, 0, 1),
LCD_SPU_DMA_START_ADDR_U0);
- armada_reg_queue_set(regs, idx, addrs[0][2],
+ armada_reg_queue_set(regs, idx, armada_addr(state, 0, 2),
LCD_SPU_DMA_START_ADDR_V0);
- armada_reg_queue_set(regs, idx, addrs[1][0],
+ armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
LCD_SPU_DMA_START_ADDR_Y1);
- armada_reg_queue_set(regs, idx, addrs[1][1],
+ armada_reg_queue_set(regs, idx, armada_addr(state, 1, 1),
LCD_SPU_DMA_START_ADDR_U1);
- armada_reg_queue_set(regs, idx, addrs[1][2],
+ armada_reg_queue_set(regs, idx, armada_addr(state, 1, 2),
LCD_SPU_DMA_START_ADDR_V1);
- val = pitches[0] << 16 | pitches[0];
+ val = armada_pitch(state, 0) << 16 | armada_pitch(state, 0);
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC);
- val = pitches[1] << 16 | pitches[2];
+ val = armada_pitch(state, 1) << 16 | armada_pitch(state, 2);
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
@@ -146,6 +144,8 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
src_x = state->src.x1 >> 16;
if (format->num_planes == 1 && src_x & (format->hsub - 1))
cfg ^= CFG_DMA_MOD(CFG_SWAPUV);
+ if (to_armada_plane_state(state)->interlace)
+ cfg |= CFG_DMA_FTOGGLE;
cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
CFG_SWAPYU | CFG_YUV2RGB) |
@@ -307,13 +307,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
kfree(plane->state);
+ plane->state = NULL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state) {
- state->base.plane = plane;
- state->base.color_encoding = DEFAULT_ENCODING;
- state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
- state->base.rotation = DRM_MODE_ROTATE_0;
state->colorkey_yr = 0xfefefe00;
state->colorkey_ug = 0x01010100;
state->colorkey_vb = 0x01010100;
@@ -323,8 +320,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
state->brightness = DEFAULT_BRIGHTNESS;
state->contrast = DEFAULT_CONTRAST;
state->saturation = DEFAULT_SATURATION;
+ __drm_atomic_helper_plane_reset(plane, &state->base.base);
+ state->base.base.color_encoding = DEFAULT_ENCODING;
+ state->base.base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
}
- plane->state = &state->base;
}
struct drm_plane_state *
@@ -337,8 +336,9 @@ armada_overlay_duplicate_state(struct drm_plane *plane)
state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
if (state)
- __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
- return &state->base;
+ __drm_atomic_helper_plane_duplicate_state(plane,
+ &state->base.base);
+ return &state->base.base;
}
static int armada_overlay_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c
index 9f36423dd394..dbd4d52e8a32 100644
--- a/drivers/gpu/drm/armada/armada_plane.c
+++ b/drivers/gpu/drm/armada/armada_plane.c
@@ -79,23 +79,6 @@ void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
}
}
-static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state,
- struct armada_regs *regs, bool interlaced)
-{
- u16 pitches[3];
- u32 addrs[2][3];
- unsigned i = 0;
-
- armada_drm_plane_calc(state, addrs, pitches, interlaced);
-
- /* write offset, base, and pitch */
- armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0);
- armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1);
- armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH);
-
- return i;
-}
-
int armada_drm_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state)
{
@@ -126,20 +109,50 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
int armada_drm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
- if (state->fb && !WARN_ON(!state->crtc)) {
- struct drm_crtc *crtc = state->crtc;
- struct drm_crtc_state *crtc_state;
-
- if (state->state)
- crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
- else
- crtc_state = crtc->state;
- return drm_atomic_helper_check_plane_state(state, crtc_state,
- 0, INT_MAX,
- true, false);
- } else {
+ struct armada_plane_state *st = to_armada_plane_state(state);
+ struct drm_crtc *crtc = state->crtc;
+ struct drm_crtc_state *crtc_state;
+ bool interlace;
+ int ret;
+
+ if (!state->fb || WARN_ON(!state->crtc)) {
state->visible = false;
+ return 0;
+ }
+
+ if (state->state)
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
+ else
+ crtc_state = crtc->state;
+
+ ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
+ INT_MAX, true, false);
+ if (ret)
+ return ret;
+
+ interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
+ if (interlace) {
+ if ((state->dst.y1 | state->dst.y2) & 1)
+ return -EINVAL;
+ st->src_hw = drm_rect_height(&state->src) >> 17;
+ st->dst_yx = state->dst.y1 >> 1;
+ st->dst_hw = drm_rect_height(&state->dst) >> 1;
+ } else {
+ st->src_hw = drm_rect_height(&state->src) >> 16;
+ st->dst_yx = state->dst.y1;
+ st->dst_hw = drm_rect_height(&state->dst);
}
+
+ st->src_hw <<= 16;
+ st->src_hw |= drm_rect_width(&state->src) >> 16;
+ st->dst_yx <<= 16;
+ st->dst_yx |= state->dst.x1 & 0x0000ffff;
+ st->dst_hw <<= 16;
+ st->dst_hw |= drm_rect_width(&state->dst) & 0x0000ffff;
+
+ armada_drm_plane_calc(state, st->addrs, st->pitches, interlace);
+ st->interlace = interlace;
+
return 0;
}
@@ -173,21 +186,25 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
val |= CFG_PDWN256x24;
armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
}
- val = armada_rect_hw_fp(&state->src);
- if (armada_rect_hw_fp(&old_state->src) != val)
+ val = armada_src_hw(state);
+ if (armada_src_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
- val = armada_rect_yx(&state->dst);
- if (armada_rect_yx(&old_state->dst) != val)
+ val = armada_dst_yx(state);
+ if (armada_dst_yx(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
- val = armada_rect_hw(&state->dst);
- if (armada_rect_hw(&old_state->dst) != val)
+ val = armada_dst_hw(state);
+ if (armada_dst_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
if (old_state->src.x1 != state->src.x1 ||
old_state->src.y1 != state->src.y1 ||
old_state->fb != state->fb ||
state->crtc->state->mode_changed) {
- idx += armada_drm_crtc_calc_fb(state, regs + idx,
- dcrtc->interlaced);
+ armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
+ LCD_CFG_GRA_START_ADDR0);
+ armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
+ LCD_CFG_GRA_START_ADDR1);
+ armada_reg_queue_mod(regs, idx, armada_pitch(state, 0), 0xffff,
+ LCD_CFG_GRA_PITCH);
}
if (old_state->fb != state->fb ||
state->crtc->state->mode_changed) {
@@ -197,7 +214,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
cfg |= CFG_PALETTE_ENA;
if (state->visible)
cfg |= CFG_GRA_ENA;
- if (dcrtc->interlaced)
+ if (to_armada_plane_state(state)->interlace)
cfg |= CFG_GRA_FTOGGLE;
cfg_mask = CFG_GRAFORMAT |
CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
@@ -248,7 +265,7 @@ static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
/* Disable plane and power down most RAMs and FIFOs */
armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
- CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66,
+ CFG_PDWN32x32 | CFG_PDWN64x66,
0, LCD_SPU_SRAM_PARA1);
dcrtc->regs_idx += idx;
@@ -262,12 +279,37 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
.atomic_disable = armada_drm_primary_plane_atomic_disable,
};
+void armada_plane_reset(struct drm_plane *plane)
+{
+ struct armada_plane_state *st;
+ if (plane->state)
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+ kfree(plane->state);
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st)
+ __drm_atomic_helper_plane_reset(plane, &st->base);
+}
+
+struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct armada_plane_state *st;
+
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
+ if (st)
+ __drm_atomic_helper_plane_duplicate_state(plane, &st->base);
+
+ return &st->base;
+}
+
static const struct drm_plane_funcs armada_primary_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_primary_helper_destroy,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .reset = armada_plane_reset,
+ .atomic_duplicate_state = armada_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h
index ff4281ba7fad..2707ec781941 100644
--- a/drivers/gpu/drm/armada/armada_plane.h
+++ b/drivers/gpu/drm/armada/armada_plane.h
@@ -1,6 +1,24 @@
#ifndef ARMADA_PLANE_H
#define ARMADA_PLANE_H
+struct armada_plane_state {
+ struct drm_plane_state base;
+ u32 src_hw;
+ u32 dst_yx;
+ u32 dst_hw;
+ u32 addrs[2][3];
+ u16 pitches[3];
+ bool interlace;
+};
+
+#define to_armada_plane_state(st) \
+ container_of(st, struct armada_plane_state, base)
+#define armada_src_hw(state) to_armada_plane_state(state)->src_hw
+#define armada_dst_yx(state) to_armada_plane_state(state)->dst_yx
+#define armada_dst_hw(state) to_armada_plane_state(state)->dst_hw
+#define armada_addr(state, f, p) to_armada_plane_state(state)->addrs[f][p]
+#define armada_pitch(state, n) to_armada_plane_state(state)->pitches[n]
+
void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
u16 pitches[3], bool interlaced);
int armada_drm_plane_prepare_fb(struct drm_plane *plane,
@@ -9,6 +27,11 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state);
int armada_drm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state);
+void armada_plane_reset(struct drm_plane *plane);
+struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane);
+void armada_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state);
+
int armada_drm_primary_plane_init(struct drm_device *drm,
struct drm_plane *primary);
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h
index cc35d492142c..2a65434500ee 100644
--- a/drivers/gpu/drm/bochs/bochs.h
+++ b/drivers/gpu/drm/bochs/bochs.h
@@ -86,7 +86,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
void bochs_hw_setformat(struct bochs_device *bochs,
const struct drm_format_info *format);
void bochs_hw_setbase(struct bochs_device *bochs,
- int x, int y, u64 addr);
+ int x, int y, int stride, u64 addr);
int bochs_hw_load_edid(struct bochs_device *bochs);
/* bochs_mm.c */
diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c
index 791ab2f79947..ebfea8744fe6 100644
--- a/drivers/gpu/drm/bochs/bochs_hw.c
+++ b/drivers/gpu/drm/bochs/bochs_hw.c
@@ -255,16 +255,22 @@ void bochs_hw_setformat(struct bochs_device *bochs,
}
void bochs_hw_setbase(struct bochs_device *bochs,
- int x, int y, u64 addr)
+ int x, int y, int stride, u64 addr)
{
- unsigned long offset = (unsigned long)addr +
+ unsigned long offset;
+ unsigned int vx, vy, vwidth;
+
+ bochs->stride = stride;
+ offset = (unsigned long)addr +
y * bochs->stride +
x * (bochs->bpp / 8);
- int vy = offset / bochs->stride;
- int vx = (offset % bochs->stride) * 8 / bochs->bpp;
+ vy = offset / bochs->stride;
+ vx = (offset % bochs->stride) * 8 / bochs->bpp;
+ vwidth = stride * 8 / bochs->bpp;
DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n",
x, y, addr, offset, vx, vy);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, vwidth);
bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx);
bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy);
}
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 5904eddc83a5..bc19dbd531ef 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -36,7 +36,8 @@ static void bochs_plane_update(struct bochs_device *bochs,
bochs_hw_setbase(bochs,
state->crtc_x,
state->crtc_y,
- gbo->bo.offset);
+ state->fb->pitches[0],
+ state->fb->offsets[0] + gbo->bo.offset);
bochs_hw_setformat(bochs, state->fb->format);
}
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index bfb21b5eefe1..4e76b2b27374 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -70,7 +70,12 @@ static int tfp410_get_modes(struct drm_connector *connector)
drm_connector_update_edid_property(connector, edid);
- return drm_add_edid_modes(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+
+ kfree(edid);
+
+ return ret;
+
fallback:
/* No EDID, fallback on the XGA standard modes */
ret = drm_add_modes_noedid(connector, 1920, 1200);
@@ -376,7 +381,8 @@ static int tfp410_fini(struct device *dev)
{
struct tfp410 *dvi = dev_get_drvdata(dev);
- cancel_delayed_work_sync(&dvi->hpd_work);
+ if (dvi->hpd_irq >= 0)
+ cancel_delayed_work_sync(&dvi->hpd_work);
drm_bridge_remove(&dvi->bridge);
diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index e95fceac8f8b..56d36779d213 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -180,7 +180,8 @@ again:
create_mode:
mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
- list_add(&mode->head, &connector->modes);
+ if (mode)
+ list_add(&mode->head, &connector->modes);
return mode;
}
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 3afed5677946..b3f2cf7eae9c 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -141,7 +141,7 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
connector->name,
- mode->name ? mode->name : "",
+ mode->name,
mode->xres, mode->yres,
mode->refresh_specified ? mode->refresh : 60,
mode->rb ? " reduced blanking" : "",
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 57e6408288c8..74a5739df506 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -158,6 +158,9 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
int interlace;
u64 tmp;
+ if (!hdisplay || !vdisplay)
+ return NULL;
+
/* allocate the drm_display_mode structure. If failure, we will
* return directly
*/
@@ -392,6 +395,9 @@ drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
int hsync, hfront_porch, vodd_front_porch_lines;
unsigned int tmp1, tmp2;
+ if (!hdisplay || !vdisplay)
+ return NULL;
+
drm_mode = drm_mode_create(dev);
if (!drm_mode)
return NULL;
@@ -1448,7 +1454,7 @@ static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
}
static int drm_mode_parse_cmdline_extra(const char *str, int length,
- struct drm_connector *connector,
+ const struct drm_connector *connector,
struct drm_cmdline_mode *mode)
{
int i;
@@ -1493,7 +1499,7 @@ static int drm_mode_parse_cmdline_extra(const char *str, int length,
static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
bool extras,
- struct drm_connector *connector,
+ const struct drm_connector *connector,
struct drm_cmdline_mode *mode)
{
const char *str_start = str;
@@ -1555,7 +1561,7 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
}
static int drm_mode_parse_cmdline_options(char *str, size_t len,
- struct drm_connector *connector,
+ const struct drm_connector *connector,
struct drm_cmdline_mode *mode)
{
unsigned int rotation = 0;
@@ -1689,7 +1695,7 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
* True if a valid modeline has been parsed, false otherwise.
*/
bool drm_mode_parse_command_line_for_connector(const char *mode_option,
- struct drm_connector *connector,
+ const struct drm_connector *connector,
struct drm_cmdline_mode *mode)
{
const char *name;
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index d8a0bcd02f34..ffd95bfeaa94 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -90,6 +90,12 @@ static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
};
+static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = {
+ .width = 720,
+ .height = 1280,
+ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = {
.width = 800,
.height = 1280,
@@ -123,6 +129,12 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
},
.driver_data = (void *)&gpd_micropc,
+ }, { /* GPD MicroPC (later BIOS versions with proper DMI strings) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MicroPC"),
+ },
+ .driver_data = (void *)&lcd720x1280_rightside_up,
}, { /*
* GPD Pocket, note that the the DMI data is less generic then
* it seems, devices with a board-vendor of "AMI Corporation"
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index cbe58d307d1c..60ce4a8ad9e1 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_EXYNOS
tristate "DRM Support for Samsung SoC EXYNOS Series"
- depends on OF && DRM && (ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_MULTIPLATFORM)
+ depends on OF && DRM && (ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_MULTIPLATFORM || COMPILE_TEST)
select DRM_KMS_HELPER
select VIDEOMODE_HELPERS
select SND_SOC_HDMI_CODEC if SND_SOC
@@ -86,7 +86,7 @@ comment "Sub-drivers"
config DRM_EXYNOS_G2D
bool "G2D"
- depends on VIDEO_SAMSUNG_S5P_G2D=n
+ depends on VIDEO_SAMSUNG_S5P_G2D=n || COMPILE_TEST
select FRAME_VECTOR
help
Choose this option if you want to use Exynos G2D for DRM.
@@ -114,7 +114,7 @@ config DRM_EXYNOS_SCALER
config DRM_EXYNOS_GSC
bool "GScaler"
- depends on VIDEO_SAMSUNG_EXYNOS_GSC=n
+ depends on VIDEO_SAMSUNG_EXYNOS_GSC=n || COMPILE_TEST
select DRM_EXYNOS_IPP
help
Choose this option if you want to use Exynos GSC for DRM.
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 0650b619de24..2d5cbfda3ca7 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -7,7 +7,6 @@
* Hyungwon Hwang <human.hwang@samsung.com>
*/
-#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/iopoll.h>
@@ -15,11 +14,15 @@
#include <linux/mfd/syscon.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include "exynos_drm_drv.h"
+#include <drm/drm_fourcc.h>
+#include <drm/drm_vblank.h>
+
#include "exynos_drm_crtc.h"
+#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_plane.h"
#include "regs-decon5433.h"
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index 13509ca8aa35..f0640950bd46 100644
--- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -6,8 +6,6 @@
* Akshu Agarwal <akshua@gmail.com>
* Ajay Kumar <ajaykumar.rs@samsung.com>
*/
-#include <drm/drmP.h>
-#include <drm/exynos_drm.h>
#include <linux/clk.h>
#include <linux/component.h>
@@ -21,10 +19,14 @@
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_vblank.h>
+#include <drm/exynos_drm.h>
+
#include "exynos_drm_crtc.h"
-#include "exynos_drm_plane.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
+#include "exynos_drm_plane.h"
#include "regs-decon7.h"
/*
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index c0653d007ca4..3a0f0ba8c63a 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -6,25 +6,24 @@
* Author: Jingoo Han <jg1.han@samsung.com>
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/of_graph.h>
#include <linux/component.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
-#include <drm/drmP.h>
+#include <drm/bridge/analogix_dp.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-
-#include <drm/bridge/analogix_dp.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_crtc.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 98bec7418f01..77ce78986408 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -8,11 +8,11 @@
* Seung-Woo Kim <sw0312.kim@samsung.com>
*/
-#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c b/drivers/gpu/drm/exynos/exynos_drm_dma.c
index bef8bc3c8e00..9ebc02768847 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dma.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dma.c
@@ -4,11 +4,13 @@
// Author: Inki Dae <inki.dae@samsung.com>
// Author: Andrzej Hajda <a.hajda@samsung.com>
-#include <drm/drmP.h>
-#include <drm/exynos_drm.h>
#include <linux/dma-iommu.h>
#include <linux/dma-mapping.h>
#include <linux/iommu.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_print.h>
+#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 6ea92173db9f..87289db12868 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -10,14 +10,14 @@
* published by the Free Software Foundation.
*/
-#include <drm/drmP.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
#include <drm/drm_atomic_helper.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <linux/of_graph.h>
-#include <linux/regulator/consumer.h>
-
#include <video/of_videomode.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index ba8932af9b43..58baf49d9926 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -7,25 +7,23 @@
* Seung-Woo Kim <sw0312.kim@samsung.com>
*/
+#include <linux/component.h>
#include <linux/pm_runtime.h>
-#include <drm/drmP.h>
+
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_probe_helper.h>
-
-#include <linux/component.h>
-
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
-#include "exynos_drm_fbdev.h"
#include "exynos_drm_fb.h"
+#include "exynos_drm_fbdev.h"
+#include "exynos_drm_g2d.h"
#include "exynos_drm_gem.h"
-#include "exynos_drm_plane.h"
#include "exynos_drm_ipp.h"
+#include "exynos_drm_plane.h"
#include "exynos_drm_vidi.h"
-#include "exynos_drm_g2d.h"
#define DRIVER_NAME "exynos"
#define DRIVER_DESC "Samsung SoC DRM"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 18b03b83f8a3..d4014ba592fd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -11,15 +11,21 @@
#ifndef _EXYNOS_DRM_DRV_H_
#define _EXYNOS_DRM_DRV_H_
-#include <drm/drmP.h>
#include <linux/module.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_plane.h>
+
#define MAX_CRTC 3
#define MAX_PLANE 5
#define MAX_FB_BUFFER 4
#define DEFAULT_WIN 0
+struct drm_crtc_state;
+struct drm_display_mode;
+
#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base)
#define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 63a4b5074a99..5f6f523821a2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -10,16 +10,9 @@
* published by the Free Software Foundation.
*/
-#include <asm/unaligned.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_panel.h>
-#include <drm/drm_probe_helper.h>
-
#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/component.h>
#include <linux/gpio/consumer.h>
#include <linux/irq.h>
#include <linux/of_device.h>
@@ -27,11 +20,19 @@
#include <linux/of_graph.h>
#include <linux/phy/phy.h>
#include <linux/regulator/consumer.h>
-#include <linux/component.h>
+
+#include <asm/unaligned.h>
#include <video/mipi_display.h>
#include <video/videomode.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index ea048905849a..64370b634cca 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -8,19 +8,19 @@
* Seung-Woo Kim <sw0312.kim@samsung.com>
*/
-#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_probe_helper.h>
-#include <uapi/drm/exynos_drm.h>
+#include <drm/exynos_drm.h>
+#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_fbdev.h"
-#include "exynos_drm_crtc.h"
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
struct exynos_drm_gem *exynos_gem)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 9dc33c6b6687..b0877b97291c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -8,14 +8,16 @@
* Seung-Woo Kim <sw0312.kim@samsung.com>
*/
-#include <drm/drmP.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_probe_helper.h>
#include <drm/exynos_drm.h>
-#include <linux/console.h>
-
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_fbdev.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 0db29690ede3..a594ab7be2c0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -6,21 +6,22 @@
* Jinyoung Jeon <jy0.jeon@samsung.com>
* Sangmin Lee <lsmin.lee@samsung.com>
*/
-#include <linux/kernel.h>
+
+#include <linux/clk.h>
#include <linux/component.h>
-#include <linux/platform_device.h>
+#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-#include <linux/clk.h>
-#include <linux/pm_runtime.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/spinlock.h>
-#include <drm/drmP.h>
#include <drm/exynos_drm.h>
-#include "regs-fimc.h"
+
#include "exynos_drm_drv.h"
#include "exynos_drm_ipp.h"
+#include "regs-fimc.h"
/*
* FIMC stands for Fully Interactive Mobile Camera and
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index e9106b1f4a50..8d0a929104e5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -6,26 +6,28 @@
* Joonyoung Shim <jy0922.shim@samsung.com>
* Inki Dae <inki.dae@samsung.com>
*/
-#include <drm/drmP.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/component.h>
-#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
#include <video/samsung_fimd.h>
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_vblank.h>
#include <drm/exynos_drm.h>
+#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
-#include "exynos_drm_crtc.h"
#include "exynos_drm_plane.h"
/*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 2e4b9434245b..50904eee96f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -4,21 +4,24 @@
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
*/
-#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
#include <linux/workqueue.h>
-#include <linux/dma-mapping.h>
-#include <linux/of.h>
-#include <drm/drmP.h>
+#include <drm/drm_file.h>
#include <drm/exynos_drm.h>
+
#include "exynos_drm_drv.h"
#include "exynos_drm_g2d.h"
#include "exynos_drm_gem.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index d8f1fe9b68d8..d734d9d51762 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -5,12 +5,13 @@
* Author: Inki Dae <inki.dae@samsung.com>
*/
-#include <drm/drmP.h>
-#include <drm/drm_vma_manager.h>
-#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
#include <linux/pfn_t.h>
+#include <linux/shmem_fs.h>
+
+#include <drm/drm_prime.h>
+#include <drm/drm_vma_manager.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 05b0fe21b81e..1e4b21c49a06 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -6,20 +6,21 @@
* Jinyoung Jeon <jy0.jeon@samsung.com>
* Sangmin Lee <lsmin.lee@samsung.com>
*/
-#include <linux/kernel.h>
-#include <linux/component.h>
-#include <linux/platform_device.h>
+
#include <linux/clk.h>
-#include <linux/pm_runtime.h>
+#include <linux/component.h>
+#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <drm/drmP.h>
#include <drm/exynos_drm.h>
-#include "regs-gsc.h"
+
#include "exynos_drm_drv.h"
#include "exynos_drm_ipp.h"
+#include "regs-gsc.h"
/*
* GSC stands for General SCaler and
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index c862099723a0..d45bfab6fe40 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -16,10 +16,9 @@
* all copies or substantial portions of the Software.
*/
-
#include <drm/drmP.h>
#include <drm/drm_mode.h>
-#include <uapi/drm/exynos_drm.h>
+#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index 8363cb40daed..b78e8c5ba553 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -5,23 +5,25 @@
* Hyungwon Hwang <human.hwang@samsung.com>
*/
-#include <linux/platform_device.h>
-#include <video/of_videomode.h>
-#include <linux/of_address.h>
-#include <video/videomode.h>
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/component.h>
#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_graph.h>
-#include <linux/clk.h>
-#include <linux/component.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <drm/drmP.h>
-#include <drm/drm_encoder.h>
-#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#include <drm/drm_encoder.h>
+#include <drm/drm_print.h>
+
#include "exynos_drm_drv.h"
/* Sysreg registers for MIC */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 2f3c9b993acd..b29afced7374 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -4,14 +4,14 @@
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
*/
-#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
+
#include "exynos_drm_crtc.h"
+#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_plane.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 85e30cb6c23f..8ebad2740ad5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -6,21 +6,21 @@
* Eunchul Kim <chulspro.kim@samsung.com>
*/
-#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/component.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
+#include <linux/kernel.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <drm/drmP.h>
#include <drm/exynos_drm.h>
-#include "regs-rotator.h"
+
#include "exynos_drm_drv.h"
#include "exynos_drm_ipp.h"
+#include "regs-rotator.h"
/*
* Rotator supports image crop/rotator and input/output DMA operations.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
index ec9c1b7d3103..9af096479e1c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
@@ -5,22 +5,22 @@
* Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
*/
-#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/component.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
+#include <linux/kernel.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <drm/drmP.h>
#include <drm/exynos_drm.h>
-#include "regs-scaler.h"
-#include "exynos_drm_fb.h"
+
#include "exynos_drm_drv.h"
+#include "exynos_drm_fb.h"
#include "exynos_drm_ipp.h"
+#include "regs-scaler.h"
#define scaler_read(offset) readl(scaler->regs + (offset))
#define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset))
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index eb2667b4500c..65b891cb9c50 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -5,21 +5,20 @@
* Authors:
* Inki Dae <inki.dae@samsung.com>
*/
-#include <drm/drmP.h>
+#include <linux/component.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
-#include <linux/component.h>
#include <linux/timer.h>
-#include <drm/exynos_drm.h>
-
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
+#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_vidi.h"
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 894a99793633..bc1565f1822a 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -9,38 +9,37 @@
* Based on drivers/media/video/s5p-tv/hdmi_drv.c
*/
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_probe_helper.h>
-
-#include "regs-hdmi.h"
-
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
+#include <drm/exynos_drm.h>
#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
#include <linux/gpio/consumer.h>
-#include <linux/regulator/consumer.h>
+#include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
-#include <linux/hdmi.h>
-#include <linux/component.h>
-#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <sound/hdmi-codec.h>
-#include <drm/exynos_drm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/wait.h>
+#include <sound/hdmi-codec.h>
#include <media/cec-notifier.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
#include "exynos_drm_crtc.h"
+#include "regs-hdmi.h"
#define HOTPLUG_DEBOUNCE_MS 1100
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index db0b698ea8ea..7b24338fad3c 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -9,33 +9,32 @@
* Based on drivers/media/video/s5p-tv/mixer_reg.c
*/
-#include <drm/drmP.h>
-
-#include "regs-mixer.h"
-#include "regs-vp.h"
-
-#include <linux/kernel.h>
-#include <linux/ktime.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/component.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_vblank.h>
#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
+#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_plane.h"
+#include "regs-mixer.h"
+#include "regs-vp.h"
#define MIXER_WIN_NR 3
#define VP_DEFAULT_WIN 2
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 2c19054ed570..2a1e071d39ee 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -635,6 +635,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->format->format);
ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, burstsize);
ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
+ ipu_idmac_enable_watermark(ipu_plane->ipu_ch, true);
ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id);
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index c3b4bc6e4155..13078c4975ff 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -395,19 +395,17 @@ static const unsigned int a3xx_registers[] = {
0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
- 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
- 0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
- 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472,
- 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
- 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
- 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed,
- 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
- 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
- 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
- 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
- 0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d,
- 0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036,
- 0x303c, 0x303c, 0x305e, 0x305f,
+ 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444,
+ 0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470,
+ 0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3,
+ 0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e,
+ 0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea,
+ 0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617,
+ 0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0,
+ 0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9,
+ 0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743,
+ 0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d,
+ 0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f,
~0 /* sentinel */
};
diff --git a/drivers/gpu/drm/msm/adreno/a5xx.xml.h b/drivers/gpu/drm/msm/adreno/a5xx.xml.h
index cf4fe14ddd6e..4a61d4e72c98 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx.xml.h
@@ -8,19 +8,19 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/envytools/rnndb/adreno.xml ( 501 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml ( 42463 bytes, from 2018-11-19 13:44:03)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml ( 14201 bytes, from 2018-12-02 17:29:54)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml ( 43052 bytes, from 2018-12-02 17:29:54)
-- /home/robclark/src/envytools/rnndb/adreno/a3xx.xml ( 83840 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a4xx.xml ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml ( 147240 bytes, from 2018-12-02 17:29:54)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml ( 140790 bytes, from 2018-12-02 17:29:54)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml ( 10431 bytes, from 2018-09-14 13:03:07)
-- /home/robclark/src/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2018-07-03 19:37:13)
-
-Copyright (C) 2013-2018 by the following authors:
+- /home/ubuntu/envytools/envytools/rnndb/./adreno.xml ( 501 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/a2xx.xml ( 79608 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/adreno_common.xml ( 14239 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/adreno_pm4.xml ( 43155 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/a3xx.xml ( 83840 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/a4xx.xml ( 112086 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/a5xx.xml ( 147291 bytes, from 2019-05-29 14:51:41)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/a6xx.xml ( 148461 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/a6xx_gmu.xml ( 10431 bytes, from 2019-05-29 01:28:15)
+- /home/ubuntu/envytools/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2019-05-29 01:28:15)
+
+Copyright (C) 2013-2019 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
@@ -2148,6 +2148,8 @@ static inline uint32_t A5XX_VSC_RESOLVE_CNTL_Y(uint32_t val)
#define REG_A5XX_HLSQ_TIMEOUT_THRESHOLD_1 0x00000e01
+#define REG_A5XX_HLSQ_DBG_ECO_CNTL 0x00000e04
+
#define REG_A5XX_HLSQ_ADDR_MODE_CNTL 0x00000e05
#define REG_A5XX_HLSQ_MODE_CNTL 0x00000e06
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
index 3041c500c5cd..9f2dd76bd67a 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
@@ -149,7 +149,6 @@ DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
{
struct drm_device *dev;
- struct dentry *ent;
int ret;
if (!minor)
@@ -166,11 +165,8 @@ int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
return ret;
}
- ent = debugfs_create_file("reset", S_IWUGO,
- minor->debugfs_root,
- dev, &reset_fops);
- if (!ent)
- return -ENOMEM;
+ debugfs_create_file("reset", S_IWUGO, minor->debugfs_root, dev,
+ &reset_fops);
return 0;
}
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index a3c778df23a8..1671db47aa57 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -309,12 +309,18 @@ static const struct {
void a5xx_set_hwcg(struct msm_gpu *gpu, bool state)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(a5xx_hwcg); i++)
gpu_write(gpu, a5xx_hwcg[i].offset,
state ? a5xx_hwcg[i].value : 0);
+ if (adreno_is_a540(adreno_gpu)) {
+ gpu_write(gpu, REG_A5XX_RBBM_CLOCK_DELAY_GPMU, state ? 0x00000770 : 0);
+ gpu_write(gpu, REG_A5XX_RBBM_CLOCK_HYST_GPMU, state ? 0x00000004 : 0);
+ }
+
gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, state ? 0xAAA8AA00 : 0);
gpu_write(gpu, REG_A5XX_RBBM_ISDB_CNT, state ? 0x182 : 0x180);
}
@@ -498,6 +504,9 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
gpu_write(gpu, REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003);
+ if (adreno_is_a540(adreno_gpu))
+ gpu_write(gpu, REG_A5XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009);
+
/* Make all blocks contribute to the GPU BUSY perf counter */
gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_GPU_BUSY_MASKED, 0xFFFFFFFF);
@@ -558,7 +567,10 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, 0x00000000);
gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x40);
- gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x40);
+ if (adreno_is_a530(adreno_gpu))
+ gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x40);
+ if (adreno_is_a540(adreno_gpu))
+ gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x400);
gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x80000060);
gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x40201B16);
@@ -583,6 +595,8 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
/* Set the highest bank bit */
gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, 2 << 7);
gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, 2 << 1);
+ if (adreno_is_a540(adreno_gpu))
+ gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, 2);
/* Protect registers from the CP */
gpu_write(gpu, REG_A5XX_CP_PROTECT_CNTL, 0x00000007);
@@ -633,6 +647,30 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000);
gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000);
+ /* Put the GPU into 64 bit by default */
+ gpu_write(gpu, REG_A5XX_CP_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_VSC_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_GRAS_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_RB_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_PC_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_HLSQ_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_VFD_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_VPC_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_UCHE_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_SP_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_TPL1_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL, 0x1);
+
+ /*
+ * VPC corner case with local memory load kill leads to corrupt
+ * internal state. Normal Disable does not work for all a5x chips.
+ * So do the following setting to disable it.
+ */
+ if (adreno_gpu->info->quirks & ADRENO_QUIRK_LMLOADKILL_DISABLE) {
+ gpu_rmw(gpu, REG_A5XX_VPC_DBG_ECO_CNTL, 0, BIT(23));
+ gpu_rmw(gpu, REG_A5XX_HLSQ_DBG_ECO_CNTL, BIT(18), 0);
+ }
+
ret = adreno_hw_init(gpu);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c
index 0ebfe2bb5707..a3a06db675ba 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_power.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c
@@ -23,6 +23,18 @@
#define AGC_POWER_CONFIG_PRODUCTION_ID 1
#define AGC_INIT_MSG_VALUE 0xBABEFACE
+/* AGC_LM_CONFIG (A540+) */
+#define AGC_LM_CONFIG (136/4)
+#define AGC_LM_CONFIG_GPU_VERSION_SHIFT 17
+#define AGC_LM_CONFIG_ENABLE_GPMU_ADAPTIVE 1
+#define AGC_LM_CONFIG_THROTTLE_DISABLE (2 << 8)
+#define AGC_LM_CONFIG_ISENSE_ENABLE (1 << 4)
+#define AGC_LM_CONFIG_ENABLE_ERROR (3 << 4)
+#define AGC_LM_CONFIG_LLM_ENABLED (1 << 16)
+#define AGC_LM_CONFIG_BCL_DISABLED (1 << 24)
+
+#define AGC_LEVEL_CONFIG (140/4)
+
static struct {
uint32_t reg;
uint32_t value;
@@ -107,7 +119,7 @@ static inline uint32_t _get_mvolts(struct msm_gpu *gpu, uint32_t freq)
}
/* Setup thermal limit management */
-static void a5xx_lm_setup(struct msm_gpu *gpu)
+static void a530_lm_setup(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
@@ -156,6 +168,45 @@ static void a5xx_lm_setup(struct msm_gpu *gpu)
gpu_write(gpu, AGC_INIT_MSG_MAGIC, AGC_INIT_MSG_VALUE);
}
+#define PAYLOAD_SIZE(_size) ((_size) * sizeof(u32))
+#define LM_DCVS_LIMIT 1
+#define LEVEL_CONFIG ~(0x303)
+
+static void a540_lm_setup(struct msm_gpu *gpu)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ u32 config;
+
+ /* The battery current limiter isn't enabled for A540 */
+ config = AGC_LM_CONFIG_BCL_DISABLED;
+ config |= adreno_gpu->rev.patchid << AGC_LM_CONFIG_GPU_VERSION_SHIFT;
+
+ /* For now disable GPMU side throttling */
+ config |= AGC_LM_CONFIG_THROTTLE_DISABLE;
+
+ /* Until we get clock scaling 0 is always the active power level */
+ gpu_write(gpu, REG_A5XX_GPMU_GPMU_VOLTAGE, 0x80000000 | 0);
+
+ /* Fixed at 6000 for now */
+ gpu_write(gpu, REG_A5XX_GPMU_GPMU_PWR_THRESHOLD, 0x80000000 | 6000);
+
+ gpu_write(gpu, AGC_MSG_STATE, 0x80000001);
+ gpu_write(gpu, AGC_MSG_COMMAND, AGC_POWER_CONFIG_PRODUCTION_ID);
+
+ gpu_write(gpu, AGC_MSG_PAYLOAD(0), 5448);
+ gpu_write(gpu, AGC_MSG_PAYLOAD(1), 1);
+
+ gpu_write(gpu, AGC_MSG_PAYLOAD(2), _get_mvolts(gpu, gpu->fast_rate));
+ gpu_write(gpu, AGC_MSG_PAYLOAD(3), gpu->fast_rate / 1000000);
+
+ gpu_write(gpu, AGC_MSG_PAYLOAD(AGC_LM_CONFIG), config);
+ gpu_write(gpu, AGC_MSG_PAYLOAD(AGC_LEVEL_CONFIG), LEVEL_CONFIG);
+ gpu_write(gpu, AGC_MSG_PAYLOAD_SIZE,
+ PAYLOAD_SIZE(AGC_LEVEL_CONFIG + 1));
+
+ gpu_write(gpu, AGC_INIT_MSG_MAGIC, AGC_INIT_MSG_VALUE);
+}
+
/* Enable SP/TP cpower collapse */
static void a5xx_pc_init(struct msm_gpu *gpu)
{
@@ -197,7 +248,8 @@ static int a5xx_gpmu_init(struct msm_gpu *gpu)
return -EINVAL;
}
- gpu_write(gpu, REG_A5XX_GPMU_WFI_CONFIG, 0x4014);
+ if (adreno_is_a530(adreno_gpu))
+ gpu_write(gpu, REG_A5XX_GPMU_WFI_CONFIG, 0x4014);
/* Kick off the GPMU */
gpu_write(gpu, REG_A5XX_GPMU_CM3_SYSRESET, 0x0);
@@ -211,12 +263,26 @@ static int a5xx_gpmu_init(struct msm_gpu *gpu)
DRM_ERROR("%s: GPMU firmware initialization timed out\n",
gpu->name);
+ if (!adreno_is_a530(adreno_gpu)) {
+ u32 val = gpu_read(gpu, REG_A5XX_GPMU_GENERAL_1);
+
+ if (val)
+ DRM_ERROR("%s: GPMU firmware initialization failed: %d\n",
+ gpu->name, val);
+ }
+
return 0;
}
/* Enable limits management */
static void a5xx_lm_enable(struct msm_gpu *gpu)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+
+ /* This init sequence only applies to A530 */
+ if (!adreno_is_a530(adreno_gpu))
+ return;
+
gpu_write(gpu, REG_A5XX_GDPM_INT_MASK, 0x0);
gpu_write(gpu, REG_A5XX_GDPM_INT_EN, 0x0A);
gpu_write(gpu, REG_A5XX_GPMU_GPMU_VOLTAGE_INTR_EN_MASK, 0x01);
@@ -228,10 +294,14 @@ static void a5xx_lm_enable(struct msm_gpu *gpu)
int a5xx_power_init(struct msm_gpu *gpu)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
int ret;
/* Set up the limits management */
- a5xx_lm_setup(gpu);
+ if (adreno_is_a530(adreno_gpu))
+ a530_lm_setup(gpu);
+ else
+ a540_lm_setup(gpu);
/* Set up SP/TP power collpase */
a5xx_pc_init(gpu);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 38e2cfa9cec7..2ca470eb5cb8 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -74,7 +74,7 @@ bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu)
u32 val;
/* This can be called from gpu state code so make sure GMU is valid */
- if (IS_ERR_OR_NULL(gmu->mmio))
+ if (!gmu->initialized)
return false;
val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
@@ -90,7 +90,7 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
u32 val;
/* This can be called from gpu state code so make sure GMU is valid */
- if (IS_ERR_OR_NULL(gmu->mmio))
+ if (!gmu->initialized)
return false;
val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
@@ -504,8 +504,10 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
wmb();
err:
- devm_iounmap(gmu->dev, pdcptr);
- devm_iounmap(gmu->dev, seqptr);
+ if (!IS_ERR_OR_NULL(pdcptr))
+ iounmap(pdcptr);
+ if (!IS_ERR_OR_NULL(seqptr))
+ iounmap(seqptr);
}
/*
@@ -695,7 +697,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
int status, ret;
- if (WARN(!gmu->mmio, "The GMU is not set up yet\n"))
+ if (WARN(!gmu->initialized, "The GMU is not set up yet\n"))
return 0;
gmu->hung = false;
@@ -765,7 +767,7 @@ bool a6xx_gmu_isidle(struct a6xx_gmu *gmu)
{
u32 reg;
- if (!gmu->mmio)
+ if (!gmu->initialized)
return true;
reg = gmu_read(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS);
@@ -1195,7 +1197,7 @@ static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev,
return ERR_PTR(-EINVAL);
}
- ret = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ ret = ioremap(res->start, resource_size(res));
if (!ret) {
DRM_DEV_ERROR(&pdev->dev, "Unable to map the %s registers\n", name);
return ERR_PTR(-EINVAL);
@@ -1211,10 +1213,10 @@ static int a6xx_gmu_get_irq(struct a6xx_gmu *gmu, struct platform_device *pdev,
irq = platform_get_irq_byname(pdev, name);
- ret = devm_request_irq(&pdev->dev, irq, handler, IRQF_TRIGGER_HIGH,
- name, gmu);
+ ret = request_irq(irq, handler, IRQF_TRIGGER_HIGH, name, gmu);
if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "Unable to get interrupt %s\n", name);
+ DRM_DEV_ERROR(&pdev->dev, "Unable to get interrupt %s %d\n",
+ name, ret);
return ret;
}
@@ -1227,27 +1229,35 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
{
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
- if (IS_ERR_OR_NULL(gmu->mmio))
+ if (!gmu->initialized)
return;
- a6xx_gmu_stop(a6xx_gpu);
-
- pm_runtime_disable(gmu->dev);
+ pm_runtime_force_suspend(gmu->dev);
if (!IS_ERR_OR_NULL(gmu->gxpd)) {
pm_runtime_disable(gmu->gxpd);
dev_pm_domain_detach(gmu->gxpd, false);
}
- a6xx_gmu_irq_disable(gmu);
+ iounmap(gmu->mmio);
+ gmu->mmio = NULL;
+
a6xx_gmu_memory_free(gmu, gmu->hfi);
iommu_detach_device(gmu->domain, gmu->dev);
iommu_domain_free(gmu->domain);
+
+ free_irq(gmu->gmu_irq, gmu);
+ free_irq(gmu->hfi_irq, gmu);
+
+ /* Drop reference taken in of_find_device_by_node */
+ put_device(gmu->dev);
+
+ gmu->initialized = false;
}
-int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
+int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
{
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
struct platform_device *pdev = of_find_device_by_node(node);
@@ -1268,34 +1278,34 @@ int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
/* Get the list of clocks */
ret = a6xx_gmu_clocks_probe(gmu);
if (ret)
- return ret;
+ goto err_put_device;
/* Set up the IOMMU context bank */
ret = a6xx_gmu_memory_probe(gmu);
if (ret)
- return ret;
+ goto err_put_device;
/* Allocate memory for for the HFI queues */
gmu->hfi = a6xx_gmu_memory_alloc(gmu, SZ_16K);
if (IS_ERR(gmu->hfi))
- goto err;
+ goto err_memory;
/* Allocate memory for the GMU debug region */
gmu->debug = a6xx_gmu_memory_alloc(gmu, SZ_16K);
if (IS_ERR(gmu->debug))
- goto err;
+ goto err_memory;
/* Map the GMU registers */
gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu");
if (IS_ERR(gmu->mmio))
- goto err;
+ goto err_memory;
/* Get the HFI and GMU interrupts */
gmu->hfi_irq = a6xx_gmu_get_irq(gmu, pdev, "hfi", a6xx_hfi_irq);
gmu->gmu_irq = a6xx_gmu_get_irq(gmu, pdev, "gmu", a6xx_gmu_irq);
if (gmu->hfi_irq < 0 || gmu->gmu_irq < 0)
- goto err;
+ goto err_mmio;
/*
* Get a link to the GX power domain to reset the GPU in case of GMU
@@ -1309,8 +1319,15 @@ int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
/* Set up the HFI queues */
a6xx_hfi_init(gmu);
+ gmu->initialized = true;
+
return 0;
-err:
+
+err_mmio:
+ iounmap(gmu->mmio);
+ free_irq(gmu->gmu_irq, gmu);
+ free_irq(gmu->hfi_irq, gmu);
+err_memory:
a6xx_gmu_memory_free(gmu, gmu->hfi);
if (gmu->domain) {
@@ -1318,6 +1335,11 @@ err:
iommu_domain_free(gmu->domain);
}
+ ret = -ENODEV;
- return -ENODEV;
+err_put_device:
+ /* Drop reference taken in of_find_device_by_node */
+ put_device(gmu->dev);
+
+ return ret;
}
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index bedd8e6a63aa..39a26dd63674 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -75,6 +75,7 @@ struct a6xx_gmu {
struct a6xx_hfi_queue queues[2];
+ bool initialized;
bool hung;
};
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index e74dce474250..be39cf01e51e 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -391,6 +391,20 @@ static int a6xx_hw_init(struct msm_gpu *gpu)
REG_A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000);
gpu_write(gpu, REG_A6XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000);
+ /* Turn on 64 bit addressing for all blocks */
+ gpu_write(gpu, REG_A6XX_CP_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_VSC_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_GRAS_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_RB_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_PC_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_HLSQ_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_VFD_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_VPC_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_UCHE_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_SP_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_TPL1_ADDR_MODE_CNTL, 0x1);
+ gpu_write(gpu, REG_A6XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL, 0x1);
+
/* enable hardware clockgating */
a6xx_set_hwcg(gpu, true);
@@ -854,7 +868,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
/* FIXME: How do we gracefully handle this? */
BUG_ON(!node);
- ret = a6xx_gmu_probe(a6xx_gpu, node);
+ ret = a6xx_gmu_init(a6xx_gpu, node);
if (ret) {
a6xx_destroy(&(a6xx_gpu->base.base));
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index b46279eb18c5..64399554f2dd 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -53,7 +53,7 @@ bool a6xx_gmu_isidle(struct a6xx_gmu *gmu);
int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state);
void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state);
-int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node);
+int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node);
void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu);
void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index b907245d3d96..5bcc169c1189 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -145,6 +145,24 @@ static const struct adreno_info gpulist[] = {
.init = a5xx_gpu_init,
.zapfw = "a530_zap.mdt",
}, {
+ .rev = ADRENO_REV(5, 4, 0, 2),
+ .revn = 540,
+ .name = "A540",
+ .fw = {
+ [ADRENO_FW_PM4] = "a530_pm4.fw",
+ [ADRENO_FW_PFP] = "a530_pfp.fw",
+ [ADRENO_FW_GPMU] = "a540_gpmu.fw2",
+ },
+ .gmem = SZ_1M,
+ /*
+ * Increase inactive period to 250 to avoid bouncing
+ * the GDSC which appears to make it grumpy
+ */
+ .inactive_period = 250,
+ .quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
+ .init = a5xx_gpu_init,
+ .zapfw = "a540_zap.mdt",
+ }, {
.rev = ADRENO_REV(6, 3, 0, ANY_ID),
.revn = 630,
.name = "A630",
@@ -351,7 +369,7 @@ static void adreno_unbind(struct device *dev, struct device *master,
{
struct msm_gpu *gpu = dev_get_drvdata(dev);
- gpu->funcs->pm_suspend(gpu);
+ pm_runtime_force_suspend(dev);
gpu->funcs->destroy(gpu);
set_gpu_pdev(dev_get_drvdata(master), NULL);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 6f7f4114afcf..3db8e499d4c5 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -67,7 +67,6 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
return ret;
mem_phys = r.start;
- mem_size = resource_size(&r);
/* Request the MDT file for the firmware */
fw = adreno_request_fw(to_adreno_gpu(gpu), fwname);
@@ -83,6 +82,13 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
goto out;
}
+ if (mem_size > resource_size(&r)) {
+ DRM_DEV_ERROR(dev,
+ "memory region is too small to load the MDT\n");
+ ret = -E2BIG;
+ goto out;
+ }
+
/* Allocate memory for the firmware image */
mem_region = memremap(mem_phys, mem_size, MEMREMAP_WC);
if (!mem_region) {
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 0925606ec9b5..d67c1a69c49a 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -61,6 +61,7 @@ enum {
enum adreno_quirks {
ADRENO_QUIRK_TWO_PASS_USE_WFI = 1,
ADRENO_QUIRK_FAULT_DETECT_MASK = 2,
+ ADRENO_QUIRK_LMLOADKILL_DISABLE = 3,
};
struct adreno_rev {
@@ -221,6 +222,11 @@ static inline int adreno_is_a530(struct adreno_gpu *gpu)
return gpu->revn == 530;
}
+static inline int adreno_is_a540(struct adreno_gpu *gpu)
+{
+ return gpu->revn == 540;
+}
+
int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value);
const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu,
const char *fwname);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
index cd6bde12029e..5cda96875e03 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
@@ -69,7 +69,6 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
struct dpu_core_perf_params *perf)
{
struct dpu_crtc_state *dpu_cstate;
- int i;
if (!kms || !kms->catalog || !crtc || !state || !perf) {
DPU_ERROR("invalid parameters\n");
@@ -80,35 +79,24 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
memset(perf, 0, sizeof(struct dpu_core_perf_params));
if (!dpu_cstate->bw_control) {
- for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- perf->bw_ctl[i] = kms->catalog->perf.max_bw_high *
+ perf->bw_ctl = kms->catalog->perf.max_bw_high *
1000ULL;
- perf->max_per_pipe_ib[i] = perf->bw_ctl[i];
- }
+ perf->max_per_pipe_ib = perf->bw_ctl;
perf->core_clk_rate = kms->perf.max_core_clk_rate;
} else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_MINIMUM) {
- for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- perf->bw_ctl[i] = 0;
- perf->max_per_pipe_ib[i] = 0;
- }
+ perf->bw_ctl = 0;
+ perf->max_per_pipe_ib = 0;
perf->core_clk_rate = 0;
} else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_FIXED) {
- for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- perf->bw_ctl[i] = kms->perf.fix_core_ab_vote;
- perf->max_per_pipe_ib[i] = kms->perf.fix_core_ib_vote;
- }
+ perf->bw_ctl = kms->perf.fix_core_ab_vote;
+ perf->max_per_pipe_ib = kms->perf.fix_core_ib_vote;
perf->core_clk_rate = kms->perf.fix_core_clk_rate;
}
DPU_DEBUG(
- "crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n",
+ "crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu\n",
crtc->base.id, perf->core_clk_rate,
- perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_MNOC],
- perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_MNOC],
- perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_LLCC],
- perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_LLCC],
- perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_EBI],
- perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_EBI]);
+ perf->max_per_pipe_ib, perf->bw_ctl);
}
int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
@@ -121,7 +109,6 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
struct dpu_crtc_state *dpu_cstate;
struct drm_crtc *tmp_crtc;
struct dpu_kms *kms;
- int i;
if (!crtc || !state) {
DPU_ERROR("invalid crtc\n");
@@ -143,31 +130,25 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
/* obtain new values */
_dpu_core_perf_calc_crtc(kms, crtc, state, &dpu_cstate->new_perf);
- for (i = DPU_CORE_PERF_DATA_BUS_ID_MNOC;
- i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- bw_sum_of_intfs = dpu_cstate->new_perf.bw_ctl[i];
- curr_client_type = dpu_crtc_get_client_type(crtc);
+ bw_sum_of_intfs = dpu_cstate->new_perf.bw_ctl;
+ curr_client_type = dpu_crtc_get_client_type(crtc);
- drm_for_each_crtc(tmp_crtc, crtc->dev) {
- if (tmp_crtc->enabled &&
- (dpu_crtc_get_client_type(tmp_crtc) ==
- curr_client_type) &&
- (tmp_crtc != crtc)) {
- struct dpu_crtc_state *tmp_cstate =
- to_dpu_crtc_state(tmp_crtc->state);
-
- DPU_DEBUG("crtc:%d bw:%llu ctrl:%d\n",
- tmp_crtc->base.id,
- tmp_cstate->new_perf.bw_ctl[i],
- tmp_cstate->bw_control);
- /*
- * For bw check only use the bw if the
- * atomic property has been already set
- */
- if (tmp_cstate->bw_control)
- bw_sum_of_intfs +=
- tmp_cstate->new_perf.bw_ctl[i];
- }
+ drm_for_each_crtc(tmp_crtc, crtc->dev) {
+ if (tmp_crtc->enabled &&
+ (dpu_crtc_get_client_type(tmp_crtc) ==
+ curr_client_type) && (tmp_crtc != crtc)) {
+ struct dpu_crtc_state *tmp_cstate =
+ to_dpu_crtc_state(tmp_crtc->state);
+
+ DPU_DEBUG("crtc:%d bw:%llu ctrl:%d\n",
+ tmp_crtc->base.id, tmp_cstate->new_perf.bw_ctl,
+ tmp_cstate->bw_control);
+ /*
+ * For bw check only use the bw if the
+ * atomic property has been already set
+ */
+ if (tmp_cstate->bw_control)
+ bw_sum_of_intfs += tmp_cstate->new_perf.bw_ctl;
}
/* convert bandwidth to kb */
@@ -198,9 +179,9 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
}
static int _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms,
- struct drm_crtc *crtc, u32 bus_id)
+ struct drm_crtc *crtc)
{
- struct dpu_core_perf_params perf = { { 0 } };
+ struct dpu_core_perf_params perf = { 0 };
enum dpu_crtc_client_type curr_client_type
= dpu_crtc_get_client_type(crtc);
struct drm_crtc *tmp_crtc;
@@ -213,13 +194,11 @@ static int _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms,
dpu_crtc_get_client_type(tmp_crtc)) {
dpu_cstate = to_dpu_crtc_state(tmp_crtc->state);
- perf.max_per_pipe_ib[bus_id] =
- max(perf.max_per_pipe_ib[bus_id],
- dpu_cstate->new_perf.max_per_pipe_ib[bus_id]);
+ perf.max_per_pipe_ib = max(perf.max_per_pipe_ib,
+ dpu_cstate->new_perf.max_per_pipe_ib);
- DPU_DEBUG("crtc=%d bus_id=%d bw=%llu\n",
- tmp_crtc->base.id, bus_id,
- dpu_cstate->new_perf.bw_ctl[bus_id]);
+ DPU_DEBUG("crtc=%d bw=%llu\n", tmp_crtc->base.id,
+ dpu_cstate->new_perf.bw_ctl);
}
}
return ret;
@@ -239,7 +218,6 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc)
struct dpu_crtc *dpu_crtc;
struct dpu_crtc_state *dpu_cstate;
struct dpu_kms *kms;
- int i;
if (!crtc) {
DPU_ERROR("invalid crtc\n");
@@ -275,10 +253,8 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc)
if (kms->perf.enable_bw_release) {
trace_dpu_cmd_release_bw(crtc->base.id);
DPU_DEBUG("Release BW crtc=%d\n", crtc->base.id);
- for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- dpu_crtc->cur_perf.bw_ctl[i] = 0;
- _dpu_core_perf_crtc_update_bus(kms, crtc, i);
- }
+ dpu_crtc->cur_perf.bw_ctl = 0;
+ _dpu_core_perf_crtc_update_bus(kms, crtc);
}
}
@@ -321,11 +297,10 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
int params_changed, bool stop_req)
{
struct dpu_core_perf_params *new, *old;
- int update_bus = 0, update_clk = 0;
+ bool update_bus = false, update_clk = false;
u64 clk_rate = 0;
struct dpu_crtc *dpu_crtc;
struct dpu_crtc_state *dpu_cstate;
- int i;
struct msm_drm_private *priv;
struct dpu_kms *kms;
int ret;
@@ -352,62 +327,49 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
new = &dpu_cstate->new_perf;
if (crtc->enabled && !stop_req) {
- for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- /*
- * cases for bus bandwidth update.
- * 1. new bandwidth vote - "ab or ib vote" is higher
- * than current vote for update request.
- * 2. new bandwidth vote - "ab or ib vote" is lower
- * than current vote at end of commit or stop.
- */
- if ((params_changed && ((new->bw_ctl[i] >
- old->bw_ctl[i]) ||
- (new->max_per_pipe_ib[i] >
- old->max_per_pipe_ib[i]))) ||
- (!params_changed && ((new->bw_ctl[i] <
- old->bw_ctl[i]) ||
- (new->max_per_pipe_ib[i] <
- old->max_per_pipe_ib[i])))) {
- DPU_DEBUG(
- "crtc=%d p=%d new_bw=%llu,old_bw=%llu\n",
- crtc->base.id, params_changed,
- new->bw_ctl[i], old->bw_ctl[i]);
- old->bw_ctl[i] = new->bw_ctl[i];
- old->max_per_pipe_ib[i] =
- new->max_per_pipe_ib[i];
- update_bus |= BIT(i);
- }
+ /*
+ * cases for bus bandwidth update.
+ * 1. new bandwidth vote - "ab or ib vote" is higher
+ * than current vote for update request.
+ * 2. new bandwidth vote - "ab or ib vote" is lower
+ * than current vote at end of commit or stop.
+ */
+ if ((params_changed && ((new->bw_ctl > old->bw_ctl) ||
+ (new->max_per_pipe_ib > old->max_per_pipe_ib))) ||
+ (!params_changed && ((new->bw_ctl < old->bw_ctl) ||
+ (new->max_per_pipe_ib < old->max_per_pipe_ib)))) {
+ DPU_DEBUG("crtc=%d p=%d new_bw=%llu,old_bw=%llu\n",
+ crtc->base.id, params_changed,
+ new->bw_ctl, old->bw_ctl);
+ old->bw_ctl = new->bw_ctl;
+ old->max_per_pipe_ib = new->max_per_pipe_ib;
+ update_bus = true;
}
if ((params_changed &&
- (new->core_clk_rate > old->core_clk_rate)) ||
- (!params_changed &&
- (new->core_clk_rate < old->core_clk_rate))) {
+ (new->core_clk_rate > old->core_clk_rate)) ||
+ (!params_changed &&
+ (new->core_clk_rate < old->core_clk_rate))) {
old->core_clk_rate = new->core_clk_rate;
- update_clk = 1;
+ update_clk = true;
}
} else {
DPU_DEBUG("crtc=%d disable\n", crtc->base.id);
memset(old, 0, sizeof(*old));
memset(new, 0, sizeof(*new));
- update_bus = ~0;
- update_clk = 1;
+ update_bus = true;
+ update_clk = true;
}
- trace_dpu_perf_crtc_update(crtc->base.id,
- new->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_MNOC],
- new->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_LLCC],
- new->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_EBI],
- new->core_clk_rate, stop_req,
- update_bus, update_clk);
-
- for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- if (update_bus & BIT(i)) {
- ret = _dpu_core_perf_crtc_update_bus(kms, crtc, i);
- if (ret) {
- DPU_ERROR("crtc-%d: failed to update bw vote for bus-%d\n",
- crtc->base.id, i);
- return ret;
- }
+
+ trace_dpu_perf_crtc_update(crtc->base.id, new->bw_ctl,
+ new->core_clk_rate, stop_req, update_bus, update_clk);
+
+ if (update_bus) {
+ ret = _dpu_core_perf_crtc_update_bus(kms, crtc);
+ if (ret) {
+ DPU_ERROR("crtc-%d: failed to update bus bw vote\n",
+ crtc->base.id);
+ return ret;
}
}
@@ -498,8 +460,6 @@ int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent)
struct dentry *entry;
entry = debugfs_create_dir("core_perf", parent);
- if (IS_ERR_OR_NULL(entry))
- return -EINVAL;
debugfs_create_u64("max_core_clk_rate", 0600, entry,
&perf->max_core_clk_rate);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
index 6f0f1710023b..cf4b9b5964c6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
@@ -34,8 +34,8 @@ enum dpu_core_perf_data_bus_id {
* @core_clk_rate: core clock rate request
*/
struct dpu_core_perf_params {
- u64 max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_MAX];
- u64 bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_MAX];
+ u64 max_per_pipe_ib;
+ u64 bw_ctl;
u64 core_clk_rate;
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 3772f745589d..40ea6286eac1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1233,19 +1233,14 @@ static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v)
{
struct drm_crtc *crtc = (struct drm_crtc *) s->private;
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
- int i;
seq_printf(s, "client type: %d\n", dpu_crtc_get_client_type(crtc));
seq_printf(s, "intf_mode: %d\n", dpu_crtc_get_intf_mode(crtc));
seq_printf(s, "core_clk_rate: %llu\n",
dpu_crtc->cur_perf.core_clk_rate);
- for (i = DPU_CORE_PERF_DATA_BUS_ID_MNOC;
- i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
- seq_printf(s, "bw_ctl[%d]: %llu\n", i,
- dpu_crtc->cur_perf.bw_ctl[i]);
- seq_printf(s, "max_per_pipe_ib[%d]: %llu\n", i,
- dpu_crtc->cur_perf.max_per_pipe_ib[i]);
- }
+ seq_printf(s, "bw_ctl: %llu\n", dpu_crtc->cur_perf.bw_ctl);
+ seq_printf(s, "max_per_pipe_ib: %llu\n",
+ dpu_crtc->cur_perf.max_per_pipe_ib);
return 0;
}
@@ -1264,10 +1259,7 @@ static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc)
dpu_crtc->debugfs_root = debugfs_create_dir(dpu_crtc->name,
crtc->dev->primary->debugfs_root);
- if (!dpu_crtc->debugfs_root)
- return -ENOMEM;
- /* don't error check these */
debugfs_create_file("status", 0400,
dpu_crtc->debugfs_root,
dpu_crtc, &debugfs_status_fops);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 82bf16d61a45..1cf4e306fccf 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -622,9 +622,6 @@ static int dpu_encoder_virt_atomic_check(
}
}
- if (!ret)
- drm_mode_set_crtcinfo(adj_mode, 0);
-
trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags,
adj_mode->private_flags);
@@ -1985,8 +1982,6 @@ static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc)
/* create overall sub-directory for the encoder */
dpu_enc->debugfs_root = debugfs_create_dir(name,
drm_enc->dev->primary->debugfs_root);
- if (!dpu_enc->debugfs_root)
- return -ENOMEM;
/* don't error check these */
debugfs_create_file("status", 0600,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
index 2307c431a894..24ab6249083a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
@@ -471,90 +471,6 @@ static const struct dpu_format dpu_format_map[] = {
};
/*
- * A5x tile formats tables:
- * These tables hold the A5x tile formats supported.
- */
-static const struct dpu_format dpu_format_map_tile[] = {
- INTERLEAVED_RGB_FMT_TILED(BGR565,
- 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
- false, 2, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(ARGB8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
- true, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(ABGR8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
- true, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(XBGR8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
- false, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(RGBA8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
- true, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(BGRA8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
- true, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(BGRX8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
- false, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(XRGB8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
- false, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(RGBX8888,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
- false, 4, 0,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
- true, 4, DPU_FORMAT_FLAG_DX,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
- COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
- true, 4, DPU_FORMAT_FLAG_DX,
- DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED),
-
- PSEUDO_YUV_FMT_TILED(NV12,
- 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C2_R_Cr,
- DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV,
- DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_NV12),
-
- PSEUDO_YUV_FMT_TILED(NV21,
- 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C1_B_Cb,
- DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV,
- DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_NV12),
-};
-
-/*
* UBWC formats table:
* This table holds the UBWC formats supported.
* If a compression ratio needs to be used for this or any other format,
@@ -599,32 +515,6 @@ static const struct dpu_format dpu_format_map_ubwc[] = {
DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12),
};
-static const struct dpu_format dpu_format_map_p010[] = {
- PSEUDO_YUV_FMT_LOOSE(NV12,
- 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C2_R_Cr,
- DPU_CHROMA_420, (DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_DX),
- DPU_FETCH_LINEAR, 2),
-};
-
-static const struct dpu_format dpu_format_map_p010_ubwc[] = {
- PSEUDO_YUV_FMT_LOOSE_TILED(NV12,
- 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C2_R_Cr,
- DPU_CHROMA_420, (DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_DX |
- DPU_FORMAT_FLAG_COMPRESSED),
- DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12),
-};
-
-static const struct dpu_format dpu_format_map_tp10_ubwc[] = {
- PSEUDO_YUV_FMT_TILED(NV12,
- 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C2_R_Cr,
- DPU_CHROMA_420, (DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_DX |
- DPU_FORMAT_FLAG_COMPRESSED),
- DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12),
-};
-
/* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support
* Note: Not using the drm_format_*_subsampling since we have formats
*/
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
index 95cfd106e1a7..71b6987bff1e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
@@ -106,9 +106,9 @@ int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
rc = -EPERM;
}
- if (rc) {
- msm_dss_enable_clk(&clk_arry[i],
- i, false);
+ if (rc && i) {
+ msm_dss_enable_clk(&clk_arry[i - 1],
+ i - 1, false);
break;
}
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 885bf88afa3e..435b846f9f52 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -56,7 +56,7 @@ static const char * const iommu_ports[] = {
#define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"
static int dpu_kms_hw_init(struct msm_kms *kms);
-static int _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
+static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
static unsigned long dpu_iomap_size(struct platform_device *pdev,
const char *name)
@@ -142,8 +142,6 @@ static void dpu_debugfs_danger_init(struct dpu_kms *dpu_kms,
struct dentry *parent)
{
struct dentry *entry = debugfs_create_dir("danger", parent);
- if (IS_ERR_OR_NULL(entry))
- return;
debugfs_create_file("danger_status", 0600, entry,
dpu_kms, &dpu_debugfs_danger_stats_fops);
@@ -218,32 +216,29 @@ void dpu_debugfs_setup_regset32(struct dpu_debugfs_regset32 *regset,
}
}
-void *dpu_debugfs_create_regset32(const char *name, umode_t mode,
+void dpu_debugfs_create_regset32(const char *name, umode_t mode,
void *parent, struct dpu_debugfs_regset32 *regset)
{
if (!name || !regset || !regset->dpu_kms || !regset->blk_len)
- return NULL;
+ return;
/* make sure offset is a multiple of 4 */
regset->offset = round_down(regset->offset, 4);
- return debugfs_create_file(name, mode, parent,
- regset, &dpu_fops_regset32);
+ debugfs_create_file(name, mode, parent, regset, &dpu_fops_regset32);
}
-static int _dpu_debugfs_init(struct dpu_kms *dpu_kms)
+static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)
{
+ struct dpu_kms *dpu_kms = to_dpu_kms(kms);
void *p = dpu_hw_util_get_log_mask_ptr();
struct dentry *entry;
if (!p)
return -EINVAL;
- entry = debugfs_create_dir("debug", dpu_kms->dev->primary->debugfs_root);
- if (IS_ERR_OR_NULL(entry))
- return -ENODEV;
+ entry = debugfs_create_dir("debug", minor->debugfs_root);
- /* allow root to be NULL */
debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, entry, p);
dpu_debugfs_danger_init(dpu_kms, entry);
@@ -578,13 +573,6 @@ fail:
return ret;
}
-#ifdef CONFIG_DEBUG_FS
-static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)
-{
- return _dpu_debugfs_init(to_dpu_kms(kms));
-}
-#endif
-
static long dpu_kms_round_pixclk(struct msm_kms *kms, unsigned long rate,
struct drm_encoder *encoder)
{
@@ -725,17 +713,20 @@ static const struct msm_kms_funcs kms_funcs = {
#endif
};
-static int _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms)
+static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms)
{
struct msm_mmu *mmu;
+ if (!dpu_kms->base.aspace)
+ return;
+
mmu = dpu_kms->base.aspace->mmu;
mmu->funcs->detach(mmu, (const char **)iommu_ports,
ARRAY_SIZE(iommu_ports));
msm_gem_address_space_put(dpu_kms->base.aspace);
- return 0;
+ dpu_kms->base.aspace = NULL;
}
static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms)
@@ -754,25 +745,20 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms)
aspace = msm_gem_address_space_create(dpu_kms->dev->dev,
domain, "dpu1");
if (IS_ERR(aspace)) {
- ret = PTR_ERR(aspace);
- goto fail;
+ iommu_domain_free(domain);
+ return PTR_ERR(aspace);
}
- dpu_kms->base.aspace = aspace;
-
ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
ARRAY_SIZE(iommu_ports));
if (ret) {
DPU_ERROR("failed to attach iommu %d\n", ret);
msm_gem_address_space_put(aspace);
- goto fail;
+ return ret;
}
+ dpu_kms->base.aspace = aspace;
return 0;
-fail:
- _dpu_kms_mmu_destroy(dpu_kms);
-
- return ret;
}
static struct dss_clk *_dpu_kms_get_clk(struct dpu_kms *dpu_kms,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
index 31e9ef96ca5d..e9f998344838 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -197,12 +197,8 @@ void dpu_debugfs_setup_regset32(struct dpu_debugfs_regset32 *regset,
* @mode: File mode within debugfs
* @parent: Parent directory entry within debugfs, can be NULL
* @regset: Pointer to persistent register block definition
- *
- * Return: dentry pointer for newly created file, use either debugfs_remove()
- * or debugfs_remove_recursive() (on a parent directory) to remove the
- * file
*/
-void *dpu_debugfs_create_regset32(const char *name, umode_t mode,
+void dpu_debugfs_create_regset32(const char *name, umode_t mode,
void *parent, struct dpu_debugfs_regset32 *regset);
/**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
index 7316b4ab1b85..986915bbbc02 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
@@ -4,11 +4,15 @@
*/
#include "dpu_kms.h"
+#include <linux/interconnect.h>
#define to_dpu_mdss(x) container_of(x, struct dpu_mdss, base)
#define HW_INTR_STATUS 0x0010
+/* Max BW defined in KBps */
+#define MAX_BW 6800000
+
struct dpu_irq_controller {
unsigned long enabled_mask;
struct irq_domain *domain;
@@ -21,8 +25,40 @@ struct dpu_mdss {
u32 hwversion;
struct dss_module_power mp;
struct dpu_irq_controller irq_controller;
+ struct icc_path *path[2];
+ u32 num_paths;
};
+static int dpu_mdss_parse_data_bus_icc_path(struct drm_device *dev,
+ struct dpu_mdss *dpu_mdss)
+{
+ struct icc_path *path0 = of_icc_get(dev->dev, "mdp0-mem");
+ struct icc_path *path1 = of_icc_get(dev->dev, "mdp1-mem");
+
+ if (IS_ERR_OR_NULL(path0))
+ return PTR_ERR_OR_ZERO(path0);
+
+ dpu_mdss->path[0] = path0;
+ dpu_mdss->num_paths = 1;
+
+ if (!IS_ERR_OR_NULL(path1)) {
+ dpu_mdss->path[1] = path1;
+ dpu_mdss->num_paths++;
+ }
+
+ return 0;
+}
+
+static void dpu_mdss_icc_request_bw(struct msm_mdss *mdss)
+{
+ struct dpu_mdss *dpu_mdss = to_dpu_mdss(mdss);
+ int i;
+ u64 avg_bw = dpu_mdss->num_paths ? MAX_BW / dpu_mdss->num_paths : 0;
+
+ for (i = 0; i < dpu_mdss->num_paths; i++)
+ icc_set_bw(dpu_mdss->path[i], avg_bw, kBps_to_icc(MAX_BW));
+}
+
static void dpu_mdss_irq(struct irq_desc *desc)
{
struct dpu_mdss *dpu_mdss = irq_desc_get_handler_data(desc);
@@ -136,6 +172,8 @@ static int dpu_mdss_enable(struct msm_mdss *mdss)
struct dss_module_power *mp = &dpu_mdss->mp;
int ret;
+ dpu_mdss_icc_request_bw(mdss);
+
ret = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true);
if (ret)
DPU_ERROR("clock enable failed, ret:%d\n", ret);
@@ -147,12 +185,15 @@ static int dpu_mdss_disable(struct msm_mdss *mdss)
{
struct dpu_mdss *dpu_mdss = to_dpu_mdss(mdss);
struct dss_module_power *mp = &dpu_mdss->mp;
- int ret;
+ int ret, i;
ret = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false);
if (ret)
DPU_ERROR("clock disable failed, ret:%d\n", ret);
+ for (i = 0; i < dpu_mdss->num_paths; i++)
+ icc_set_bw(dpu_mdss->path[i], 0, 0);
+
return ret;
}
@@ -163,6 +204,7 @@ static void dpu_mdss_destroy(struct drm_device *dev)
struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss);
struct dss_module_power *mp = &dpu_mdss->mp;
int irq;
+ int i;
pm_runtime_suspend(dev->dev);
pm_runtime_disable(dev->dev);
@@ -172,6 +214,9 @@ static void dpu_mdss_destroy(struct drm_device *dev)
msm_dss_put_clk(mp->clk_config, mp->num_clk);
devm_kfree(&pdev->dev, mp->clk_config);
+ for (i = 0; i < dpu_mdss->num_paths; i++)
+ icc_put(dpu_mdss->path[i]);
+
if (dpu_mdss->mmio)
devm_iounmap(&pdev->dev, dpu_mdss->mmio);
dpu_mdss->mmio = NULL;
@@ -211,6 +256,10 @@ int dpu_mdss_init(struct drm_device *dev)
}
dpu_mdss->mmio_len = resource_size(res);
+ ret = dpu_mdss_parse_data_bus_icc_path(dev, dpu_mdss);
+ if (ret)
+ return ret;
+
mp = &dpu_mdss->mp;
ret = msm_dss_parse_clock(pdev, mp);
if (ret) {
@@ -232,14 +281,16 @@ int dpu_mdss_init(struct drm_device *dev)
irq_set_chained_handler_and_data(irq, dpu_mdss_irq,
dpu_mdss);
+ priv->mdss = &dpu_mdss->base;
+
pm_runtime_enable(dev->dev);
+ dpu_mdss_icc_request_bw(priv->mdss);
+
pm_runtime_get_sync(dev->dev);
dpu_mdss->hwversion = readl_relaxed(dpu_mdss->mmio);
pm_runtime_put_sync(dev->dev);
- priv->mdss = &dpu_mdss->base;
-
return ret;
irq_error:
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index d831cedb55ec..1858b40b18d8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -21,6 +21,7 @@
#include <linux/debugfs.h>
#include <linux/dma-buf.h>
+#include <drm/drm_damage_helper.h>
#include <drm/drm_atomic_uapi.h>
#include "msm_drv.h"
@@ -1324,9 +1325,6 @@ static int _dpu_plane_init_debugfs(struct drm_plane *plane)
debugfs_create_dir(pdpu->pipe_name,
plane->dev->primary->debugfs_root);
- if (!pdpu->debugfs_root)
- return -ENOMEM;
-
/* don't error check these */
debugfs_create_x32("features", 0600,
pdpu->debugfs_root, &pdpu->features);
@@ -1535,6 +1533,8 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
if (ret)
DPU_ERROR("failed to install zpos property, rc = %d\n", ret);
+ drm_plane_enable_fb_damage_clips(plane);
+
/* success! finalize initialization */
drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
index 7dac604b268d..765484437d11 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
@@ -138,16 +138,12 @@ TRACE_EVENT(dpu_trace_counter,
)
TRACE_EVENT(dpu_perf_crtc_update,
- TP_PROTO(u32 crtc, u64 bw_ctl_mnoc, u64 bw_ctl_llcc,
- u64 bw_ctl_ebi, u32 core_clk_rate,
- bool stop_req, u32 update_bus, u32 update_clk),
- TP_ARGS(crtc, bw_ctl_mnoc, bw_ctl_llcc, bw_ctl_ebi, core_clk_rate,
- stop_req, update_bus, update_clk),
+ TP_PROTO(u32 crtc, u64 bw_ctl, u32 core_clk_rate,
+ bool stop_req, bool update_bus, bool update_clk),
+ TP_ARGS(crtc, bw_ctl, core_clk_rate, stop_req, update_bus, update_clk),
TP_STRUCT__entry(
__field(u32, crtc)
- __field(u64, bw_ctl_mnoc)
- __field(u64, bw_ctl_llcc)
- __field(u64, bw_ctl_ebi)
+ __field(u64, bw_ctl)
__field(u32, core_clk_rate)
__field(bool, stop_req)
__field(u32, update_bus)
@@ -155,20 +151,16 @@ TRACE_EVENT(dpu_perf_crtc_update,
),
TP_fast_assign(
__entry->crtc = crtc;
- __entry->bw_ctl_mnoc = bw_ctl_mnoc;
- __entry->bw_ctl_llcc = bw_ctl_llcc;
- __entry->bw_ctl_ebi = bw_ctl_ebi;
+ __entry->bw_ctl = bw_ctl;
__entry->core_clk_rate = core_clk_rate;
__entry->stop_req = stop_req;
__entry->update_bus = update_bus;
__entry->update_clk = update_clk;
),
TP_printk(
- "crtc=%d bw_mnoc=%llu bw_llcc=%llu bw_ebi=%llu clk_rate=%u stop_req=%d u_bus=%d u_clk=%d",
+ "crtc=%d bw_ctl=%llu clk_rate=%u stop_req=%d u_bus=%d u_clk=%d",
__entry->crtc,
- __entry->bw_ctl_mnoc,
- __entry->bw_ctl_llcc,
- __entry->bw_ctl_ebi,
+ __entry->bw_ctl,
__entry->core_clk_rate,
__entry->stop_req,
__entry->update_bus,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c
index 3c9236bb291c..8bc3aea7cd86 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c
@@ -310,8 +310,6 @@ void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)
int i, j;
entry = debugfs_create_dir("vbif", debugfs_root);
- if (IS_ERR_OR_NULL(entry))
- return;
for (i = 0; i < dpu_kms->catalog->vbif_count; i++) {
struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i];
@@ -319,8 +317,6 @@ void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)
snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id);
debugfs_vbif = debugfs_create_dir(vbif_name, entry);
- if (IS_ERR_OR_NULL(debugfs_vbif))
- continue;
debugfs_create_u32("features", 0600, debugfs_vbif,
(u32 *)&vbif->features);
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
index 005066f7154d..2d46d1126283 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
@@ -15,6 +15,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <drm/drm_damage_helper.h>
#include "mdp4_kms.h"
#define DOWN_SCALE_MAX 8
@@ -391,6 +392,8 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
mdp4_plane_install_properties(plane, &plane->base);
+ drm_plane_enable_fb_damage_clips(plane);
+
return plane;
fail:
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
index f86351b16e0f..dd1daf0e305a 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
@@ -713,7 +713,7 @@ fail:
if (cfg_handler)
mdp5_cfg_destroy(cfg_handler);
- return NULL;
+ return ERR_PTR(ret);
}
static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index 97179bec8902..1c55401956c4 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -16,6 +16,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/interconnect.h>
#include <linux/of_irq.h>
#include "msm_drv.h"
@@ -1048,9 +1049,46 @@ static const struct component_ops mdp5_ops = {
.unbind = mdp5_unbind,
};
+static int mdp5_setup_interconnect(struct platform_device *pdev)
+{
+ struct icc_path *path0 = of_icc_get(&pdev->dev, "mdp0-mem");
+ struct icc_path *path1 = of_icc_get(&pdev->dev, "mdp1-mem");
+ struct icc_path *path_rot = of_icc_get(&pdev->dev, "rotator-mem");
+
+ if (IS_ERR(path0))
+ return PTR_ERR(path0);
+
+ if (!path0) {
+ /* no interconnect support is not necessarily a fatal
+ * condition, the platform may simply not have an
+ * interconnect driver yet. But warn about it in case
+ * bootloader didn't setup bus clocks high enough for
+ * scanout.
+ */
+ dev_warn(&pdev->dev, "No interconnect support may cause display underflows!\n");
+ return 0;
+ }
+
+ icc_set_bw(path0, 0, MBps_to_icc(6400));
+
+ if (!IS_ERR_OR_NULL(path1))
+ icc_set_bw(path1, 0, MBps_to_icc(6400));
+ if (!IS_ERR_OR_NULL(path_rot))
+ icc_set_bw(path_rot, 0, MBps_to_icc(6400));
+
+ return 0;
+}
+
static int mdp5_dev_probe(struct platform_device *pdev)
{
+ int ret;
+
DBG("");
+
+ ret = mdp5_setup_interconnect(pdev);
+ if (ret)
+ return ret;
+
return component_add(&pdev->dev, &mdp5_ops);
}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
index 1105c2433f14..91609bde033a 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -16,6 +16,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <drm/drm_damage_helper.h>
#include <drm/drm_print.h>
#include "mdp5_kms.h"
@@ -1099,6 +1100,8 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
mdp5_plane_install_properties(plane, &plane->base);
+ drm_plane_enable_fb_damage_clips(plane);
+
return plane;
fail:
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index ada942498b4e..55ea4bc2ee9c 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -242,6 +242,8 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
goto fail;
}
+ msm_dsi_manager_setup_encoder(msm_dsi->id);
+
priv->bridges[priv->num_bridges++] = msm_dsi->bridge;
priv->connectors[priv->num_connectors++] = msm_dsi->connector;
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 20a5d3cb0cab..0da8a4e428ad 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -71,7 +71,6 @@ struct msm_dsi {
*/
struct drm_panel *panel;
struct drm_bridge *external_bridge;
- unsigned long device_flags;
struct device *phy_dev;
bool phy_enabled;
@@ -89,7 +88,7 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id);
struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id);
int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
-void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags);
+void msm_dsi_manager_setup_encoder(int id);
int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
bool msm_dsi_manager_validate_current_config(u8 id);
@@ -161,8 +160,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host,
int msm_dsi_host_power_off(struct mipi_dsi_host *host);
int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
const struct drm_display_mode *mode);
-struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
- unsigned long *panel_flags);
+struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
+unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
void msm_dsi_host_unregister(struct mipi_dsi_host *host);
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
index 9ddf16380289..b7b7c1a9164a 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
@@ -110,6 +110,25 @@ static const struct msm_dsi_config msm8996_dsi_cfg = {
.num_dsi = 2,
};
+static const char * const dsi_msm8998_bus_clk_names[] = {
+ "iface", "bus", "core",
+};
+
+static const struct msm_dsi_config msm8998_dsi_cfg = {
+ .io_offset = DSI_6G_REG_SHIFT,
+ .reg_cfg = {
+ .num = 2,
+ .regs = {
+ {"vdd", 367000, 16 }, /* 0.9 V */
+ {"vdda", 62800, 2 }, /* 1.2 V */
+ },
+ },
+ .bus_clk_names = dsi_msm8998_bus_clk_names,
+ .num_bus_clks = ARRAY_SIZE(dsi_msm8998_bus_clk_names),
+ .io_start = { 0xc994000, 0xc996000 },
+ .num_dsi = 2,
+};
+
static const char * const dsi_sdm845_bus_clk_names[] = {
"iface", "bus",
};
@@ -178,6 +197,8 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
&msm8916_dsi_cfg, &msm_dsi_6g_host_ops},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1,
&msm8996_dsi_cfg, &msm_dsi_6g_host_ops},
+ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0,
+ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1,
&sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops},
};
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
index a6a3d2bad263..e2b7a7dfbe49 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
@@ -17,6 +17,7 @@
#define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000
#define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001
#define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001
+#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000
#define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001
#define MSM_DSI_V2_VER_MINOR_8064 0x0
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index dbf490176c2c..aa35d18ab43c 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -1041,7 +1041,7 @@ static void dsi_wait4video_done(struct msm_dsi_host *msm_host)
ret = wait_for_completion_timeout(&msm_host->video_comp,
msecs_to_jiffies(70));
- if (ret <= 0)
+ if (ret == 0)
DRM_DEV_ERROR(dev, "wait for video done timed out\n");
dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 0);
@@ -1590,8 +1590,6 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
msm_host->format = dsi->format;
msm_host->mode_flags = dsi->mode_flags;
- msm_dsi_manager_attach_dsi_device(msm_host->id, dsi->mode_flags);
-
/* Some gpios defined in panel DT need to be controlled by host */
ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev);
if (ret)
@@ -2434,17 +2432,14 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
return 0;
}
-struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
- unsigned long *panel_flags)
+struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
{
- struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
- struct drm_panel *panel;
-
- panel = of_drm_find_panel(msm_host->device_node);
- if (panel_flags)
- *panel_flags = msm_host->mode_flags;
+ return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
+}
- return panel;
+unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
+{
+ return to_msm_dsi_host(host)->mode_flags;
}
struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index ec6cb0f7f206..271aa7bbca92 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -225,64 +225,80 @@ static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
return dsi_bridge->id;
}
-static enum drm_connector_status dsi_mgr_connector_detect(
- struct drm_connector *connector, bool force)
+static bool dsi_mgr_is_cmd_mode(struct msm_dsi *msm_dsi)
+{
+ unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
+ return !(host_flags & MIPI_DSI_MODE_VIDEO);
+}
+
+void msm_dsi_manager_setup_encoder(int id)
{
- int id = dsi_mgr_connector_get_id(connector);
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
- struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
- struct msm_drm_private *priv = connector->dev->dev_private;
+ struct msm_drm_private *priv = msm_dsi->dev->dev_private;
struct msm_kms *kms = priv->kms;
+ struct drm_encoder *encoder = msm_dsi_get_encoder(msm_dsi);
- DBG("id=%d", id);
- if (!msm_dsi->panel) {
- msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
- &msm_dsi->device_flags);
-
- /* There is only 1 panel in the global panel list
- * for dual DSI mode. Therefore slave dsi should get
- * the drm_panel instance from master dsi, and
- * keep using the panel flags got from the current DSI link.
- */
- if (!msm_dsi->panel && IS_DUAL_DSI() &&
- !IS_MASTER_DSI_LINK(id) && other_dsi)
- msm_dsi->panel = msm_dsi_host_get_panel(
- other_dsi->host, NULL);
+ if (encoder && kms->funcs->set_encoder_mode)
+ kms->funcs->set_encoder_mode(kms, encoder,
+ dsi_mgr_is_cmd_mode(msm_dsi));
+}
+static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
+{
+ struct msm_drm_private *priv = conn->dev->dev_private;
+ struct msm_kms *kms = priv->kms;
+ struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+ struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+ struct msm_dsi *master_dsi, *slave_dsi;
+ struct drm_panel *panel;
- if (msm_dsi->panel && kms->funcs->set_encoder_mode) {
- bool cmd_mode = !(msm_dsi->device_flags &
- MIPI_DSI_MODE_VIDEO);
- struct drm_encoder *encoder =
- msm_dsi_get_encoder(msm_dsi);
+ if (IS_DUAL_DSI() && !IS_MASTER_DSI_LINK(id)) {
+ master_dsi = other_dsi;
+ slave_dsi = msm_dsi;
+ } else {
+ master_dsi = msm_dsi;
+ slave_dsi = other_dsi;
+ }
- kms->funcs->set_encoder_mode(kms, encoder, cmd_mode);
- }
+ /*
+ * There is only 1 panel in the global panel list for dual DSI mode.
+ * Therefore slave dsi should get the drm_panel instance from master
+ * dsi.
+ */
+ panel = msm_dsi_host_get_panel(master_dsi->host);
+ if (IS_ERR(panel)) {
+ DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
+ PTR_ERR(panel));
+ return PTR_ERR(panel);
+ }
- if (msm_dsi->panel && IS_DUAL_DSI())
- drm_object_attach_property(&connector->base,
- connector->dev->mode_config.tile_property, 0);
+ if (!panel || !IS_DUAL_DSI())
+ goto out;
- /* Set split display info to kms once dual DSI panel is
- * connected to both hosts.
- */
- if (msm_dsi->panel && IS_DUAL_DSI() &&
- other_dsi && other_dsi->panel) {
- bool cmd_mode = !(msm_dsi->device_flags &
- MIPI_DSI_MODE_VIDEO);
- struct drm_encoder *encoder = msm_dsi_get_encoder(
- dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
- struct drm_encoder *slave_enc = msm_dsi_get_encoder(
- dsi_mgr_get_dsi(DSI_ENCODER_SLAVE));
-
- if (kms->funcs->set_split_display)
- kms->funcs->set_split_display(kms, encoder,
- slave_enc, cmd_mode);
- else
- pr_err("mdp does not support dual DSI\n");
- }
+ drm_object_attach_property(&conn->base,
+ conn->dev->mode_config.tile_property, 0);
+
+ /*
+ * Set split display info to kms once dual DSI panel is connected to
+ * both hosts.
+ */
+ if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
+ kms->funcs->set_split_display(kms, master_dsi->encoder,
+ slave_dsi->encoder,
+ dsi_mgr_is_cmd_mode(msm_dsi));
}
+out:
+ msm_dsi->panel = panel;
+ return 0;
+}
+
+static enum drm_connector_status dsi_mgr_connector_detect(
+ struct drm_connector *connector, bool force)
+{
+ int id = dsi_mgr_connector_get_id(connector);
+ struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+
return msm_dsi->panel ? connector_status_connected :
connector_status_disconnected;
}
@@ -595,7 +611,17 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id)
drm_connector_attach_encoder(connector, msm_dsi->encoder);
+ ret = msm_dsi_manager_panel_init(connector, id);
+ if (ret) {
+ DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
+ goto fail;
+ }
+
return connector;
+
+fail:
+ connector->funcs->destroy(msm_dsi->connector);
+ return ERR_PTR(ret);
}
bool msm_dsi_manager_validate_current_config(u8 id)
@@ -751,35 +777,6 @@ bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len)
return true;
}
-void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags)
-{
- struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
- struct drm_device *dev = msm_dsi->dev;
- struct msm_drm_private *priv;
- struct msm_kms *kms;
- struct drm_encoder *encoder;
- bool cmd_mode;
-
- /*
- * drm_device pointer is assigned to msm_dsi only in the modeset_init
- * path. If mipi_dsi_attach() happens in DSI driver's probe path
- * (generally the case when we're connected to a drm_panel of the type
- * mipi_dsi_device), this would be NULL. In such cases, try to set the
- * encoder mode in the DSI connector's detect() op.
- */
- if (!dev)
- return;
-
- priv = dev->dev_private;
- kms = priv->kms;
- encoder = msm_dsi_get_encoder(msm_dsi);
- cmd_mode = !(device_flags &
- MIPI_DSI_MODE_VIDEO);
-
- if (encoder && kms->funcs->set_encoder_mode)
- kms->funcs->set_encoder_mode(kms, encoder, cmd_mode);
-}
-
int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
{
struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index bc6f64b202f3..4097eca1b3ef 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -499,6 +499,8 @@ static const struct of_device_id dsi_phy_dt_match[] = {
#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY
{ .compatible = "qcom,dsi-phy-10nm",
.data = &dsi_phy_10nm_cfgs },
+ { .compatible = "qcom,dsi-phy-10nm-8998",
+ .data = &dsi_phy_10nm_8998_cfgs },
#endif
{}
};
@@ -608,10 +610,12 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
goto fail;
phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
- if (IS_ERR_OR_NULL(phy->pll))
+ if (IS_ERR_OR_NULL(phy->pll)) {
DRM_DEV_INFO(dev,
"%s: pll init failed: %ld, need separate pll clk driver\n",
__func__, PTR_ERR(phy->pll));
+ phy->pll = NULL;
+ }
dsi_phy_disable_resource(phy);
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
index 86322c88b98e..c4069ce6afe6 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
@@ -13,6 +13,9 @@
#define dsi_phy_read(offset) msm_readl((offset))
#define dsi_phy_write(offset, data) msm_writel((data), (offset))
+/* v3.0.0 10nm implementation that requires the old timings settings */
+#define V3_0_0_10NM_OLD_TIMINGS_QUIRK BIT(0)
+
struct msm_dsi_phy_ops {
int (*init) (struct msm_dsi_phy *phy);
int (*enable)(struct msm_dsi_phy *phy, int src_pll_id,
@@ -33,6 +36,7 @@ struct msm_dsi_phy_cfg {
bool src_pll_truthtable[DSI_MAX][DSI_MAX];
const resource_size_t io_start[DSI_MAX];
const int num_dsi_phy;
+ const int quirks;
};
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs;
@@ -41,6 +45,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs;
struct msm_dsi_dphy_timing {
u32 clk_pre;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
index 44959e79ce28..47403d4f2d28 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
@@ -42,6 +42,9 @@ static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy)
u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 };
void __iomem *lane_base = phy->lane_base;
+ if (phy->cfg->quirks & V3_0_0_10NM_OLD_TIMINGS_QUIRK)
+ tx_dctrl[3] = 0x02;
+
/* Strength ctrl settings */
for (i = 0; i < 5; i++) {
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i),
@@ -74,9 +77,11 @@ static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy)
tx_dctrl[i]);
}
- /* Toggle BIT 0 to release freeze I/0 */
- dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05);
- dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04);
+ if (!(phy->cfg->quirks & V3_0_0_10NM_OLD_TIMINGS_QUIRK)) {
+ /* Toggle BIT 0 to release freeze I/0 */
+ dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05);
+ dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04);
+ }
}
static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
@@ -221,3 +226,22 @@ const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = {
.io_start = { 0xae94400, 0xae96400 },
.num_dsi_phy = 2,
};
+
+const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs = {
+ .type = MSM_DSI_PHY_10NM,
+ .src_pll_truthtable = { {false, false}, {true, false} },
+ .reg_cfg = {
+ .num = 1,
+ .regs = {
+ {"vdds", 36000, 32},
+ },
+ },
+ .ops = {
+ .enable = dsi_10nm_phy_enable,
+ .disable = dsi_10nm_phy_disable,
+ .init = dsi_10nm_phy_init,
+ },
+ .io_start = { 0xc994400, 0xc996400 },
+ .num_dsi_phy = 2,
+ .quirks = V3_0_0_10NM_OLD_TIMINGS_QUIRK,
+};
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
index aabab6311043..8f6100db90ed 100644
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
@@ -104,8 +104,13 @@ struct dsi_pll_10nm {
struct dsi_pll_regs reg_setup;
/* private clocks: */
- struct clk_hw *hws[NUM_DSI_CLOCKS_MAX];
- u32 num_hws;
+ struct clk_hw *out_div_clk_hw;
+ struct clk_hw *bit_clk_hw;
+ struct clk_hw *byte_clk_hw;
+ struct clk_hw *by_2_bit_clk_hw;
+ struct clk_hw *post_out_div_clk_hw;
+ struct clk_hw *pclk_mux_hw;
+ struct clk_hw *out_dsiclk_hw;
/* clock-provider: */
struct clk_hw_onecell_data *hw_data;
@@ -617,8 +622,19 @@ static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll,
static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll)
{
struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+ struct device *dev = &pll_10nm->pdev->dev;
DBG("DSI PLL%d", pll_10nm->id);
+ of_clk_del_provider(dev->of_node);
+
+ clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw);
+ clk_hw_unregister_mux(pll_10nm->pclk_mux_hw);
+ clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw);
+ clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw);
+ clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw);
+ clk_hw_unregister_divider(pll_10nm->bit_clk_hw);
+ clk_hw_unregister_divider(pll_10nm->out_div_clk_hw);
+ clk_hw_unregister(&pll_10nm->base.clk_hw);
}
/*
@@ -639,10 +655,8 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
.ops = &clk_ops_dsi_pll_10nm_vco,
};
struct device *dev = &pll_10nm->pdev->dev;
- struct clk_hw **hws = pll_10nm->hws;
struct clk_hw_onecell_data *hw_data;
struct clk_hw *hw;
- int num = 0;
int ret;
DBG("DSI%d", pll_10nm->id);
@@ -660,8 +674,6 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
if (ret)
return ret;
- hws[num++] = &pll_10nm->base.clk_hw;
-
snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id);
@@ -670,10 +682,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
pll_10nm->mmio +
REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE,
0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto err_base_clk_hw;
+ }
- hws[num++] = hw;
+ pll_10nm->out_div_clk_hw = hw;
snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
@@ -685,10 +699,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
REG_DSI_10nm_PHY_CMN_CLK_CFG0,
0, 4, CLK_DIVIDER_ONE_BASED,
&pll_10nm->postdiv_lock);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto err_out_div_clk_hw;
+ }
- hws[num++] = hw;
+ pll_10nm->bit_clk_hw = hw;
snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->id);
snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
@@ -696,10 +712,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
/* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */
hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
CLK_SET_RATE_PARENT, 1, 8);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto err_bit_clk_hw;
+ }
- hws[num++] = hw;
+ pll_10nm->byte_clk_hw = hw;
hw_data->hws[DSI_BYTE_PLL_CLK] = hw;
snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id);
@@ -707,20 +725,24 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
0, 1, 2);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto err_byte_clk_hw;
+ }
- hws[num++] = hw;
+ pll_10nm->by_2_bit_clk_hw = hw;
snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id);
snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
0, 1, 4);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto err_by_2_bit_clk_hw;
+ }
- hws[num++] = hw;
+ pll_10nm->post_out_div_clk_hw = hw;
snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id);
snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
@@ -734,10 +756,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
}, 4, 0, pll_10nm->phy_cmn_mmio +
REG_DSI_10nm_PHY_CMN_CLK_CFG1,
0, 2, 0, NULL);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto err_post_out_div_clk_hw;
+ }
- hws[num++] = hw;
+ pll_10nm->pclk_mux_hw = hw;
snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->id);
snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id);
@@ -748,14 +772,14 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
REG_DSI_10nm_PHY_CMN_CLK_CFG0,
4, 4, CLK_DIVIDER_ONE_BASED,
&pll_10nm->postdiv_lock);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto err_pclk_mux_hw;
+ }
- hws[num++] = hw;
+ pll_10nm->out_dsiclk_hw = hw;
hw_data->hws[DSI_PIXEL_PLL_CLK] = hw;
- pll_10nm->num_hws = num;
-
hw_data->num = NUM_PROVIDED_CLKS;
pll_10nm->hw_data = hw_data;
@@ -763,10 +787,29 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
pll_10nm->hw_data);
if (ret) {
DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
- return ret;
+ goto err_dsiclk_hw;
}
return 0;
+
+err_dsiclk_hw:
+ clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw);
+err_pclk_mux_hw:
+ clk_hw_unregister_mux(pll_10nm->pclk_mux_hw);
+err_post_out_div_clk_hw:
+ clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw);
+err_by_2_bit_clk_hw:
+ clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw);
+err_byte_clk_hw:
+ clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw);
+err_bit_clk_hw:
+ clk_hw_unregister_divider(pll_10nm->bit_clk_hw);
+err_out_div_clk_hw:
+ clk_hw_unregister_divider(pll_10nm->out_div_clk_hw);
+err_base_clk_hw:
+ clk_hw_unregister(&pll_10nm->base.clk_hw);
+
+ return ret;
}
struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
@@ -775,9 +818,6 @@ struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
struct msm_dsi_pll *pll;
int ret;
- if (!pdev)
- return ERR_PTR(-ENODEV);
-
pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL);
if (!pll_10nm)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 31deb87abfc6..229d49740677 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -259,13 +259,24 @@ static int msm_drm_uninit(struct device *dev)
struct msm_mdss *mdss = priv->mdss;
int i;
+ /*
+ * Shutdown the hw if we're far enough along where things might be on.
+ * If we run this too early, we'll end up panicking in any variety of
+ * places. Since we don't register the drm device until late in
+ * msm_drm_init, drm_dev->registered is used as an indicator that the
+ * shutdown will be successful.
+ */
+ if (ddev->registered) {
+ drm_dev_unregister(ddev);
+ drm_atomic_helper_shutdown(ddev);
+ }
+
/* We must cancel and cleanup any pending vblank enable/disable
* work before drm_irq_uninstall() to avoid work re-enabling an
* irq after uninstall has disabled it.
*/
flush_workqueue(priv->wq);
- destroy_workqueue(priv->wq);
/* clean up event worker threads */
for (i = 0; i < priv->num_crtcs; i++) {
@@ -279,8 +290,6 @@ static int msm_drm_uninit(struct device *dev)
drm_kms_helper_poll_fini(ddev);
- drm_dev_unregister(ddev);
-
msm_perf_debugfs_cleanup(priv);
msm_rd_debugfs_cleanup(priv);
@@ -288,7 +297,7 @@ static int msm_drm_uninit(struct device *dev)
if (fbdev && priv->fbdev)
msm_fbdev_free(ddev);
#endif
- drm_atomic_helper_shutdown(ddev);
+
drm_mode_config_cleanup(ddev);
pm_runtime_get_sync(dev);
@@ -313,6 +322,7 @@ static int msm_drm_uninit(struct device *dev)
ddev->dev_private = NULL;
drm_dev_put(ddev);
+ destroy_workqueue(priv->wq);
kfree(priv);
return 0;
@@ -611,6 +621,7 @@ static void load_gpu(struct drm_device *dev)
static int context_init(struct drm_device *dev, struct drm_file *file)
{
+ struct msm_drm_private *priv = dev->dev_private;
struct msm_file_private *ctx;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -619,6 +630,7 @@ static int context_init(struct drm_device *dev, struct drm_file *file)
msm_submitqueue_init(dev, ctx);
+ ctx->aspace = priv->gpu->aspace;
file->driver_priv = ctx;
return 0;
@@ -1317,16 +1329,24 @@ static int msm_pdev_probe(struct platform_device *pdev)
ret = add_gpu_components(&pdev->dev, &match);
if (ret)
- return ret;
+ goto fail;
/* on all devices that I am aware of, iommu's which can map
* any address the cpu can see are used:
*/
ret = dma_set_mask_and_coherent(&pdev->dev, ~0);
if (ret)
- return ret;
+ goto fail;
+
+ ret = component_master_add_with_match(&pdev->dev, &msm_drm_ops, match);
+ if (ret)
+ goto fail;
- return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match);
+ return 0;
+
+fail:
+ of_platform_depopulate(&pdev->dev);
+ return ret;
}
static int msm_pdev_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index e20e6b429804..d9aa7bad454d 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -68,6 +68,7 @@ struct msm_file_private {
rwlock_t queuelock;
struct list_head submitqueues;
int queueid;
+ struct msm_gem_address_space *aspace;
};
enum msm_mdp_plane_property {
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 68fa2c8f61e6..a816ceb58716 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -16,6 +16,7 @@
*/
#include <drm/drm_crtc.h>
+#include <drm/drm_damage_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_probe_helper.h>
@@ -35,6 +36,7 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
static const struct drm_framebuffer_funcs msm_framebuffer_funcs = {
.create_handle = drm_gem_fb_create_handle,
.destroy = drm_gem_fb_destroy,
+ .dirty = drm_atomic_helper_dirtyfb,
};
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 35f55dd25994..d31d9f927887 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -352,8 +352,10 @@ put_iova(struct drm_gem_object *obj)
WARN_ON(!mutex_is_locked(&msm_obj->lock));
list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) {
- msm_gem_purge_vma(vma->aspace, vma);
- msm_gem_close_vma(vma->aspace, vma);
+ if (vma->aspace) {
+ msm_gem_purge_vma(vma->aspace, vma);
+ msm_gem_close_vma(vma->aspace, vma);
+ }
del_vma(vma);
}
}
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 812d1b1369a5..36aeb58c132b 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -141,6 +141,7 @@ void msm_gem_free_work(struct work_struct *work);
struct msm_gem_submit {
struct drm_device *dev;
struct msm_gpu *gpu;
+ struct msm_gem_address_space *aspace;
struct list_head node; /* node in ring submit list */
struct list_head bo_list;
struct ww_acquire_ctx ticket;
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 1b681306aca3..d3801bfa4407 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -32,8 +32,9 @@
#define BO_PINNED 0x2000
static struct msm_gem_submit *submit_create(struct drm_device *dev,
- struct msm_gpu *gpu, struct msm_gpu_submitqueue *queue,
- uint32_t nr_bos, uint32_t nr_cmds)
+ struct msm_gpu *gpu, struct msm_gem_address_space *aspace,
+ struct msm_gpu_submitqueue *queue, uint32_t nr_bos,
+ uint32_t nr_cmds)
{
struct msm_gem_submit *submit;
uint64_t sz = sizeof(*submit) + ((u64)nr_bos * sizeof(submit->bos[0])) +
@@ -47,6 +48,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
return NULL;
submit->dev = dev;
+ submit->aspace = aspace;
submit->gpu = gpu;
submit->fence = NULL;
submit->cmd = (void *)&submit->bos[nr_bos];
@@ -160,7 +162,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit,
struct msm_gem_object *msm_obj = submit->bos[i].obj;
if (submit->bos[i].flags & BO_PINNED)
- msm_gem_unpin_iova(&msm_obj->base, submit->gpu->aspace);
+ msm_gem_unpin_iova(&msm_obj->base, submit->aspace);
if (submit->bos[i].flags & BO_LOCKED)
ww_mutex_unlock(&msm_obj->base.resv->lock);
@@ -264,7 +266,7 @@ static int submit_pin_objects(struct msm_gem_submit *submit)
/* if locking succeeded, pin bo: */
ret = msm_gem_get_and_pin_iova(&msm_obj->base,
- submit->gpu->aspace, &iova);
+ submit->aspace, &iova);
if (ret)
break;
@@ -477,7 +479,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
}
}
- submit = submit_create(dev, gpu, queue, args->nr_bos, args->nr_cmds);
+ submit = submit_create(dev, gpu, ctx->aspace, queue, args->nr_bos,
+ args->nr_cmds);
if (!submit) {
ret = -ENOMEM;
goto out_unlock;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index bf4ee2766431..0a4c77fb3d94 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -684,7 +684,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_ringbuffer *ring,
struct msm_gem_object *msm_obj = submit->bos[i].obj;
/* move to inactive: */
msm_gem_move_to_inactive(&msm_obj->base);
- msm_gem_unpin_iova(&msm_obj->base, gpu->aspace);
+ msm_gem_unpin_iova(&msm_obj->base, submit->aspace);
drm_gem_object_put(&msm_obj->base);
}
@@ -768,8 +768,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
/* submit takes a reference to the bo and iova until retired: */
drm_gem_object_get(&msm_obj->base);
- msm_gem_get_and_pin_iova(&msm_obj->base,
- submit->gpu->aspace, &iova);
+ msm_gem_get_and_pin_iova(&msm_obj->base, submit->aspace, &iova);
if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 12bb54cefd46..19263290b9b7 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -30,7 +30,7 @@ static int msm_fault_handler(struct iommu_domain *domain, struct device *dev,
struct msm_iommu *iommu = arg;
if (iommu->base.handler)
return iommu->base.handler(iommu->base.arg, iova, flags);
- pr_warn_ratelimited("*** fault: iova=%08lx, flags=%d\n", iova, flags);
+ pr_warn_ratelimited("*** fault: iova=%16lx, flags=%d\n", iova, flags);
return 0;
}
diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c
index 5ab21bd2decb..95948cfe7a12 100644
--- a/drivers/gpu/drm/msm/msm_perf.c
+++ b/drivers/gpu/drm/msm/msm_perf.c
@@ -205,7 +205,6 @@ int msm_perf_debugfs_init(struct drm_minor *minor)
{
struct msm_drm_private *priv = minor->dev->dev_private;
struct msm_perf_state *perf;
- struct dentry *ent;
/* only create on first minor: */
if (priv->perf)
@@ -220,19 +219,9 @@ int msm_perf_debugfs_init(struct drm_minor *minor)
mutex_init(&perf->read_lock);
priv->perf = perf;
- ent = debugfs_create_file("perf", S_IFREG | S_IRUGO,
- minor->debugfs_root, perf, &perf_debugfs_fops);
- if (!ent) {
- DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/perf\n",
- minor->debugfs_root);
- goto fail;
- }
-
+ debugfs_create_file("perf", S_IFREG | S_IRUGO, minor->debugfs_root,
+ perf, &perf_debugfs_fops);
return 0;
-
-fail:
- msm_perf_debugfs_cleanup(priv);
- return -1;
}
void msm_perf_debugfs_cleanup(struct msm_drm_private *priv)
diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c
index d21172933d92..480d810037ce 100644
--- a/drivers/gpu/drm/msm/msm_rd.c
+++ b/drivers/gpu/drm/msm/msm_rd.c
@@ -244,8 +244,6 @@ static void rd_cleanup(struct msm_rd_state *rd)
static struct msm_rd_state *rd_init(struct drm_minor *minor, const char *name)
{
struct msm_rd_state *rd;
- struct dentry *ent;
- int ret = 0;
rd = kzalloc(sizeof(*rd), GFP_KERNEL);
if (!rd)
@@ -258,20 +256,10 @@ static struct msm_rd_state *rd_init(struct drm_minor *minor, const char *name)
init_waitqueue_head(&rd->fifo_event);
- ent = debugfs_create_file(name, S_IFREG | S_IRUGO,
- minor->debugfs_root, rd, &rd_debugfs_fops);
- if (!ent) {
- DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/%s\n",
- minor->debugfs_root, name);
- ret = -ENOMEM;
- goto fail;
- }
+ debugfs_create_file(name, S_IFREG | S_IRUGO, minor->debugfs_root, rd,
+ &rd_debugfs_fops);
return rd;
-
-fail:
- rd_cleanup(rd);
- return ERR_PTR(ret);
}
int msm_rd_debugfs_init(struct drm_minor *minor)
diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
index bef4edde6f9f..14c96edb13df 100644
--- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
@@ -15,13 +15,14 @@
#include "drm_selftest.h"
#include "test-drm_modeset_common.h"
+static const struct drm_connector no_connector = {};
+
static int drm_cmdline_test_res(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -42,11 +43,10 @@ static int drm_cmdline_test_res(void *ignored)
static int drm_cmdline_test_res_missing_x(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("x480",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -54,11 +54,10 @@ static int drm_cmdline_test_res_missing_x(void *ignored)
static int drm_cmdline_test_res_missing_y(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("1024x",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -66,11 +65,10 @@ static int drm_cmdline_test_res_missing_y(void *ignored)
static int drm_cmdline_test_res_bad_y(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("1024xtest",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -78,11 +76,10 @@ static int drm_cmdline_test_res_bad_y(void *ignored)
static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("1024x-24",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -90,11 +87,10 @@ static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
static int drm_cmdline_test_res_vesa(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480M",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -115,11 +111,10 @@ static int drm_cmdline_test_res_vesa(void *ignored)
static int drm_cmdline_test_res_vesa_rblank(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480MR",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -140,11 +135,10 @@ static int drm_cmdline_test_res_vesa_rblank(void *ignored)
static int drm_cmdline_test_res_rblank(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480R",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -165,11 +159,10 @@ static int drm_cmdline_test_res_rblank(void *ignored)
static int drm_cmdline_test_res_bpp(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -191,11 +184,10 @@ static int drm_cmdline_test_res_bpp(void *ignored)
static int drm_cmdline_test_res_bad_bpp(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-test",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -203,11 +195,10 @@ static int drm_cmdline_test_res_bad_bpp(void *ignored)
static int drm_cmdline_test_res_refresh(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480@60",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -229,11 +220,10 @@ static int drm_cmdline_test_res_refresh(void *ignored)
static int drm_cmdline_test_res_bad_refresh(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480@refresh",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -241,11 +231,10 @@ static int drm_cmdline_test_res_bad_refresh(void *ignored)
static int drm_cmdline_test_res_bpp_refresh(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -268,11 +257,10 @@ static int drm_cmdline_test_res_bpp_refresh(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60i",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -295,11 +283,10 @@ static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60m",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -322,11 +309,10 @@ static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60d",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -349,11 +335,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-24@60de",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -361,11 +346,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60e",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -388,11 +372,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -415,10 +398,11 @@ static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
+ static const struct drm_connector connector = {
+ .connector_type = DRM_MODE_CONNECTOR_DVII,
+ };
- connector.connector_type = DRM_MODE_CONNECTOR_DVII;
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
&connector,
&mode));
@@ -443,11 +427,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60ime",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -470,11 +453,10 @@ static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ig
static int drm_cmdline_test_res_margins_force_on(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480me",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -495,11 +477,10 @@ static int drm_cmdline_test_res_margins_force_on(void *ignored)
static int drm_cmdline_test_res_vesa_margins(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480Mm",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -520,11 +501,10 @@ static int drm_cmdline_test_res_vesa_margins(void *ignored)
static int drm_cmdline_test_res_invalid_mode(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480f",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -532,11 +512,10 @@ static int drm_cmdline_test_res_invalid_mode(void *ignored)
static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480e-24",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -544,11 +523,10 @@ static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
static int drm_cmdline_test_name(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(strcmp(mode.name, "NTSC"));
FAIL_ON(mode.refresh_specified);
@@ -559,11 +537,10 @@ static int drm_cmdline_test_name(void *ignored)
static int drm_cmdline_test_name_bpp(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(strcmp(mode.name, "NTSC"));
@@ -577,11 +554,10 @@ static int drm_cmdline_test_name_bpp(void *ignored)
static int drm_cmdline_test_name_bpp_refresh(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC-24@60",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -589,11 +565,10 @@ static int drm_cmdline_test_name_bpp_refresh(void *ignored)
static int drm_cmdline_test_name_refresh(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -601,11 +576,10 @@ static int drm_cmdline_test_name_refresh(void *ignored)
static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60m",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -613,11 +587,10 @@ static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60f",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -625,11 +598,10 @@ static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
static int drm_cmdline_test_name_option(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC,rotate=180",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(strcmp(mode.name, "NTSC"));
@@ -640,11 +612,10 @@ static int drm_cmdline_test_name_option(void *ignored)
static int drm_cmdline_test_name_bpp_option(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24,rotate=180",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(strcmp(mode.name, "NTSC"));
@@ -657,11 +628,10 @@ static int drm_cmdline_test_name_bpp_option(void *ignored)
static int drm_cmdline_test_rotate_0(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=0",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -683,11 +653,10 @@ static int drm_cmdline_test_rotate_0(void *ignored)
static int drm_cmdline_test_rotate_90(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=90",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -709,11 +678,10 @@ static int drm_cmdline_test_rotate_90(void *ignored)
static int drm_cmdline_test_rotate_180(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=180",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -735,11 +703,10 @@ static int drm_cmdline_test_rotate_180(void *ignored)
static int drm_cmdline_test_rotate_270(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -761,11 +728,10 @@ static int drm_cmdline_test_rotate_270(void *ignored)
static int drm_cmdline_test_rotate_invalid_val(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=42",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -773,11 +739,10 @@ static int drm_cmdline_test_rotate_invalid_val(void *ignored)
static int drm_cmdline_test_rotate_truncated(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=",
- &connector,
+ &no_connector,
&mode));
return 0;
@@ -785,11 +750,10 @@ static int drm_cmdline_test_rotate_truncated(void *ignored)
static int drm_cmdline_test_hmirror(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_x",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -811,11 +775,10 @@ static int drm_cmdline_test_hmirror(void *ignored)
static int drm_cmdline_test_vmirror(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_y",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -837,11 +800,10 @@ static int drm_cmdline_test_vmirror(void *ignored)
static int drm_cmdline_test_margin_options(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -866,11 +828,10 @@ static int drm_cmdline_test_margin_options(void *ignored)
static int drm_cmdline_test_multiple_options(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270,reflect_x",
- &connector,
+ &no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
@@ -892,11 +853,10 @@ static int drm_cmdline_test_multiple_options(void *ignored)
static int drm_cmdline_test_invalid_option(void *ignored)
{
- struct drm_connector connector = { };
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,test=42",
- &connector,
+ &no_connector,
&mode));
return 0;
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index a7fd5a4955c9..58c403eda04e 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1739,7 +1739,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
mutex_lock(&ttm_global_mutex);
list_add_tail(&bdev->device_list, &glob->device_list);
mutex_unlock(&ttm_global_mutex);
- bdev->vm_ops = &ttm_bo_vm_ops;
return 0;
out_no_sys:
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 0c4576cbafcf..6dacff49c1cc 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -42,6 +42,8 @@
#include <linux/uaccess.h>
#include <linux/mem_encrypt.h>
+#define TTM_BO_VM_NUM_PREFAULT 16
+
static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo,
struct vm_fault *vmf)
{
@@ -104,30 +106,25 @@ static unsigned long ttm_bo_io_mem_pfn(struct ttm_buffer_object *bo,
+ page_offset;
}
-/**
- * ttm_bo_vm_reserve - Reserve a buffer object in a retryable vm callback
- * @bo: The buffer object
- * @vmf: The fault structure handed to the callback
- *
- * vm callbacks like fault() and *_mkwrite() allow for the mm_sem to be dropped
- * during long waits, and after the wait the callback will be restarted. This
- * is to allow other threads using the same virtual memory space concurrent
- * access to map(), unmap() completely unrelated buffer objects. TTM buffer
- * object reservations sometimes wait for GPU and should therefore be
- * considered long waits. This function reserves the buffer object interruptibly
- * taking this into account. Starvation is avoided by the vm system not
- * allowing too many repeated restarts.
- * This function is intended to be used in customized fault() and _mkwrite()
- * handlers.
- *
- * Return:
- * 0 on success and the bo was reserved.
- * VM_FAULT_RETRY if blocking wait.
- * VM_FAULT_NOPAGE if blocking wait and retrying was not allowed.
- */
-vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
- struct vm_fault *vmf)
+static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
{
+ struct vm_area_struct *vma = vmf->vma;
+ struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
+ vma->vm_private_data;
+ struct ttm_bo_device *bdev = bo->bdev;
+ unsigned long page_offset;
+ unsigned long page_last;
+ unsigned long pfn;
+ struct ttm_tt *ttm = NULL;
+ struct page *page;
+ int err;
+ int i;
+ vm_fault_t ret = VM_FAULT_NOPAGE;
+ unsigned long address = vmf->address;
+ struct ttm_mem_type_manager *man =
+ &bdev->man[bo->mem.mem_type];
+ struct vm_area_struct cvma;
+
/*
* Work around locking order reversal in fault / nopfn
* between mmap_sem and bo_reserve: Perform a trylock operation
@@ -154,55 +151,14 @@ vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
return VM_FAULT_NOPAGE;
}
- return 0;
-}
-EXPORT_SYMBOL(ttm_bo_vm_reserve);
-
-/**
- * ttm_bo_vm_fault_reserved - TTM fault helper
- * @vmf: The struct vm_fault given as argument to the fault callback
- * @prot: The page protection to be used for this memory area.
- * @num_prefault: Maximum number of prefault pages. The caller may want to
- * specify this based on madvice settings and the size of the GPU object
- * backed by the memory.
- *
- * This function inserts one or more page table entries pointing to the
- * memory backing the buffer object, and then returns a return code
- * instructing the caller to retry the page access.
- *
- * Return:
- * VM_FAULT_NOPAGE on success or pending signal
- * VM_FAULT_SIGBUS on unspecified error
- * VM_FAULT_OOM on out-of-memory
- * VM_FAULT_RETRY if retryable wait
- */
-vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
- pgprot_t prot,
- pgoff_t num_prefault)
-{
- struct vm_area_struct *vma = vmf->vma;
- struct vm_area_struct cvma = *vma;
- struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
- vma->vm_private_data;
- struct ttm_bo_device *bdev = bo->bdev;
- unsigned long page_offset;
- unsigned long page_last;
- unsigned long pfn;
- struct ttm_tt *ttm = NULL;
- struct page *page;
- int err;
- pgoff_t i;
- vm_fault_t ret = VM_FAULT_NOPAGE;
- unsigned long address = vmf->address;
- struct ttm_mem_type_manager *man =
- &bdev->man[bo->mem.mem_type];
-
/*
* Refuse to fault imported pages. This should be handled
* (if at all) by redirecting mmap to the exporter.
*/
- if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SG))
- return VM_FAULT_SIGBUS;
+ if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) {
+ ret = VM_FAULT_SIGBUS;
+ goto out_unlock;
+ }
if (bdev->driver->fault_reserve_notify) {
struct dma_fence *moving = dma_fence_get(bo->moving);
@@ -213,9 +169,11 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
break;
case -EBUSY:
case -ERESTARTSYS:
- return VM_FAULT_NOPAGE;
+ ret = VM_FAULT_NOPAGE;
+ goto out_unlock;
default:
- return VM_FAULT_SIGBUS;
+ ret = VM_FAULT_SIGBUS;
+ goto out_unlock;
}
if (bo->moving != moving) {
@@ -231,12 +189,21 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
* move.
*/
ret = ttm_bo_vm_fault_idle(bo, vmf);
- if (unlikely(ret != 0))
- return ret;
+ if (unlikely(ret != 0)) {
+ if (ret == VM_FAULT_RETRY &&
+ !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
+ /* The BO has already been unreserved. */
+ return ret;
+ }
+
+ goto out_unlock;
+ }
err = ttm_mem_io_lock(man, true);
- if (unlikely(err != 0))
- return VM_FAULT_NOPAGE;
+ if (unlikely(err != 0)) {
+ ret = VM_FAULT_NOPAGE;
+ goto out_unlock;
+ }
err = ttm_mem_io_reserve_vm(bo);
if (unlikely(err != 0)) {
ret = VM_FAULT_SIGBUS;
@@ -253,8 +220,18 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
goto out_io_unlock;
}
- cvma.vm_page_prot = ttm_io_prot(bo->mem.placement, prot);
- if (!bo->mem.bus.is_iomem) {
+ /*
+ * Make a local vma copy to modify the page_prot member
+ * and vm_flags if necessary. The vma parameter is protected
+ * by mmap_sem in write mode.
+ */
+ cvma = *vma;
+ cvma.vm_page_prot = vm_get_page_prot(cvma.vm_flags);
+
+ if (bo->mem.bus.is_iomem) {
+ cvma.vm_page_prot = ttm_io_prot(bo->mem.placement,
+ cvma.vm_page_prot);
+ } else {
struct ttm_operation_ctx ctx = {
.interruptible = false,
.no_wait_gpu = false,
@@ -263,21 +240,24 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
};
ttm = bo->ttm;
- if (ttm_tt_populate(bo->ttm, &ctx)) {
+ cvma.vm_page_prot = ttm_io_prot(bo->mem.placement,
+ cvma.vm_page_prot);
+
+ /* Allocate all page at once, most common usage */
+ if (ttm_tt_populate(ttm, &ctx)) {
ret = VM_FAULT_OOM;
goto out_io_unlock;
}
- } else {
- /* Iomem should not be marked encrypted */
- cvma.vm_page_prot = pgprot_decrypted(cvma.vm_page_prot);
}
/*
* Speculatively prefault a number of pages. Only error on
* first page.
*/
- for (i = 0; i < num_prefault; ++i) {
+ for (i = 0; i < TTM_BO_VM_NUM_PREFAULT; ++i) {
if (bo->mem.bus.is_iomem) {
+ /* Iomem should not be marked encrypted */
+ cvma.vm_page_prot = pgprot_decrypted(cvma.vm_page_prot);
pfn = ttm_bo_io_mem_pfn(bo, page_offset);
} else {
page = ttm->pages[page_offset];
@@ -315,26 +295,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
ret = VM_FAULT_NOPAGE;
out_io_unlock:
ttm_mem_io_unlock(man);
- return ret;
-}
-EXPORT_SYMBOL(ttm_bo_vm_fault_reserved);
-
-static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
-{
- struct vm_area_struct *vma = vmf->vma;
- pgprot_t prot;
- struct ttm_buffer_object *bo = vma->vm_private_data;
- vm_fault_t ret;
-
- ret = ttm_bo_vm_reserve(bo, vmf);
- if (ret)
- return ret;
-
- prot = vm_get_page_prot(vma->vm_flags);
- ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT);
- if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
- return ret;
-
+out_unlock:
reservation_object_unlock(bo->resv);
return ret;
}
@@ -434,7 +395,7 @@ static int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr,
return ret;
}
-const struct vm_operations_struct ttm_bo_vm_ops = {
+static const struct vm_operations_struct ttm_bo_vm_ops = {
.fault = ttm_bo_vm_fault,
.open = ttm_bo_vm_open,
.close = ttm_bo_vm_close,
@@ -487,7 +448,7 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
if (unlikely(ret != 0))
goto out_unref;
- vma->vm_ops = bdev->vm_ops;
+ vma->vm_ops = &ttm_bo_vm_ops;
/*
* Note: We're transferring the bo reference to
@@ -519,7 +480,7 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
ttm_bo_get(bo);
- vma->vm_ops = bo->bdev->vm_ops;
+ vma->vm_ops = &ttm_bo_vm_ops;
vma->vm_private_data = bo;
vma->vm_flags |= VM_MIXEDMAP;
vma->vm_flags |= VM_IO | VM_DONTEXPAND;
diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig
index d5fd81a521f6..6b28a326f8bb 100644
--- a/drivers/gpu/drm/vmwgfx/Kconfig
+++ b/drivers/gpu/drm/vmwgfx/Kconfig
@@ -8,7 +8,6 @@ config DRM_VMWGFX
select FB_CFB_IMAGEBLIT
select DRM_TTM
select FB
- select AS_DIRTY_HELPERS
# Only needed for the transitional use of drm_crtc_init - can be removed
# again once vmwgfx sets up the primary plane itself.
select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile
index c877a21a0739..8841bd30e1e5 100644
--- a/drivers/gpu/drm/vmwgfx/Makefile
+++ b/drivers/gpu/drm/vmwgfx/Makefile
@@ -8,7 +8,7 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \
vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \
vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o \
- vmwgfx_validation.o vmwgfx_page_dirty.o \
+ vmwgfx_validation.o \
ttm_object.o ttm_lock.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h
index 61414f105c67..f2bfd3d80598 100644
--- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h
+++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h
@@ -1280,6 +1280,7 @@ svga3dsurface_get_pixel_offset(SVGA3dSurfaceFormat format,
return offset;
}
+
static inline u32
svga3dsurface_get_image_offset(SVGA3dSurfaceFormat format,
surf_size_struct baseLevelSize,
@@ -1374,236 +1375,4 @@ svga3dsurface_is_screen_target_format(SVGA3dSurfaceFormat format)
return svga3dsurface_is_dx_screen_target_format(format);
}
-/**
- * struct svga3dsurface_mip - Mimpmap level information
- * @bytes: Bytes required in the backing store of this mipmap level.
- * @img_stride: Byte stride per image.
- * @row_stride: Byte stride per block row.
- * @size: The size of the mipmap.
- */
-struct svga3dsurface_mip {
- size_t bytes;
- size_t img_stride;
- size_t row_stride;
- struct drm_vmw_size size;
-
-};
-
-/**
- * struct svga3dsurface_cache - Cached surface information
- * @desc: Pointer to the surface descriptor
- * @mip: Array of mipmap level information. Valid size is @num_mip_levels.
- * @mip_chain_bytes: Bytes required in the backing store for the whole chain
- * of mip levels.
- * @sheet_bytes: Bytes required in the backing store for a sheet
- * representing a single sample.
- * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in
- * a chain.
- * @num_layers: Number of slices in an array texture or number of faces in
- * a cubemap texture.
- */
-struct svga3dsurface_cache {
- const struct svga3d_surface_desc *desc;
- struct svga3dsurface_mip mip[DRM_VMW_MAX_MIP_LEVELS];
- size_t mip_chain_bytes;
- size_t sheet_bytes;
- u32 num_mip_levels;
- u32 num_layers;
-};
-
-/**
- * struct svga3dsurface_loc - Surface location
- * @sub_resource: Surface subresource. Defined as layer * num_mip_levels +
- * mip_level.
- * @x: X coordinate.
- * @y: Y coordinate.
- * @z: Z coordinate.
- */
-struct svga3dsurface_loc {
- u32 sub_resource;
- u32 x, y, z;
-};
-
-/**
- * svga3dsurface_subres - Compute the subresource from layer and mipmap.
- * @cache: Surface layout data.
- * @mip_level: The mipmap level.
- * @layer: The surface layer (face or array slice).
- *
- * Return: The subresource.
- */
-static inline u32 svga3dsurface_subres(const struct svga3dsurface_cache *cache,
- u32 mip_level, u32 layer)
-{
- return cache->num_mip_levels * layer + mip_level;
-}
-
-/**
- * svga3dsurface_setup_cache - Build a surface cache entry
- * @size: The surface base level dimensions.
- * @format: The surface format.
- * @num_mip_levels: Number of mipmap levels.
- * @num_layers: Number of layers.
- * @cache: Pointer to a struct svga3dsurface_cach object to be filled in.
- *
- * Return: Zero on success, -EINVAL on invalid surface layout.
- */
-static inline int svga3dsurface_setup_cache(const struct drm_vmw_size *size,
- SVGA3dSurfaceFormat format,
- u32 num_mip_levels,
- u32 num_layers,
- u32 num_samples,
- struct svga3dsurface_cache *cache)
-{
- const struct svga3d_surface_desc *desc;
- u32 i;
-
- memset(cache, 0, sizeof(*cache));
- cache->desc = desc = svga3dsurface_get_desc(format);
- cache->num_mip_levels = num_mip_levels;
- cache->num_layers = num_layers;
- for (i = 0; i < cache->num_mip_levels; i++) {
- struct svga3dsurface_mip *mip = &cache->mip[i];
-
- mip->size = svga3dsurface_get_mip_size(*size, i);
- mip->bytes = svga3dsurface_get_image_buffer_size
- (desc, &mip->size, 0);
- mip->row_stride =
- __KERNEL_DIV_ROUND_UP(mip->size.width,
- desc->block_size.width) *
- desc->bytes_per_block * num_samples;
- if (!mip->row_stride)
- goto invalid_dim;
-
- mip->img_stride =
- __KERNEL_DIV_ROUND_UP(mip->size.height,
- desc->block_size.height) *
- mip->row_stride;
- if (!mip->img_stride)
- goto invalid_dim;
-
- cache->mip_chain_bytes += mip->bytes;
- }
- cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
- if (!cache->sheet_bytes)
- goto invalid_dim;
-
- return 0;
-
-invalid_dim:
- VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
- return -EINVAL;
-}
-
-/**
- * svga3dsurface_get_loc - Get a surface location from an offset into the
- * backing store
- * @cache: Surface layout data.
- * @loc: Pointer to a struct svga3dsurface_loc to be filled in.
- * @offset: Offset into the surface backing store.
- */
-static inline void
-svga3dsurface_get_loc(const struct svga3dsurface_cache *cache,
- struct svga3dsurface_loc *loc,
- size_t offset)
-{
- const struct svga3dsurface_mip *mip = &cache->mip[0];
- const struct svga3d_surface_desc *desc = cache->desc;
- u32 layer;
- int i;
-
- if (offset >= cache->sheet_bytes)
- offset %= cache->sheet_bytes;
-
- layer = offset / cache->mip_chain_bytes;
- offset -= layer * cache->mip_chain_bytes;
- for (i = 0; i < cache->num_mip_levels; ++i, ++mip) {
- if (mip->bytes > offset)
- break;
- offset -= mip->bytes;
- }
-
- loc->sub_resource = svga3dsurface_subres(cache, i, layer);
- loc->z = offset / mip->img_stride;
- offset -= loc->z * mip->img_stride;
- loc->z *= desc->block_size.depth;
- loc->y = offset / mip->row_stride;
- offset -= loc->y * mip->row_stride;
- loc->y *= desc->block_size.height;
- loc->x = offset / desc->bytes_per_block;
- loc->x *= desc->block_size.width;
-}
-
-/**
- * svga3dsurface_inc_loc - Clamp increment a surface location with one block
- * size
- * in each dimension.
- * @loc: Pointer to a struct svga3dsurface_loc to be incremented.
- *
- * When computing the size of a range as size = end - start, the range does not
- * include the end element. However a location representing the last byte
- * of a touched region in the backing store *is* included in the range.
- * This function modifies such a location to match the end definition
- * given as start + size which is the one used in a SVGA3dBox.
- */
-static inline void
-svga3dsurface_inc_loc(const struct svga3dsurface_cache *cache,
- struct svga3dsurface_loc *loc)
-{
- const struct svga3d_surface_desc *desc = cache->desc;
- u32 mip = loc->sub_resource % cache->num_mip_levels;
- const struct drm_vmw_size *size = &cache->mip[mip].size;
-
- loc->sub_resource++;
- loc->x += desc->block_size.width;
- if (loc->x > size->width)
- loc->x = size->width;
- loc->y += desc->block_size.height;
- if (loc->y > size->height)
- loc->y = size->height;
- loc->z += desc->block_size.depth;
- if (loc->z > size->depth)
- loc->z = size->depth;
-}
-
-/**
- * svga3dsurface_min_loc - The start location in a subresource
- * @cache: Surface layout data.
- * @sub_resource: The subresource.
- * @loc: Pointer to a struct svga3dsurface_loc to be filled in.
- */
-static inline void
-svga3dsurface_min_loc(const struct svga3dsurface_cache *cache,
- u32 sub_resource,
- struct svga3dsurface_loc *loc)
-{
- loc->sub_resource = sub_resource;
- loc->x = loc->y = loc->z = 0;
-}
-
-/**
- * svga3dsurface_min_loc - The end location in a subresource
- * @cache: Surface layout data.
- * @sub_resource: The subresource.
- * @loc: Pointer to a struct svga3dsurface_loc to be filled in.
- *
- * Following the end definition given in svga3dsurface_inc_loc(),
- * Compute the end location of a surface subresource.
- */
-static inline void
-svga3dsurface_max_loc(const struct svga3dsurface_cache *cache,
- u32 sub_resource,
- struct svga3dsurface_loc *loc)
-{
- const struct drm_vmw_size *size;
- u32 mip;
-
- loc->sub_resource = sub_resource + 1;
- mip = sub_resource % cache->num_mip_levels;
- size = &cache->mip[mip].size;
- loc->x = size->width;
- loc->y = size->height;
- loc->z = size->depth;
-}
-
#endif /* _SVGA3D_SURFACEDEFS_H_ */
diff --git a/drivers/gpu/drm/vmwgfx/ttm_lock.c b/drivers/gpu/drm/vmwgfx/ttm_lock.c
index 5971c72e6d10..16b2083cb9d4 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_lock.c
+++ b/drivers/gpu/drm/vmwgfx/ttm_lock.c
@@ -29,6 +29,7 @@
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
*/
+#include <drm/ttm/ttm_module.h>
#include <linux/atomic.h>
#include <linux/errno.h>
#include <linux/wait.h>
@@ -48,6 +49,8 @@ void ttm_lock_init(struct ttm_lock *lock)
init_waitqueue_head(&lock->queue);
lock->rw = 0;
lock->flags = 0;
+ lock->kill_takers = false;
+ lock->signal = SIGKILL;
}
void ttm_read_unlock(struct ttm_lock *lock)
@@ -63,6 +66,11 @@ static bool __ttm_read_lock(struct ttm_lock *lock)
bool locked = false;
spin_lock(&lock->lock);
+ if (unlikely(lock->kill_takers)) {
+ send_sig(lock->signal, current, 0);
+ spin_unlock(&lock->lock);
+ return false;
+ }
if (lock->rw >= 0 && lock->flags == 0) {
++lock->rw;
locked = true;
@@ -90,6 +98,11 @@ static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
*locked = false;
spin_lock(&lock->lock);
+ if (unlikely(lock->kill_takers)) {
+ send_sig(lock->signal, current, 0);
+ spin_unlock(&lock->lock);
+ return false;
+ }
if (lock->rw >= 0 && lock->flags == 0) {
++lock->rw;
block = false;
@@ -134,6 +147,11 @@ static bool __ttm_write_lock(struct ttm_lock *lock)
bool locked = false;
spin_lock(&lock->lock);
+ if (unlikely(lock->kill_takers)) {
+ send_sig(lock->signal, current, 0);
+ spin_unlock(&lock->lock);
+ return false;
+ }
if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
lock->rw = -1;
lock->flags &= ~TTM_WRITE_LOCK_PENDING;
@@ -164,6 +182,88 @@ int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
return ret;
}
+static int __ttm_vt_unlock(struct ttm_lock *lock)
+{
+ int ret = 0;
+
+ spin_lock(&lock->lock);
+ if (unlikely(!(lock->flags & TTM_VT_LOCK)))
+ ret = -EINVAL;
+ lock->flags &= ~TTM_VT_LOCK;
+ wake_up_all(&lock->queue);
+ spin_unlock(&lock->lock);
+
+ return ret;
+}
+
+static void ttm_vt_lock_remove(struct ttm_base_object **p_base)
+{
+ struct ttm_base_object *base = *p_base;
+ struct ttm_lock *lock = container_of(base, struct ttm_lock, base);
+ int ret;
+
+ *p_base = NULL;
+ ret = __ttm_vt_unlock(lock);
+ BUG_ON(ret != 0);
+}
+
+static bool __ttm_vt_lock(struct ttm_lock *lock)
+{
+ bool locked = false;
+
+ spin_lock(&lock->lock);
+ if (lock->rw == 0) {
+ lock->flags &= ~TTM_VT_LOCK_PENDING;
+ lock->flags |= TTM_VT_LOCK;
+ locked = true;
+ } else {
+ lock->flags |= TTM_VT_LOCK_PENDING;
+ }
+ spin_unlock(&lock->lock);
+ return locked;
+}
+
+int ttm_vt_lock(struct ttm_lock *lock,
+ bool interruptible,
+ struct ttm_object_file *tfile)
+{
+ int ret = 0;
+
+ if (interruptible) {
+ ret = wait_event_interruptible(lock->queue,
+ __ttm_vt_lock(lock));
+ if (unlikely(ret != 0)) {
+ spin_lock(&lock->lock);
+ lock->flags &= ~TTM_VT_LOCK_PENDING;
+ wake_up_all(&lock->queue);
+ spin_unlock(&lock->lock);
+ return ret;
+ }
+ } else
+ wait_event(lock->queue, __ttm_vt_lock(lock));
+
+ /*
+ * Add a base-object, the destructor of which will
+ * make sure the lock is released if the client dies
+ * while holding it.
+ */
+
+ ret = ttm_base_object_init(tfile, &lock->base, false,
+ ttm_lock_type, &ttm_vt_lock_remove, NULL);
+ if (ret)
+ (void)__ttm_vt_unlock(lock);
+ else
+ lock->vt_holder = tfile;
+
+ return ret;
+}
+
+int ttm_vt_unlock(struct ttm_lock *lock)
+{
+ return ttm_ref_object_base_unref(lock->vt_holder,
+ lock->base.handle, TTM_REF_USAGE);
+}
+
void ttm_suspend_unlock(struct ttm_lock *lock)
{
spin_lock(&lock->lock);
diff --git a/drivers/gpu/drm/vmwgfx/ttm_lock.h b/drivers/gpu/drm/vmwgfx/ttm_lock.h
index 3d454e8b491f..0c3af9836863 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_lock.h
+++ b/drivers/gpu/drm/vmwgfx/ttm_lock.h
@@ -63,6 +63,8 @@
* @lock: Spinlock protecting some lock members.
* @rw: Read-write lock counter. Protected by @lock.
* @flags: Lock state. Protected by @lock.
+ * @kill_takers: Boolean whether to kill takers of the lock.
+ * @signal: Signal to send when kill_takers is true.
*/
struct ttm_lock {
@@ -71,6 +73,9 @@ struct ttm_lock {
spinlock_t lock;
int32_t rw;
uint32_t flags;
+ bool kill_takers;
+ int signal;
+ struct ttm_object_file *vt_holder;
};
@@ -215,4 +220,29 @@ extern void ttm_write_unlock(struct ttm_lock *lock);
*/
extern int ttm_write_lock(struct ttm_lock *lock, bool interruptible);
+/**
+ * ttm_lock_set_kill
+ *
+ * @lock: Pointer to a struct ttm_lock
+ * @val: Boolean whether to kill processes taking the lock.
+ * @signal: Signal to send to the process taking the lock.
+ *
+ * The kill-when-taking-lock functionality is used to kill processes that keep
+ * on using the TTM functionality when its resources has been taken down, for
+ * example when the X server exits. A typical sequence would look like this:
+ * - X server takes lock in write mode.
+ * - ttm_lock_set_kill() is called with @val set to true.
+ * - As part of X server exit, TTM resources are taken down.
+ * - X server releases the lock on file release.
+ * - Another dri client wants to render, takes the lock and is killed.
+ *
+ */
+static inline void ttm_lock_set_kill(struct ttm_lock *lock, bool val,
+ int signal)
+{
+ lock->kill_takers = val;
+ if (val)
+ lock->signal = signal;
+}
+
#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index e8bc7a7ac031..5d5c2bce01f3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -463,8 +463,6 @@ void vmw_bo_bo_free(struct ttm_buffer_object *bo)
{
struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo);
- WARN_ON(vmw_bo->dirty);
- WARN_ON(!RB_EMPTY_ROOT(&vmw_bo->res_tree));
vmw_bo_unmap(vmw_bo);
kfree(vmw_bo);
}
@@ -478,11 +476,8 @@ void vmw_bo_bo_free(struct ttm_buffer_object *bo)
static void vmw_user_bo_destroy(struct ttm_buffer_object *bo)
{
struct vmw_user_buffer_object *vmw_user_bo = vmw_user_buffer_object(bo);
- struct vmw_buffer_object *vbo = &vmw_user_bo->vbo;
- WARN_ON(vbo->dirty);
- WARN_ON(!RB_EMPTY_ROOT(&vbo->res_tree));
- vmw_bo_unmap(vbo);
+ vmw_bo_unmap(&vmw_user_bo->vbo);
ttm_prime_object_kfree(vmw_user_bo, prime);
}
@@ -515,9 +510,8 @@ int vmw_bo_init(struct vmw_private *dev_priv,
acc_size = vmw_bo_acc_size(dev_priv, size, user);
memset(vmw_bo, 0, sizeof(*vmw_bo));
- BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3);
- vmw_bo->base.priority = 3;
- vmw_bo->res_tree = RB_ROOT;
+
+ INIT_LIST_HEAD(&vmw_bo->res_list);
ret = ttm_bo_init(bdev, &vmw_bo->base, size,
ttm_bo_type_device, placement,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
index a56c9d802382..63f111068a44 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
@@ -88,8 +88,6 @@ static const struct vmw_res_func vmw_gb_context_func = {
.res_type = vmw_res_context,
.needs_backup = true,
.may_evict = true,
- .prio = 3,
- .dirty_prio = 3,
.type_name = "guest backed contexts",
.backup_placement = &vmw_mob_placement,
.create = vmw_gb_context_create,
@@ -102,8 +100,6 @@ static const struct vmw_res_func vmw_dx_context_func = {
.res_type = vmw_res_dx_context,
.needs_backup = true,
.may_evict = true,
- .prio = 3,
- .dirty_prio = 3,
.type_name = "dx contexts",
.backup_placement = &vmw_mob_placement,
.create = vmw_dx_context_create,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
index 8c699cb2565b..b4f6e1217c9d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
@@ -116,8 +116,6 @@ static const struct vmw_res_func vmw_cotable_func = {
.res_type = vmw_res_cotable,
.needs_backup = true,
.may_evict = true,
- .prio = 3,
- .dirty_prio = 3,
.type_name = "context guest backed object tables",
.backup_placement = &vmw_mob_placement,
.create = vmw_cotable_create,
@@ -309,7 +307,7 @@ static int vmw_cotable_unbind(struct vmw_resource *res,
struct ttm_buffer_object *bo = val_buf->bo;
struct vmw_fence_obj *fence;
- if (!vmw_resource_mob_attached(res))
+ if (list_empty(&res->mob_head))
return 0;
WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB);
@@ -455,7 +453,6 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
goto out_wait;
}
- vmw_resource_mob_detach(res);
res->backup = buf;
res->backup_size = new_size;
vcotbl->size_read_back = cur_size_read_back;
@@ -470,12 +467,12 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
res->backup = old_buf;
res->backup_size = old_size;
vcotbl->size_read_back = old_size_read_back;
- vmw_resource_mob_attach(res);
goto out_wait;
}
- vmw_resource_mob_attach(res);
/* Let go of the old mob. */
+ list_del(&res->mob_head);
+ list_add_tail(&res->mob_head, &buf->res_list);
vmw_bo_unreference(&old_buf);
res->id = vcotbl->type;
@@ -499,7 +496,7 @@ out_wait:
* is called before bind() in the validation sequence is instead used for two
* things.
* 1) Unscrub the cotable if it is scrubbed and still attached to a backup
- * buffer.
+ * buffer, that is, if @res->mob_head is non-empty.
* 2) Resize the cotable if needed.
*/
static int vmw_cotable_create(struct vmw_resource *res)
@@ -515,7 +512,7 @@ static int vmw_cotable_create(struct vmw_resource *res)
new_size *= 2;
if (likely(new_size <= res->backup_size)) {
- if (vcotbl->scrubbed && vmw_resource_mob_attached(res)) {
+ if (vcotbl->scrubbed && !list_empty(&res->mob_head)) {
ret = vmw_cotable_unscrub(res);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 8349a6cc126f..4ff11a0077e1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -254,6 +254,7 @@ static int vmw_restrict_dma_mask;
static int vmw_assume_16bpp;
static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
+static void vmw_master_init(struct vmw_master *);
static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
void *ptr);
@@ -761,6 +762,10 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
DRM_INFO("MMIO at 0x%08x size is %u kiB\n",
dev_priv->mmio_start, dev_priv->mmio_size / 1024);
+ vmw_master_init(&dev_priv->fbdev_master);
+ ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
+ dev_priv->active_master = &dev_priv->fbdev_master;
+
dev_priv->mmio_virt = memremap(dev_priv->mmio_start,
dev_priv->mmio_size, MEMREMAP_WB);
@@ -828,11 +833,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
DRM_ERROR("Failed initializing TTM buffer object driver.\n");
goto out_no_bdev;
}
- dev_priv->vm_ops = *dev_priv->bdev.vm_ops;
- dev_priv->vm_ops.fault = vmw_bo_vm_fault;
- dev_priv->vm_ops.pfn_mkwrite = vmw_bo_vm_mkwrite;
- dev_priv->vm_ops.page_mkwrite = vmw_bo_vm_mkwrite;
- dev_priv->bdev.vm_ops = &dev_priv->vm_ops;
/*
* Enable VRAM, but initially don't use it until SVGA is enabled and
@@ -1007,7 +1007,18 @@ static void vmw_driver_unload(struct drm_device *dev)
static void vmw_postclose(struct drm_device *dev,
struct drm_file *file_priv)
{
- struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+ struct vmw_fpriv *vmw_fp;
+
+ vmw_fp = vmw_fpriv(file_priv);
+
+ if (vmw_fp->locked_master) {
+ struct vmw_master *vmaster =
+ vmw_master(vmw_fp->locked_master);
+
+ ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+ ttm_vt_unlock(&vmaster->lock);
+ drm_master_put(&vmw_fp->locked_master);
+ }
ttm_object_file_release(&vmw_fp->tfile);
kfree(vmw_fp);
@@ -1036,6 +1047,55 @@ out_no_tfile:
return ret;
}
+static struct vmw_master *vmw_master_check(struct drm_device *dev,
+ struct drm_file *file_priv,
+ unsigned int flags)
+{
+ int ret;
+ struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+ struct vmw_master *vmaster;
+
+ if (!drm_is_primary_client(file_priv) || !(flags & DRM_AUTH))
+ return NULL;
+
+ ret = mutex_lock_interruptible(&dev->master_mutex);
+ if (unlikely(ret != 0))
+ return ERR_PTR(-ERESTARTSYS);
+
+ if (drm_is_current_master(file_priv)) {
+ mutex_unlock(&dev->master_mutex);
+ return NULL;
+ }
+
+ /*
+ * Check if we were previously master, but now dropped. In that
+ * case, allow at least render node functionality.
+ */
+ if (vmw_fp->locked_master) {
+ mutex_unlock(&dev->master_mutex);
+
+ if (flags & DRM_RENDER_ALLOW)
+ return NULL;
+
+ DRM_ERROR("Dropped master trying to access ioctl that "
+ "requires authentication.\n");
+ return ERR_PTR(-EACCES);
+ }
+ mutex_unlock(&dev->master_mutex);
+
+ /*
+ * Take the TTM lock. Possibly sleep waiting for the authenticating
+ * master to become master again, or for a SIGTERM if the
+ * authenticating master exits.
+ */
+ vmaster = vmw_master(file_priv->master);
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (unlikely(ret != 0))
+ vmaster = ERR_PTR(ret);
+
+ return vmaster;
+}
+
static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg,
long (*ioctl_func)(struct file *, unsigned int,
@@ -1044,6 +1104,7 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->minor->dev;
unsigned int nr = DRM_IOCTL_NR(cmd);
+ struct vmw_master *vmaster;
unsigned int flags;
long ret;
@@ -1079,7 +1140,21 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
} else if (!drm_ioctl_flags(nr, &flags))
return -EINVAL;
- return ioctl_func(filp, cmd, arg);
+ vmaster = vmw_master_check(dev, file_priv, flags);
+ if (IS_ERR(vmaster)) {
+ ret = PTR_ERR(vmaster);
+
+ if (ret != -ERESTARTSYS)
+ DRM_INFO("IOCTL ERROR Command %d, Error %ld.\n",
+ nr, ret);
+ return ret;
+ }
+
+ ret = ioctl_func(filp, cmd, arg);
+ if (vmaster)
+ ttm_read_unlock(&vmaster->lock);
+
+ return ret;
out_io_encoding:
DRM_ERROR("Invalid command format, ioctl %d\n",
@@ -1106,10 +1181,65 @@ static void vmw_lastclose(struct drm_device *dev)
{
}
+static void vmw_master_init(struct vmw_master *vmaster)
+{
+ ttm_lock_init(&vmaster->lock);
+}
+
+static int vmw_master_create(struct drm_device *dev,
+ struct drm_master *master)
+{
+ struct vmw_master *vmaster;
+
+ vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL);
+ if (unlikely(!vmaster))
+ return -ENOMEM;
+
+ vmw_master_init(vmaster);
+ ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+ master->driver_priv = vmaster;
+
+ return 0;
+}
+
+static void vmw_master_destroy(struct drm_device *dev,
+ struct drm_master *master)
+{
+ struct vmw_master *vmaster = vmw_master(master);
+
+ master->driver_priv = NULL;
+ kfree(vmaster);
+}
+
static int vmw_master_set(struct drm_device *dev,
struct drm_file *file_priv,
bool from_open)
{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+ struct vmw_master *active = dev_priv->active_master;
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
+ int ret = 0;
+
+ if (active) {
+ BUG_ON(active != &dev_priv->fbdev_master);
+ ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile);
+ if (unlikely(ret != 0))
+ return ret;
+
+ ttm_lock_set_kill(&active->lock, true, SIGTERM);
+ dev_priv->active_master = NULL;
+ }
+
+ ttm_lock_set_kill(&vmaster->lock, false, SIGTERM);
+ if (!from_open) {
+ ttm_vt_unlock(&vmaster->lock);
+ BUG_ON(vmw_fp->locked_master != file_priv->master);
+ drm_master_put(&vmw_fp->locked_master);
+ }
+
+ dev_priv->active_master = vmaster;
+
/*
* Inform a new master that the layout may have changed while
* it was gone.
@@ -1124,10 +1254,31 @@ static void vmw_master_drop(struct drm_device *dev,
struct drm_file *file_priv)
{
struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
+ int ret;
+
+ /**
+ * Make sure the master doesn't disappear while we have
+ * it locked.
+ */
+ vmw_fp->locked_master = drm_master_get(file_priv->master);
+ ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
vmw_kms_legacy_hotspot_clear(dev_priv);
+ if (unlikely((ret != 0))) {
+ DRM_ERROR("Unable to lock TTM at VT switch.\n");
+ drm_master_put(&vmw_fp->locked_master);
+ }
+
+ ttm_lock_set_kill(&vmaster->lock, false, SIGTERM);
+
if (!dev_priv->enable_fb)
vmw_svga_disable(dev_priv);
+
+ dev_priv->active_master = &dev_priv->fbdev_master;
+ ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
+ ttm_vt_unlock(&dev_priv->fbdev_master.lock);
}
/**
@@ -1406,6 +1557,8 @@ static struct drm_driver driver = {
.disable_vblank = vmw_disable_vblank,
.ioctls = vmw_ioctls,
.num_ioctls = ARRAY_SIZE(vmw_ioctls),
+ .master_create = vmw_master_create,
+ .master_destroy = vmw_master_destroy,
.master_set = vmw_master_set,
.master_drop = vmw_master_drop,
.open = vmw_driver_open,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 3a358a5495e4..366dcfc1f9bb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -44,9 +44,9 @@
#include <linux/sync_file.h>
#define VMWGFX_DRIVER_NAME "vmwgfx"
-#define VMWGFX_DRIVER_DATE "20190328"
+#define VMWGFX_DRIVER_DATE "20180704"
#define VMWGFX_DRIVER_MAJOR 2
-#define VMWGFX_DRIVER_MINOR 16
+#define VMWGFX_DRIVER_MINOR 15
#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
#define VMWGFX_MAX_RELOCATIONS 2048
@@ -81,30 +81,19 @@
#define VMW_RES_SHADER ttm_driver_type4
struct vmw_fpriv {
+ struct drm_master *locked_master;
struct ttm_object_file *tfile;
bool gb_aware; /* user-space is guest-backed aware */
};
-/**
- * struct vmw_buffer_object - TTM buffer object with vmwgfx additions
- * @base: The TTM buffer object
- * @res_tree: RB tree of resources using this buffer object as a backing MOB
- * @pin_count: pin depth
- * @dx_query_ctx: DX context if this buffer object is used as a DX query MOB
- * @map: Kmap object for semi-persistent mappings
- * @res_prios: Eviction priority counts for attached resources
- * @dirty: structure for user-space dirty-tracking
- */
struct vmw_buffer_object {
struct ttm_buffer_object base;
- struct rb_root res_tree;
+ struct list_head res_list;
s32 pin_count;
/* Not ref-counted. Protected by binding_mutex */
struct vmw_resource *dx_query_ctx;
/* Protected by reservation */
struct ttm_bo_kmap_obj map;
- u32 res_prios[TTM_MAX_BO_PRIORITY];
- struct vmw_bo_dirty *dirty;
};
/**
@@ -135,8 +124,7 @@ struct vmw_res_func;
* @res_dirty: Resource contains data not yet in the backup buffer. Protected
* by resource reserved.
* @backup_dirty: Backup buffer contains data not yet in the HW resource.
- * Protected by resource reserved.
- * @coherent: Emulate coherency by tracking vm accesses.
+ * Protecte by resource reserved.
* @backup: The backup buffer if any. Protected by resource reserved.
* @backup_offset: Offset into the backup buffer if any. Protected by resource
* reserved. Note that only a few resource types can have a @backup_offset
@@ -145,32 +133,28 @@ struct vmw_res_func;
* pin-count greater than zero. It is not on the resource LRU lists and its
* backup buffer is pinned. Hence it can't be evicted.
* @func: Method vtable for this resource. Immutable.
- * @mob_node; Node for the MOB backup rbtree. Protected by @backup reserved.
* @lru_head: List head for the LRU list. Protected by @dev_priv::resource_lock.
+ * @mob_head: List head for the MOB backup list. Protected by @backup reserved.
* @binding_head: List head for the context binding list. Protected by
* the @dev_priv::binding_mutex
* @res_free: The resource destructor.
* @hw_destroy: Callback to destroy the resource on the device, as part of
* resource destruction.
*/
-struct vmw_resource_dirty;
struct vmw_resource {
struct kref kref;
struct vmw_private *dev_priv;
int id;
- u32 used_prio;
unsigned long backup_size;
- u32 res_dirty : 1;
- u32 backup_dirty : 1;
- u32 coherent : 1;
+ bool res_dirty;
+ bool backup_dirty;
struct vmw_buffer_object *backup;
unsigned long backup_offset;
unsigned long pin_count;
const struct vmw_res_func *func;
- struct rb_node mob_node;
struct list_head lru_head;
+ struct list_head mob_head;
struct list_head binding_head;
- struct vmw_resource_dirty *dirty;
void (*res_free) (struct vmw_resource *res);
void (*hw_destroy) (struct vmw_resource *res);
};
@@ -392,6 +376,10 @@ struct vmw_sw_context{
struct vmw_legacy_display;
struct vmw_overlay;
+struct vmw_master {
+ struct ttm_lock lock;
+};
+
struct vmw_vga_topology_state {
uint32_t width;
uint32_t height;
@@ -554,8 +542,11 @@ struct vmw_private {
spinlock_t svga_lock;
/**
- * PM management.
+ * Master management.
*/
+
+ struct vmw_master *active_master;
+ struct vmw_master fbdev_master;
struct notifier_block pm_nb;
bool refuse_hibernation;
bool suspend_locked;
@@ -604,9 +595,6 @@ struct vmw_private {
/* Validation memory reservation */
struct vmw_validation_mem vvm;
-
- /* VM operations */
- struct vm_operations_struct vm_ops;
};
static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res)
@@ -624,6 +612,11 @@ static inline struct vmw_fpriv *vmw_fpriv(struct drm_file *file_priv)
return (struct vmw_fpriv *)file_priv->driver_priv;
}
+static inline struct vmw_master *vmw_master(struct drm_master *master)
+{
+ return (struct vmw_master *) master->driver_priv;
+}
+
/*
* The locking here is fine-grained, so that it is performed once
* for every read- and write operation. This is of course costly, but we
@@ -676,8 +669,7 @@ extern void vmw_resource_unreference(struct vmw_resource **p_res);
extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res);
extern struct vmw_resource *
vmw_resource_reference_unless_doomed(struct vmw_resource *res);
-extern int vmw_resource_validate(struct vmw_resource *res, bool intr,
- bool dirtying);
+extern int vmw_resource_validate(struct vmw_resource *res, bool intr);
extern int vmw_resource_reserve(struct vmw_resource *res, bool interruptible,
bool no_backup);
extern bool vmw_resource_needs_backup(const struct vmw_resource *res);
@@ -717,23 +709,6 @@ extern void vmw_query_move_notify(struct ttm_buffer_object *bo,
extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob);
extern void vmw_resource_evict_all(struct vmw_private *dev_priv);
extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo);
-void vmw_resource_mob_attach(struct vmw_resource *res);
-void vmw_resource_mob_detach(struct vmw_resource *res);
-void vmw_resource_dirty_update(struct vmw_resource *res, pgoff_t start,
- pgoff_t end);
-int vmw_resources_clean(struct vmw_buffer_object *vbo, pgoff_t start,
- pgoff_t end, pgoff_t *num_prefault);
-
-/**
- * vmw_resource_mob_attached - Whether a resource currently has a mob attached
- * @res: The resource
- *
- * Return: true if the resource has a mob attached, false otherwise.
- */
-static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
-{
- return !RB_EMPTY_NODE(&res->mob_node);
-}
/**
* vmw_user_resource_noref_release - release a user resource pointer looked up
@@ -812,54 +787,6 @@ static inline void vmw_user_bo_noref_release(void)
ttm_base_object_noref_release();
}
-/**
- * vmw_bo_adjust_prio - Adjust the buffer object eviction priority
- * according to attached resources
- * @vbo: The struct vmw_buffer_object
- */
-static inline void vmw_bo_prio_adjust(struct vmw_buffer_object *vbo)
-{
- int i = ARRAY_SIZE(vbo->res_prios);
-
- while (i--) {
- if (vbo->res_prios[i]) {
- vbo->base.priority = i;
- return;
- }
- }
-
- vbo->base.priority = 3;
-}
-
-/**
- * vmw_bo_prio_add - Notify a buffer object of a newly attached resource
- * eviction priority
- * @vbo: The struct vmw_buffer_object
- * @prio: The resource priority
- *
- * After being notified, the code assigns the highest resource eviction priority
- * to the backing buffer object (mob).
- */
-static inline void vmw_bo_prio_add(struct vmw_buffer_object *vbo, int prio)
-{
- if (vbo->res_prios[prio]++ == 0)
- vmw_bo_prio_adjust(vbo);
-}
-
-/**
- * vmw_bo_prio_del - Notify a buffer object of a resource with a certain
- * priority being removed
- * @vbo: The struct vmw_buffer_object
- * @prio: The resource priority
- *
- * After being notified, the code assigns the highest resource eviction priority
- * to the backing buffer object (mob).
- */
-static inline void vmw_bo_prio_del(struct vmw_buffer_object *vbo, int prio)
-{
- if (--vbo->res_prios[prio] == 0)
- vmw_bo_prio_adjust(vbo);
-}
/**
* Misc Ioctl functionality - vmwgfx_ioctl.c
@@ -1089,6 +1016,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
int vmw_kms_write_svga(struct vmw_private *vmw_priv,
unsigned width, unsigned height, unsigned pitch,
unsigned bpp, unsigned depth);
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster);
bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
uint32_t pitch,
uint32_t height);
@@ -1411,25 +1339,6 @@ int vmw_host_log(const char *log);
DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__)
/**
- * VMW_DEBUG_KMS - Debug output for kernel mode-setting
- *
- * This macro is for debugging vmwgfx mode-setting code.
- */
-#define VMW_DEBUG_KMS(fmt, ...) \
- DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__)
-
-/* Resource dirtying - vmwgfx_page_dirty.c */
-void vmw_bo_dirty_scan(struct vmw_buffer_object *vbo);
-int vmw_bo_dirty_add(struct vmw_buffer_object *vbo);
-void vmw_bo_dirty_transfer_to_res(struct vmw_resource *res);
-void vmw_bo_dirty_clear_res(struct vmw_resource *res);
-void vmw_bo_dirty_release(struct vmw_buffer_object *vbo);
-void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo,
- pgoff_t start, pgoff_t end);
-vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf);
-vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf);
-
-/**
* Inline helper functions
*/
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 319c1ca35663..33533d126277 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -2560,6 +2560,7 @@ static int vmw_cmd_dx_check_subresource(struct vmw_private *dev_priv,
offsetof(typeof(*cmd), sid));
cmd = container_of(header, typeof(*cmd), header);
+
return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
VMW_RES_DIRTY_NONE, user_surface_converter,
&cmd->sid, NULL);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e7222fa2cfdf..b97bc8e5944b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1462,7 +1462,7 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
if (dev_priv->active_display_unit == vmw_du_screen_target &&
(drm_rect_width(&rects[i]) > dev_priv->stdu_max_width ||
drm_rect_height(&rects[i]) > dev_priv->stdu_max_height)) {
- VMW_DEBUG_KMS("Screen size not supported.\n");
+ DRM_ERROR("Screen size not supported.\n");
return -EINVAL;
}
@@ -1486,7 +1486,7 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
* limit on primary bounding box
*/
if (pixel_mem > dev_priv->prim_bb_mem) {
- VMW_DEBUG_KMS("Combined output size too large.\n");
+ DRM_ERROR("Combined output size too large.\n");
return -EINVAL;
}
@@ -1496,7 +1496,7 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
bb_mem = (u64) bounding_box.x2 * bounding_box.y2 * 4;
if (bb_mem > dev_priv->prim_bb_mem) {
- VMW_DEBUG_KMS("Topology is beyond supported limits.\n");
+ DRM_ERROR("Topology is beyond supported limits.\n");
return -EINVAL;
}
}
@@ -1645,7 +1645,6 @@ static int vmw_kms_check_topology(struct drm_device *dev,
struct vmw_connector_state *vmw_conn_state;
if (!du->pref_active && new_crtc_state->enable) {
- VMW_DEBUG_KMS("Enabling a disabled display unit\n");
ret = -EINVAL;
goto clean;
}
@@ -1702,10 +1701,8 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev,
return ret;
ret = vmw_kms_check_implicit(dev, state);
- if (ret) {
- VMW_DEBUG_KMS("Invalid implicit state\n");
+ if (ret)
return ret;
- }
if (!state->allow_modeset)
return ret;
@@ -2350,9 +2347,6 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
if (!arg->num_outputs) {
struct drm_rect def_rect = {0, 0, 800, 600};
- VMW_DEBUG_KMS("Default layout x1 = %d y1 = %d x2 = %d y2 = %d\n",
- def_rect.x1, def_rect.y1,
- def_rect.x2, def_rect.y2);
vmw_du_update_layout(dev_priv, 1, &def_rect);
return 0;
}
@@ -2373,7 +2367,6 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
drm_rects = (struct drm_rect *)rects;
- VMW_DEBUG_KMS("Layout count = %u\n", arg->num_outputs);
for (i = 0; i < arg->num_outputs; i++) {
struct drm_vmw_rect curr_rect;
@@ -2390,10 +2383,6 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
drm_rects[i].x2 = curr_rect.x + curr_rect.w;
drm_rects[i].y2 = curr_rect.y + curr_rect.h;
- VMW_DEBUG_KMS(" x1 = %d y1 = %d x2 = %d y2 = %d\n",
- drm_rects[i].x1, drm_rects[i].y1,
- drm_rects[i].x2, drm_rects[i].y2);
-
/*
* Currently this check is limiting the topology within
* mode_config->max (which actually is max texture size
@@ -2404,9 +2393,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
if (drm_rects[i].x1 < 0 || drm_rects[i].y1 < 0 ||
drm_rects[i].x2 > mode_config->max_width ||
drm_rects[i].y2 > mode_config->max_height) {
- VMW_DEBUG_KMS("Invalid layout %d %d %d %d\n",
- drm_rects[i].x1, drm_rects[i].y1,
- drm_rects[i].x2, drm_rects[i].y2);
+ DRM_ERROR("Invalid GUI layout.\n");
ret = -EINVAL;
goto out_free;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
deleted file mode 100644
index 730c51e397dd..000000000000
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
+++ /dev/null
@@ -1,472 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR MIT
-/**************************************************************************
- *
- * Copyright 2019 VMware, Inc., Palo Alto, CA., USA
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-#include "vmwgfx_drv.h"
-
-/*
- * Different methods for tracking dirty:
- * VMW_BO_DIRTY_PAGETABLE - Scan the pagetable for hardware dirty bits
- * VMW_BO_DIRTY_MKWRITE - Write-protect page table entries and record write-
- * accesses in the VM mkwrite() callback
- */
-enum vmw_bo_dirty_method {
- VMW_BO_DIRTY_PAGETABLE,
- VMW_BO_DIRTY_MKWRITE,
-};
-
-/*
- * No dirtied pages at scan trigger a transition to the _MKWRITE method,
- * similarly a certain percentage of dirty pages trigger a transition to
- * the _PAGETABLE method. How many triggers should we wait for before
- * changing method?
- */
-#define VMW_DIRTY_NUM_CHANGE_TRIGGERS 2
-
-/* Percentage to trigger a transition to the _PAGETABLE method */
-#define VMW_DIRTY_PERCENTAGE 10
-
-/**
- * struct vmw_bo_dirty - Dirty information for buffer objects
- * @start: First currently dirty bit
- * @end: Last currently dirty bit + 1
- * @method: The currently used dirty method
- * @change_count: Number of consecutive method change triggers
- * @ref_count: Reference count for this structure
- * @bitmap_size: The size of the bitmap in bits. Typically equal to the
- * nuber of pages in the bo.
- * @size: The accounting size for this struct.
- * @bitmap: A bitmap where each bit represents a page. A set bit means a
- * dirty page.
- */
-struct vmw_bo_dirty {
- unsigned long start;
- unsigned long end;
- enum vmw_bo_dirty_method method;
- unsigned int change_count;
- unsigned int ref_count;
- unsigned long bitmap_size;
- size_t size;
- unsigned long bitmap[0];
-};
-
-/**
- * vmw_bo_dirty_scan_pagetable - Perform a pagetable scan for dirty bits
- * @vbo: The buffer object to scan
- *
- * Scans the pagetable for dirty bits. Clear those bits and modify the
- * dirty structure with the results. This function may change the
- * dirty-tracking method.
- */
-static void vmw_bo_dirty_scan_pagetable(struct vmw_buffer_object *vbo)
-{
- struct vmw_bo_dirty *dirty = vbo->dirty;
- pgoff_t offset = drm_vma_node_start(&vbo->base.vma_node);
- struct address_space *mapping = vbo->base.bdev->dev_mapping;
- pgoff_t num_marked;
-
- num_marked = apply_as_clean(mapping,
- offset, dirty->bitmap_size,
- offset, &dirty->bitmap[0],
- &dirty->start, &dirty->end);
- if (num_marked == 0)
- dirty->change_count++;
- else
- dirty->change_count = 0;
-
- if (dirty->change_count > VMW_DIRTY_NUM_CHANGE_TRIGGERS) {
- dirty->change_count = 0;
- dirty->method = VMW_BO_DIRTY_MKWRITE;
- apply_as_wrprotect(mapping,
- offset, dirty->bitmap_size);
- apply_as_clean(mapping,
- offset, dirty->bitmap_size,
- offset, &dirty->bitmap[0],
- &dirty->start, &dirty->end);
- }
-}
-
-/**
- * vmw_bo_dirty_scan_mkwrite - Reset the mkwrite dirty-tracking method
- * @vbo: The buffer object to scan
- *
- * Write-protect pages written to so that consecutive write accesses will
- * trigger a call to mkwrite.
- *
- * This function may change the dirty-tracking method.
- */
-static void vmw_bo_dirty_scan_mkwrite(struct vmw_buffer_object *vbo)
-{
- struct vmw_bo_dirty *dirty = vbo->dirty;
- unsigned long offset = drm_vma_node_start(&vbo->base.vma_node);
- struct address_space *mapping = vbo->base.bdev->dev_mapping;
- pgoff_t num_marked;
-
- if (dirty->end <= dirty->start)
- return;
-
- num_marked = apply_as_wrprotect(vbo->base.bdev->dev_mapping,
- dirty->start + offset,
- dirty->end - dirty->start);
-
- if (100UL * num_marked / dirty->bitmap_size >
- VMW_DIRTY_PERCENTAGE) {
- dirty->change_count++;
- } else {
- dirty->change_count = 0;
- }
-
- if (dirty->change_count > VMW_DIRTY_NUM_CHANGE_TRIGGERS) {
- pgoff_t start = 0;
- pgoff_t end = dirty->bitmap_size;
-
- dirty->method = VMW_BO_DIRTY_PAGETABLE;
- apply_as_clean(mapping, offset, end, offset, &dirty->bitmap[0],
- &start, &end);
- bitmap_clear(&dirty->bitmap[0], 0, dirty->bitmap_size);
- if (dirty->start < dirty->end)
- bitmap_set(&dirty->bitmap[0], dirty->start,
- dirty->end - dirty->start);
- dirty->change_count = 0;
- }
-}
-
-/**
- * vmw_bo_dirty_scan - Scan for dirty pages and add them to the dirty
- * tracking structure
- * @vbo: The buffer object to scan
- *
- * This function may change the dirty tracking method.
- */
-void vmw_bo_dirty_scan(struct vmw_buffer_object *vbo)
-{
- struct vmw_bo_dirty *dirty = vbo->dirty;
-
- if (dirty->method == VMW_BO_DIRTY_PAGETABLE)
- vmw_bo_dirty_scan_pagetable(vbo);
- else
- vmw_bo_dirty_scan_mkwrite(vbo);
-}
-
-/**
- * vmw_bo_dirty_pre_unmap - write-protect and pick up dirty pages before
- * an unmap_mapping_range operation.
- * @vbo: The buffer object,
- * @start: First page of the range within the buffer object.
- * @end: Last page of the range within the buffer object + 1.
- *
- * If we're using the _PAGETABLE scan method, we may leak dirty pages
- * when calling unmap_mapping_range(). This function makes sure we pick
- * up all dirty pages.
- */
-static void vmw_bo_dirty_pre_unmap(struct vmw_buffer_object *vbo,
- pgoff_t start, pgoff_t end)
-{
- struct vmw_bo_dirty *dirty = vbo->dirty;
- unsigned long offset = drm_vma_node_start(&vbo->base.vma_node);
- struct address_space *mapping = vbo->base.bdev->dev_mapping;
-
- if (dirty->method != VMW_BO_DIRTY_PAGETABLE || start >= end)
- return;
-
- apply_as_wrprotect(mapping, start + offset, end - start);
- apply_as_clean(mapping, start + offset, end - start, offset,
- &dirty->bitmap[0], &dirty->start, &dirty->end);
-}
-
-/**
- * vmw_bo_dirty_unmap - Clear all ptes pointing to a range within a bo
- * @vbo: The buffer object,
- * @start: First page of the range within the buffer object.
- * @end: Last page of the range within the buffer object + 1.
- *
- * This is similar to ttm_bo_unmap_virtual_locked() except it takes a subrange.
- */
-void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo,
- pgoff_t start, pgoff_t end)
-{
- unsigned long offset = drm_vma_node_start(&vbo->base.vma_node);
- struct address_space *mapping = vbo->base.bdev->dev_mapping;
-
- vmw_bo_dirty_pre_unmap(vbo, start, end);
- unmap_shared_mapping_range(mapping, (offset + start) << PAGE_SHIFT,
- (loff_t) (end - start) << PAGE_SHIFT);
-}
-
-/**
- * vmw_bo_dirty_add - Add a dirty-tracking user to a buffer object
- * @vbo: The buffer object
- *
- * This function registers a dirty-tracking user to a buffer object.
- * A user can be for example a resource or a vma in a special user-space
- * mapping.
- *
- * Return: Zero on success, -ENOMEM on memory allocation failure.
- */
-int vmw_bo_dirty_add(struct vmw_buffer_object *vbo)
-{
- struct vmw_bo_dirty *dirty = vbo->dirty;
- pgoff_t num_pages = vbo->base.num_pages;
- size_t size, acc_size;
- int ret;
- static struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false
- };
-
- if (dirty) {
- dirty->ref_count++;
- return 0;
- }
-
- size = sizeof(*dirty) + BITS_TO_LONGS(num_pages) * sizeof(long);
- acc_size = ttm_round_pot(size);
- ret = ttm_mem_global_alloc(&ttm_mem_glob, acc_size, &ctx);
- if (ret) {
- VMW_DEBUG_USER("Out of graphics memory for buffer object "
- "dirty tracker.\n");
- return ret;
- }
- dirty = kvzalloc(size, GFP_KERNEL);
- if (!dirty) {
- ret = -ENOMEM;
- goto out_no_dirty;
- }
-
- dirty->size = acc_size;
- dirty->bitmap_size = num_pages;
- dirty->start = dirty->bitmap_size;
- dirty->end = 0;
- dirty->ref_count = 1;
- if (num_pages < PAGE_SIZE / sizeof(pte_t)) {
- dirty->method = VMW_BO_DIRTY_PAGETABLE;
- } else {
- struct address_space *mapping = vbo->base.bdev->dev_mapping;
- pgoff_t offset = drm_vma_node_start(&vbo->base.vma_node);
-
- dirty->method = VMW_BO_DIRTY_MKWRITE;
-
- /* Write-protect and then pick up already dirty bits */
- apply_as_wrprotect(mapping, offset, num_pages);
- apply_as_clean(mapping, offset, num_pages, offset,
- &dirty->bitmap[0], &dirty->start, &dirty->end);
- }
-
- vbo->dirty = dirty;
-
- return 0;
-
-out_no_dirty:
- ttm_mem_global_free(&ttm_mem_glob, acc_size);
- return ret;
-}
-
-/**
- * vmw_bo_dirty_release - Release a dirty-tracking user from a buffer object
- * @vbo: The buffer object
- *
- * This function releases a dirty-tracking user from a buffer object.
- * If the reference count reaches zero, then the dirty-tracking object is
- * freed and the pointer to it cleared.
- *
- * Return: Zero on success, -ENOMEM on memory allocation failure.
- */
-void vmw_bo_dirty_release(struct vmw_buffer_object *vbo)
-{
- struct vmw_bo_dirty *dirty = vbo->dirty;
-
- if (dirty && --dirty->ref_count == 0) {
- size_t acc_size = dirty->size;
-
- kvfree(dirty);
- ttm_mem_global_free(&ttm_mem_glob, acc_size);
- vbo->dirty = NULL;
- }
-}
-
-/**
- * vmw_bo_dirty_transfer_to_res - Pick up a resource's dirty region from
- * its backing mob.
- * @res: The resource
- *
- * This function will pick up all dirty ranges affecting the resource from
- * it's backup mob, and call vmw_resource_dirty_update() once for each
- * range. The transferred ranges will be cleared from the backing mob's
- * dirty tracking.
- */
-void vmw_bo_dirty_transfer_to_res(struct vmw_resource *res)
-{
- struct vmw_buffer_object *vbo = res->backup;
- struct vmw_bo_dirty *dirty = vbo->dirty;
- pgoff_t start, cur, end;
- unsigned long res_start = res->backup_offset;
- unsigned long res_end = res->backup_offset + res->backup_size;
-
- WARN_ON_ONCE(res_start & ~PAGE_MASK);
- res_start >>= PAGE_SHIFT;
- res_end = DIV_ROUND_UP(res_end, PAGE_SIZE);
-
- if (res_start >= dirty->end || res_end <= dirty->start)
- return;
-
- cur = max(res_start, dirty->start);
- res_end = max(res_end, dirty->end);
- while (cur < res_end) {
- unsigned long num;
-
- start = find_next_bit(&dirty->bitmap[0], res_end, cur);
- if (start >= res_end)
- break;
-
- end = find_next_zero_bit(&dirty->bitmap[0], res_end, start + 1);
- cur = end + 1;
- num = end - start;
- bitmap_clear(&dirty->bitmap[0], start, num);
- vmw_resource_dirty_update(res, start, end);
- }
-
- if (res_start <= dirty->start && res_end > dirty->start)
- dirty->start = res_end;
- if (res_start < dirty->end && res_end >= dirty->end)
- dirty->end = res_start;
-}
-
-/**
- * vmw_bo_dirty_clear_res - Clear a resource's dirty region from
- * its backing mob.
- * @res: The resource
- *
- * This function will clear all dirty ranges affecting the resource from
- * it's backup mob's dirty tracking.
- */
-void vmw_bo_dirty_clear_res(struct vmw_resource *res)
-{
- unsigned long res_start = res->backup_offset;
- unsigned long res_end = res->backup_offset + res->backup_size;
- struct vmw_buffer_object *vbo = res->backup;
- struct vmw_bo_dirty *dirty = vbo->dirty;
-
- res_start >>= PAGE_SHIFT;
- res_end = DIV_ROUND_UP(res_end, PAGE_SIZE);
-
- if (res_start >= dirty->end || res_end <= dirty->start)
- return;
-
- res_start = max(res_start, dirty->start);
- res_end = min(res_end, dirty->end);
- bitmap_clear(&dirty->bitmap[0], res_start, res_end - res_start);
-
- if (res_start <= dirty->start && res_end > dirty->start)
- dirty->start = res_end;
- if (res_start < dirty->end && res_end >= dirty->end)
- dirty->end = res_start;
-}
-
-vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf)
-{
- struct vm_area_struct *vma = vmf->vma;
- struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
- vma->vm_private_data;
- vm_fault_t ret;
- unsigned long page_offset;
- struct vmw_buffer_object *vbo =
- container_of(bo, typeof(*vbo), base);
-
- ret = ttm_bo_vm_reserve(bo, vmf);
- if (ret)
- return ret;
-
- page_offset = vmf->pgoff - drm_vma_node_start(&bo->vma_node);
- if (unlikely(page_offset >= bo->num_pages)) {
- ret = VM_FAULT_SIGBUS;
- goto out_unlock;
- }
-
- if (vbo->dirty && vbo->dirty->method == VMW_BO_DIRTY_MKWRITE &&
- !test_bit(page_offset, &vbo->dirty->bitmap[0])) {
- struct vmw_bo_dirty *dirty = vbo->dirty;
-
- __set_bit(page_offset, &dirty->bitmap[0]);
- dirty->start = min(dirty->start, page_offset);
- dirty->end = max(dirty->end, page_offset + 1);
- }
-
-out_unlock:
- reservation_object_unlock(bo->resv);
- return ret;
-}
-
-vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf)
-{
- struct vm_area_struct *vma = vmf->vma;
- struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
- vma->vm_private_data;
- struct vmw_buffer_object *vbo =
- container_of(bo, struct vmw_buffer_object, base);
- pgoff_t num_prefault;
- pgprot_t prot;
- vm_fault_t ret;
-
- ret = ttm_bo_vm_reserve(bo, vmf);
- if (ret)
- return ret;
-
- num_prefault = (vma->vm_flags & VM_RAND_READ) ? 1 :
- TTM_BO_VM_NUM_PREFAULT;
-
- if (vbo->dirty) {
- pgoff_t allowed_prefault;
- unsigned long page_offset;
-
- page_offset = vmf->pgoff - drm_vma_node_start(&bo->vma_node);
- if (page_offset >= bo->num_pages ||
- vmw_resources_clean(vbo, page_offset,
- page_offset + PAGE_SIZE,
- &allowed_prefault)) {
- ret = VM_FAULT_SIGBUS;
- goto out_unlock;
- }
-
- num_prefault = min(num_prefault, allowed_prefault);
- }
-
- /*
- * If we don't track dirty using the MKWRITE method, make sure
- * sure the page protection is write-enabled so we don't get
- * a lot of unnecessary write faults.
- */
- if (vbo->dirty && vbo->dirty->method == VMW_BO_DIRTY_MKWRITE)
- prot = vma->vm_page_prot;
- else
- prot = vm_get_page_prot(vma->vm_flags);
-
- ret = ttm_bo_vm_fault_reserved(vmf, prot, num_prefault);
- if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
- return ret;
-
-out_unlock:
- reservation_object_unlock(bo->resv);
- return ret;
-}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index d70ee0df5c13..1d38a8b2f2ec 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -34,51 +34,6 @@
#define VMW_RES_EVICT_ERR_COUNT 10
-/**
- * vmw_resource_mob_attach - Mark a resource as attached to its backing mob
- * @res: The resource
- */
-void vmw_resource_mob_attach(struct vmw_resource *res)
-{
- struct vmw_buffer_object *backup = res->backup;
- struct rb_node **new = &backup->res_tree.rb_node, *parent = NULL;
-
- lockdep_assert_held(&backup->base.resv->lock.base);
- res->used_prio = (res->res_dirty) ? res->func->dirty_prio :
- res->func->prio;
-
- while (*new) {
- struct vmw_resource *this =
- container_of(*new, struct vmw_resource, mob_node);
-
- parent = *new;
- new = (res->backup_offset < this->backup_offset) ?
- &((*new)->rb_left) : &((*new)->rb_right);
- }
-
- rb_link_node(&res->mob_node, parent, new);
- rb_insert_color(&res->mob_node, &backup->res_tree);
-
- vmw_bo_prio_add(backup, res->used_prio);
-}
-
-/**
- * vmw_resource_mob_detach - Mark a resource as detached from its backing mob
- * @res: The resource
- */
-void vmw_resource_mob_detach(struct vmw_resource *res)
-{
- struct vmw_buffer_object *backup = res->backup;
-
- lockdep_assert_held(&backup->base.resv->lock.base);
- if (vmw_resource_mob_attached(res)) {
- rb_erase(&res->mob_node, &backup->res_tree);
- RB_CLEAR_NODE(&res->mob_node);
- vmw_bo_prio_del(backup, res->used_prio);
- }
-}
-
-
struct vmw_resource *vmw_resource_reference(struct vmw_resource *res)
{
kref_get(&res->kref);
@@ -125,7 +80,7 @@ static void vmw_resource_release(struct kref *kref)
struct ttm_buffer_object *bo = &res->backup->base;
ttm_bo_reserve(bo, false, false, NULL);
- if (vmw_resource_mob_attached(res) &&
+ if (!list_empty(&res->mob_head) &&
res->func->unbind != NULL) {
struct ttm_validate_buffer val_buf;
@@ -134,11 +89,7 @@ static void vmw_resource_release(struct kref *kref)
res->func->unbind(res, false, &val_buf);
}
res->backup_dirty = false;
- vmw_resource_mob_detach(res);
- if (res->dirty)
- res->func->dirty_free(res);
- if (res->coherent)
- vmw_bo_dirty_release(res->backup);
+ list_del_init(&res->mob_head);
ttm_bo_unreserve(bo);
vmw_bo_unreference(&res->backup);
}
@@ -220,17 +171,14 @@ int vmw_resource_init(struct vmw_private *dev_priv, struct vmw_resource *res,
res->res_free = res_free;
res->dev_priv = dev_priv;
res->func = func;
- RB_CLEAR_NODE(&res->mob_node);
INIT_LIST_HEAD(&res->lru_head);
+ INIT_LIST_HEAD(&res->mob_head);
INIT_LIST_HEAD(&res->binding_head);
res->id = -1;
res->backup = NULL;
res->backup_offset = 0;
res->backup_dirty = false;
res->res_dirty = false;
- res->coherent = false;
- res->used_prio = 3;
- res->dirty = NULL;
if (delay_id)
return 0;
else
@@ -395,8 +343,7 @@ out_no_bo:
* should be retried once resources have been freed up.
*/
static int vmw_resource_do_validate(struct vmw_resource *res,
- struct ttm_validate_buffer *val_buf,
- bool dirtying)
+ struct ttm_validate_buffer *val_buf)
{
int ret = 0;
const struct vmw_res_func *func = res->func;
@@ -408,47 +355,14 @@ static int vmw_resource_do_validate(struct vmw_resource *res,
}
if (func->bind &&
- ((func->needs_backup && !vmw_resource_mob_attached(res) &&
+ ((func->needs_backup && list_empty(&res->mob_head) &&
val_buf->bo != NULL) ||
(!func->needs_backup && val_buf->bo != NULL))) {
ret = func->bind(res, val_buf);
if (unlikely(ret != 0))
goto out_bind_failed;
if (func->needs_backup)
- vmw_resource_mob_attach(res);
- }
-
- /*
- * Handle the case where the backup mob is marked coherent but
- * the resource isn't.
- */
- if (func->dirty_alloc && vmw_resource_mob_attached(res) &&
- !res->coherent) {
- if (res->backup->dirty && !res->dirty) {
- ret = func->dirty_alloc(res);
- if (ret)
- return ret;
- } else if (!res->backup->dirty && res->dirty) {
- func->dirty_free(res);
- }
- }
-
- /*
- * Transfer the dirty regions to the resource and update
- * the resource.
- */
- if (res->dirty) {
- if (dirtying && !res->res_dirty) {
- pgoff_t start = res->backup_offset >> PAGE_SHIFT;
- pgoff_t end = __KERNEL_DIV_ROUND_UP
- (res->backup_offset + res->backup_size,
- PAGE_SIZE);
-
- vmw_bo_dirty_unmap(res->backup, start, end);
- }
-
- vmw_bo_dirty_transfer_to_res(res);
- return func->dirty_sync(res);
+ list_add_tail(&res->mob_head, &res->backup->res_list);
}
return 0;
@@ -488,29 +402,19 @@ void vmw_resource_unreserve(struct vmw_resource *res,
if (switch_backup && new_backup != res->backup) {
if (res->backup) {
- vmw_resource_mob_detach(res);
- if (res->coherent)
- vmw_bo_dirty_release(res->backup);
+ lockdep_assert_held(&res->backup->base.resv->lock.base);
+ list_del_init(&res->mob_head);
vmw_bo_unreference(&res->backup);
}
if (new_backup) {
res->backup = vmw_bo_reference(new_backup);
-
- /*
- * The validation code should already have added a
- * dirty tracker here.
- */
- WARN_ON(res->coherent && !new_backup->dirty);
-
- vmw_resource_mob_attach(res);
+ lockdep_assert_held(&new_backup->base.resv->lock.base);
+ list_add_tail(&res->mob_head, &new_backup->res_list);
} else {
res->backup = NULL;
}
- } else if (switch_backup && res->coherent) {
- vmw_bo_dirty_release(res->backup);
}
-
if (switch_backup)
res->backup_offset = new_backup_offset;
@@ -565,7 +469,7 @@ vmw_resource_check_buffer(struct ww_acquire_ctx *ticket,
if (unlikely(ret != 0))
goto out_no_reserve;
- if (res->func->needs_backup && !vmw_resource_mob_attached(res))
+ if (res->func->needs_backup && list_empty(&res->mob_head))
return 0;
backup_dirty = res->backup_dirty;
@@ -670,11 +574,11 @@ static int vmw_resource_do_evict(struct ww_acquire_ctx *ticket,
return ret;
if (unlikely(func->unbind != NULL &&
- (!func->needs_backup || vmw_resource_mob_attached(res)))) {
+ (!func->needs_backup || !list_empty(&res->mob_head)))) {
ret = func->unbind(res, res->res_dirty, &val_buf);
if (unlikely(ret != 0))
goto out_no_unbind;
- vmw_resource_mob_detach(res);
+ list_del_init(&res->mob_head);
}
ret = func->destroy(res);
res->backup_dirty = true;
@@ -691,7 +595,6 @@ out_no_unbind:
* to the device.
* @res: The resource to make visible to the device.
* @intr: Perform waits interruptible if possible.
- * @dirtying: Pending GPU operation will dirty the resource
*
* On succesful return, any backup DMA buffer pointed to by @res->backup will
* be reserved and validated.
@@ -701,8 +604,7 @@ out_no_unbind:
* Return: Zero on success, -ERESTARTSYS if interrupted, negative error code
* on failure.
*/
-int vmw_resource_validate(struct vmw_resource *res, bool intr,
- bool dirtying)
+int vmw_resource_validate(struct vmw_resource *res, bool intr)
{
int ret;
struct vmw_resource *evict_res;
@@ -719,7 +621,7 @@ int vmw_resource_validate(struct vmw_resource *res, bool intr,
if (res->backup)
val_buf.bo = &res->backup->base;
do {
- ret = vmw_resource_do_validate(res, &val_buf, dirtying);
+ ret = vmw_resource_do_validate(res, &val_buf);
if (likely(ret != -EBUSY))
break;
@@ -758,7 +660,7 @@ int vmw_resource_validate(struct vmw_resource *res, bool intr,
if (unlikely(ret != 0))
goto out_no_validate;
else if (!res->func->needs_backup && res->backup) {
- WARN_ON_ONCE(vmw_resource_mob_attached(res));
+ list_del_init(&res->mob_head);
vmw_bo_unreference(&res->backup);
}
@@ -782,23 +684,22 @@ out_no_validate:
*/
void vmw_resource_unbind_list(struct vmw_buffer_object *vbo)
{
+
+ struct vmw_resource *res, *next;
struct ttm_validate_buffer val_buf = {
.bo = &vbo->base,
.num_shared = 0
};
lockdep_assert_held(&vbo->base.resv->lock.base);
- while (!RB_EMPTY_ROOT(&vbo->res_tree)) {
- struct rb_node *node = vbo->res_tree.rb_node;
- struct vmw_resource *res =
- container_of(node, struct vmw_resource, mob_node);
-
- if (!WARN_ON_ONCE(!res->func->unbind))
- (void) res->func->unbind(res, res->res_dirty, &val_buf);
+ list_for_each_entry_safe(res, next, &vbo->res_list, mob_head) {
+ if (!res->func->unbind)
+ continue;
+ (void) res->func->unbind(res, res->res_dirty, &val_buf);
res->backup_dirty = true;
res->res_dirty = false;
- vmw_resource_mob_detach(res);
+ list_del_init(&res->mob_head);
}
(void) ttm_bo_wait(&vbo->base, false, false);
@@ -1019,7 +920,7 @@ int vmw_resource_pin(struct vmw_resource *res, bool interruptible)
/* Do we really need to pin the MOB as well? */
vmw_bo_pin_reserved(vbo, true);
}
- ret = vmw_resource_validate(res, interruptible, true);
+ ret = vmw_resource_validate(res, interruptible);
if (vbo)
ttm_bo_unreserve(&vbo->base);
if (ret)
@@ -1079,101 +980,3 @@ enum vmw_res_type vmw_res_type(const struct vmw_resource *res)
{
return res->func->res_type;
}
-
-/**
- * vmw_resource_update_dirty - Update a resource's dirty tracker with a
- * sequential range of touched backing store memory.
- * @res: The resource.
- * @start: The first page touched.
- * @end: The last page touched + 1.
- */
-void vmw_resource_dirty_update(struct vmw_resource *res, pgoff_t start,
- pgoff_t end)
-{
- if (res->dirty)
- res->func->dirty_range_add(res, start << PAGE_SHIFT,
- end << PAGE_SHIFT);
-}
-
-/**
- * vmw_resources_clean - Clean resources intersecting a mob range
- * @vbo: The mob buffer object
- * @start: The mob page offset starting the range
- * @end: The mob page offset ending the range
- * @num_prefault: Returns how many pages including the first have been
- * cleaned and are ok to prefault
- */
-int vmw_resources_clean(struct vmw_buffer_object *vbo, pgoff_t start,
- pgoff_t end, pgoff_t *num_prefault)
-{
- struct rb_node *cur = vbo->res_tree.rb_node;
- struct vmw_resource *found = NULL;
- unsigned long res_start = start << PAGE_SHIFT;
- unsigned long res_end = end << PAGE_SHIFT;
- unsigned long last_cleaned = 0;
-
- /*
- * Find the resource with lowest backup_offset that intersects the
- * range.
- */
- while (cur) {
- struct vmw_resource *cur_res =
- container_of(cur, struct vmw_resource, mob_node);
-
- if (cur_res->backup_offset >= res_end) {
- cur = cur->rb_left;
- } else if (cur_res->backup_offset + cur_res->backup_size <=
- res_start) {
- cur = cur->rb_right;
- } else {
- found = cur_res;
- cur = cur->rb_left;
- /* Continue to look for resources with lower offsets */
- }
- }
-
- /*
- * In order of increasing backup_offset, clean dirty resorces
- * intersecting the range.
- */
- while (found) {
- if (found->res_dirty) {
- int ret;
-
- if (!found->func->clean)
- return -EINVAL;
-
- ret = found->func->clean(found);
- if (ret)
- return ret;
-
- found->res_dirty = false;
- }
- last_cleaned = found->backup_offset + found->backup_size;
- cur = rb_next(&found->mob_node);
- if (!cur)
- break;
-
- found = container_of(cur, struct vmw_resource, mob_node);
- if (found->backup_offset >= res_end)
- break;
- }
-
- /*
- * Set number of pages allowed prefaulting and fence the buffer object
- */
- *num_prefault = 1;
- if (last_cleaned > res_start) {
- struct ttm_buffer_object *bo = &vbo->base;
-
- *num_prefault = __KERNEL_DIV_ROUND_UP(last_cleaned - res_start,
- PAGE_SIZE);
- vmw_bo_fence_single(bo, NULL);
- if (bo->moving)
- dma_fence_put(bo->moving);
- bo->moving = dma_fence_get
- (reservation_object_get_excl(bo->resv));
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
index 3b7438b2d289..7e19eba0b0b8 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
@@ -71,13 +71,6 @@ struct vmw_user_resource_conv {
* @commit_notify: If the resource is a command buffer managed resource,
* callback to notify that a define or remove command
* has been committed to the device.
- * @dirty_alloc: Allocate a dirty tracker. NULL if dirty-tracking is not
- * supported.
- * @dirty_free: Free the dirty tracker.
- * @dirty_sync: Upload the dirty mob contents to the resource.
- * @dirty_add_range: Add a sequential dirty range to the resource
- * dirty tracker.
- * @clean: Clean the resource.
*/
struct vmw_res_func {
enum vmw_res_type res_type;
@@ -85,8 +78,6 @@ struct vmw_res_func {
const char *type_name;
struct ttm_placement *backup_placement;
bool may_evict;
- u32 prio;
- u32 dirty_prio;
int (*create) (struct vmw_resource *res);
int (*destroy) (struct vmw_resource *res);
@@ -97,12 +88,6 @@ struct vmw_res_func {
struct ttm_validate_buffer *val_buf);
void (*commit_notify)(struct vmw_resource *res,
enum vmw_cmdbuf_res_state state);
- int (*dirty_alloc)(struct vmw_resource *res);
- void (*dirty_free)(struct vmw_resource *res);
- int (*dirty_sync)(struct vmw_resource *res);
- void (*dirty_range_add)(struct vmw_resource *res, size_t start,
- size_t end);
- int (*clean)(struct vmw_resource *res);
};
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
index e139fdfd1635..d310d21f0d54 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
@@ -95,8 +95,6 @@ static const struct vmw_res_func vmw_gb_shader_func = {
.res_type = vmw_res_shader,
.needs_backup = true,
.may_evict = true,
- .prio = 3,
- .dirty_prio = 3,
.type_name = "guest backed shaders",
.backup_placement = &vmw_mob_placement,
.create = vmw_gb_shader_create,
@@ -108,9 +106,7 @@ static const struct vmw_res_func vmw_gb_shader_func = {
static const struct vmw_res_func vmw_dx_shader_func = {
.res_type = vmw_res_shader,
.needs_backup = true,
- .may_evict = true,
- .prio = 3,
- .dirty_prio = 3,
+ .may_evict = false,
.type_name = "dx shaders",
.backup_placement = &vmw_mob_placement,
.create = vmw_dx_shader_create,
@@ -427,7 +423,7 @@ static int vmw_dx_shader_create(struct vmw_resource *res)
WARN_ON_ONCE(!shader->committed);
- if (vmw_resource_mob_attached(res)) {
+ if (!list_empty(&res->mob_head)) {
mutex_lock(&dev_priv->binding_mutex);
ret = vmw_dx_shader_unscrub(res);
mutex_unlock(&dev_priv->binding_mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 862ca44680ca..219471903bc1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -68,20 +68,6 @@ struct vmw_surface_offset {
uint32_t bo_offset;
};
-/**
- * vmw_surface_dirty - Surface dirty-tracker
- * @cache: Cached layout information of the surface.
- * @size: Accounting size for the struct vmw_surface_dirty.
- * @num_subres: Number of subresources.
- * @boxes: Array of SVGA3dBoxes indicating dirty regions. One per subresource.
- */
-struct vmw_surface_dirty {
- struct svga3dsurface_cache cache;
- size_t size;
- u32 num_subres;
- SVGA3dBox boxes[0];
-};
-
static void vmw_user_surface_free(struct vmw_resource *res);
static struct vmw_resource *
vmw_user_surface_base_to_res(struct ttm_base_object *base);
@@ -110,13 +96,6 @@ vmw_gb_surface_reference_internal(struct drm_device *dev,
struct drm_vmw_gb_surface_ref_ext_rep *rep,
struct drm_file *file_priv);
-static void vmw_surface_dirty_free(struct vmw_resource *res);
-static int vmw_surface_dirty_alloc(struct vmw_resource *res);
-static int vmw_surface_dirty_sync(struct vmw_resource *res);
-static void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start,
- size_t end);
-static int vmw_surface_clean(struct vmw_resource *res);
-
static const struct vmw_user_resource_conv user_surface_conv = {
.object_type = VMW_RES_SURFACE,
.base_obj_to_res = vmw_user_surface_base_to_res,
@@ -133,8 +112,6 @@ static const struct vmw_res_func vmw_legacy_surface_func = {
.res_type = vmw_res_surface,
.needs_backup = false,
.may_evict = true,
- .prio = 1,
- .dirty_prio = 1,
.type_name = "legacy surfaces",
.backup_placement = &vmw_srf_placement,
.create = &vmw_legacy_srf_create,
@@ -147,19 +124,12 @@ static const struct vmw_res_func vmw_gb_surface_func = {
.res_type = vmw_res_surface,
.needs_backup = true,
.may_evict = true,
- .prio = 1,
- .dirty_prio = 2,
.type_name = "guest backed surfaces",
.backup_placement = &vmw_mob_placement,
.create = vmw_gb_surface_create,
.destroy = vmw_gb_surface_destroy,
.bind = vmw_gb_surface_bind,
- .unbind = vmw_gb_surface_unbind,
- .dirty_alloc = vmw_surface_dirty_alloc,
- .dirty_free = vmw_surface_dirty_free,
- .dirty_sync = vmw_surface_dirty_sync,
- .dirty_range_add = vmw_surface_dirty_range_add,
- .clean = vmw_surface_clean,
+ .unbind = vmw_gb_surface_unbind
};
/**
@@ -667,7 +637,6 @@ static void vmw_user_surface_free(struct vmw_resource *res)
struct vmw_private *dev_priv = srf->res.dev_priv;
uint32_t size = user_srf->size;
- WARN_ON_ONCE(res->dirty);
if (user_srf->master)
drm_master_put(&user_srf->master);
kfree(srf->offsets);
@@ -946,6 +915,12 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
if (unlikely(drm_is_render_client(file_priv)))
require_exist = true;
+ if (READ_ONCE(vmw_fpriv(file_priv)->locked_master)) {
+ DRM_ERROR("Locked master refused legacy "
+ "surface reference.\n");
+ return -EACCES;
+ }
+
handle = u_handle;
}
@@ -1195,16 +1170,10 @@ static int vmw_gb_surface_bind(struct vmw_resource *res,
cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE;
cmd2->header.size = sizeof(cmd2->body);
cmd2->body.sid = res->id;
+ res->backup_dirty = false;
}
vmw_fifo_commit(dev_priv, submit_size);
- if (res->backup->dirty && res->backup_dirty) {
- /* We've just made a full upload. Cear dirty regions. */
- vmw_bo_dirty_clear_res(res);
- }
-
- res->backup_dirty = false;
-
return 0;
}
@@ -1669,8 +1638,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
}
}
} else if (req->base.drm_surface_flags &
- (drm_vmw_surface_flag_create_buffer |
- drm_vmw_surface_flag_coherent))
+ drm_vmw_surface_flag_create_buffer)
ret = vmw_user_bo_alloc(dev_priv, tfile,
res->backup_size,
req->base.drm_surface_flags &
@@ -1684,26 +1652,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
goto out_unlock;
}
- if (req->base.drm_surface_flags & drm_vmw_surface_flag_coherent) {
- struct vmw_buffer_object *backup = res->backup;
-
- ttm_bo_reserve(&backup->base, false, false, NULL);
- if (!res->func->dirty_alloc)
- ret = -EINVAL;
- if (!ret)
- ret = vmw_bo_dirty_add(backup);
- if (!ret) {
- res->coherent = true;
- ret = res->func->dirty_alloc(res);
- }
- ttm_bo_unreserve(&backup->base);
- if (ret) {
- vmw_resource_unreference(&res);
- goto out_unlock;
- }
-
- }
-
tmp = vmw_resource_reference(res);
ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
req->base.drm_surface_flags &
@@ -1812,338 +1760,3 @@ out_bad_resource:
return ret;
}
-
-/**
- * vmw_subres_dirty_add - Add a dirty region to a subresource
- * @dirty: The surfaces's dirty tracker.
- * @loc_start: The location corresponding to the start of the region.
- * @loc_end: The location corresponding to the end of the region.
- *
- * As we are assuming that @loc_start and @loc_end represent a sequential
- * range of backing store memory, if the region spans multiple lines then
- * regardless of the x coordinate, the full lines are dirtied.
- * Correspondingly if the region spans multiple z slices, then full rather
- * than partial z slices are dirtied.
- */
-static void vmw_subres_dirty_add(struct vmw_surface_dirty *dirty,
- const struct svga3dsurface_loc *loc_start,
- const struct svga3dsurface_loc *loc_end)
-{
- const struct svga3dsurface_cache *cache = &dirty->cache;
- SVGA3dBox *box = &dirty->boxes[loc_start->sub_resource];
- u32 mip = loc_start->sub_resource % cache->num_mip_levels;
- const struct drm_vmw_size *size = &cache->mip[mip].size;
- u32 box_c2 = box->z + box->d;
-
- if (WARN_ON(loc_start->sub_resource >= dirty->num_subres))
- return;
-
- if (box->d == 0 || box->z > loc_start->z)
- box->z = loc_start->z;
- if (box_c2 < loc_end->z)
- box->d = loc_end->z - box->z;
-
- if (loc_start->z + 1 == loc_end->z) {
- box_c2 = box->y + box->h;
- if (box->h == 0 || box->y > loc_start->y)
- box->y = loc_start->y;
- if (box_c2 < loc_end->y)
- box->h = loc_end->y - box->y;
-
- if (loc_start->y + 1 == loc_end->y) {
- box_c2 = box->x + box->w;
- if (box->w == 0 || box->x > loc_start->x)
- box->x = loc_start->x;
- if (box_c2 < loc_end->x)
- box->w = loc_end->x - box->x;
- } else {
- box->x = 0;
- box->w = size->width;
- }
- } else {
- box->y = 0;
- box->h = size->height;
- box->x = 0;
- box->w = size->width;
- }
-}
-
-/**
- * vmw_subres_dirty_full - Mark a full subresource as dirty
- * @dirty: The surface's dirty tracker.
- * @subres: The subresource
- */
-static void vmw_subres_dirty_full(struct vmw_surface_dirty *dirty, u32 subres)
-{
- const struct svga3dsurface_cache *cache = &dirty->cache;
- u32 mip = subres % cache->num_mip_levels;
- const struct drm_vmw_size *size = &cache->mip[mip].size;
- SVGA3dBox *box = &dirty->boxes[subres];
-
- box->x = 0;
- box->y = 0;
- box->z = 0;
- box->w = size->width;
- box->h = size->height;
- box->d = size->depth;
-}
-
-/*
- * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for texture
- * surfaces.
- */
-static void vmw_surface_tex_dirty_range_add(struct vmw_resource *res,
- size_t start, size_t end)
-{
- struct vmw_surface_dirty *dirty =
- (struct vmw_surface_dirty *) res->dirty;
- size_t backup_end = res->backup_offset + res->backup_size;
- struct svga3dsurface_loc loc1, loc2;
- const struct svga3dsurface_cache *cache;
-
- start = max_t(size_t, start, res->backup_offset) - res->backup_offset;
- end = min(end, backup_end) - res->backup_offset;
- cache = &dirty->cache;
- svga3dsurface_get_loc(cache, &loc1, start);
- svga3dsurface_get_loc(cache, &loc2, end - 1);
- svga3dsurface_inc_loc(cache, &loc2);
-
- if (loc1.sub_resource + 1 == loc2.sub_resource) {
- /* Dirty range covers a single sub-resource */
- vmw_subres_dirty_add(dirty, &loc1, &loc2);
- } else {
- /* Dirty range covers multiple sub-resources */
- struct svga3dsurface_loc loc_min, loc_max;
- u32 sub_res = loc1.sub_resource;
-
- svga3dsurface_max_loc(cache, loc1.sub_resource, &loc_max);
- vmw_subres_dirty_add(dirty, &loc1, &loc_max);
- svga3dsurface_min_loc(cache, loc2.sub_resource - 1, &loc_min);
- vmw_subres_dirty_add(dirty, &loc_min, &loc2);
- for (sub_res = loc1.sub_resource + 1;
- sub_res < loc2.sub_resource - 1; ++sub_res)
- vmw_subres_dirty_full(dirty, sub_res);
- }
-}
-
-/*
- * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for buffer
- * surfaces.
- */
-static void vmw_surface_buf_dirty_range_add(struct vmw_resource *res,
- size_t start, size_t end)
-{
- struct vmw_surface_dirty *dirty =
- (struct vmw_surface_dirty *) res->dirty;
- const struct svga3dsurface_cache *cache = &dirty->cache;
- size_t backup_end = res->backup_offset + cache->mip_chain_bytes;
- SVGA3dBox *box = &dirty->boxes[0];
- u32 box_c2;
-
- box->h = box->d = 1;
- start = max_t(size_t, start, res->backup_offset) - res->backup_offset;
- end = min(end, backup_end) - res->backup_offset;
- box_c2 = box->x + box->w;
- if (box->w == 0 || box->x > start)
- box->x = start;
- if (box_c2 < end)
- box->w = end - box->x;
-}
-
-/*
- * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for surfaces
- */
-static void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start,
- size_t end)
-{
- struct vmw_surface *srf = vmw_res_to_srf(res);
-
- if (WARN_ON(end <= res->backup_offset ||
- start >= res->backup_offset + res->backup_size))
- return;
-
- if (srf->format == SVGA3D_BUFFER)
- vmw_surface_buf_dirty_range_add(res, start, end);
- else
- vmw_surface_tex_dirty_range_add(res, start, end);
-}
-
-/*
- * vmw_surface_dirty_sync - The surface's dirty_sync callback.
- */
-static int vmw_surface_dirty_sync(struct vmw_resource *res)
-{
- struct vmw_private *dev_priv = res->dev_priv;
- bool has_dx = 0;
- u32 i, num_dirty;
- struct vmw_surface_dirty *dirty =
- (struct vmw_surface_dirty *) res->dirty;
- size_t alloc_size;
- const struct svga3dsurface_cache *cache = &dirty->cache;
- struct {
- SVGA3dCmdHeader header;
- SVGA3dCmdDXUpdateSubResource body;
- } *cmd1;
- struct {
- SVGA3dCmdHeader header;
- SVGA3dCmdUpdateGBImage body;
- } *cmd2;
- void *cmd;
-
- num_dirty = 0;
- for (i = 0; i < dirty->num_subres; ++i) {
- const SVGA3dBox *box = &dirty->boxes[i];
-
- if (box->d)
- num_dirty++;
- }
-
- if (!num_dirty)
- goto out;
-
- alloc_size = num_dirty * ((has_dx) ? sizeof(*cmd1) : sizeof(*cmd2));
- cmd = VMW_FIFO_RESERVE(dev_priv, alloc_size);
- if (!cmd)
- return -ENOMEM;
-
- cmd1 = cmd;
- cmd2 = cmd;
-
- for (i = 0; i < dirty->num_subres; ++i) {
- const SVGA3dBox *box = &dirty->boxes[i];
-
- if (!box->d)
- continue;
-
- /*
- * DX_UPDATE_SUBRESOURCE is aware of array surfaces.
- * UPDATE_GB_IMAGE is not.
- */
- if (has_dx) {
- cmd1->header.id = SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE;
- cmd1->header.size = sizeof(cmd1->body);
- cmd1->body.sid = res->id;
- cmd1->body.subResource = i;
- cmd1->body.box = *box;
- cmd1++;
- } else {
- cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
- cmd2->header.size = sizeof(cmd2->body);
- cmd2->body.image.sid = res->id;
- cmd2->body.image.face = i / cache->num_mip_levels;
- cmd2->body.image.mipmap = i -
- (cache->num_mip_levels * cmd2->body.image.face);
- cmd2->body.box = *box;
- cmd2++;
- }
-
- }
- vmw_fifo_commit(dev_priv, alloc_size);
- out:
- memset(&dirty->boxes[0], 0, sizeof(dirty->boxes[0]) *
- dirty->num_subres);
-
- return 0;
-}
-
-/*
- * vmw_surface_dirty_alloc - The surface's dirty_alloc callback.
- */
-static int vmw_surface_dirty_alloc(struct vmw_resource *res)
-{
- struct vmw_surface *srf = vmw_res_to_srf(res);
- struct vmw_surface_dirty *dirty;
- u32 num_layers = 1;
- u32 num_mip;
- u32 num_subres;
- u32 num_samples;
- size_t dirty_size, acc_size;
- static struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false
- };
- int ret;
-
- if (srf->array_size)
- num_layers = srf->array_size;
- else if (srf->flags & SVGA3D_SURFACE_CUBEMAP)
- num_layers *= SVGA3D_MAX_SURFACE_FACES;
-
- num_mip = srf->mip_levels[0];
- if (!num_mip)
- num_mip = 1;
-
- num_subres = num_layers * num_mip;
- dirty_size = sizeof(*dirty) + num_subres * sizeof(dirty->boxes[0]);
- acc_size = ttm_round_pot(dirty_size);
- ret = ttm_mem_global_alloc(vmw_mem_glob(res->dev_priv),
- acc_size, &ctx);
- if (ret) {
- VMW_DEBUG_USER("Out of graphics memory for surface "
- "dirty tracker.\n");
- return ret;
- }
-
- dirty = kvzalloc(dirty_size, GFP_KERNEL);
- if (!dirty) {
- ret = -ENOMEM;
- goto out_no_dirty;
- }
-
- num_samples = max_t(u32, 1, srf->multisample_count);
- ret = svga3dsurface_setup_cache(&srf->base_size, srf->format, num_mip,
- num_layers, num_samples, &dirty->cache);
- if (ret)
- goto out_no_cache;
-
- dirty->num_subres = num_subres;
- dirty->size = acc_size;
- res->dirty = (struct vmw_resource_dirty *) dirty;
-
- return 0;
-
-out_no_cache:
- kvfree(dirty);
-out_no_dirty:
- ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size);
- return ret;
-}
-
-/*
- * vmw_surface_dirty_free - The surface's dirty_free callback
- */
-static void vmw_surface_dirty_free(struct vmw_resource *res)
-{
- struct vmw_surface_dirty *dirty =
- (struct vmw_surface_dirty *) res->dirty;
- size_t acc_size = dirty->size;
-
- kvfree(dirty);
- ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size);
- res->dirty = NULL;
-}
-
-/*
- * vmw_surface_clean - The surface's clean callback
- */
-static int vmw_surface_clean(struct vmw_resource *res)
-{
- struct vmw_private *dev_priv = res->dev_priv;
- size_t alloc_size;
- struct {
- SVGA3dCmdHeader header;
- SVGA3dCmdReadbackGBSurface body;
- } *cmd;
-
- alloc_size = sizeof(*cmd);
- cmd = VMW_FIFO_RESERVE(dev_priv, alloc_size);
- if (!cmd)
- return -ENOMEM;
-
- cmd->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE;
- cmd->header.size = sizeof(cmd->body);
- cmd->body.sid = res->id;
- vmw_fifo_commit(dev_priv, alloc_size);
-
- return 0;
-}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
index 9aaf807ed73c..f611b2290a1b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
@@ -33,8 +33,6 @@
* struct vmw_validation_bo_node - Buffer object validation metadata.
* @base: Metadata used for TTM reservation- and validation.
* @hash: A hash entry used for the duplicate detection hash table.
- * @coherent_count: If switching backup buffers, number of new coherent
- * resources that will have this buffer as a backup buffer.
* @as_mob: Validate as mob.
* @cpu_blit: Validate for cpu blit access.
*
@@ -44,7 +42,6 @@
struct vmw_validation_bo_node {
struct ttm_validate_buffer base;
struct drm_hash_item hash;
- unsigned int coherent_count;
u32 as_mob : 1;
u32 cpu_blit : 1;
};
@@ -462,19 +459,6 @@ int vmw_validation_res_reserve(struct vmw_validation_context *ctx,
if (ret)
goto out_unreserve;
}
-
- if (val->switching_backup && val->new_backup &&
- res->coherent) {
- struct vmw_validation_bo_node *bo_node =
- vmw_validation_find_bo_dup(ctx,
- val->new_backup);
-
- if (WARN_ON(!bo_node)) {
- ret = -EINVAL;
- goto out_unreserve;
- }
- bo_node->coherent_count++;
- }
}
return 0;
@@ -578,9 +562,6 @@ int vmw_validation_bo_validate(struct vmw_validation_context *ctx, bool intr)
int ret;
list_for_each_entry(entry, &ctx->bo_list, base.head) {
- struct vmw_buffer_object *vbo =
- container_of(entry->base.bo, typeof(*vbo), base);
-
if (entry->cpu_blit) {
struct ttm_operation_ctx ctx = {
.interruptible = intr,
@@ -595,27 +576,6 @@ int vmw_validation_bo_validate(struct vmw_validation_context *ctx, bool intr)
}
if (ret)
return ret;
-
- /*
- * Rather than having the resource code allocating the bo
- * dirty tracker in resource_unreserve() where we can't fail,
- * Do it here when validating the buffer object.
- */
- if (entry->coherent_count) {
- unsigned int coherent_count = entry->coherent_count;
-
- while (coherent_count) {
- ret = vmw_bo_dirty_add(vbo);
- if (ret)
- return ret;
-
- coherent_count--;
- }
- entry->coherent_count -= coherent_count;
- }
-
- if (vbo->dirty)
- vmw_bo_dirty_scan(vbo);
}
return 0;
}
@@ -641,8 +601,7 @@ int vmw_validation_res_validate(struct vmw_validation_context *ctx, bool intr)
struct vmw_resource *res = val->res;
struct vmw_buffer_object *backup = res->backup;
- ret = vmw_resource_validate(res, intr, val->dirty_set &&
- val->dirty);
+ ret = vmw_resource_validate(res, intr);
if (ret) {
if (ret != -ERESTARTSYS)
DRM_ERROR("Failed to validate resource.\n");
@@ -869,34 +828,3 @@ int vmw_validation_preload_res(struct vmw_validation_context *ctx,
ctx->mem_size_left += size;
return 0;
}
-
-/**
- * vmw_validation_bo_backoff - Unreserve buffer objects registered with a
- * validation context
- * @ctx: The validation context
- *
- * This function unreserves the buffer objects previously reserved using
- * vmw_validation_bo_reserve. It's typically used as part of an error path
- */
-void vmw_validation_bo_backoff(struct vmw_validation_context *ctx)
-{
- struct vmw_validation_bo_node *entry;
-
- /*
- * Switching coherent resource backup buffers failed.
- * Release corresponding buffer object dirty trackers.
- */
- list_for_each_entry(entry, &ctx->bo_list, base.head) {
- if (entry->coherent_count) {
- unsigned int coherent_count = entry->coherent_count;
- struct vmw_buffer_object *vbo =
- container_of(entry->base.bo, typeof(*vbo),
- base);
-
- while (coherent_count--)
- vmw_bo_dirty_release(vbo);
- }
- }
-
- ttm_eu_backoff_reservation(&ctx->ticket, &ctx->bo_list);
-}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
index fd83e017c2a5..1d2322ad6fd5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
@@ -173,6 +173,20 @@ vmw_validation_bo_reserve(struct vmw_validation_context *ctx,
}
/**
+ * vmw_validation_bo_backoff - Unreserve buffer objects registered with a
+ * validation context
+ * @ctx: The validation context
+ *
+ * This function unreserves the buffer objects previously reserved using
+ * vmw_validation_bo_reserve. It's typically used as part of an error path
+ */
+static inline void
+vmw_validation_bo_backoff(struct vmw_validation_context *ctx)
+{
+ ttm_eu_backoff_reservation(&ctx->ticket, &ctx->bo_list);
+}
+
+/**
* vmw_validation_bo_fence - Unreserve and fence buffer objects registered
* with a validation context
* @ctx: The validation context
@@ -254,6 +268,4 @@ int vmw_validation_preload_res(struct vmw_validation_context *ctx,
unsigned int size);
void vmw_validation_res_set_dirty(struct vmw_validation_context *ctx,
void *val_private, u32 dirty);
-void vmw_validation_bo_backoff(struct vmw_validation_context *ctx);
-
#endif