Commit d8dab40a authored by Daniel Vetter's avatar Daniel Vetter

Merge tag 'drm-misc-next-2023-04-12' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v6.4-rc1:

Cross-subsystem Changes:
- Convert MIPI DSIM bridge dt to yaml.

Core Changes:
- Fix UAF race in drm scheduler.

Driver Changes:
- Add primary plane positioning support to VKMS.
- Convert omapdrm fbdev emulation to in-kernel client.
- Assorted small fixes to vkms, vc4, nouveau, vmwgfx.
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/b7c37d4e-8f16-85dc-0f5f-3bd98f961395@linux.intel.com
parents 55bf1496 fd35174e
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/samsung,mipi-dsim.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung MIPI DSIM bridge controller
maintainers:
- Inki Dae <inki.dae@samsung.com>
- Jagan Teki <jagan@amarulasolutions.com>
- Marek Szyprowski <m.szyprowski@samsung.com>
description: |
Samsung MIPI DSIM bridge controller can be found it on Exynos
and i.MX8M Mini/Nano/Plus SoC's.
properties:
compatible:
oneOf:
- enum:
- samsung,exynos3250-mipi-dsi
- samsung,exynos4210-mipi-dsi
- samsung,exynos5410-mipi-dsi
- samsung,exynos5422-mipi-dsi
- samsung,exynos5433-mipi-dsi
- fsl,imx8mm-mipi-dsim
- fsl,imx8mp-mipi-dsim
- items:
- const: fsl,imx8mn-mipi-dsim
- const: fsl,imx8mm-mipi-dsim
reg:
maxItems: 1
interrupts:
maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
clocks:
minItems: 2
maxItems: 5
clock-names:
minItems: 2
maxItems: 5
samsung,phy-type:
$ref: /schemas/types.yaml#/definitions/uint32
description: phandle to the samsung phy-type
power-domains:
maxItems: 1
samsung,power-domain:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the associated samsung power domain
vddcore-supply:
description: MIPI DSIM Core voltage supply (e.g. 1.1V)
vddio-supply:
description: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
samsung,burst-clock-frequency:
$ref: /schemas/types.yaml#/definitions/uint32
description:
DSIM high speed burst mode frequency.
samsung,esc-clock-frequency:
$ref: /schemas/types.yaml#/definitions/uint32
description:
DSIM escape mode frequency.
samsung,pll-clock-frequency:
$ref: /schemas/types.yaml#/definitions/uint32
description:
DSIM oscillator clock frequency.
phys:
maxItems: 1
phy-names:
const: dsim
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/properties/port
description:
Input port node to receive pixel data from the
display controller. Exactly one endpoint must be
specified.
port@1:
$ref: /schemas/graph.yaml#/properties/port
description:
DSI output port node to the panel or the next bridge
in the chain.
required:
- clock-names
- clocks
- compatible
- interrupts
- reg
- samsung,burst-clock-frequency
- samsung,esc-clock-frequency
- samsung,pll-clock-frequency
allOf:
- $ref: ../dsi-controller.yaml#
- if:
properties:
compatible:
contains:
const: samsung,exynos5433-mipi-dsi
then:
properties:
clocks:
minItems: 5
clock-names:
items:
- const: bus_clk
- const: phyclk_mipidphy0_bitclkdiv8
- const: phyclk_mipidphy0_rxclkesc0
- const: sclk_rgb_vclk_to_dsim0
- const: sclk_mipi
ports:
required:
- port@0
required:
- ports
- vddcore-supply
- vddio-supply
- if:
properties:
compatible:
contains:
const: samsung,exynos5410-mipi-dsi
then:
properties:
clocks:
minItems: 2
clock-names:
items:
- const: bus_clk
- const: pll_clk
required:
- vddcore-supply
- vddio-supply
- if:
properties:
compatible:
contains:
const: samsung,exynos4210-mipi-dsi
then:
properties:
clocks:
minItems: 2
clock-names:
items:
- const: bus_clk
- const: sclk_mipi
required:
- vddcore-supply
- vddio-supply
- if:
properties:
compatible:
contains:
const: samsung,exynos3250-mipi-dsi
then:
properties:
clocks:
minItems: 2
clock-names:
items:
- const: bus_clk
- const: pll_clk
required:
- vddcore-supply
- vddio-supply
- samsung,phy-type
additionalProperties:
type: object
examples:
- |
#include <dt-bindings/clock/exynos5433.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
dsi@13900000 {
compatible = "samsung,exynos5433-mipi-dsi";
reg = <0x13900000 0xC0>;
interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
phys = <&mipi_phy 1>;
phy-names = "dsim";
clocks = <&cmu_disp CLK_PCLK_DSIM0>,
<&cmu_disp CLK_PHYCLK_MIPIDPHY0_BITCLKDIV8>,
<&cmu_disp CLK_PHYCLK_MIPIDPHY0_RXCLKESC0>,
<&cmu_disp CLK_SCLK_RGB_VCLK_TO_DSIM0>,
<&cmu_disp CLK_SCLK_DSIM0>;
clock-names = "bus_clk",
"phyclk_mipidphy0_bitclkdiv8",
"phyclk_mipidphy0_rxclkesc0",
"sclk_rgb_vclk_to_dsim0",
"sclk_mipi";
power-domains = <&pd_disp>;
vddcore-supply = <&ldo6_reg>;
vddio-supply = <&ldo7_reg>;
samsung,burst-clock-frequency = <512000000>;
samsung,esc-clock-frequency = <16000000>;
samsung,pll-clock-frequency = <24000000>;
pinctrl-names = "default";
pinctrl-0 = <&te_irq>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dsi_to_mic: endpoint {
remote-endpoint = <&mic_to_dsi>;
};
};
};
};
Exynos MIPI DSI Master
Required properties:
- compatible: value should be one of the following
"samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
"samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
"samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
"samsung,exynos5422-mipi-dsi" /* for Exynos5422/5800 SoCs */
"samsung,exynos5433-mipi-dsi" /* for Exynos5433 SoCs */
"fsl,imx8mm-mipi-dsim" /* for i.MX8M Mini/Nano SoCs */
"fsl,imx8mp-mipi-dsim" /* for i.MX8M Plus SoCs */
- reg: physical base address and length of the registers set for the device
- interrupts: should contain DSI interrupt
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- clock-names: should include "bus_clk"and "sclk_mipi" entries
the use of "pll_clk" is deprecated
- phys: list of phy specifiers, must contain an entry for each required
entry in phy-names
- phy-names: should include "dsim" entry
- vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V)
- vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
- samsung,pll-clock-frequency: specifies frequency of the oscillator clock
- #address-cells, #size-cells: should be set respectively to <1> and <0>
according to DSI host bindings (see MIPI DSI bindings [1])
- samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
mode
- samsung,esc-clock-frequency: specifies DSI frequency in escape mode
Optional properties:
- power-domains: a phandle to DSIM power domain node
Child nodes:
Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).
Video interfaces:
Device node can contain following video interface port nodes according to [2]:
0: RGB input,
1: DSI output
[1]: Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
dsi@11c80000 {
compatible = "samsung,exynos4210-mipi-dsi";
reg = <0x11C80000 0x10000>;
interrupts = <0 79 0>;
clocks = <&clock 286>, <&clock 143>;
clock-names = "bus_clk", "sclk_mipi";
phys = <&mipi_phy 1>;
phy-names = "dsim";
vddcore-supply = <&vusb_reg>;
vddio-supply = <&vmipi_reg>;
power-domains = <&pd_lcd0>;
#address-cells = <1>;
#size-cells = <0>;
samsung,pll-clock-frequency = <24000000>;
panel@1 {
reg = <0>;
...
port {
panel_ep: endpoint {
remote-endpoint = <&dsi_ep>;
};
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
decon_to_mic: endpoint {
remote-endpoint = <&mic_to_decon>;
};
};
port@1 {
reg = <1>;
dsi_ep: endpoint {
reg = <0>;
samsung,burst-clock-frequency = <500000000>;
samsung,esc-clock-frequency = <20000000>;
remote-endpoint = <&panel_ep>;
};
};
};
};
......@@ -6631,6 +6631,7 @@ M: Jagan Teki <jagan@amarulasolutions.com>
M: Marek Szyprowski <m.szyprowski@samsung.com>
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml
F: drivers/gpu/drm/bridge/samsung-dsim.c
F: include/drm/bridge/samsung-dsim.h
......
......@@ -606,7 +606,7 @@ gv100_disp_curs = {
.user = 73,
};
const struct nvkm_disp_mthd_list
static const struct nvkm_disp_mthd_list
gv100_disp_core_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
......
......@@ -47,7 +47,7 @@ ga100_mc_device_enabled(struct nvkm_mc *mc, u32 mask)
return (nvkm_rd32(mc->subdev.device, 0x000600) & mask) == mask;
}
const struct nvkm_mc_device_func
static const struct nvkm_mc_device_func
ga100_mc_device = {
.enabled = ga100_mc_device_enabled,
.enable = ga100_mc_device_enable,
......
......@@ -47,15 +47,15 @@ static int fb_show(struct seq_file *m, void *arg)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct omap_drm_private *priv = dev->dev_private;
struct drm_fb_helper *helper = dev->fb_helper;
struct drm_framebuffer *fb;
seq_printf(m, "fbcon ");
omap_framebuffer_describe(priv->fbdev->fb, m);
omap_framebuffer_describe(helper->fb, m);
mutex_lock(&dev->mode_config.fb_lock);
list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
if (fb == priv->fbdev->fb)
if (fb == helper->fb)
continue;
seq_printf(m, "user ");
......
......@@ -6,6 +6,7 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/sort.h>
#include <linux/sys_soc.h>
......@@ -14,7 +15,6 @@
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_panel.h>
......@@ -24,6 +24,7 @@
#include "omap_dmm_tiler.h"
#include "omap_drv.h"
#include "omap_fbdev.h"
#define DRIVER_NAME MODULE_NAME
#define DRIVER_DESC "OMAP DRM"
......@@ -219,7 +220,6 @@ static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs =
static const struct drm_mode_config_funcs omap_mode_config_funcs = {
.fb_create = omap_framebuffer_create,
.output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = omap_atomic_check,
.atomic_commit = drm_atomic_helper_commit,
};
......@@ -652,7 +652,6 @@ static const struct drm_driver omap_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM |
DRIVER_ATOMIC | DRIVER_RENDER,
.open = dev_open,
.lastclose = drm_fb_helper_lastclose,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = omap_debugfs_init,
#endif
......@@ -741,8 +740,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
goto err_cleanup_modeset;
}
omap_fbdev_init(ddev);
drm_kms_helper_poll_init(ddev);
/*
......@@ -753,12 +750,12 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
if (ret)
goto err_cleanup_helpers;
omap_fbdev_setup(ddev);
return 0;
err_cleanup_helpers:
drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev);
err_cleanup_modeset:
omap_modeset_fini(ddev);
err_free_overlays:
......@@ -784,8 +781,6 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev);
drm_atomic_helper_shutdown(ddev);
omap_modeset_fini(ddev);
......
......@@ -21,7 +21,6 @@
#include "omap_crtc.h"
#include "omap_encoder.h"
#include "omap_fb.h"
#include "omap_fbdev.h"
#include "omap_gem.h"
#include "omap_irq.h"
#include "omap_plane.h"
......@@ -77,8 +76,6 @@ struct omap_drm_private {
struct drm_private_obj glob_obj;
struct drm_fb_helper *fbdev;
struct workqueue_struct *wq;
/* lock for obj_list below */
......
......@@ -4,14 +4,17 @@
* Author: Rob Clark <rob@ti.com>
*/
#include <drm/drm_crtc.h>
#include <drm/drm_util.h>
#include <drm/drm_drv.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_util.h>
#include "omap_drv.h"
#include "omap_fbdev.h"
MODULE_PARM_DESC(ywrap, "Enable ywrap scrolling (omap44xx and later, default 'y')");
static bool ywrap_enabled = true;
......@@ -25,8 +28,6 @@ module_param_named(ywrap, ywrap_enabled, bool, 0644);
struct omap_fbdev {
struct drm_fb_helper base;
struct drm_framebuffer *fb;
struct drm_gem_object *bo;
bool ywrap_enabled;
/* for deferred dmm roll when getting called in atomic ctx */
......@@ -38,12 +39,14 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi);
static void pan_worker(struct work_struct *work)
{
struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
struct fb_info *fbi = fbdev->base.info;
struct drm_fb_helper *helper = &fbdev->base;
struct fb_info *fbi = helper->info;
struct drm_gem_object *bo = drm_gem_fb_get_obj(helper->fb, 0);
int npages;
/* DMM roll shifts in 4K pages: */
npages = fbi->fix.line_length >> PAGE_SHIFT;
omap_gem_roll(fbdev->bo, fbi->var.yoffset * npages);
omap_gem_roll(bo, fbi->var.yoffset * npages);
}
static int omap_fbdev_pan_display(struct fb_var_screeninfo *var,
......@@ -71,6 +74,25 @@ static int omap_fbdev_pan_display(struct fb_var_screeninfo *var,
return drm_fb_helper_pan_display(var, fbi);
}
static void omap_fbdev_fb_destroy(struct fb_info *info)
{
struct drm_fb_helper *helper = info->par;
struct drm_framebuffer *fb = helper->fb;
struct drm_gem_object *bo = drm_gem_fb_get_obj(fb, 0);
struct omap_fbdev *fbdev = to_omap_fbdev(helper);
DBG();
drm_fb_helper_fini(helper);
omap_gem_unpin(bo);
drm_framebuffer_remove(fb);
drm_client_release(&helper->client);
drm_fb_helper_unprepare(helper);
kfree(fbdev);
}
static const struct fb_ops omap_fb_ops = {
.owner = THIS_MODULE,
......@@ -86,6 +108,8 @@ static const struct fb_ops omap_fb_ops = {
.fb_fillrect = drm_fb_helper_sys_fillrect,
.fb_copyarea = drm_fb_helper_sys_copyarea,
.fb_imageblit = drm_fb_helper_sys_imageblit,
.fb_destroy = omap_fbdev_fb_destroy,
};
static int omap_fbdev_create(struct drm_fb_helper *helper,
......@@ -98,6 +122,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
union omap_gem_size gsize;
struct fb_info *fbi = NULL;
struct drm_mode_fb_cmd2 mode_cmd = {0};
struct drm_gem_object *bo;
dma_addr_t dma_addr;
int ret;
......@@ -128,20 +153,20 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
.bytes = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height),
};
DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index);
fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
if (!fbdev->bo) {
bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
if (!bo) {
dev_err(dev->dev, "failed to allocate buffer object\n");
ret = -ENOMEM;
goto fail;
}
fb = omap_framebuffer_init(dev, &mode_cmd, &fbdev->bo);
fb = omap_framebuffer_init(dev, &mode_cmd, &bo);
if (IS_ERR(fb)) {
dev_err(dev->dev, "failed to allocate fb\n");
/* note: if fb creation failed, we can't rely on fb destroy
* to unref the bo:
*/
drm_gem_object_put(fbdev->bo);
drm_gem_object_put(bo);
ret = PTR_ERR(fb);
goto fail;
}
......@@ -154,7 +179,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
* to it). Then we just need to be sure that we are able to re-
* pin it in case of an opps.
*/
ret = omap_gem_pin(fbdev->bo, &dma_addr);
ret = omap_gem_pin(bo, &dma_addr);
if (ret) {
dev_err(dev->dev, "could not pin framebuffer\n");
ret = -ENOMEM;
......@@ -170,17 +195,16 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
DBG("fbi=%p, dev=%p", fbi, dev);
fbdev->fb = fb;
helper->fb = fb;
fbi->fbops = &omap_fb_ops;
drm_fb_helper_fill_info(fbi, helper, sizes);
fbi->screen_buffer = omap_gem_vaddr(fbdev->bo);
fbi->screen_size = fbdev->bo->size;
fbi->screen_buffer = omap_gem_vaddr(bo);
fbi->screen_size = bo->size;
fbi->fix.smem_start = dma_addr;
fbi->fix.smem_len = fbdev->bo->size;
fbi->fix.smem_len = bo->size;
/* if we have DMM, then we can use it for scrolling by just
* shuffling pages around in DMM rather than doing sw blit.
......@@ -193,7 +217,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height);
DBG("allocated %dx%d fb", fb->width, fb->height);
return 0;
......@@ -220,75 +244,94 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi)
return fbi->par;
}
/* initialize fbdev helper */
void omap_fbdev_init(struct drm_device *dev)
/*
* struct drm_client
*/
static void omap_fbdev_client_unregister(struct drm_client_dev *client)
{
struct omap_drm_private *priv = dev->dev_private;
struct omap_fbdev *fbdev = NULL;
struct drm_fb_helper *helper;
int ret = 0;
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
if (!priv->num_pipes)
return;
if (fb_helper->info) {
drm_fb_helper_unregister_info(fb_helper);
} else {
drm_client_release(&fb_helper->client);
drm_fb_helper_unprepare(fb_helper);
kfree(fb_helper);
}
}
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
if (!fbdev)
return;
static int omap_fbdev_client_restore(struct drm_client_dev *client)
{
drm_fb_helper_lastclose(client->dev);
INIT_WORK(&fbdev->work, pan_worker);
return 0;
}
helper = &fbdev->base;
static int omap_fbdev_client_hotplug(struct drm_client_dev *client)
{
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
struct drm_device *dev = client->dev;
int ret;
drm_fb_helper_prepare(dev, helper, 32, &omap_fb_helper_funcs);
if (dev->fb_helper)
return drm_fb_helper_hotplug_event(dev->fb_helper);
ret = drm_fb_helper_init(dev, helper);
ret = drm_fb_helper_init(dev, fb_helper);
if (ret)
goto fail;
goto err_drm_err;
ret = drm_fb_helper_initial_config(helper);
ret = drm_fb_helper_initial_config(fb_helper);
if (ret)
goto fini;
goto err_drm_fb_helper_fini;
priv->fbdev = helper;
return;
fini:
drm_fb_helper_fini(helper);
fail:
drm_fb_helper_unprepare(helper);
kfree(fbdev);
return 0;
dev_warn(dev->dev, "omap_fbdev_init failed\n");
err_drm_fb_helper_fini:
drm_fb_helper_fini(fb_helper);
err_drm_err:
drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret);
return ret;
}
void omap_fbdev_fini(struct drm_device *dev)
static const struct drm_client_funcs omap_fbdev_client_funcs = {
.owner = THIS_MODULE,
.unregister = omap_fbdev_client_unregister,
.restore = omap_fbdev_client_restore,
.hotplug = omap_fbdev_client_hotplug,
};
void omap_fbdev_setup(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
struct drm_fb_helper *helper = priv->fbdev;
struct omap_fbdev *fbdev;
struct drm_fb_helper *helper;
int ret;
DBG();
drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
if (!helper)
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
if (!fbdev)
return;
helper = &fbdev->base;
drm_fb_helper_unregister_info(helper);
drm_fb_helper_prepare(dev, helper, 32, &omap_fb_helper_funcs);
drm_fb_helper_fini(helper);
ret = drm_client_init(dev, &helper->client, "fbdev", &omap_fbdev_client_funcs);
if (ret)
goto err_drm_client_init;
INIT_WORK(&fbdev->work, pan_worker);
fbdev = to_omap_fbdev(helper);
ret = omap_fbdev_client_hotplug(&helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
/* unpin the GEM object pinned in omap_fbdev_create() */
if (fbdev->bo)
omap_gem_unpin(fbdev->bo);
drm_client_register(&helper->client);
/* this will free the backing object */
if (fbdev->fb)
drm_framebuffer_remove(fbdev->fb);
return;
err_drm_client_init:
drm_fb_helper_unprepare(helper);
kfree(fbdev);
priv->fbdev = NULL;
}
......@@ -10,16 +10,11 @@
#define __OMAPDRM_FBDEV_H__
struct drm_device;
struct drm_fb_helper;
#ifdef CONFIG_DRM_FBDEV_EMULATION
void omap_fbdev_init(struct drm_device *dev);
void omap_fbdev_fini(struct drm_device *dev);
void omap_fbdev_setup(struct drm_device *dev);
#else
static inline void omap_fbdev_init(struct drm_device *dev)
{
}
static inline void omap_fbdev_fini(struct drm_device *dev)
static inline void omap_fbdev_setup(struct drm_device *dev)
{
}
#endif
......
......@@ -507,12 +507,19 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
{
struct drm_sched_entity *entity = sched_job->entity;
bool first;
ktime_t submit_ts;
trace_drm_sched_job(sched_job, entity);
atomic_inc(entity->rq->sched->score);
WRITE_ONCE(entity->last_user, current->group_leader);
/*
* After the sched_job is pushed into the entity queue, it may be
* completed and freed up at any time. We can no longer access it.
* Make sure to set the submit_ts first, to avoid a race.
*/
sched_job->submit_ts = submit_ts = ktime_get();
first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node);
sched_job->submit_ts = ktime_get();
/* first job wakes up scheduler */
if (first) {
......@@ -529,7 +536,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
spin_unlock(&entity->rq_lock);
if (drm_sched_policy == DRM_SCHED_POLICY_FIFO)
drm_sched_rq_update_fifo(entity, sched_job->submit_ts);
drm_sched_rq_update_fifo(entity, submit_ts);
drm_sched_wakeup(entity->rq->sched);
}
......
......@@ -57,8 +57,6 @@
V3D_INT_FLDONE | \
V3D_INT_FRDONE)
DECLARE_WAIT_QUEUE_HEAD(render_wait);
static void
vc4_overflow_mem_work(struct work_struct *work)
{
......
......@@ -4,21 +4,19 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
static void vkms_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}
static const struct drm_connector_funcs vkms_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = vkms_connector_destroy,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_encoder_funcs vkms_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
static int vkms_conn_get_modes(struct drm_connector *connector)
{
int count;
......@@ -91,7 +89,8 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_VIRTUAL);
ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs,
DRM_MODE_ENCODER_VIRTUAL, NULL);
if (ret) {
DRM_ERROR("Failed to init encoder\n");
goto err_encoder;
......
......@@ -132,7 +132,6 @@ static int vkms_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
plane);
struct drm_crtc_state *crtc_state;
bool can_position = false;
int ret;
if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
......@@ -143,20 +142,13 @@ static int vkms_plane_atomic_check(struct drm_plane *plane,
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
if (plane->type != DRM_PLANE_TYPE_PRIMARY)
can_position = true;
ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING,
can_position, true);
true, true);
if (ret != 0)
return ret;
/* for now primary plane must be visible and full screen */
if (!new_plane_state->visible && !can_position)
return -EINVAL;
return 0;
}
......
......@@ -45,6 +45,9 @@
#include <drm/ttm/ttm_placement.h>
#include <generated/utsrelease.h>
#ifdef CONFIG_X86
#include <asm/hypervisor.h>
#endif
#include <linux/cc_platform.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
......@@ -897,6 +900,16 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
cap2_names, ARRAY_SIZE(cap2_names));
}
if (!vmwgfx_supported(dev_priv)) {
vmw_disable_backdoor();
drm_err_once(&dev_priv->drm,
"vmwgfx seems to be running on an unsupported hypervisor.");
drm_err_once(&dev_priv->drm,
"This configuration is likely broken.");
drm_err_once(&dev_priv->drm,
"Please switch to a supported graphics device to avoid problems.");
}
ret = vmw_dma_select_mode(dev_priv);
if (unlikely(ret != 0)) {
drm_info(&dev_priv->drm,
......@@ -1320,6 +1333,22 @@ static void vmw_master_drop(struct drm_device *dev,
vmw_kms_legacy_hotspot_clear(dev_priv);
}
bool vmwgfx_supported(struct vmw_private *vmw)
{
#if defined(CONFIG_X86)
return hypervisor_is_type(X86_HYPER_VMWARE);
#elif defined(CONFIG_ARM64)
/*
* On aarch64 only svga3 is supported
*/
return vmw->pci_id == VMWGFX_PCI_ID_SVGA3;
#else
drm_warn_once(&vmw->drm,
"vmwgfx is running on an unknown architecture.");
return false;
#endif
}
/**
* __vmw_svga_enable - Enable SVGA mode, FIFO and use of VRAM.
*
......
......@@ -773,6 +773,7 @@ static inline u32 vmw_max_num_uavs(struct vmw_private *dev_priv)
extern void vmw_svga_enable(struct vmw_private *dev_priv);
extern void vmw_svga_disable(struct vmw_private *dev_priv);
bool vmwgfx_supported(struct vmw_private *vmw);
/**
......@@ -1358,6 +1359,7 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst,
struct vmw_diff_cpy *diff);
/* Host messaging -vmwgfx_msg.c: */
void vmw_disable_backdoor(void);
int vmw_host_get_guestinfo(const char *guest_info_param,
char *buffer, size_t *length);
__printf(1, 2) int vmw_host_printf(const char *fmt, ...);
......
......@@ -1396,70 +1396,10 @@ static void vmw_framebuffer_bo_destroy(struct drm_framebuffer *framebuffer)
kfree(vfbd);
}
static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer,
struct drm_file *file_priv,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned int num_clips)
{
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
struct vmw_framebuffer_bo *vfbd =
vmw_framebuffer_to_vfbd(framebuffer);
struct drm_clip_rect norect;
int ret, increment = 1;
drm_modeset_lock_all(&dev_priv->drm);
if (!num_clips) {
num_clips = 1;
clips = &norect;
norect.x1 = norect.y1 = 0;
norect.x2 = framebuffer->width;
norect.y2 = framebuffer->height;
} else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
num_clips /= 2;
increment = 2;
}
switch (dev_priv->active_display_unit) {
case vmw_du_legacy:
ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0,
clips, num_clips, increment);
break;
default:
ret = -EINVAL;
WARN_ONCE(true, "Dirty called with invalid display system.\n");
break;
}
vmw_cmd_flush(dev_priv, false);
drm_modeset_unlock_all(&dev_priv->drm);
return ret;
}
static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer,
struct drm_file *file_priv,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned int num_clips)
{
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
if (dev_priv->active_display_unit == vmw_du_legacy &&
vmw_cmd_supported(dev_priv))
return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags,
color, clips, num_clips);
return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color,
clips, num_clips);
}
static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = {
.create_handle = vmw_framebuffer_bo_create_handle,
.destroy = vmw_framebuffer_bo_destroy,
.dirty = vmw_framebuffer_bo_dirty_ext,
.dirty = drm_atomic_helper_dirtyfb,
};
/**
......
......@@ -507,11 +507,6 @@ void vmw_du_connector_destroy_state(struct drm_connector *connector,
*/
int vmw_kms_ldu_init_display(struct vmw_private *dev_priv);
int vmw_kms_ldu_close_display(struct vmw_private *dev_priv);
int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned int num_clips, int increment);
int vmw_kms_update_proxy(struct vmw_resource *res,
const struct drm_clip_rect *clips,
unsigned num_clips,
......
......@@ -275,6 +275,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
.atomic_duplicate_state = vmw_du_crtc_duplicate_state,
.atomic_destroy_state = vmw_du_crtc_destroy_state,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
};
......@@ -314,6 +315,12 @@ static const struct
drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = {
};
static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned int flags, unsigned int color,
struct drm_mode_rect *clips,
unsigned int num_clips);
/*
* Legacy Display Plane Functions
*/
......@@ -332,7 +339,6 @@ vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane,
struct drm_framebuffer *fb;
struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc;
ldu = vmw_crtc_to_ldu(crtc);
dev_priv = vmw_priv(plane->dev);
fb = new_state->fb;
......@@ -345,8 +351,31 @@ vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane,
vmw_ldu_del_active(dev_priv, ldu);
vmw_ldu_commit_list(dev_priv);
}
if (vfb && vmw_cmd_supported(dev_priv)) {
struct drm_mode_rect fb_rect = {
.x1 = 0,
.y1 = 0,
.x2 = vfb->base.width,
.y2 = vfb->base.height
};
struct drm_mode_rect *damage_rects = drm_plane_get_damage_clips(new_state);
u32 rect_count = drm_plane_get_damage_clips_count(new_state);
int ret;
if (!damage_rects) {
damage_rects = &fb_rect;
rect_count = 1;
}
ret = vmw_kms_ldu_do_bo_dirty(dev_priv, vfb, 0, 0, damage_rects, rect_count);
drm_WARN_ONCE(plane->dev, ret,
"vmw_kms_ldu_do_bo_dirty failed with: ret=%d\n", ret);
vmw_cmd_flush(dev_priv, false);
}
}
static const struct drm_plane_funcs vmw_ldu_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
......@@ -577,11 +606,11 @@ int vmw_kms_ldu_close_display(struct vmw_private *dev_priv)
}
int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,
static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned int num_clips, int increment)
struct drm_mode_rect *clips,
unsigned int num_clips)
{
size_t fifo_size;
int i;
......@@ -597,7 +626,7 @@ int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,
return -ENOMEM;
memset(cmd, 0, fifo_size);
for (i = 0; i < num_clips; i++, clips += increment) {
for (i = 0; i < num_clips; i++, clips++) {
cmd[i].header = SVGA_CMD_UPDATE;
cmd[i].body.x = clips->x1;
cmd[i].body.y = clips->y1;
......
......@@ -702,32 +702,6 @@ static inline void hypervisor_ppn_remove(PPN64 pfn)
/* Header to the text description of mksGuestStat instance descriptor */
#define MKSSTAT_KERNEL_DESCRIPTION "vmwgfx"
/**
* mksstat_init_record: Initializes an MKSGuestStatCounter-based record
* for the respective mksGuestStat index.
*
* @stat_idx: Index of the MKSGuestStatCounter-based mksGuestStat record.
* @pstat: Pointer to array of MKSGuestStatCounterTime.
* @pinfo: Pointer to array of MKSGuestStatInfoEntry.
* @pstrs: Pointer to current end of the name/description sequence.
* Return: Pointer to the new end of the names/description sequence.
*/
static inline char *mksstat_init_record(mksstat_kern_stats_t stat_idx,
MKSGuestStatCounterTime *pstat, MKSGuestStatInfoEntry *pinfo, char *pstrs)
{
char *const pstrd = pstrs + strlen(mksstat_kern_name_desc[stat_idx][0]) + 1;
strcpy(pstrs, mksstat_kern_name_desc[stat_idx][0]);
strcpy(pstrd, mksstat_kern_name_desc[stat_idx][1]);
pinfo[stat_idx].name.s = pstrs;
pinfo[stat_idx].description.s = pstrd;
pinfo[stat_idx].flags = MKS_GUEST_STAT_FLAG_NONE;
pinfo[stat_idx].stat.counter = (MKSGuestStatCounter *)&pstat[stat_idx];
return pstrd + strlen(mksstat_kern_name_desc[stat_idx][1]) + 1;
}
/**
* mksstat_init_record_time: Initializes an MKSGuestStatCounterTime-based record
* for the respective mksGuestStat index.
......@@ -1205,3 +1179,12 @@ int vmw_mksstat_remove_ioctl(struct drm_device *dev, void *data,
return -EAGAIN;
}
/**
* vmw_disable_backdoor: Disables all backdoor communication
* with the hypervisor.
*/
void vmw_disable_backdoor(void)
{
vmw_msg_enabled = 0;
}
......@@ -53,12 +53,6 @@ struct vmw_overlay {
struct vmw_stream stream[VMW_MAX_NUM_STREAMS];
};
static inline struct vmw_overlay *vmw_overlay(struct drm_device *dev)
{
struct vmw_private *dev_priv = vmw_priv(dev);
return dev_priv ? dev_priv->overlay_priv : NULL;
}
struct vmw_escape_header {
uint32_t cmd;
SVGAFifoCmdEscape body;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment