aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_fb_helper.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-08 08:23:15 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-08 08:23:15 -0800
commit851ca779d110f694b5d078bc4af06d3ad37169e8 (patch)
tree3d03de09e44ef02a6f73924f32fa21646347e64e /drivers/gpu/drm/drm_fb_helper.c
parentb5dd0c658c31b469ccff1b637e5124851e7a4a1c (diff)
parent4b057e73f28f1df13b77b77a52094238ffdf8abd (diff)
Merge tag 'drm-next-2019-03-06' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie: "This is the main drm pull request for the 5.1 merge window. The big changes I'd highlight are: - nouveau has HMM support now, there is finally an in-tree user so we can quieten down the rip it out people. - i915 now enables fastboot by default on Skylake+ - Displayport Multistream support has been refactored and should hopefully be more reliable. Core: - header cleanups aiming towards removing drmP.h - dma-buf fence seqnos to 64-bits - common helper for DP mst hotplug for radeon,i915,amdgpu + new refcounting scheme - MST i2c improvements - drm_syncobj_cb removal - ARM FB compression fourcc - P010 + P016 fourcc - allwinner tiled format modifier - i2c over aux I2C_M_STOP support - DRM_AUTH handling fixes TTM: - ref/unref renaming New driver: - ARM komeda display driver scheduler: - refactor mirror list handling - rework hw fence processing - 0 run queue entity fix bridge: - TI DS90C185 LVDS bridge - thc631lvdm83d bridge improvements - cadence + allwinner DSI ported to generic phy panels: - Sitronix ST7701 panel - Kingdisplay KD097D04 - LeMaker BL035-RGB-002 - PDA 91-00156-A0 - Innolux EE101IA-01D i915: - Enable fastboot by default on SKL+/VLV/CHV - Export RPCS configuration for ICL media driver - Coffelake PCI ID - CNL clocks setup fixes - ACPI/PMIC support for MIPI/DSI - Per-engine WA init for all engines - Shrinker locking fixes - Kerneldoc updates - Lots of ring improvements and reset fixes - Coffeelake GVT Support - VFIO GVT EDID Region support - runtime PM wakeref tracking - ILK->IVB primary plane enable delays - userptr mutex locking fixes - DSI fixes - LVDS/TV cleanups - HW readout fixes - LUT robustness fixes - ICL display and watermark fixes - gem mmap race fix amdgpu: - add scheduled dependencies interface - DCC on scanout surfaces - vega10/20 BACO support - Multiple IH rings on soc15 - XGMI locking fixes - DC i2c/aux cleanups - runtime SMU debug interface - Kexec improvmeents - SR-IOV fixes - DC freesync + ABM fixes - GDS fixes - GPUVM fixes - vega20 PCIE DPM switching fixes - Context priority handling fixes radeon: - fix missing break in evergreen parser nouveau: - SVM support via HMM msm: - QCOM Compressed modifier support exynos: - s5pv210 rotator support imx: - zpos property support - pending update fixes v3d: - cache flush improvments vc4: - reflection support - HDMI overscan support tegra: - CEC refactoring - HDMI audio fixes - Tegra186 prep work - SOR crossbar device tree fixes sun4i: - implicit fencing support - YUV and scalar support improvements - A23 support - tiling fixes atmel-hlcdc: - clipping and rotation property fixes qxl: - BO and PRIME improvements - generic fbdev emulation dw-hdmi: - HDMI 2.0 2160p - YUV420 ouput rockchip: - implicit fencing support - reflection proerties virtio-gpu: - use generic fbdev emulation tilcdc: - cpufreq vs crtc init fix rcar-du: - R8A774C0 support - D3/E3 RGB output routing fixes and DPAD0 support - RA87744 LVDS support bochs: - atomic and generic fbdev emulation - ID mismatch error on bochs load meson: - remove firmware fbs" * tag 'drm-next-2019-03-06' of git://anongit.freedesktop.org/drm/drm: (1130 commits) drm/amd/display: Use vrr friendly pageflip throttling in DC. drm/imx: only send commit done event when all state has been applied drm/imx: allow building under COMPILE_TEST drm/imx: imx-tve: depend on COMMON_CLK drm/imx: ipuv3-plane: add zpos property drm/imx: ipuv3-plane: add function to query atomic update status gpu: ipu-v3: prg: add function to get channel configure status gpu: ipu-v3: pre: add double buffer status readback drm/amdgpu: Bump amdgpu version for context priority override. drm/amdgpu/powerplay: fix typo in BACO header guards drm/amdgpu/powerplay: fix return codes in BACO code drm/amdgpu: add missing license on baco files drm/bochs: Fix the ID mismatch error drm/nouveau/dmem: use dma addresses during migration copies drm/nouveau/dmem: use physical vram addresses during migration copies drm/nouveau/dmem: extend copy function to allow direct use of physical addresses drm/nouveau/svm: new ioctl to migrate process memory to GPU memory drm/nouveau/dmem: device memory helpers for SVM drm/nouveau/svm: initial support for shared virtual memory drm/nouveau: prepare for enabling svm with existing userspace interfaces ...
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c171
1 files changed, 116 insertions, 55 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d73703a695e8..0e9349ff2d16 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1874,6 +1874,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int i;
struct drm_fb_helper_surface_size sizes;
int gamma_size = 0;
+ int best_depth = 0;
memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
sizes.surface_depth = 24;
@@ -1881,7 +1882,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
sizes.fb_width = (u32)-1;
sizes.fb_height = (u32)-1;
- /* if driver picks 8 or 16 by default use that for both depth/bpp */
+ /*
+ * If driver picks 8 or 16 by default use that for both depth/bpp
+ * to begin with
+ */
if (preferred_bpp != sizes.surface_bpp)
sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
@@ -1916,6 +1920,55 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
}
}
+ /*
+ * If we run into a situation where, for example, the primary plane
+ * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
+ * 16) we need to scale down the depth of the sizes we request.
+ */
+ for (i = 0; i < fb_helper->crtc_count; i++) {
+ struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+ struct drm_crtc *crtc = mode_set->crtc;
+ struct drm_plane *plane = crtc->primary;
+ int j;
+
+ DRM_DEBUG("test CRTC %d primary plane\n", i);
+
+ for (j = 0; j < plane->format_count; j++) {
+ const struct drm_format_info *fmt;
+
+ fmt = drm_format_info(plane->format_types[j]);
+
+ /*
+ * Do not consider YUV or other complicated formats
+ * for framebuffers. This means only legacy formats
+ * are supported (fmt->depth is a legacy field) but
+ * the framebuffer emulation can only deal with such
+ * formats, specifically RGB/BGA formats.
+ */
+ if (fmt->depth == 0)
+ continue;
+
+ /* We found a perfect fit, great */
+ if (fmt->depth == sizes.surface_depth) {
+ best_depth = fmt->depth;
+ break;
+ }
+
+ /* Skip depths above what we're looking for */
+ if (fmt->depth > sizes.surface_depth)
+ continue;
+
+ /* Best depth found so far */
+ if (fmt->depth > best_depth)
+ best_depth = fmt->depth;
+ }
+ }
+ if (sizes.surface_depth != best_depth) {
+ DRM_INFO("requested bpp %d, scaled depth down to %d",
+ sizes.surface_bpp, best_depth);
+ sizes.surface_depth = best_depth;
+ }
+
crtc_count = 0;
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_display_mode *desired_mode;
@@ -2455,7 +2508,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
/*
* This function checks if rotation is necessary because of panel orientation
* and if it is, if it is supported.
- * If rotation is necessary and supported, its gets set in fb_crtc.rotation.
+ * If rotation is necessary and supported, it gets set in fb_crtc.rotation.
* If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
* or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
* one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
@@ -2891,7 +2944,7 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
return 0;
err_drm_fb_helper_fini:
- drm_fb_helper_fini(fb_helper);
+ drm_fb_helper_fbdev_teardown(dev);
return ret;
}
@@ -2986,18 +3039,16 @@ static int drm_fbdev_fb_release(struct fb_info *info, int user)
return 0;
}
-/*
- * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
- * unregister_framebuffer() or fb_release().
- */
-static void drm_fbdev_fb_destroy(struct fb_info *info)
+static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
{
- struct drm_fb_helper *fb_helper = info->par;
struct fb_info *fbi = fb_helper->fbdev;
struct fb_ops *fbops = NULL;
void *shadow = NULL;
- if (fbi->fbdefio) {
+ if (!fb_helper->dev)
+ return;
+
+ if (fbi && fbi->fbdefio) {
fb_deferred_io_cleanup(fbi);
shadow = fbi->screen_buffer;
fbops = fbi->fbops;
@@ -3011,15 +3062,22 @@ static void drm_fbdev_fb_destroy(struct fb_info *info)
}
drm_client_framebuffer_delete(fb_helper->buffer);
- /*
- * FIXME:
- * Remove conditional when all CMA drivers have been moved over to using
- * drm_fbdev_generic_setup().
- */
- if (fb_helper->client.funcs) {
- drm_client_release(&fb_helper->client);
- kfree(fb_helper);
- }
+}
+
+static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
+{
+ drm_fbdev_cleanup(fb_helper);
+ drm_client_release(&fb_helper->client);
+ kfree(fb_helper);
+}
+
+/*
+ * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
+ * unregister_framebuffer() or fb_release().
+ */
+static void drm_fbdev_fb_destroy(struct fb_info *info)
+{
+ drm_fbdev_release(info->par);
}
static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
@@ -3072,7 +3130,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
struct drm_framebuffer *fb;
struct fb_info *fbi;
u32 format;
- int ret;
DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
sizes->surface_width, sizes->surface_height,
@@ -3089,10 +3146,8 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
fb = buffer->fb;
fbi = drm_fb_helper_alloc_fbi(fb_helper);
- if (IS_ERR(fbi)) {
- ret = PTR_ERR(fbi);
- goto err_free_buffer;
- }
+ if (IS_ERR(fbi))
+ return PTR_ERR(fbi);
fbi->par = fb_helper;
fbi->fbops = &drm_fbdev_fb_ops;
@@ -3123,8 +3178,7 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
if (!fbops || !shadow) {
kfree(fbops);
vfree(shadow);
- ret = -ENOMEM;
- goto err_fb_info_destroy;
+ return -ENOMEM;
}
*fbops = *fbi->fbops;
@@ -3136,13 +3190,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
}
return 0;
-
-err_fb_info_destroy:
- drm_fb_helper_fini(fb_helper);
-err_free_buffer:
- drm_client_framebuffer_delete(buffer);
-
- return ret;
}
EXPORT_SYMBOL(drm_fb_helper_generic_probe);
@@ -3154,25 +3201,16 @@ static void drm_fbdev_client_unregister(struct drm_client_dev *client)
{
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
- if (fb_helper->fbdev) {
- drm_fb_helper_unregister_fbi(fb_helper);
+ if (fb_helper->fbdev)
/* drm_fbdev_fb_destroy() takes care of cleanup */
- return;
- }
-
- /* Did drm_fb_helper_fbdev_setup() run? */
- if (fb_helper->dev)
- drm_fb_helper_fini(fb_helper);
-
- drm_client_release(client);
- kfree(fb_helper);
+ drm_fb_helper_unregister_fbi(fb_helper);
+ else
+ drm_fbdev_release(fb_helper);
}
static int drm_fbdev_client_restore(struct drm_client_dev *client)
{
- struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
-
- drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
+ drm_fb_helper_lastclose(client->dev);
return 0;
}
@@ -3183,7 +3221,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
struct drm_device *dev = client->dev;
int ret;
- /* If drm_fb_helper_fbdev_setup() failed, we only try once */
+ /* Setup is not retried if it has failed */
if (!fb_helper->dev && fb_helper->funcs)
return 0;
@@ -3195,15 +3233,34 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
return 0;
}
- ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_helper_generic_funcs,
- fb_helper->preferred_bpp, 0);
- if (ret) {
- fb_helper->dev = NULL;
- fb_helper->fbdev = NULL;
- return ret;
- }
+ drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
+
+ ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector);
+ if (ret)
+ goto err;
+
+ ret = drm_fb_helper_single_add_all_connectors(fb_helper);
+ if (ret)
+ goto err_cleanup;
+
+ if (!drm_drv_uses_atomic_modeset(dev))
+ drm_helper_disable_unused_functions(dev);
+
+ ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
+ if (ret)
+ goto err_cleanup;
return 0;
+
+err_cleanup:
+ drm_fbdev_cleanup(fb_helper);
+err:
+ fb_helper->dev = NULL;
+ fb_helper->fbdev = NULL;
+
+ DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
+
+ return ret;
}
static const struct drm_client_funcs drm_fbdev_client_funcs = {
@@ -3262,6 +3319,10 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
drm_client_add(&fb_helper->client);
+ if (!preferred_bpp)
+ preferred_bpp = dev->mode_config.preferred_depth;
+ if (!preferred_bpp)
+ preferred_bpp = 32;
fb_helper->preferred_bpp = preferred_bpp;
ret = drm_fbdev_client_hotplug(&fb_helper->client);