Skip to content

Commit 072f1f9

Browse files
committed
drm/msm: add support for "stolen" mem
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>
1 parent 5bf9c0b commit 072f1f9

File tree

4 files changed

+66
-11
lines changed

4 files changed

+66
-11
lines changed

drivers/gpu/drm/msm/msm_drv.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,21 +182,57 @@ static int get_mdp_ver(struct platform_device *pdev)
182182
return 4;
183183
}
184184

185+
#include <linux/of_address.h>
186+
185187
static int msm_init_vram(struct drm_device *dev)
186188
{
187189
struct msm_drm_private *priv = dev->dev_private;
190+
unsigned long size = 0;
191+
int ret = 0;
192+
193+
#ifdef CONFIG_OF
194+
/* In the device-tree world, we could have a 'memory-region'
195+
* phandle, which gives us a link to our "vram". Allocating
196+
* is all nicely abstracted behind the dma api, but we need
197+
* to know the entire size to allocate it all in one go. There
198+
* are two cases:
199+
* 1) device with no IOMMU, in which case we need exclusive
200+
* access to a VRAM carveout big enough for all gpu
201+
* buffers
202+
* 2) device with IOMMU, but where the bootloader puts up
203+
* a splash screen. In this case, the VRAM carveout
204+
* need only be large enough for fbdev fb. But we need
205+
* exclusive access to the buffer to avoid the kernel
206+
* using those pages for other purposes (which appears
207+
* as corruption on screen before we have a chance to
208+
* load and do initial modeset)
209+
*/
210+
struct device_node *node;
211+
212+
node = of_parse_phandle(dev->dev->of_node, "memory-region", 0);
213+
if (node) {
214+
struct resource r;
215+
ret = of_address_to_resource(node, 0, &r);
216+
if (ret)
217+
return ret;
218+
size = r.end - r.start;
219+
DRM_INFO("using VRAM carveout: %lx@%08x\n", size, r.start);
220+
} else
221+
#endif
188222

189223
/* if we have no IOMMU, then we need to use carveout allocator.
190224
* Grab the entire CMA chunk carved out in early startup in
191225
* mach-msm:
192226
*/
193227
if (!iommu_present(&platform_bus_type)) {
228+
DRM_INFO("using %s VRAM carveout\n", vram);
229+
size = memparse(vram, NULL);
230+
}
231+
232+
if (size) {
194233
DEFINE_DMA_ATTRS(attrs);
195-
unsigned long size;
196234
void *p;
197235

198-
DBG("using %s VRAM carveout", vram);
199-
size = memparse(vram, NULL);
200236
priv->vram.size = size;
201237

202238
drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
@@ -220,7 +256,7 @@ static int msm_init_vram(struct drm_device *dev)
220256
(uint32_t)(priv->vram.paddr + size));
221257
}
222258

223-
return 0;
259+
return ret;
224260
}
225261

226262
static int msm_load(struct drm_device *dev, unsigned long flags)

drivers/gpu/drm/msm/msm_fbdev.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
110110
size = mode_cmd.pitches[0] * mode_cmd.height;
111111
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
112112
mutex_lock(&dev->struct_mutex);
113-
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
113+
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT |
114+
MSM_BO_WC | MSM_BO_STOLEN);
114115
mutex_unlock(&dev->struct_mutex);
115116
if (IS_ERR(fbdev->bo)) {
116117
ret = PTR_ERR(fbdev->bo);

drivers/gpu/drm/msm/msm_gem.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ static dma_addr_t physaddr(struct drm_gem_object *obj)
3232
priv->vram.paddr;
3333
}
3434

35+
static bool use_pages(struct drm_gem_object *obj)
36+
{
37+
struct msm_gem_object *msm_obj = to_msm_bo(obj);
38+
return !msm_obj->vram_node;
39+
}
40+
3541
/* allocate pages from VRAM carveout, used when no IOMMU: */
3642
static struct page **get_pages_vram(struct drm_gem_object *obj,
3743
int npages)
@@ -72,7 +78,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
7278
struct page **p;
7379
int npages = obj->size >> PAGE_SHIFT;
7480

75-
if (iommu_present(&platform_bus_type))
81+
if (use_pages(obj))
7682
p = drm_gem_get_pages(obj);
7783
else
7884
p = get_pages_vram(obj, npages);
@@ -116,7 +122,7 @@ static void put_pages(struct drm_gem_object *obj)
116122
sg_free_table(msm_obj->sgt);
117123
kfree(msm_obj->sgt);
118124

119-
if (iommu_present(&platform_bus_type))
125+
if (use_pages(obj))
120126
drm_gem_put_pages(obj, msm_obj->pages, true, false);
121127
else {
122128
drm_mm_remove_node(msm_obj->vram_node);
@@ -580,6 +586,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
580586
struct msm_drm_private *priv = dev->dev_private;
581587
struct msm_gem_object *msm_obj;
582588
unsigned sz;
589+
bool use_vram = false;
583590

584591
switch (flags & MSM_BO_CACHE_MASK) {
585592
case MSM_BO_UNCACHED:
@@ -592,15 +599,23 @@ static int msm_gem_new_impl(struct drm_device *dev,
592599
return -EINVAL;
593600
}
594601

595-
sz = sizeof(*msm_obj);
596602
if (!iommu_present(&platform_bus_type))
603+
use_vram = true;
604+
else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
605+
use_vram = true;
606+
607+
if (WARN_ON(use_vram && !priv->vram.size))
608+
return -EINVAL;
609+
610+
sz = sizeof(*msm_obj);
611+
if (use_vram)
597612
sz += sizeof(struct drm_mm_node);
598613

599614
msm_obj = kzalloc(sz, GFP_KERNEL);
600615
if (!msm_obj)
601616
return -ENOMEM;
602617

603-
if (!iommu_present(&platform_bus_type))
618+
if (use_vram)
604619
msm_obj->vram_node = (void *)&msm_obj[1];
605620

606621
msm_obj->flags = flags;
@@ -630,7 +645,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
630645
if (ret)
631646
goto fail;
632647

633-
if (iommu_present(&platform_bus_type)) {
648+
if (use_pages(obj)) {
634649
ret = drm_gem_object_init(dev, obj, size);
635650
if (ret)
636651
goto fail;

drivers/gpu/drm/msm/msm_gem.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#include <linux/reservation.h>
2222
#include "msm_drv.h"
2323

24+
/* Additional internal-use only BO flags: */
25+
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
26+
2427
struct msm_gem_object {
2528
struct drm_gem_object base;
2629

@@ -59,7 +62,7 @@ struct msm_gem_object {
5962
struct reservation_object _resv;
6063

6164
/* For physically contiguous buffers. Used when we don't have
62-
* an IOMMU.
65+
* an IOMMU. Also used for stolen/splashscreen buffer.
6366
*/
6467
struct drm_mm_node *vram_node;
6568
};

0 commit comments

Comments
 (0)