We'll want to extend this a bit to handle also a reserved-memory ("stolen") region, so that drm/msm can take-over bootloader splash screen. First split it out into it's own fxn to reduce noise in the following patch.
Signed-off-by: Rob Clark robdclark@gmail.com --- drivers/gpu/drm/msm/msm_drv.c | 58 +++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index a426911..b250610 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -182,29 +182,9 @@ static int get_mdp_ver(struct platform_device *pdev) return 4; }
-static int msm_load(struct drm_device *dev, unsigned long flags) +static int msm_init_vram(struct drm_device *dev) { - struct platform_device *pdev = dev->platformdev; - struct msm_drm_private *priv; - struct msm_kms *kms; - int ret; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(dev->dev, "failed to allocate private data\n"); - return -ENOMEM; - } - - dev->dev_private = priv; - - priv->wq = alloc_ordered_workqueue("msm", 0); - init_waitqueue_head(&priv->fence_event); - init_waitqueue_head(&priv->pending_crtcs_event); - - INIT_LIST_HEAD(&priv->inactive_list); - INIT_LIST_HEAD(&priv->fence_cbs); - - drm_mode_config_init(dev); + struct msm_drm_private *priv = dev->dev_private;
/* if we have no IOMMU, then we need to use carveout allocator. * Grab the entire CMA chunk carved out in early startup in @@ -232,8 +212,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) if (!p) { dev_err(dev->dev, "failed to allocate VRAM\n"); priv->vram.paddr = 0; - ret = -ENOMEM; - goto fail; + return -ENOMEM; }
dev_info(dev->dev, "VRAM: %08x->%08x\n", @@ -241,6 +220,37 @@ static int msm_load(struct drm_device *dev, unsigned long flags) (uint32_t)(priv->vram.paddr + size)); }
+ return 0; +} + +static int msm_load(struct drm_device *dev, unsigned long flags) +{ + struct platform_device *pdev = dev->platformdev; + struct msm_drm_private *priv; + struct msm_kms *kms; + int ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(dev->dev, "failed to allocate private data\n"); + return -ENOMEM; + } + + dev->dev_private = priv; + + priv->wq = alloc_ordered_workqueue("msm", 0); + init_waitqueue_head(&priv->fence_event); + init_waitqueue_head(&priv->pending_crtcs_event); + + INIT_LIST_HEAD(&priv->inactive_list); + INIT_LIST_HEAD(&priv->fence_cbs); + + drm_mode_config_init(dev); + + ret = msm_init_vram(dev); + if (ret) + goto fail; + platform_set_drvdata(pdev, dev);
/* Bind all our sub-components: */
Add support to use the VRAM carveout (if specified in dtb) for fbdev scanout buffer. This allows drm/msm to take over a bootloader splash- screen, and avoids corruption on screen that results if the kernel uses memory that is still being scanned out for itself.
Signed-off-by: Rob Clark robdclark@gmail.com --- drivers/gpu/drm/msm/msm_drv.c | 44 +++++++++++++++++++++++++++++++++++++---- drivers/gpu/drm/msm/msm_fbdev.c | 3 ++- drivers/gpu/drm/msm/msm_gem.c | 25 ++++++++++++++++++----- drivers/gpu/drm/msm/msm_gem.h | 5 ++++- 4 files changed, 66 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index b250610..0c38f34 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -182,21 +182,57 @@ static int get_mdp_ver(struct platform_device *pdev) return 4; }
+#include <linux/of_address.h> + static int msm_init_vram(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; + unsigned long size = 0; + int ret = 0; + +#ifdef CONFIG_OF + /* In the device-tree world, we could have a 'memory-region' + * phandle, which gives us a link to our "vram". Allocating + * is all nicely abstracted behind the dma api, but we need + * to know the entire size to allocate it all in one go. There + * are two cases: + * 1) device with no IOMMU, in which case we need exclusive + * access to a VRAM carveout big enough for all gpu + * buffers + * 2) device with IOMMU, but where the bootloader puts up + * a splash screen. In this case, the VRAM carveout + * need only be large enough for fbdev fb. But we need + * exclusive access to the buffer to avoid the kernel + * using those pages for other purposes (which appears + * as corruption on screen before we have a chance to + * load and do initial modeset) + */ + struct device_node *node; + + node = of_parse_phandle(dev->dev->of_node, "memory-region", 0); + if (node) { + struct resource r; + ret = of_address_to_resource(node, 0, &r); + if (ret) + return ret; + size = r.end - r.start; + DRM_INFO("using VRAM carveout: %lx@%08x\n", size, r.start); + } else +#endif
/* if we have no IOMMU, then we need to use carveout allocator. * Grab the entire CMA chunk carved out in early startup in * mach-msm: */ if (!iommu_present(&platform_bus_type)) { + DRM_INFO("using %s VRAM carveout\n", vram); + size = memparse(vram, NULL); + } + + if (size) { DEFINE_DMA_ATTRS(attrs); - unsigned long size; void *p;
- DBG("using %s VRAM carveout", vram); - size = memparse(vram, NULL); priv->vram.size = size;
drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1); @@ -220,7 +256,7 @@ static int msm_init_vram(struct drm_device *dev) (uint32_t)(priv->vram.paddr + size)); }
- return 0; + return ret; }
static int msm_load(struct drm_device *dev, unsigned long flags) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index df60f65..95f6532 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -110,7 +110,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, size = mode_cmd.pitches[0] * mode_cmd.height; DBG("allocating %d bytes for fb %d", size, dev->primary->index); mutex_lock(&dev->struct_mutex); - fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC); + fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | + MSM_BO_WC | MSM_BO_STOLEN); mutex_unlock(&dev->struct_mutex); if (IS_ERR(fbdev->bo)) { ret = PTR_ERR(fbdev->bo); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 49dea4f..479d8af 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -32,6 +32,12 @@ static dma_addr_t physaddr(struct drm_gem_object *obj) priv->vram.paddr; }
+static bool use_pages(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + return !msm_obj->vram_node; +} + /* allocate pages from VRAM carveout, used when no IOMMU: */ static struct page **get_pages_vram(struct drm_gem_object *obj, int npages) @@ -72,7 +78,7 @@ static struct page **get_pages(struct drm_gem_object *obj) struct page **p; int npages = obj->size >> PAGE_SHIFT;
- if (iommu_present(&platform_bus_type)) + if (use_pages(obj)) p = drm_gem_get_pages(obj); else p = get_pages_vram(obj, npages); @@ -116,7 +122,7 @@ static void put_pages(struct drm_gem_object *obj) sg_free_table(msm_obj->sgt); kfree(msm_obj->sgt);
- if (iommu_present(&platform_bus_type)) + if (use_pages(obj)) drm_gem_put_pages(obj, msm_obj->pages, true, false); else { drm_mm_remove_node(msm_obj->vram_node); @@ -580,6 +586,7 @@ static int msm_gem_new_impl(struct drm_device *dev, struct msm_drm_private *priv = dev->dev_private; struct msm_gem_object *msm_obj; unsigned sz; + bool use_vram = false;
switch (flags & MSM_BO_CACHE_MASK) { case MSM_BO_UNCACHED: @@ -592,15 +599,23 @@ static int msm_gem_new_impl(struct drm_device *dev, return -EINVAL; }
- sz = sizeof(*msm_obj); if (!iommu_present(&platform_bus_type)) + use_vram = true; + else if ((flags & MSM_BO_STOLEN) && priv->vram.size) + use_vram = true; + + if (WARN_ON(use_vram && !priv->vram.size)) + return -EINVAL; + + sz = sizeof(*msm_obj); + if (use_vram) sz += sizeof(struct drm_mm_node);
msm_obj = kzalloc(sz, GFP_KERNEL); if (!msm_obj) return -ENOMEM;
- if (!iommu_present(&platform_bus_type)) + if (use_vram) msm_obj->vram_node = (void *)&msm_obj[1];
msm_obj->flags = flags; @@ -630,7 +645,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, if (ret) goto fail;
- if (iommu_present(&platform_bus_type)) { + if (use_pages(obj)) { ret = drm_gem_object_init(dev, obj, size); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 8fbbd05..85d481e 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -21,6 +21,9 @@ #include <linux/reservation.h> #include "msm_drv.h"
+/* Additional internal-use only BO flags: */ +#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ + struct msm_gem_object { struct drm_gem_object base;
@@ -59,7 +62,7 @@ struct msm_gem_object { struct reservation_object _resv;
/* For physically contiguous buffers. Used when we don't have - * an IOMMU. + * an IOMMU. Also used for stolen/splashscreen buffer. */ struct drm_mm_node *vram_node; };
Add a reserved-memory region for bootloader splashscreen, and assign it to the display device, so that drm/msm can take over the bootloader's splashscreen.
Signed-off-by: Rob Clark robdclark@gmail.com --- arch/arm/boot/dts/qcom-apq8064-ifc6410.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts index 416f3f5..0928129 100644 --- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts +++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts @@ -15,6 +15,16 @@ 0x90000000 0x70000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + splashmem: framebuffer@90000000 { + reg = <0x90000000 0x800000>; + }; + }; + aliases { serial0 = &serial0; serial1 = &serial1; @@ -183,5 +193,9 @@
}; }; + + mdp: qcom,mdp@5100000 { + memory-region = <&splashmem>; + }; }; };
On 3 March 2015 at 20:04, Rob Clark robdclark@gmail.com wrote:
Add a reserved-memory region for bootloader splashscreen, and assign it to the display device, so that drm/msm can take over the bootloader's splashscreen.
Hi Rob,
Rather silly question - does the bootloader always use/preserve the same amount of memory regardless of the display's resolution & bpp ? If not would this patch work in such cases ?
Cheers Emil
On Wed, Mar 4, 2015 at 6:10 PM, Emil Velikov emil.l.velikov@gmail.com wrote:
On 3 March 2015 at 20:04, Rob Clark robdclark@gmail.com wrote:
Add a reserved-memory region for bootloader splashscreen, and assign it to the display device, so that drm/msm can take over the bootloader's splashscreen.
Hi Rob,
Rather silly question - does the bootloader always use/preserve the same amount of memory regardless of the display's resolution & bpp ? If not would this patch work in such cases ?
In most cases, the bootloader puts up a splash screen on built-in lcd panel, which sort of makes the problem easier (fixed resolution). For external display, I think you just have to size it for worst-case (largest) resolution.
(ofc it is RFC since I was hoping to get comments if anyone has better suggestions.. probably should have cc'd more people ;-))
BR, -R
Cheers Emil
On 4 March 2015 at 23:19, Rob Clark robdclark@gmail.com wrote:
On Wed, Mar 4, 2015 at 6:10 PM, Emil Velikov emil.l.velikov@gmail.com wrote:
On 3 March 2015 at 20:04, Rob Clark robdclark@gmail.com wrote:
Add a reserved-memory region for bootloader splashscreen, and assign it to the display device, so that drm/msm can take over the bootloader's splashscreen.
Hi Rob,
Rather silly question - does the bootloader always use/preserve the same amount of memory regardless of the display's resolution & bpp ? If not would this patch work in such cases ?
In most cases, the bootloader puts up a splash screen on built-in lcd panel, which sort of makes the problem easier (fixed resolution). For external display, I think you just have to size it for worst-case (largest) resolution.
(ofc it is RFC since I was hoping to get comments if anyone has better suggestions.. probably should have cc'd more people ;-))
I believe that Intel managed to get flicker-free boot. iirc Jess Barnes was one of the people working on it. That said I'm not sure how much of their work is applicable in non-x86 land :-\
-Emil
dri-devel@lists.freedesktop.org