diff options
145 files changed, 2619 insertions, 3483 deletions
diff --git a/Documentation/devicetree/bindings/display/msm/dpu.txt b/Documentation/devicetree/bindings/display/msm/dpu.txt index ad2e8830324e..a61dd40f3792 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu.txt +++ b/Documentation/devicetree/bindings/display/msm/dpu.txt @@ -28,6 +28,11 @@ Required properties: - #address-cells: number of address cells for the MDSS children. Should be 1. - #size-cells: Should be 1. - ranges: parent bus address space is the same as the child bus address space. +- interconnects : interconnect path specifier for MDSS according to + Documentation/devicetree/bindings/interconnect/interconnect.txt. Should be + 2 paths corresponding to 2 AXI ports. +- interconnect-names : MDSS will have 2 port names to differentiate between the + 2 interconnect paths defined with interconnect specifier. Optional properties: - assigned-clocks: list of clock specifiers for clocks needing rate assignment @@ -86,6 +91,11 @@ Example: interrupt-controller; #interrupt-cells = <1>; + interconnects = <&rsc_hlos MASTER_MDP0 &rsc_hlos SLAVE_EBI1>, + <&rsc_hlos MASTER_MDP1 &rsc_hlos SLAVE_EBI1>; + + interconnect-names = "mdp0-mem", "mdp1-mem"; + iommus = <&apps_iommu 0>; #address-cells = <2>; diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index 9ae946942720..af95586c898f 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -88,6 +88,7 @@ Required properties: * "qcom,dsi-phy-28nm-8960" * "qcom,dsi-phy-14nm" * "qcom,dsi-phy-10nm" + * "qcom,dsi-phy-10nm-8998" - reg: Physical base address and length of the registers of PLL, PHY. Some revisions require the PHY regulator base address, whereas others require the PHY lane base address. See below for each PHY revision. diff --git a/MAINTAINERS b/MAINTAINERS index d6600715a662..692882987769 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1203,7 +1203,7 @@ M: James (Qian) Wang <james.qian.wang@arm.com> M: Liviu Dudau <liviu.dudau@arm.com> L: Mali DP Maintainers <malidp@foss.arm.com> S: Supported -T: git git://linux-arm.org/linux-ld.git for-upstream/mali-dp +T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/arm/display/include/ F: drivers/gpu/drm/arm/display/komeda/ F: Documentation/devicetree/bindings/display/arm,komeda.txt @@ -1214,7 +1214,7 @@ M: Liviu Dudau <liviu.dudau@arm.com> M: Brian Starkey <brian.starkey@arm.com> L: Mali DP Maintainers <malidp@foss.arm.com> S: Supported -T: git git://linux-arm.org/linux-ld.git for-upstream/mali-dp +T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/arm/ F: Documentation/devicetree/bindings/display/arm,malidp.txt F: Documentation/gpu/afbc.rst @@ -5191,7 +5191,6 @@ T: git git://people.freedesktop.org/~thomash/linux S: Supported F: drivers/gpu/drm/vmwgfx/ F: include/uapi/drm/vmwgfx_drm.h -F: mm/as_dirty_helpers.c DRM DRIVERS M: David Airlie <airlied@linux.ie> 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", ®, &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 diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile index 7cc8b47e488b..5fe5ef20701a 100644 --- a/drivers/gpu/ipu-v3/Makefile +++ b/drivers/gpu/ipu-v3/Makefile @@ -2,8 +2,8 @@ obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \ - ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-image-convert.o \ - ipu-smfc.o ipu-vdi.o + ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \ + ipu-image-convert.o ipu-smfc.o ipu-vdi.o ifdef CONFIG_DRM imx-ipu-v3-objs += ipu-pre.o ipu-prg.o diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c new file mode 100644 index 000000000000..d1ca7ba94a12 --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Mentor Graphics Inc. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/sizes.h> +#include "ipu-prv.h" + +#define QUANT_MAP(q) \ + ((q) == V4L2_QUANTIZATION_FULL_RANGE || \ + (q) == V4L2_QUANTIZATION_DEFAULT ? 0 : 1) + +/* identity matrix */ +static const struct ipu_ic_csc_params identity = { + .coeff = { + { 128, 0, 0, }, + { 0, 128, 0, }, + { 0, 0, 128, }, + }, + .offset = { 0, 0, 0, }, + .scale = 2, +}; + +/* + * RGB full-range to RGB limited-range + * + * R_lim = 0.8588 * R_full + 16 + * G_lim = 0.8588 * G_full + 16 + * B_lim = 0.8588 * B_full + 16 + */ +static const struct ipu_ic_csc_params rgbf2rgbl = { + .coeff = { + { 220, 0, 0, }, + { 0, 220, 0, }, + { 0, 0, 220, }, + }, + .offset = { 64, 64, 64, }, + .scale = 1, +}; + +/* + * RGB limited-range to RGB full-range + * + * R_full = 1.1644 * (R_lim - 16) + * G_full = 1.1644 * (G_lim - 16) + * B_full = 1.1644 * (B_lim - 16) + */ +static const struct ipu_ic_csc_params rgbl2rgbf = { + .coeff = { + { 149, 0, 0, }, + { 0, 149, 0, }, + { 0, 0, 149, }, + }, + .offset = { -37, -37, -37, }, + .scale = 2, +}; + +/* + * YUV full-range to YUV limited-range + * + * Y_lim = 0.8588 * Y_full + 16 + * Cb_lim = 0.8784 * (Cb_full - 128) + 128 + * Cr_lim = 0.8784 * (Cr_full - 128) + 128 + */ +static const struct ipu_ic_csc_params yuvf2yuvl = { + .coeff = { + { 220, 0, 0, }, + { 0, 225, 0, }, + { 0, 0, 225, }, + }, + .offset = { 64, 62, 62, }, + .scale = 1, + .sat = true, +}; + +/* + * YUV limited-range to YUV full-range + * + * Y_full = 1.1644 * (Y_lim - 16) + * Cb_full = 1.1384 * (Cb_lim - 128) + 128 + * Cr_full = 1.1384 * (Cr_lim - 128) + 128 + */ +static const struct ipu_ic_csc_params yuvl2yuvf = { + .coeff = { + { 149, 0, 0, }, + { 0, 146, 0, }, + { 0, 0, 146, }, + }, + .offset = { -37, -35, -35, }, + .scale = 2, +}; + +static const struct ipu_ic_csc_params *rgb2rgb[] = { + &identity, + &rgbf2rgbl, + &rgbl2rgbf, + &identity, +}; + +static const struct ipu_ic_csc_params *yuv2yuv[] = { + &identity, + &yuvf2yuvl, + &yuvl2yuvf, + &identity, +}; + +/* + * BT.601 RGB full-range to YUV full-range + * + * Y = .2990 * R + .5870 * G + .1140 * B + * U = -.1687 * R - .3313 * G + .5000 * B + 128 + * V = .5000 * R - .4187 * G - .0813 * B + 128 + */ +static const struct ipu_ic_csc_params rgbf2yuvf_601 = { + .coeff = { + { 77, 150, 29, }, + { -43, -85, 128, }, + { 128, -107, -21, }, + }, + .offset = { 0, 512, 512, }, + .scale = 1, +}; + +/* BT.601 RGB full-range to YUV limited-range */ +static const struct ipu_ic_csc_params rgbf2yuvl_601 = { + .coeff = { + { 66, 129, 25, }, + { -38, -74, 112, }, + { 112, -94, -18, }, + }, + .offset = { 64, 512, 512, }, + .scale = 1, + .sat = true, +}; + +/* BT.601 RGB limited-range to YUV full-range */ +static const struct ipu_ic_csc_params rgbl2yuvf_601 = { + .coeff = { + { 89, 175, 34, }, + { -50, -99, 149, }, + { 149, -125, -24, }, + }, + .offset = { -75, 512, 512, }, + .scale = 1, +}; + +/* BT.601 RGB limited-range to YUV limited-range */ +static const struct ipu_ic_csc_params rgbl2yuvl_601 = { + .coeff = { + { 77, 150, 29, }, + { -44, -87, 131, }, + { 131, -110, -21, }, + }, + .offset = { 0, 512, 512, }, + .scale = 1, + .sat = true, +}; + +/* + * BT.601 YUV full-range to RGB full-range + * + * R = 1. * Y + 0 * (Cb - 128) + 1.4020 * (Cr - 128) + * G = 1. * Y - .3441 * (Cb - 128) - .7141 * (Cr - 128) + * B = 1. * Y + 1.7720 * (Cb - 128) + 0 * (Cr - 128) + * + * equivalently (factoring out the offsets): + * + * R = 1. * Y + 0 * Cb + 1.4020 * Cr - 179.456 + * G = 1. * Y - .3441 * Cb - .7141 * Cr + 135.450 + * B = 1. * Y + 1.7720 * Cb + 0 * Cr - 226.816 + */ +static const struct ipu_ic_csc_params yuvf2rgbf_601 = { + .coeff = { + { 128, 0, 179, }, + { 128, -44, -91, }, + { 128, 227, 0, }, + }, + .offset = { -359, 271, -454, }, + .scale = 2, +}; + +/* BT.601 YUV full-range to RGB limited-range */ +static const struct ipu_ic_csc_params yuvf2rgbl_601 = { + .coeff = { + { 110, 0, 154, }, + { 110, -38, -78, }, + { 110, 195, 0, }, + }, + .offset = { -276, 265, -358, }, + .scale = 2, +}; + +/* BT.601 YUV limited-range to RGB full-range */ +static const struct ipu_ic_csc_params yuvl2rgbf_601 = { + .coeff = { + { 75, 0, 102, }, + { 75, -25, -52, }, + { 75, 129, 0, }, + }, + .offset = { -223, 136, -277, }, + .scale = 3, +}; + +/* BT.601 YUV limited-range to RGB limited-range */ +static const struct ipu_ic_csc_params yuvl2rgbl_601 = { + .coeff = { + { 128, 0, 175, }, + { 128, -43, -89, }, + { 128, 222, 0, }, + }, + .offset = { -351, 265, -443, }, + .scale = 2, +}; + +static const struct ipu_ic_csc_params *rgb2yuv_601[] = { + &rgbf2yuvf_601, + &rgbf2yuvl_601, + &rgbl2yuvf_601, + &rgbl2yuvl_601, +}; + +static const struct ipu_ic_csc_params *yuv2rgb_601[] = { + &yuvf2rgbf_601, + &yuvf2rgbl_601, + &yuvl2rgbf_601, + &yuvl2rgbl_601, +}; + +/* + * REC.709 encoding from RGB full range to YUV full range: + * + * Y = .2126 * R + .7152 * G + .0722 * B + * U = -.1146 * R - .3854 * G + .5000 * B + 128 + * V = .5000 * R - .4542 * G - .0458 * B + 128 + */ +static const struct ipu_ic_csc_params rgbf2yuvf_709 = { + .coeff = { + { 54, 183, 19 }, + { -29, -99, 128 }, + { 128, -116, -12 }, + }, + .offset = { 0, 512, 512 }, + .scale = 1, +}; + +/* Rec.709 RGB full-range to YUV limited-range */ +static const struct ipu_ic_csc_params rgbf2yuvl_709 = { + .coeff = { + { 47, 157, 16, }, + { -26, -87, 112, }, + { 112, -102, -10, }, + }, + .offset = { 64, 512, 512, }, + .scale = 1, + .sat = true, +}; + +/* Rec.709 RGB limited-range to YUV full-range */ +static const struct ipu_ic_csc_params rgbl2yuvf_709 = { + .coeff = { + { 63, 213, 22, }, + { -34, -115, 149, }, + { 149, -135, -14, }, + }, + .offset = { -75, 512, 512, }, + .scale = 1, +}; + +/* Rec.709 RGB limited-range to YUV limited-range */ +static const struct ipu_ic_csc_params rgbl2yuvl_709 = { + .coeff = { + { 54, 183, 18, }, + { -30, -101, 131, }, + { 131, -119, -12, }, + }, + .offset = { 0, 512, 512, }, + .scale = 1, + .sat = true, +}; + +/* + * Inverse REC.709 encoding from YUV full range to RGB full range: + * + * R = 1. * Y + 0 * (Cb - 128) + 1.5748 * (Cr - 128) + * G = 1. * Y - .1873 * (Cb - 128) - .4681 * (Cr - 128) + * B = 1. * Y + 1.8556 * (Cb - 128) + 0 * (Cr - 128) + * + * equivalently (factoring out the offsets): + * + * R = 1. * Y + 0 * Cb + 1.5748 * Cr - 201.574 + * G = 1. * Y - .1873 * Cb - .4681 * Cr + 83.891 + * B = 1. * Y + 1.8556 * Cb + 0 * Cr - 237.517 + */ +static const struct ipu_ic_csc_params yuvf2rgbf_709 = { + .coeff = { + { 128, 0, 202 }, + { 128, -24, -60 }, + { 128, 238, 0 }, + }, + .offset = { -403, 168, -475 }, + .scale = 2, +}; + +/* Rec.709 YUV full-range to RGB limited-range */ +static const struct ipu_ic_csc_params yuvf2rgbl_709 = { + .coeff = { + { 110, 0, 173, }, + { 110, -21, -51, }, + { 110, 204, 0, }, + }, + .offset = { -314, 176, -376, }, + .scale = 2, +}; + +/* Rec.709 YUV limited-range to RGB full-range */ +static const struct ipu_ic_csc_params yuvl2rgbf_709 = { + .coeff = { + { 75, 0, 115, }, + { 75, -14, -34, }, + { 75, 135, 0, }, + }, + .offset = { -248, 77, -289, }, + .scale = 3, +}; + +/* Rec.709 YUV limited-range to RGB limited-range */ +static const struct ipu_ic_csc_params yuvl2rgbl_709 = { + .coeff = { + { 128, 0, 197, }, + { 128, -23, -59, }, + { 128, 232, 0, }, + }, + .offset = { -394, 164, -464, }, + .scale = 2, +}; + +static const struct ipu_ic_csc_params *rgb2yuv_709[] = { + &rgbf2yuvf_709, + &rgbf2yuvl_709, + &rgbl2yuvf_709, + &rgbl2yuvl_709, +}; + +static const struct ipu_ic_csc_params *yuv2rgb_709[] = { + &yuvf2rgbf_709, + &yuvf2rgbl_709, + &yuvl2rgbf_709, + &yuvl2rgbl_709, +}; + +static int calc_csc_coeffs(struct ipu_ic_csc *csc) +{ + const struct ipu_ic_csc_params **params_tbl; + int tbl_idx; + + tbl_idx = (QUANT_MAP(csc->in_cs.quant) << 1) | + QUANT_MAP(csc->out_cs.quant); + + if (csc->in_cs.cs == csc->out_cs.cs) { + csc->params = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ? + *yuv2yuv[tbl_idx] : *rgb2rgb[tbl_idx]; + + return 0; + } + + /* YUV <-> RGB encoding is required */ + + switch (csc->out_cs.enc) { + case V4L2_YCBCR_ENC_601: + params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ? + yuv2rgb_601 : rgb2yuv_601; + break; + case V4L2_YCBCR_ENC_709: + params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ? + yuv2rgb_709 : rgb2yuv_709; + break; + default: + return -ENOTSUPP; + } + + csc->params = *params_tbl[tbl_idx]; + + return 0; +} + +int __ipu_ic_calc_csc(struct ipu_ic_csc *csc) +{ + return calc_csc_coeffs(csc); +} +EXPORT_SYMBOL_GPL(__ipu_ic_calc_csc); + +int ipu_ic_calc_csc(struct ipu_ic_csc *csc, + enum v4l2_ycbcr_encoding in_enc, + enum v4l2_quantization in_quant, + enum ipu_color_space in_cs, + enum v4l2_ycbcr_encoding out_enc, + enum v4l2_quantization out_quant, + enum ipu_color_space out_cs) +{ + ipu_ic_fill_colorspace(&csc->in_cs, in_enc, in_quant, in_cs); + ipu_ic_fill_colorspace(&csc->out_cs, out_enc, out_quant, out_cs); + + return __ipu_ic_calc_csc(csc); +} +EXPORT_SYMBOL_GPL(ipu_ic_calc_csc); diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c index 89c3961f0fce..846461bac70d 100644 --- a/drivers/gpu/ipu-v3/ipu-ic.c +++ b/drivers/gpu/ipu-v3/ipu-ic.c @@ -140,8 +140,10 @@ struct ipu_ic { const struct ic_task_regoffs *reg; const struct ic_task_bitfields *bit; - enum ipu_color_space in_cs, g_in_cs; - enum ipu_color_space out_cs; + struct ipu_ic_colorspace in_cs; + struct ipu_ic_colorspace g_in_cs; + struct ipu_ic_colorspace out_cs; + bool graphics; bool rotation; bool in_use; @@ -169,60 +171,11 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset) writel(value, ic->priv->base + offset); } -struct ic_csc_params { - s16 coeff[3][3]; /* signed 9-bit integer coefficients */ - s16 offset[3]; /* signed 11+2-bit fixed point offset */ - u8 scale:2; /* scale coefficients * 2^(scale-1) */ - bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */ -}; - -/* - * Y = R * .299 + G * .587 + B * .114; - * U = R * -.169 + G * -.332 + B * .500 + 128.; - * V = R * .500 + G * -.419 + B * -.0813 + 128.; - */ -static const struct ic_csc_params ic_csc_rgb2ycbcr = { - .coeff = { - { 77, 150, 29 }, - { 469, 427, 128 }, - { 128, 405, 491 }, - }, - .offset = { 0, 512, 512 }, - .scale = 1, -}; - -/* transparent RGB->RGB matrix for graphics combining */ -static const struct ic_csc_params ic_csc_rgb2rgb = { - .coeff = { - { 128, 0, 0 }, - { 0, 128, 0 }, - { 0, 0, 128 }, - }, - .scale = 2, -}; - -/* - * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); - * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); - * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); - */ -static const struct ic_csc_params ic_csc_ycbcr2rgb = { - .coeff = { - { 149, 0, 204 }, - { 149, 462, 408 }, - { 149, 255, 0 }, - }, - .offset = { -446, 266, -554 }, - .scale = 2, -}; - static int init_csc(struct ipu_ic *ic, - enum ipu_color_space inf, - enum ipu_color_space outf, + const struct ipu_ic_csc *csc, int csc_index) { struct ipu_ic_priv *priv = ic->priv; - const struct ic_csc_params *params; u32 __iomem *base; const u16 (*c)[3]; const u16 *a; @@ -231,27 +184,16 @@ static int init_csc(struct ipu_ic *ic, base = (u32 __iomem *) (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]); - if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB) - params = &ic_csc_ycbcr2rgb; - else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV) - params = &ic_csc_rgb2ycbcr; - else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB) - params = &ic_csc_rgb2rgb; - else { - dev_err(priv->ipu->dev, "Unsupported color space conversion\n"); - return -EINVAL; - } - /* Cast to unsigned */ - c = (const u16 (*)[3])params->coeff; - a = (const u16 *)params->offset; + c = (const u16 (*)[3])csc->params.coeff; + a = (const u16 *)csc->params.offset; param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) | ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff); writel(param, base++); - param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) | - (params->sat << 9); + param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) | + (csc->params.sat << 10); writel(param, base++); param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) | @@ -338,14 +280,14 @@ void ipu_ic_task_enable(struct ipu_ic *ic) if (ic->rotation) ic_conf |= ic->bit->ic_conf_rot_en; - if (ic->in_cs != ic->out_cs) + if (ic->in_cs.cs != ic->out_cs.cs) ic_conf |= ic->bit->ic_conf_csc1_en; if (ic->graphics) { ic_conf |= ic->bit->ic_conf_cmb_en; ic_conf |= ic->bit->ic_conf_csc1_en; - if (ic->g_in_cs != ic->out_cs) + if (ic->g_in_cs.cs != ic->out_cs.cs) ic_conf |= ic->bit->ic_conf_csc2_en; } @@ -380,11 +322,12 @@ void ipu_ic_task_disable(struct ipu_ic *ic) EXPORT_SYMBOL_GPL(ipu_ic_task_disable); int ipu_ic_task_graphics_init(struct ipu_ic *ic, - enum ipu_color_space in_g_cs, + const struct ipu_ic_colorspace *g_in_cs, bool galpha_en, u32 galpha, bool colorkey_en, u32 colorkey) { struct ipu_ic_priv *priv = ic->priv; + struct ipu_ic_csc csc2; unsigned long flags; u32 reg, ic_conf; int ret = 0; @@ -397,21 +340,36 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic, ic_conf = ipu_ic_read(ic, IC_CONF); if (!(ic_conf & ic->bit->ic_conf_csc1_en)) { - /* need transparent CSC1 conversion */ - ret = init_csc(ic, IPUV3_COLORSPACE_RGB, - IPUV3_COLORSPACE_RGB, 0); + struct ipu_ic_csc csc1; + + ret = ipu_ic_calc_csc(&csc1, + V4L2_YCBCR_ENC_601, + V4L2_QUANTIZATION_FULL_RANGE, + IPUV3_COLORSPACE_RGB, + V4L2_YCBCR_ENC_601, + V4L2_QUANTIZATION_FULL_RANGE, + IPUV3_COLORSPACE_RGB); if (ret) goto unlock; - } - - ic->g_in_cs = in_g_cs; - if (ic->g_in_cs != ic->out_cs) { - ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1); + /* need transparent CSC1 conversion */ + ret = init_csc(ic, &csc1, 0); if (ret) goto unlock; } + ic->g_in_cs = *g_in_cs; + csc2.in_cs = ic->g_in_cs; + csc2.out_cs = ic->out_cs; + + ret = __ipu_ic_calc_csc(&csc2); + if (ret) + goto unlock; + + ret = init_csc(ic, &csc2, 1); + if (ret) + goto unlock; + if (galpha_en) { ic_conf |= IC_CONF_IC_GLB_LOC_A; reg = ipu_ic_read(ic, IC_CMBP_1); @@ -437,10 +395,9 @@ unlock: EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init); int ipu_ic_task_init_rsc(struct ipu_ic *ic, + const struct ipu_ic_csc *csc, int in_width, int in_height, int out_width, int out_height, - enum ipu_color_space in_cs, - enum ipu_color_space out_cs, u32 rsc) { struct ipu_ic_priv *priv = ic->priv; @@ -472,28 +429,23 @@ int ipu_ic_task_init_rsc(struct ipu_ic *ic, ipu_ic_write(ic, rsc, ic->reg->rsc); /* Setup color space conversion */ - ic->in_cs = in_cs; - ic->out_cs = out_cs; + ic->in_cs = csc->in_cs; + ic->out_cs = csc->out_cs; - if (ic->in_cs != ic->out_cs) { - ret = init_csc(ic, ic->in_cs, ic->out_cs, 0); - if (ret) - goto unlock; - } + ret = init_csc(ic, csc, 0); -unlock: spin_unlock_irqrestore(&priv->lock, flags); return ret; } int ipu_ic_task_init(struct ipu_ic *ic, + const struct ipu_ic_csc *csc, int in_width, int in_height, - int out_width, int out_height, - enum ipu_color_space in_cs, - enum ipu_color_space out_cs) + int out_width, int out_height) { - return ipu_ic_task_init_rsc(ic, in_width, in_height, out_width, - out_height, in_cs, out_cs, 0); + return ipu_ic_task_init_rsc(ic, csc, + in_width, in_height, + out_width, out_height, 0); } EXPORT_SYMBOL_GPL(ipu_ic_task_init); diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c index 36e88434513a..61643382bbde 100644 --- a/drivers/gpu/ipu-v3/ipu-image-convert.c +++ b/drivers/gpu/ipu-v3/ipu-image-convert.c @@ -146,6 +146,7 @@ struct ipu_image_convert_ctx { /* Source/destination image data and rotation mode */ struct ipu_image_convert_image in; struct ipu_image_convert_image out; + struct ipu_ic_csc csc; enum ipu_rotate_mode rot_mode; u32 downsize_coeff_h; u32 downsize_coeff_v; @@ -1279,6 +1280,15 @@ static void init_idmac_channel(struct ipu_image_convert_ctx *ctx, if (rot_mode) ipu_cpmem_set_rotation(channel, rot_mode); + /* + * Skip writing U and V components to odd rows in the output + * channels for planar 4:2:0. + */ + if ((channel == chan->out_chan || + channel == chan->rotation_out_chan) && + image->fmt->planar && image->fmt->uv_height_dec == 2) + ipu_cpmem_skip_odd_chroma_rows(channel); + if (channel == chan->rotation_in_chan || channel == chan->rotation_out_chan) { burst_size = 8; @@ -1308,7 +1318,6 @@ static int convert_start(struct ipu_image_convert_run *run, unsigned int tile) struct ipu_image_convert_priv *priv = chan->priv; struct ipu_image_convert_image *s_image = &ctx->in; struct ipu_image_convert_image *d_image = &ctx->out; - enum ipu_color_space src_cs, dest_cs; unsigned int dst_tile = ctx->out_tile_map[tile]; unsigned int dest_width, dest_height; unsigned int col, row; @@ -1318,9 +1327,6 @@ static int convert_start(struct ipu_image_convert_run *run, unsigned int tile) dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n", __func__, chan->ic_task, ctx, run, tile, dst_tile); - src_cs = ipu_pixelformat_to_colorspace(s_image->fmt->fourcc); - dest_cs = ipu_pixelformat_to_colorspace(d_image->fmt->fourcc); - if (ipu_rot_mode_is_irt(ctx->rot_mode)) { /* swap width/height for resizer */ dest_width = d_image->tile[dst_tile].height; @@ -1343,13 +1349,12 @@ static int convert_start(struct ipu_image_convert_run *run, unsigned int tile) s_image->tile[tile].height, dest_width, dest_height, rsc); /* setup the IC resizer and CSC */ - ret = ipu_ic_task_init_rsc(chan->ic, - s_image->tile[tile].width, - s_image->tile[tile].height, - dest_width, - dest_height, - src_cs, dest_cs, - rsc); + ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc, + s_image->tile[tile].width, + s_image->tile[tile].height, + dest_width, + dest_height, + rsc); if (ret) { dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret); return ret; @@ -2049,6 +2054,16 @@ ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task, calc_tile_resize_coefficients(ctx); + ret = ipu_ic_calc_csc(&ctx->csc, + s_image->base.pix.ycbcr_enc, + s_image->base.pix.quantization, + ipu_pixelformat_to_colorspace(s_image->fmt->fourcc), + d_image->base.pix.ycbcr_enc, + d_image->base.pix.quantization, + ipu_pixelformat_to_colorspace(d_image->fmt->fourcc)); + if (ret) + goto out_free; + dump_format(ctx, s_image); dump_format(ctx, d_image); diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index 84ab482d0db6..c8c770b05ed9 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig @@ -23,6 +23,7 @@ config VGA_SWITCHEROO depends on X86 depends on ACPI depends on PCI + depends on (FRAMEBUFFER_CONSOLE=n || FB=y) select VGA_ARB help Many laptops released in 2008/9/10 have two GPUs with a multiplexer diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index 10ffe00f1a54..f87fe0203720 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -193,8 +193,8 @@ static int prp_set_fmt(struct v4l2_subdev *sd, sdformat->format.code = cc->codes[0]; } - imx_media_fill_default_mbus_fields(&sdformat->format, infmt, - true); + if (sdformat->format.field == V4L2_FIELD_ANY) + sdformat->format.field = V4L2_FIELD_NONE; break; case PRP_SRC_PAD_PRPENC: case PRP_SRC_PAD_PRPVF: @@ -203,6 +203,8 @@ static int prp_set_fmt(struct v4l2_subdev *sd, break; } + imx_media_try_colorimetry(&sdformat->format, true); + fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); *fmt = sdformat->format; out: diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 64037b0a8387..f2fe3c11c70e 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -456,6 +456,7 @@ static int prp_setup_rotation(struct prp_priv *priv) const struct imx_media_pixfmt *outcc, *incc; struct v4l2_mbus_framefmt *infmt; struct v4l2_pix_format *outfmt; + struct ipu_ic_csc csc; dma_addr_t phys[2]; int ret; @@ -464,6 +465,17 @@ static int prp_setup_rotation(struct prp_priv *priv) incc = priv->cc[PRPENCVF_SINK_PAD]; outcc = vdev->cc; + ret = ipu_ic_calc_csc(&csc, + infmt->ycbcr_enc, infmt->quantization, + incc->cs, + outfmt->ycbcr_enc, outfmt->quantization, + outcc->cs); + if (ret) { + v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n", + ret); + return ret; + } + ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[0], outfmt->sizeimage); if (ret) { @@ -477,10 +489,9 @@ static int prp_setup_rotation(struct prp_priv *priv) goto free_rot0; } - ret = ipu_ic_task_init(priv->ic, + ret = ipu_ic_task_init(priv->ic, &csc, infmt->width, infmt->height, - outfmt->height, outfmt->width, - incc->cs, outcc->cs); + outfmt->height, outfmt->width); if (ret) { v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret); goto free_rot1; @@ -572,6 +583,7 @@ static int prp_setup_norotation(struct prp_priv *priv) const struct imx_media_pixfmt *outcc, *incc; struct v4l2_mbus_framefmt *infmt; struct v4l2_pix_format *outfmt; + struct ipu_ic_csc csc; dma_addr_t phys[2]; int ret; @@ -580,10 +592,20 @@ static int prp_setup_norotation(struct prp_priv *priv) incc = priv->cc[PRPENCVF_SINK_PAD]; outcc = vdev->cc; - ret = ipu_ic_task_init(priv->ic, + ret = ipu_ic_calc_csc(&csc, + infmt->ycbcr_enc, infmt->quantization, + incc->cs, + outfmt->ycbcr_enc, outfmt->quantization, + outcc->cs); + if (ret) { + v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n", + ret); + return ret; + } + + ret = ipu_ic_task_init(priv->ic, &csc, infmt->width, infmt->height, - outfmt->width, outfmt->height, - incc->cs, outcc->cs); + outfmt->width, outfmt->height); if (ret) { v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret); return ret; @@ -885,8 +907,6 @@ static void prp_try_fmt(struct prp_priv *priv, /* propagate colorimetry from sink */ sdformat->format.colorspace = infmt->colorspace; sdformat->format.xfer_func = infmt->xfer_func; - sdformat->format.quantization = infmt->quantization; - sdformat->format.ycbcr_enc = infmt->ycbcr_enc; } else { v4l_bound_align_image(&sdformat->format.width, MIN_W_SINK, MAX_W_SINK, W_ALIGN_SINK, @@ -894,9 +914,11 @@ static void prp_try_fmt(struct prp_priv *priv, MIN_H_SINK, MAX_H_SINK, H_ALIGN_SINK, S_ALIGN); - imx_media_fill_default_mbus_fields(&sdformat->format, infmt, - true); + if (sdformat->format.field == V4L2_FIELD_ANY) + sdformat->format.field = V4L2_FIELD_NONE; } + + imx_media_try_colorimetry(&sdformat->format, true); } static int prp_set_fmt(struct v4l2_subdev *sd, diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 1d248aca40a9..dce4addadff4 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1375,9 +1375,15 @@ static void csi_try_field(struct csi_priv *priv, struct v4l2_mbus_framefmt *infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which); - /* no restrictions on sink pad field type */ - if (sdformat->pad == CSI_SINK_PAD) + /* + * no restrictions on sink pad field type except must + * be initialized. + */ + if (sdformat->pad == CSI_SINK_PAD) { + if (sdformat->format.field == V4L2_FIELD_ANY) + sdformat->format.field = V4L2_FIELD_NONE; return; + } switch (infmt->field) { case V4L2_FIELD_SEQ_TB: @@ -1455,8 +1461,6 @@ static void csi_try_fmt(struct csi_priv *priv, /* propagate colorimetry from sink */ sdformat->format.colorspace = infmt->colorspace; sdformat->format.xfer_func = infmt->xfer_func; - sdformat->format.quantization = infmt->quantization; - sdformat->format.ycbcr_enc = infmt->ycbcr_enc; break; case CSI_SINK_PAD: @@ -1476,10 +1480,6 @@ static void csi_try_fmt(struct csi_priv *priv, csi_try_field(priv, cfg, sdformat); - imx_media_fill_default_mbus_fields( - &sdformat->format, infmt, - priv->active_output_pad == CSI_SRC_PAD_DIRECT); - /* Reset crop and compose rectangles */ crop->left = 0; crop->top = 0; @@ -1495,6 +1495,9 @@ static void csi_try_fmt(struct csi_priv *priv, break; } + + imx_media_try_colorimetry(&sdformat->format, + priv->active_output_pad == CSI_SRC_PAD_DIRECT); } static int csi_set_fmt(struct v4l2_subdev *sd, diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index b41842dba5ec..05b63395084e 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -511,21 +511,18 @@ int imx_media_init_cfg(struct v4l2_subdev *sd, EXPORT_SYMBOL_GPL(imx_media_init_cfg); /* - * Check whether the field and colorimetry parameters in tryfmt are - * uninitialized, and if so fill them with the values from fmt, - * or if tryfmt->colorspace has been initialized, all the default - * colorimetry params can be derived from tryfmt->colorspace. + * Default the colorspace in tryfmt to SRGB if set to an unsupported + * colorspace or not initialized. Then set the remaining colorimetry + * parameters based on the colorspace if they are uninitialized. * * tryfmt->code must be set on entry. * * If this format is destined to be routed through the Image Converter, - * quantization and Y`CbCr encoding must be fixed. The IC expects and - * produces fixed quantization and Y`CbCr encoding at its input and output - * (full range for RGB, limited range for YUV, and V4L2_YCBCR_ENC_601). + * Y`CbCr encoding must be fixed. The IC supports only BT.601 Y`CbCr + * or Rec.709 Y`CbCr encoding. */ -void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, - struct v4l2_mbus_framefmt *fmt, - bool ic_route) +void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt, + bool ic_route) { const struct imx_media_pixfmt *cc; bool is_rgb = false; @@ -533,44 +530,46 @@ void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true); if (!cc) cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY); - if (cc && cc->cs != IPUV3_COLORSPACE_YUV) + if (cc && cc->cs == IPUV3_COLORSPACE_RGB) is_rgb = true; - /* fill field if necessary */ - if (tryfmt->field == V4L2_FIELD_ANY) - tryfmt->field = fmt->field; + switch (tryfmt->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_JPEG: + case V4L2_COLORSPACE_SRGB: + case V4L2_COLORSPACE_BT2020: + case V4L2_COLORSPACE_OPRGB: + case V4L2_COLORSPACE_DCI_P3: + case V4L2_COLORSPACE_RAW: + break; + default: + tryfmt->colorspace = V4L2_COLORSPACE_SRGB; + break; + } + + if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) + tryfmt->xfer_func = + V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace); - /* fill colorimetry if necessary */ - if (tryfmt->colorspace == V4L2_COLORSPACE_DEFAULT) { - tryfmt->colorspace = fmt->colorspace; - tryfmt->xfer_func = fmt->xfer_func; - tryfmt->ycbcr_enc = fmt->ycbcr_enc; - tryfmt->quantization = fmt->quantization; + if (ic_route) { + if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 && + tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709) + tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601; } else { - if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) { - tryfmt->xfer_func = - V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace); - } if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) { tryfmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace); } - if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) { - tryfmt->quantization = - V4L2_MAP_QUANTIZATION_DEFAULT( - is_rgb, tryfmt->colorspace, - tryfmt->ycbcr_enc); - } } - if (ic_route) { - tryfmt->quantization = is_rgb ? - V4L2_QUANTIZATION_FULL_RANGE : - V4L2_QUANTIZATION_LIM_RANGE; - tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601; - } + if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) + tryfmt->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, + tryfmt->colorspace, + tryfmt->ycbcr_enc); } -EXPORT_SYMBOL_GPL(imx_media_fill_default_mbus_fields); +EXPORT_SYMBOL_GPL(imx_media_try_colorimetry); int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, struct v4l2_rect *compose, diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 4487374c9435..fbafd7fb7aeb 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -617,14 +617,13 @@ static void vdic_try_fmt(struct vdic_priv *priv, &sdformat->format.height, MIN_H, MAX_H_VDIC, H_ALIGN, S_ALIGN); - imx_media_fill_default_mbus_fields(&sdformat->format, infmt, - true); - /* input must be interlaced! Choose SEQ_TB if not */ if (!V4L2_FIELD_HAS_BOTH(sdformat->format.field)) sdformat->format.field = V4L2_FIELD_SEQ_TB; break; } + + imx_media_try_colorimetry(&sdformat->format, true); } static int vdic_set_fmt(struct v4l2_subdev *sd, diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 6587aa49e005..23024c9bc887 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -172,9 +172,8 @@ int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus, const struct imx_media_pixfmt **cc); int imx_media_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg); -void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, - struct v4l2_mbus_framefmt *fmt, - bool ic_route); +void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt, + bool ic_route); int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, struct v4l2_rect *compose, const struct v4l2_mbus_framefmt *mbus, diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index a708a0340eb1..6e2f4c3eb24f 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -1003,8 +1003,6 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, sdformat->format.colorspace = in_fmt->colorspace; sdformat->format.xfer_func = in_fmt->xfer_func; - sdformat->format.quantization = in_fmt->quantization; - sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc; break; case IMX7_CSI_PAD_SINK: *cc = imx_media_find_mbus_format(sdformat->format.code, @@ -1015,14 +1013,14 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, false); sdformat->format.code = (*cc)->codes[0]; } - - imx_media_fill_default_mbus_fields(&sdformat->format, in_fmt, - false); break; default: return -EINVAL; break; } + + imx_media_try_colorimetry(&sdformat->format, false); + return 0; } diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 083f16747369..e946e20c61d8 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -537,7 +537,7 @@ void drm_connector_list_update(struct drm_connector *connector); /* parsing cmdline modes */ 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); struct drm_display_mode * drm_mode_create_from_cmdline_mode(struct drm_device *dev, diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 435d02f719a8..49d9cdfc58f2 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -768,14 +768,4 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx); void ttm_bo_swapout_all(struct ttm_bo_device *bdev); int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo); - -/* Default number of pre-faulted pages in the TTM fault handler */ -#define TTM_BO_VM_NUM_PREFAULT 16 - -vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo, - struct vm_fault *vmf); - -vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, - pgprot_t prot, - pgoff_t num_prefault); #endif diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index a2d810a2504d..c9b8ba492f24 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -442,9 +442,6 @@ extern struct ttm_bo_global { * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver. * @man: An array of mem_type_managers. * @vma_manager: Address space manager - * @vm_ops: Pointer to the struct vm_operations_struct used for this - * device's VM operations. The driver may override this before the first - * mmap() call. * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. * @dev_mapping: A pointer to the struct address_space representing the @@ -463,7 +460,6 @@ struct ttm_bo_device { struct ttm_bo_global *glob; struct ttm_bo_driver *driver; struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; - const struct vm_operations_struct *vm_ops; /* * Protected by internal locks. @@ -492,8 +488,6 @@ struct ttm_bo_device { bool no_retry; }; -extern const struct vm_operations_struct ttm_bo_vm_ops; - /** * struct ttm_lru_bulk_move_pos * diff --git a/include/linux/mm.h b/include/linux/mm.h index 798cdda9560e..dd0b5f4e1e45 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2686,24 +2686,7 @@ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, extern int apply_to_page_range(struct mm_struct *mm, unsigned long address, unsigned long size, pte_fn_t fn, void *data); -struct pfn_range_apply; -typedef int (*pter_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, - struct pfn_range_apply *closure); -struct pfn_range_apply { - struct mm_struct *mm; - pter_fn_t ptefn; - unsigned int alloc; -}; -extern int apply_to_pfn_range(struct pfn_range_apply *closure, - unsigned long address, unsigned long size); -unsigned long apply_as_wrprotect(struct address_space *mapping, - pgoff_t first_index, pgoff_t nr); -unsigned long apply_as_clean(struct address_space *mapping, - pgoff_t first_index, pgoff_t nr, - pgoff_t bitmap_pgoff, - unsigned long *bitmap, - pgoff_t *start, - pgoff_t *end); + #ifdef CONFIG_PAGE_POISONING extern bool page_poisoning_enabled(void); extern void kernel_poison_pages(struct page *page, int numpages, int enable); diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 02cab33f2f25..399f58317cff 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -891,13 +891,11 @@ struct drm_vmw_shader_arg { * surface. * @drm_vmw_surface_flag_create_buffer: Create a backup buffer if none is * given. - * @drm_vmw_surface_flag_coherent: Back surface with coherent memory. */ enum drm_vmw_surface_flags { drm_vmw_surface_flag_shareable = (1 << 0), drm_vmw_surface_flag_scanout = (1 << 1), - drm_vmw_surface_flag_create_buffer = (1 << 2), - drm_vmw_surface_flag_coherent = (1 << 3), + drm_vmw_surface_flag_create_buffer = (1 << 2) }; /** diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index b03fafa1ff58..06b0b57e996c 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -387,20 +387,64 @@ enum ipu_ic_task { IC_NUM_TASKS, }; +/* + * The parameters that describe a colorspace according to the + * Image Converter: + * - Y'CbCr encoding + * - quantization + * - "colorspace" (RGB or YUV). + */ +struct ipu_ic_colorspace { + enum v4l2_ycbcr_encoding enc; + enum v4l2_quantization quant; + enum ipu_color_space cs; +}; + +static inline void +ipu_ic_fill_colorspace(struct ipu_ic_colorspace *ic_cs, + enum v4l2_ycbcr_encoding enc, + enum v4l2_quantization quant, + enum ipu_color_space cs) +{ + ic_cs->enc = enc; + ic_cs->quant = quant; + ic_cs->cs = cs; +} + +struct ipu_ic_csc_params { + s16 coeff[3][3]; /* signed 9-bit integer coefficients */ + s16 offset[3]; /* signed 11+2-bit fixed point offset */ + u8 scale:2; /* scale coefficients * 2^(scale-1) */ + bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */ +}; + +struct ipu_ic_csc { + struct ipu_ic_colorspace in_cs; + struct ipu_ic_colorspace out_cs; + struct ipu_ic_csc_params params; +}; + struct ipu_ic; + +int __ipu_ic_calc_csc(struct ipu_ic_csc *csc); +int ipu_ic_calc_csc(struct ipu_ic_csc *csc, + enum v4l2_ycbcr_encoding in_enc, + enum v4l2_quantization in_quant, + enum ipu_color_space in_cs, + enum v4l2_ycbcr_encoding out_enc, + enum v4l2_quantization out_quant, + enum ipu_color_space out_cs); int ipu_ic_task_init(struct ipu_ic *ic, + const struct ipu_ic_csc *csc, int in_width, int in_height, - int out_width, int out_height, - enum ipu_color_space in_cs, - enum ipu_color_space out_cs); + int out_width, int out_height); int ipu_ic_task_init_rsc(struct ipu_ic *ic, + const struct ipu_ic_csc *csc, int in_width, int in_height, int out_width, int out_height, - enum ipu_color_space in_cs, - enum ipu_color_space out_cs, u32 rsc); int ipu_ic_task_graphics_init(struct ipu_ic *ic, - enum ipu_color_space in_g_cs, + const struct ipu_ic_colorspace *g_in_cs, bool galpha_en, u32 galpha, bool colorkey_en, u32 colorkey); void ipu_ic_task_enable(struct ipu_ic *ic); diff --git a/mm/Kconfig b/mm/Kconfig index 5006d0e6a5c7..f0c76ba47695 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -765,7 +765,4 @@ config GUP_BENCHMARK config ARCH_HAS_PTE_SPECIAL bool -config AS_DIRTY_HELPERS - bool - endmenu diff --git a/mm/Makefile b/mm/Makefile index f5d412bbc2f7..ac5e5ba78874 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -104,4 +104,3 @@ obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_HMM) += hmm.o obj-$(CONFIG_MEMFD_CREATE) += memfd.o -obj-$(CONFIG_AS_DIRTY_HELPERS) += as_dirty_helpers.o diff --git a/mm/as_dirty_helpers.c b/mm/as_dirty_helpers.c deleted file mode 100644 index f600e31534fb..000000000000 --- a/mm/as_dirty_helpers.c +++ /dev/null @@ -1,300 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/mm.h> -#include <linux/mm_types.h> -#include <linux/hugetlb.h> -#include <linux/bitops.h> -#include <linux/mmu_notifier.h> -#include <asm/cacheflush.h> -#include <asm/tlbflush.h> - -/** - * struct apply_as - Closure structure for apply_as_range - * @base: struct pfn_range_apply we derive from - * @start: Address of first modified pte - * @end: Address of last modified pte + 1 - * @total: Total number of modified ptes - * @vma: Pointer to the struct vm_area_struct we're currently operating on - */ -struct apply_as { - struct pfn_range_apply base; - unsigned long start; - unsigned long end; - unsigned long total; - struct vm_area_struct *vma; -}; - -/** - * apply_pt_wrprotect - Leaf pte callback to write-protect a pte - * @pte: Pointer to the pte - * @token: Page table token, see apply_to_pfn_range() - * @addr: The virtual page address - * @closure: Pointer to a struct pfn_range_apply embedded in a - * struct apply_as - * - * The function write-protects a pte and records the range in - * virtual address space of touched ptes for efficient range TLB flushes. - * - * Return: Always zero. - */ -static int apply_pt_wrprotect(pte_t *pte, pgtable_t token, - unsigned long addr, - struct pfn_range_apply *closure) -{ - struct apply_as *aas = container_of(closure, typeof(*aas), base); - pte_t ptent = *pte; - - if (pte_write(ptent)) { - pte_t old_pte = ptep_modify_prot_start(aas->vma, addr, pte); - - ptent = pte_wrprotect(old_pte); - ptep_modify_prot_commit(aas->vma, addr, pte, old_pte, ptent); - aas->total++; - aas->start = min(aas->start, addr); - aas->end = max(aas->end, addr + PAGE_SIZE); - } - - return 0; -} - -/** - * struct apply_as_clean - Closure structure for apply_as_clean - * @base: struct apply_as we derive from - * @bitmap_pgoff: Address_space Page offset of the first bit in @bitmap - * @bitmap: Bitmap with one bit for each page offset in the address_space range - * covered. - * @start: Address_space page offset of first modified pte relative - * to @bitmap_pgoff - * @end: Address_space page offset of last modified pte relative - * to @bitmap_pgoff - */ -struct apply_as_clean { - struct apply_as base; - pgoff_t bitmap_pgoff; - unsigned long *bitmap; - pgoff_t start; - pgoff_t end; -}; - -/** - * apply_pt_clean - Leaf pte callback to clean a pte - * @pte: Pointer to the pte - * @token: Page table token, see apply_to_pfn_range() - * @addr: The virtual page address - * @closure: Pointer to a struct pfn_range_apply embedded in a - * struct apply_as_clean - * - * The function cleans a pte and records the range in - * virtual address space of touched ptes for efficient TLB flushes. - * It also records dirty ptes in a bitmap representing page offsets - * in the address_space, as well as the first and last of the bits - * touched. - * - * Return: Always zero. - */ -static int apply_pt_clean(pte_t *pte, pgtable_t token, - unsigned long addr, - struct pfn_range_apply *closure) -{ - struct apply_as *aas = container_of(closure, typeof(*aas), base); - struct apply_as_clean *clean = container_of(aas, typeof(*clean), base); - pte_t ptent = *pte; - - if (pte_dirty(ptent)) { - pgoff_t pgoff = ((addr - aas->vma->vm_start) >> PAGE_SHIFT) + - aas->vma->vm_pgoff - clean->bitmap_pgoff; - pte_t old_pte = ptep_modify_prot_start(aas->vma, addr, pte); - - ptent = pte_mkclean(old_pte); - ptep_modify_prot_commit(aas->vma, addr, pte, old_pte, ptent); - - aas->total++; - aas->start = min(aas->start, addr); - aas->end = max(aas->end, addr + PAGE_SIZE); - - __set_bit(pgoff, clean->bitmap); - clean->start = min(clean->start, pgoff); - clean->end = max(clean->end, pgoff + 1); - } - - return 0; -} - -/** - * apply_as_range - Apply a pte callback to all PTEs pointing into a range - * of an address_space. - * @mapping: Pointer to the struct address_space - * @aas: Closure structure - * @first_index: First page offset in the address_space - * @nr: Number of incremental page offsets to cover - * - * Return: Number of ptes touched. Note that this number might be larger - * than @nr if there are overlapping vmas - */ -static unsigned long apply_as_range(struct address_space *mapping, - struct apply_as *aas, - pgoff_t first_index, pgoff_t nr) -{ - struct vm_area_struct *vma; - pgoff_t vba, vea, cba, cea; - unsigned long start_addr, end_addr; - struct mmu_notifier_range range; - - i_mmap_lock_read(mapping); - vma_interval_tree_foreach(vma, &mapping->i_mmap, first_index, - first_index + nr - 1) { - unsigned long vm_flags = READ_ONCE(vma->vm_flags); - - /* - * We can only do advisory flag tests below, since we can't - * require the vm's mmap_sem to be held to protect the flags. - * Therefore, callers that strictly depend on specific mmap - * flags to remain constant throughout the operation must - * either ensure those flags are immutable for all relevant - * vmas or can't use this function. Fixing this properly would - * require the vma::vm_flags to be protected by a separate - * lock taken after the i_mmap_lock - */ - - /* Skip non-applicable VMAs */ - if ((vm_flags & (VM_SHARED | VM_WRITE)) != - (VM_SHARED | VM_WRITE)) - continue; - - /* Warn on and skip VMAs whose flags indicate illegal usage */ - if (WARN_ON((vm_flags & (VM_HUGETLB | VM_IO)) != VM_IO)) - continue; - - /* Clip to the vma */ - vba = vma->vm_pgoff; - vea = vba + vma_pages(vma); - cba = first_index; - cba = max(cba, vba); - cea = first_index + nr; - cea = min(cea, vea); - - /* Translate to virtual address */ - start_addr = ((cba - vba) << PAGE_SHIFT) + vma->vm_start; - end_addr = ((cea - vba) << PAGE_SHIFT) + vma->vm_start; - if (start_addr >= end_addr) - continue; - - aas->base.mm = vma->vm_mm; - aas->vma = vma; - aas->start = end_addr; - aas->end = start_addr; - - mmu_notifier_range_init(&range, MMU_NOTIFY_PROTECTION_PAGE, 0, - vma, vma->vm_mm, start_addr, end_addr); - mmu_notifier_invalidate_range_start(&range); - - /* Needed when we only change protection? */ - flush_cache_range(vma, start_addr, end_addr); - - /* - * We're not using tlb_gather_mmu() since typically - * only a small subrange of PTEs are affected. - */ - inc_tlb_flush_pending(vma->vm_mm); - - /* Should not error since aas->base.alloc == 0 */ - WARN_ON(apply_to_pfn_range(&aas->base, start_addr, - end_addr - start_addr)); - if (aas->end > aas->start) - flush_tlb_range(vma, aas->start, aas->end); - - mmu_notifier_invalidate_range_end(&range); - dec_tlb_flush_pending(vma->vm_mm); - } - i_mmap_unlock_read(mapping); - - return aas->total; -} - -/** - * apply_as_wrprotect - Write-protect all ptes in an address_space range - * @mapping: The address_space we want to write protect - * @first_index: The first page offset in the range - * @nr: Number of incremental page offsets to cover - * - * WARNING: This function should only be used for address spaces whose - * vmas are marked VM_IO and that do not contain huge pages. - * To avoid interference with COW'd pages, vmas not marked VM_SHARED are - * simply skipped. - * - * Return: The number of ptes actually write-protected. Note that - * already write-protected ptes are not counted. - */ -unsigned long apply_as_wrprotect(struct address_space *mapping, - pgoff_t first_index, pgoff_t nr) -{ - struct apply_as aas = { - .base = { - .alloc = 0, - .ptefn = apply_pt_wrprotect, - }, - .total = 0, - }; - - return apply_as_range(mapping, &aas, first_index, nr); -} -EXPORT_SYMBOL_GPL(apply_as_wrprotect); - -/** - * apply_as_clean - Clean all ptes in an address_space range - * @mapping: The address_space we want to clean - * @first_index: The first page offset in the range - * @nr: Number of incremental page offsets to cover - * @bitmap_pgoff: The page offset of the first bit in @bitmap - * @bitmap: Pointer to a bitmap of at least @nr bits. The bitmap needs to - * cover the whole range @first_index..@first_index + @nr. - * @start: Pointer to number of the first set bit in @bitmap. - * is modified as new bits are set by the function. - * @end: Pointer to the number of the last set bit in @bitmap. - * none set. The value is modified as new bits are set by the function. - * - * Note: When this function returns there is no guarantee that a CPU has - * not already dirtied new ptes. However it will not clean any ptes not - * reported in the bitmap. - * - * If a caller needs to make sure all dirty ptes are picked up and none - * additional are added, it first needs to write-protect the address-space - * range and make sure new writers are blocked in page_mkwrite() or - * pfn_mkwrite(). And then after a TLB flush following the write-protection - * pick up all dirty bits. - * - * WARNING: This function should only be used for address spaces whose - * vmas are marked VM_IO and that do not contain huge pages. - * To avoid interference with COW'd pages, vmas not marked VM_SHARED are - * simply skipped. - * - * Return: The number of dirty ptes actually cleaned. - */ -unsigned long apply_as_clean(struct address_space *mapping, - pgoff_t first_index, pgoff_t nr, - pgoff_t bitmap_pgoff, - unsigned long *bitmap, - pgoff_t *start, - pgoff_t *end) -{ - bool none_set = (*start >= *end); - struct apply_as_clean clean = { - .base = { - .base = { - .alloc = 0, - .ptefn = apply_pt_clean, - }, - .total = 0, - }, - .bitmap_pgoff = bitmap_pgoff, - .bitmap = bitmap, - .start = none_set ? nr : *start, - .end = none_set ? 0 : *end, - }; - unsigned long ret = apply_as_range(mapping, &clean.base, first_index, - nr); - - *start = clean.start; - *end = clean.end; - return ret; -} -EXPORT_SYMBOL_GPL(apply_as_clean); diff --git a/mm/memory.c b/mm/memory.c index 462aa47f8878..ddf20bd0c317 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2032,17 +2032,18 @@ int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long } EXPORT_SYMBOL(vm_iomap_memory); -static int apply_to_pte_range(struct pfn_range_apply *closure, pmd_t *pmd, - unsigned long addr, unsigned long end) +static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, unsigned long end, + pte_fn_t fn, void *data) { pte_t *pte; int err; pgtable_t token; spinlock_t *uninitialized_var(ptl); - pte = (closure->mm == &init_mm) ? + pte = (mm == &init_mm) ? pte_alloc_kernel(pmd, addr) : - pte_alloc_map_lock(closure->mm, pmd, addr, &ptl); + pte_alloc_map_lock(mm, pmd, addr, &ptl); if (!pte) return -ENOMEM; @@ -2053,109 +2054,86 @@ static int apply_to_pte_range(struct pfn_range_apply *closure, pmd_t *pmd, token = pmd_pgtable(*pmd); do { - err = closure->ptefn(pte++, token, addr, closure); + err = fn(pte++, token, addr, data); if (err) break; } while (addr += PAGE_SIZE, addr != end); arch_leave_lazy_mmu_mode(); - if (closure->mm != &init_mm) + if (mm != &init_mm) pte_unmap_unlock(pte-1, ptl); return err; } -static int apply_to_pmd_range(struct pfn_range_apply *closure, pud_t *pud, - unsigned long addr, unsigned long end) +static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, + pte_fn_t fn, void *data) { pmd_t *pmd; unsigned long next; - int err = 0; + int err; BUG_ON(pud_huge(*pud)); - pmd = pmd_alloc(closure->mm, pud, addr); + pmd = pmd_alloc(mm, pud, addr); if (!pmd) return -ENOMEM; - do { next = pmd_addr_end(addr, end); - if (!closure->alloc && pmd_none_or_clear_bad(pmd)) - continue; - err = apply_to_pte_range(closure, pmd, addr, next); + err = apply_to_pte_range(mm, pmd, addr, next, fn, data); if (err) break; } while (pmd++, addr = next, addr != end); return err; } -static int apply_to_pud_range(struct pfn_range_apply *closure, p4d_t *p4d, - unsigned long addr, unsigned long end) +static int apply_to_pud_range(struct mm_struct *mm, p4d_t *p4d, + unsigned long addr, unsigned long end, + pte_fn_t fn, void *data) { pud_t *pud; unsigned long next; - int err = 0; + int err; - pud = pud_alloc(closure->mm, p4d, addr); + pud = pud_alloc(mm, p4d, addr); if (!pud) return -ENOMEM; - do { next = pud_addr_end(addr, end); - if (!closure->alloc && pud_none_or_clear_bad(pud)) - continue; - err = apply_to_pmd_range(closure, pud, addr, next); + err = apply_to_pmd_range(mm, pud, addr, next, fn, data); if (err) break; } while (pud++, addr = next, addr != end); return err; } -static int apply_to_p4d_range(struct pfn_range_apply *closure, pgd_t *pgd, - unsigned long addr, unsigned long end) +static int apply_to_p4d_range(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, + pte_fn_t fn, void *data) { p4d_t *p4d; unsigned long next; - int err = 0; + int err; - p4d = p4d_alloc(closure->mm, pgd, addr); + p4d = p4d_alloc(mm, pgd, addr); if (!p4d) return -ENOMEM; - do { next = p4d_addr_end(addr, end); - if (!closure->alloc && p4d_none_or_clear_bad(p4d)) - continue; - err = apply_to_pud_range(closure, p4d, addr, next); + err = apply_to_pud_range(mm, p4d, addr, next, fn, data); if (err) break; } while (p4d++, addr = next, addr != end); return err; } -/** - * apply_to_pfn_range - Scan a region of virtual memory, calling a provided - * function on each leaf page table entry - * @closure: Details about how to scan and what function to apply - * @addr: Start virtual address - * @size: Size of the region - * - * If @closure->alloc is set to 1, the function will fill in the page table - * as necessary. Otherwise it will skip non-present parts. - * Note: The caller must ensure that the range does not contain huge pages. - * The caller must also assure that the proper mmu_notifier functions are - * called before and after the call to apply_to_pfn_range. - * - * WARNING: Do not use this function unless you know exactly what you are - * doing. It is lacking support for huge pages and transparent huge pages. - * - * Return: Zero on success. If the provided function returns a non-zero status, - * the page table walk will terminate and that status will be returned. - * If @closure->alloc is set to 1, then this function may also return memory - * allocation errors arising from allocating page table memory. +/* + * Scan a region of virtual memory, filling in page tables as necessary + * and calling a provided function on each leaf page table. */ -int apply_to_pfn_range(struct pfn_range_apply *closure, - unsigned long addr, unsigned long size) +int apply_to_page_range(struct mm_struct *mm, unsigned long addr, + unsigned long size, pte_fn_t fn, void *data) { pgd_t *pgd; unsigned long next; @@ -2165,65 +2143,16 @@ int apply_to_pfn_range(struct pfn_range_apply *closure, if (WARN_ON(addr >= end)) return -EINVAL; - pgd = pgd_offset(closure->mm, addr); + pgd = pgd_offset(mm, addr); do { next = pgd_addr_end(addr, end); - if (!closure->alloc && pgd_none_or_clear_bad(pgd)) - continue; - err = apply_to_p4d_range(closure, pgd, addr, next); + err = apply_to_p4d_range(mm, pgd, addr, next, fn, data); if (err) break; } while (pgd++, addr = next, addr != end); return err; } - -/** - * struct page_range_apply - Closure structure for apply_to_page_range() - * @pter: The base closure structure we derive from - * @fn: The leaf pte function to call - * @data: The leaf pte function closure - */ -struct page_range_apply { - struct pfn_range_apply pter; - pte_fn_t fn; - void *data; -}; - -/* - * Callback wrapper to enable use of apply_to_pfn_range for - * the apply_to_page_range interface - */ -static int apply_to_page_range_wrapper(pte_t *pte, pgtable_t token, - unsigned long addr, - struct pfn_range_apply *pter) -{ - struct page_range_apply *pra = - container_of(pter, typeof(*pra), pter); - - return pra->fn(pte, token, addr, pra->data); -} - -/* - * Scan a region of virtual memory, filling in page tables as necessary - * and calling a provided function on each leaf page table. - * - * WARNING: Do not use this function unless you know exactly what you are - * doing. It is lacking support for huge pages and transparent huge pages. - */ -int apply_to_page_range(struct mm_struct *mm, unsigned long addr, - unsigned long size, pte_fn_t fn, void *data) -{ - struct page_range_apply pra = { - .pter = {.mm = mm, - .alloc = 1, - .ptefn = apply_to_page_range_wrapper }, - .fn = fn, - .data = data - }; - - return apply_to_pfn_range(&pra.pter, addr, size); -} EXPORT_SYMBOL_GPL(apply_to_page_range); /* @@ -2309,7 +2238,7 @@ static vm_fault_t do_page_mkwrite(struct vm_fault *vmf) ret = vmf->vma->vm_ops->page_mkwrite(vmf); /* Restore original flags so that caller is not surprised */ vmf->flags = old_flags; - if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY))) + if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) return ret; if (unlikely(!(ret & VM_FAULT_LOCKED))) { lock_page(page); @@ -2586,7 +2515,7 @@ static vm_fault_t wp_pfn_shared(struct vm_fault *vmf) pte_unmap_unlock(vmf->pte, vmf->ptl); vmf->flags |= FAULT_FLAG_MKWRITE; ret = vma->vm_ops->pfn_mkwrite(vmf); - if (ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)) + if (ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)) return ret; return finish_mkwrite_fault(vmf); } @@ -2607,8 +2536,7 @@ static vm_fault_t wp_page_shared(struct vm_fault *vmf) pte_unmap_unlock(vmf->pte, vmf->ptl); tmp = do_page_mkwrite(vmf); if (unlikely(!tmp || (tmp & - (VM_FAULT_ERROR | VM_FAULT_NOPAGE | - VM_FAULT_RETRY)))) { + (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))) { put_page(vmf->page); return tmp; } @@ -3673,8 +3601,7 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf) unlock_page(vmf->page); tmp = do_page_mkwrite(vmf); if (unlikely(!tmp || - (tmp & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | - VM_FAULT_RETRY)))) { + (tmp & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))) { put_page(vmf->page); return tmp; } |