diff options
108 files changed, 1331 insertions, 191 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a465d5242774..88561b3ce28a 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3777,12 +3777,15 @@ shutdown the other cpus. Instead use the REBOOT_VECTOR irq. - nomodeset Disable kernel modesetting. DRM drivers will not perform - display-mode changes or accelerated rendering. Only the - system framebuffer will be available for use if this was - set-up by the firmware or boot loader. - - Useful as fallback, or for testing and debugging. + nomodeset Disable kernel modesetting. Most systems' firmware + sets up a display mode and provides framebuffer memory + for output. With nomodeset, DRM and fbdev drivers will + not load if they could possibly displace the pre- + initialized output. Only the system framebuffer will + be available for use. The respective drivers will not + perform display-mode changes or accelerated rendering. + + Useful as error fallback, or for testing and debugging. nomodule Disable module load diff --git a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml new file mode 100644 index 000000000000..116c1b6030a2 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/newvision,nv3051d.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NewVision NV3051D based LCD panel + +description: | + The NewVision NV3051D is a driver chip used to drive DSI panels. For now, + this driver only supports the 640x480 panels found in the Anbernic RG353 + based devices. + +maintainers: + - Chris Morgan <macromorgan@hotmail.com> + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - enum: + - anbernic,rg353p-panel + - anbernic,rg353v-panel + - const: newvision,nv3051d + + reg: true + backlight: true + port: true + reset-gpios: + description: Active low reset GPIO + vdd-supply: true + +required: + - compatible + - reg + - backlight + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + dsi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "anbernic,rg353p-panel", "newvision,nv3051d"; + reg = <0>; + backlight = <&backlight>; + reset-gpios = <&gpio4 0 GPIO_ACTIVE_LOW>; + vdd-supply = <&vcc3v3_lcd>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index c2c615cb0f48..592e43911a07 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -887,6 +887,8 @@ patternProperties: description: Shenzhen Netxeon Technology CO., LTD "^neweast,.*": description: Guangdong Neweast Optoelectronics CO., LTD + "^newvision,.*": + description: New Vision Display (Shenzhen) Co., Ltd. "^nexbox,.*": description: Nexbox "^nextthing,.*": diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 4d2411e32ebb..e53375033146 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -26,6 +26,11 @@ Valid mode specifiers (mode_option argument):: with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string. Things between square brackets are optional. +Valid names are:: + + - NSTC: 480i output, with the CCIR System-M TV mode and NTSC color encoding + - PAL: 576i output, with the CCIR System-B TV mode and PAL color encoding + If 'M' is specified in the mode_option argument (after <yres> and before <bpp> and <refresh>, if specified) the timings will be calculated using VESA(TM) Coordinated Video Timings instead of looking up the mode from a table. diff --git a/MAINTAINERS b/MAINTAINERS index 178a7a383b5f..7dc3b719b2a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6701,8 +6701,10 @@ F: drivers/gpu/drm/drm_aperture.c F: drivers/gpu/drm/tiny/ofdrm.c F: drivers/gpu/drm/tiny/simpledrm.c F: drivers/video/aperture.c +F: drivers/video/nomodeset.c F: include/drm/drm_aperture.h F: include/linux/aperture.h +F: include/video/nomodeset.h DRM DRIVER FOR SIS VIDEO CARDS S: Orphan / Obsolete diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 13bfd2d09c56..b809513b03fe 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -129,6 +129,7 @@ static struct file_system_type dma_buf_fs_type = { static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) { struct dma_buf *dmabuf; + int ret; if (!is_dma_buf_file(file)) return -EINVAL; @@ -144,7 +145,11 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) dmabuf->size >> PAGE_SHIFT) return -EINVAL; - return dmabuf->ops->mmap(dmabuf, vma); + dma_resv_lock(dmabuf->resv, NULL); + ret = dmabuf->ops->mmap(dmabuf, vma); + dma_resv_unlock(dmabuf->resv); + + return ret; } static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence) diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 28fb04eccdd0..1131fb943992 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -13,6 +13,7 @@ #include <linux/dma-buf.h> #include <linux/dma-heap.h> #include <linux/dma-map-ops.h> +#include <linux/dma-resv.h> #include <linux/err.h> #include <linux/highmem.h> #include <linux/io.h> @@ -182,6 +183,8 @@ static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) { struct cma_heap_buffer *buffer = dmabuf->priv; + dma_resv_assert_held(dmabuf->resv); + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) return -EINVAL; diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index fcf836ba9c1f..e8bd10e60998 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -13,6 +13,7 @@ #include <linux/dma-buf.h> #include <linux/dma-mapping.h> #include <linux/dma-heap.h> +#include <linux/dma-resv.h> #include <linux/err.h> #include <linux/highmem.h> #include <linux/mm.h> @@ -201,6 +202,8 @@ static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) struct sg_page_iter piter; int ret; + dma_resv_assert_held(dmabuf->resv); + for_each_sgtable_page(table, &piter, vma->vm_pgoff) { struct page *page = sg_page_iter_page(&piter); diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 2bcdb935a3ac..283816fbd72f 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -2,6 +2,7 @@ #include <linux/cred.h> #include <linux/device.h> #include <linux/dma-buf.h> +#include <linux/dma-resv.h> #include <linux/highmem.h> #include <linux/init.h> #include <linux/kernel.h> @@ -49,6 +50,8 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) { struct udmabuf *ubuf = buf->priv; + dma_resv_assert_held(buf->resv); + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) return -EINVAL; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 34f5a092c99e..722ded626399 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -8,7 +8,6 @@ menuconfig DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA - select DRM_NOMODESET select DRM_PANEL_ORIENTATION_QUIRKS select HDMI select FB_CMDLINE @@ -19,6 +18,7 @@ menuconfig DRM # gallium uses SYS_kcmp for os_same_file_description() to de-duplicate # device and dmabuf fd. Let's make sure that is available for our userspace. select KCMP + select VIDEO_NOMODESET help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select @@ -514,11 +514,6 @@ config DRM_EXPORT_FOR_TESTS config DRM_PANEL_ORIENTATION_QUIRKS tristate -# Separate option because nomodeset parameter is global and expected built-in -config DRM_NOMODESET - bool - default n - config DRM_LIB_RANDOM bool default n diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index c44a54cadb61..f92cd7892711 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -72,7 +72,6 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \ drm_privacy_screen_x86.o obj-$(CONFIG_DRM) += drm.o -obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o # diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 962730772b2f..dc01c43f6193 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -514,7 +514,6 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc) } static const struct drm_crtc_funcs malidp_crtc_funcs = { - .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .reset = malidp_crtc_reset, @@ -526,7 +525,7 @@ static const struct drm_crtc_funcs malidp_crtc_funcs = { int malidp_crtc_init(struct drm_device *drm) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct drm_plane *primary = NULL, *plane; int ret; @@ -548,8 +547,8 @@ int malidp_crtc_init(struct drm_device *drm) return -EINVAL; } - ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL, - &malidp_crtc_funcs, NULL); + ret = drmm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL, + &malidp_crtc_funcs, NULL); if (ret) return ret; diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index b734dbdcc577..589c1c66a6dc 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -23,6 +23,7 @@ #include <drm/drm_fourcc.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_managed.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> @@ -168,7 +169,7 @@ static void malidp_atomic_commit_se_config(struct drm_crtc *crtc, */ static int malidp_set_and_wait_config_valid(struct drm_device *drm) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; int ret; @@ -189,7 +190,7 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm) static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) { struct drm_device *drm = state->dev; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); int loop = 5; malidp->event = malidp->crtc.state->event; @@ -230,7 +231,7 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) static void malidp_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *drm = state->dev; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int i; @@ -392,10 +393,12 @@ static const struct drm_mode_config_funcs malidp_mode_config_funcs = { static int malidp_init(struct drm_device *drm) { int ret; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; - drm_mode_config_init(drm); + ret = drmm_mode_config_init(drm); + if (ret) + goto out; drm->mode_config.min_width = hwdev->min_line_size; drm->mode_config.min_height = hwdev->min_line_size; @@ -406,29 +409,21 @@ static int malidp_init(struct drm_device *drm) ret = malidp_crtc_init(drm); if (ret) - goto crtc_fail; + goto out; ret = malidp_mw_connector_init(drm); if (ret) - goto crtc_fail; - - return 0; + goto out; -crtc_fail: - drm_mode_config_cleanup(drm); +out: return ret; } -static void malidp_fini(struct drm_device *drm) -{ - drm_mode_config_cleanup(drm); -} - static int malidp_irq_init(struct platform_device *pdev) { int irq_de, irq_se, ret = 0; struct drm_device *drm = dev_get_drvdata(&pdev->dev); - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; /* fetch the interrupts from DT */ @@ -462,7 +457,7 @@ static int malidp_dumb_create(struct drm_file *file_priv, struct drm_device *drm, struct drm_mode_create_dumb *args) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); /* allocate for the worst case scenario, i.e. rotated buffers */ u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 1); @@ -508,7 +503,7 @@ static void malidp_error_stats_dump(const char *prefix, static int malidp_show_stats(struct seq_file *m, void *arg) { struct drm_device *drm = m->private; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); unsigned long irqflags; struct malidp_error_stats de_errors, se_errors; @@ -531,7 +526,7 @@ static ssize_t malidp_debugfs_write(struct file *file, const char __user *ubuf, { struct seq_file *m = file->private_data; struct drm_device *drm = m->private; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); unsigned long irqflags; spin_lock_irqsave(&malidp->errors_lock, irqflags); @@ -552,7 +547,7 @@ static const struct file_operations malidp_debugfs_fops = { static void malidp_debugfs_init(struct drm_minor *minor) { - struct malidp_drm *malidp = minor->dev->dev_private; + struct malidp_drm *malidp = drm_to_malidp(minor->dev); malidp_error_stats_init(&malidp->de_errors); malidp_error_stats_init(&malidp->se_errors); @@ -652,7 +647,7 @@ static ssize_t core_id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *drm = dev_get_drvdata(dev); - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); return snprintf(buf, PAGE_SIZE, "%08x\n", malidp->core_id); } @@ -670,7 +665,7 @@ ATTRIBUTE_GROUPS(mali_dp); static int malidp_runtime_pm_suspend(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; /* we can only suspend if the hardware is in config mode */ @@ -689,7 +684,7 @@ static int malidp_runtime_pm_suspend(struct device *dev) static int malidp_runtime_pm_resume(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; clk_prepare_enable(hwdev->pclk); @@ -716,11 +711,13 @@ static int malidp_bind(struct device *dev) int ret = 0, i; u32 version, out_depth = 0; - malidp = devm_kzalloc(dev, sizeof(*malidp), GFP_KERNEL); - if (!malidp) - return -ENOMEM; + malidp = devm_drm_dev_alloc(dev, &malidp_driver, typeof(*malidp), base); + if (IS_ERR(malidp)) + return PTR_ERR(malidp); + + drm = &malidp->base; - hwdev = devm_kzalloc(dev, sizeof(*hwdev), GFP_KERNEL); + hwdev = drmm_kzalloc(drm, sizeof(*hwdev), GFP_KERNEL); if (!hwdev) return -ENOMEM; @@ -753,13 +750,6 @@ static int malidp_bind(struct device *dev) if (ret && ret != -ENODEV) return ret; - drm = drm_dev_alloc(&malidp_driver, dev); - if (IS_ERR(drm)) { - ret = PTR_ERR(drm); - goto alloc_fail; - } - - drm->dev_private = malidp; dev_set_drvdata(dev, drm); /* Enable power management */ @@ -878,17 +868,13 @@ irq_init_fail: bind_fail: of_node_put(malidp->crtc.port); malidp->crtc.port = NULL; - malidp_fini(drm); query_hw_fail: pm_runtime_put(dev); if (pm_runtime_enabled(dev)) pm_runtime_disable(dev); else malidp_runtime_pm_suspend(dev); - drm->dev_private = NULL; dev_set_drvdata(dev, NULL); - drm_dev_put(drm); -alloc_fail: of_reserved_mem_device_release(dev); return ret; @@ -897,7 +883,7 @@ alloc_fail: static void malidp_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; drm_dev_unregister(drm); @@ -909,15 +895,12 @@ static void malidp_unbind(struct device *dev) component_unbind_all(dev, drm); of_node_put(malidp->crtc.port); malidp->crtc.port = NULL; - malidp_fini(drm); pm_runtime_put(dev); if (pm_runtime_enabled(dev)) pm_runtime_disable(dev); else malidp_runtime_pm_suspend(dev); - drm->dev_private = NULL; dev_set_drvdata(dev, NULL); - drm_dev_put(drm); of_reserved_mem_device_release(dev); } diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index cdfddfabf2d1..bc0387876dea 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -29,6 +29,7 @@ struct malidp_error_stats { }; struct malidp_drm { + struct drm_device base; struct malidp_hw_device *dev; struct drm_crtc crtc; struct drm_writeback_connector mw_connector; @@ -44,6 +45,7 @@ struct malidp_drm { #endif }; +#define drm_to_malidp(x) container_of(x, struct malidp_drm, base) #define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc) struct malidp_plane { diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index e9de542f9b7c..9b845d3f34e1 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -1168,7 +1168,7 @@ static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 ir static irqreturn_t malidp_de_irq(int irq, void *arg) { struct drm_device *drm = arg; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev; struct malidp_hw *hw; const struct malidp_irq_map *de; @@ -1226,7 +1226,7 @@ static irqreturn_t malidp_de_irq(int irq, void *arg) static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg) { struct drm_device *drm = arg; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); wake_up(&malidp->wq); @@ -1252,7 +1252,7 @@ void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev) int malidp_de_irq_init(struct drm_device *drm, int irq) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; int ret; @@ -1286,7 +1286,7 @@ void malidp_de_irq_fini(struct malidp_hw_device *hwdev) static irqreturn_t malidp_se_irq(int irq, void *arg) { struct drm_device *drm = arg; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; struct malidp_hw *hw = hwdev->hw; const struct malidp_irq_map *se = &hw->map.se_irq_map; @@ -1363,7 +1363,7 @@ static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg) int malidp_se_irq_init(struct drm_device *drm, int irq) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; int ret; diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c index ef76d0e6ee2f..626709bec6f5 100644 --- a/drivers/gpu/drm/arm/malidp_mw.c +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -129,7 +129,7 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct malidp_mw_connector_state *mw_state = to_mw_state(conn_state); - struct malidp_drm *malidp = encoder->dev->dev_private; + struct malidp_drm *malidp = drm_to_malidp(encoder->dev); struct drm_framebuffer *fb; int i, n_planes; @@ -207,7 +207,7 @@ static u32 *get_writeback_formats(struct malidp_drm *malidp, int *n_formats) int malidp_mw_connector_init(struct drm_device *drm) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); u32 *formats; int ret, n_formats; @@ -236,7 +236,7 @@ int malidp_mw_connector_init(struct drm_device *drm) void malidp_mw_atomic_commit(struct drm_device *drm, struct drm_atomic_state *old_state) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); struct drm_writeback_connector *mw_conn = &malidp->mw_connector; struct drm_connector_state *conn_state = mw_conn->base.state; struct malidp_hw_device *hwdev = malidp->dev; diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 45f5e35e7f24..34547edf1ee3 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -68,14 +68,6 @@ /* readahead for partial-frame prefetch */ #define MALIDP_MMU_PREFETCH_READAHEAD 8 -static void malidp_de_plane_destroy(struct drm_plane *plane) -{ - struct malidp_plane *mp = to_malidp_plane(plane); - - drm_plane_cleanup(plane); - kfree(mp); -} - /* * Replicate what the default ->reset hook does: free the state pointer and * allocate a new empty object. We just need enough space to store @@ -151,7 +143,7 @@ bool malidp_format_mod_supported(struct drm_device *drm, { const struct drm_format_info *info; const u64 *modifiers; - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); const struct malidp_hw_regmap *map = &malidp->dev->hw->map; if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID)) @@ -260,7 +252,6 @@ static bool malidp_format_mod_supported_per_plane(struct drm_plane *plane, static const struct drm_plane_funcs malidp_de_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = malidp_de_plane_destroy, .reset = malidp_plane_reset, .atomic_duplicate_state = malidp_duplicate_plane_state, .atomic_destroy_state = malidp_destroy_plane_state, @@ -931,7 +922,7 @@ static const uint64_t linear_only_modifiers[] = { int malidp_de_planes_init(struct drm_device *drm) { - struct malidp_drm *malidp = drm->dev_private; + struct malidp_drm *malidp = drm_to_malidp(drm); const struct malidp_hw_regmap *map = &malidp->dev->hw->map; struct malidp_plane *plane = NULL; enum drm_plane_type plane_type; @@ -972,12 +963,6 @@ int malidp_de_planes_init(struct drm_device *drm) for (i = 0; i < map->n_layers; i++) { u8 id = map->layers[i].id; - plane = kzalloc(sizeof(*plane), GFP_KERNEL); - if (!plane) { - ret = -ENOMEM; - goto cleanup; - } - /* build the list of DRM supported formats based on the map */ for (n = 0, j = 0; j < map->n_pixel_formats; j++) { if ((map->pixel_formats[j].layer & id) == id) @@ -990,13 +975,14 @@ int malidp_de_planes_init(struct drm_device *drm) /* * All the layers except smart layer supports AFBC modifiers. */ - ret = drm_universal_plane_init(drm, &plane->base, crtcs, - &malidp_de_plane_funcs, formats, n, - (id == DE_SMART) ? linear_only_modifiers : modifiers, - plane_type, NULL); - - if (ret < 0) + plane = drmm_universal_plane_alloc(drm, struct malidp_plane, base, + crtcs, &malidp_de_plane_funcs, formats, n, + (id == DE_SMART) ? linear_only_modifiers : + modifiers, plane_type, NULL); + if (IS_ERR(plane)) { + ret = PTR_ERR(plane); goto cleanup; + } drm_plane_helper_add(&plane->base, &malidp_de_plane_helper_funcs); diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index bbc535cc50dd..d553e793e673 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -1237,3 +1237,7 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode) return ret; } EXPORT_SYMBOL(drm_client_modeset_dpms); + +#ifdef CONFIG_DRM_KUNIT_TEST +#include "tests/drm_client_modeset_test.c" +#endif diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4671dc23abe0..3841aba17abd 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2807,6 +2807,8 @@ u32 drm_edid_get_panel_id(struct i2c_adapter *adapter) if (edid_block_status_valid(status, edid_block_tag(base_block))) panel_id = edid_extract_panel_id(base_block); + else + edid_block_dump(KERN_NOTICE, base_block, 0); kfree(base_block); diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index ef4ab59d6935..5d9ef267ebb3 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -172,20 +172,9 @@ static const struct drm_edid *edid_load(struct drm_connector *connector, const c fwdata = generic_edid[builtin]; fwsize = sizeof(generic_edid[builtin]); } else { - struct platform_device *pdev; int err; - pdev = platform_device_register_simple(connector->name, -1, NULL, 0); - if (IS_ERR(pdev)) { - drm_err(connector->dev, - "[CONNECTOR:%d:%s] Failed to register EDID firmware platform device for connector \"%s\"\n", - connector->base.id, connector->name, - connector->name); - return ERR_CAST(pdev); - } - - err = request_firmware(&fw, name, &pdev->dev); - platform_device_unregister(pdev); + err = request_firmware(&fw, name, connector->dev->dev); if (err) { drm_err(connector->dev, "[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n", diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e0384f967c0b..a1f86e436ae8 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -367,9 +367,8 @@ static void drm_fb_helper_resume_worker(struct work_struct *work) console_unlock(); } -static void drm_fb_helper_damage_work(struct work_struct *work) +static void drm_fb_helper_fb_dirty(struct drm_fb_helper *helper) { - struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper, damage_work); struct drm_device *dev = helper->dev; struct drm_clip_rect *clip = &helper->damage_clip; struct drm_clip_rect clip_copy; @@ -419,7 +418,6 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, INIT_LIST_HEAD(&helper->kernel_fb_list); spin_lock_init(&helper->damage_lock); INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker); - INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work); helper->damage_clip.x1 = helper->damage_clip.y1 = ~0; mutex_init(&helper->lock); helper->funcs = funcs; @@ -551,7 +549,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) return; cancel_work_sync(&fb_helper->resume_work); - cancel_work_sync(&fb_helper->damage_work); info = fb_helper->info; if (info) { @@ -576,8 +573,8 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_fini); -static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y, - u32 width, u32 height) +static void drm_fb_helper_add_damage_clip(struct drm_fb_helper *helper, u32 x, u32 y, + u32 width, u32 height) { struct drm_clip_rect *clip = &helper->damage_clip; unsigned long flags; @@ -588,8 +585,21 @@ static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y, clip->x2 = max_t(u32, clip->x2, x + width); clip->y2 = max_t(u32, clip->y2, y + height); spin_unlock_irqrestore(&helper->damage_lock, flags); +} - schedule_work(&helper->damage_work); +static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y, + u32 width, u32 height) +{ + struct fb_info *info = helper->info; + + drm_fb_helper_add_damage_clip(helper, x, y, width, height); + + /* + * The current fbdev emulation only flushes buffers if a damage + * update is necessary. And we can assume that deferred I/O has + * been enabled as damage updates require deferred I/O for mmap. + */ + fb_deferred_io_schedule_flush(info); } /* @@ -644,22 +654,26 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagerefli min_off = min(min_off, start); max_off = max(max_off, end); } - if (min_off >= max_off) - return; - if (helper->funcs->fb_dirty) { - /* - * As we can only track pages, we might reach beyond the end - * of the screen and account for non-existing scanlines. Hence, - * keep the covered memory area within the screen buffer. - */ - max_off = min(max_off, info->screen_size); + /* + * As we can only track pages, we might reach beyond the end + * of the screen and account for non-existing scanlines. Hence, + * keep the covered memory area within the screen buffer. + */ + max_off = min(max_off, info->screen_size); + if (min_off < max_off) { drm_fb_helper_memory_range_to_clip(info, min_off, max_off - min_off, &damage_area); - drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1, - drm_rect_width(&damage_area), - drm_rect_height(&damage_area)); + drm_fb_helper_add_damage_clip(helper, damage_area.x1, damage_area.y1, + drm_rect_width(&damage_area), + drm_rect_height(&damage_area)); } + + /* + * Flushes all dirty pages from mmap's pageref list and the + * areas that have been written by struct fb_ops callbacks. + */ + drm_fb_helper_fb_dirty(helper); } EXPORT_SYMBOL(drm_fb_helper_deferred_io); diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index e09331bb3bc7..6242dfbe9240 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -297,12 +297,12 @@ const struct drm_format_info *__drm_format_info(u32 format) .vsub = 2, .is_yuv = true }, { .format = DRM_FORMAT_Q410, .depth = 0, .num_planes = 3, .char_per_block = { 2, 2, 2 }, - .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, - .vsub = 0, .is_yuv = true }, + .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1, + .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_Q401, .depth = 0, .num_planes = 3, .char_per_block = { 2, 2, 2 }, - .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, - .vsub = 0, .is_yuv = true }, + .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1, + .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2, .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true}, diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 125160b534be..b6c7e3803bb3 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -433,25 +433,19 @@ int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct iosys_map *map) { int ret; - ret = ttm_bo_reserve(&gbo->bo, true, false, NULL); - if (ret) - return ret; + dma_resv_assert_held(gbo->bo.base.resv); ret = drm_gem_vram_pin_locked(gbo, 0); if (ret) - goto err_ttm_bo_unreserve; + return ret; ret = drm_gem_vram_kmap_locked(gbo, map); if (ret) goto err_drm_gem_vram_unpin_locked; - ttm_bo_unreserve(&gbo->bo); - return 0; err_drm_gem_vram_unpin_locked: drm_gem_vram_unpin_locked(gbo); -err_ttm_bo_unreserve: - ttm_bo_unreserve(&gbo->bo); return ret; } EXPORT_SYMBOL(drm_gem_vram_vmap); @@ -467,16 +461,10 @@ EXPORT_SYMBOL(drm_gem_vram_vmap); void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, struct iosys_map *map) { - int ret; - - ret = ttm_bo_reserve(&gbo->bo, false, false, NULL); - if (WARN_ONCE(ret, "ttm_bo_reserve_failed(): ret=%d\n", ret)) - return; + dma_resv_assert_held(gbo->bo.base.resv); drm_gem_vram_kunmap_locked(gbo, map); drm_gem_vram_unpin_locked(gbo); - - ttm_bo_unreserve(&gbo->bo); } EXPORT_SYMBOL(drm_gem_vram_vunmap); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 5d4ac79381c4..3c8034a8c27b 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1750,11 +1750,78 @@ static int drm_mode_parse_cmdline_options(const char *str, return 0; } -static const char * const drm_named_modes_whitelist[] = { - "NTSC", - "PAL", +struct drm_named_mode { + const char *name; + unsigned int pixel_clock_khz; + unsigned int xres; + unsigned int yres; + unsigned int flags; +}; + +#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \ + { \ + .name = _name, \ + .pixel_clock_khz = _pclk, \ + .xres = _x, \ + .yres = _y, \ + .flags = _flags, \ + } + +static const struct drm_named_mode drm_named_modes[] = { + NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE), + NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE), }; +static int drm_mode_parse_cmdline_named_mode(const char *name, + unsigned int name_end, + struct drm_cmdline_mode *cmdline_mode) +{ + unsigned int i; + + if (!name_end) + return 0; + + /* If the name starts with a digit, it's not a named mode */ + if (isdigit(name[0])) + return 0; + + /* + * If there's an equal sign in the name, the command-line + * contains only an option and no mode. + */ + if (strnchr(name, name_end, '=')) + return 0; + + /* The connection status extras can be set without a mode. */ + if (name_end == 1 && + (name[0] == 'd' || name[0] == 'D' || name[0] == 'e')) + return 0; + + /* + * We're sure we're a named mode at this point, iterate over the + * list of modes we're aware of. + */ + for (i = 0; i < ARRAY_SIZE(drm_named_modes); i++) { + const struct drm_named_mode *mode = &drm_named_modes[i]; + int ret; + + ret = str_has_prefix(name, mode->name); + if (ret != name_end) + continue; + + strcpy(cmdline_mode->name, mode->name); + cmdline_mode->pixel_clock = mode->pixel_clock_khz; + cmdline_mode->xres = mode->xres; + cmdline_mode->yres = mode->yres; + cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + cmdline_mode->specified = true; + + return 1; + } + + return -EINVAL; +} + /** * drm_mode_parse_command_line_for_connector - parse command line modeline for connector * @mode_option: optional per connector mode option @@ -1791,7 +1858,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; const char *options_ptr = NULL; char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; - int i, len, ret; + int len, ret; memset(mode, 0, sizeof(*mode)); mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; @@ -1832,18 +1899,19 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, parse_extras = true; } - /* First check for a named mode */ - for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) { - ret = str_has_prefix(name, drm_named_modes_whitelist[i]); - if (ret == mode_end) { - if (refresh_ptr) - return false; /* named + refresh is invalid */ + if (!mode_end) + return false; + + ret = drm_mode_parse_cmdline_named_mode(name, mode_end, mode); + if (ret < 0) + return false; - strcpy(mode->name, drm_named_modes_whitelist[i]); - mode->specified = true; - break; - } - } + /* + * Having a mode that starts by a letter (and thus is named) and + * an at-sign (used to specify a refresh rate) is disallowed. + */ + if (ret && refresh_ptr) + return false; /* No named mode? Check for a normal mode argument, e.g. 1024x768 */ if (!mode->specified && isdigit(name[0])) { diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 20e109a802ae..f924b8b4ab6b 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -781,6 +781,8 @@ int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) struct drm_gem_object *obj = dma_buf->priv; struct drm_device *dev = obj->dev; + dma_resv_assert_held(dma_buf->resv); + if (!dev->driver->gem_prime_mmap) return -ENOSYS; diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c index a0d5aa727d58..d9978b79828c 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -658,7 +658,7 @@ static enum drm_mode_status dsi_encoder_mode_valid(struct drm_encoder *encoder, * reset adj_mode to the mode value each time, * so we don't adjust the mode twice */ - drm_mode_copy(&adj_mode, mode); + drm_mode_init(&adj_mode, mode); crtc_funcs = crtc->helper_private; if (crtc_funcs && crtc_funcs->mode_fixup) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index ec6f7ae47783..9322ac29008b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -97,6 +97,8 @@ static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct * struct drm_i915_private *i915 = to_i915(obj->base.dev); int ret; + dma_resv_assert_held(dma_buf->resv); + if (obj->base.size < vma->vm_end - vma->vm_start) return -EINVAL; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 4c80b6896dc3..12fa78f286ff 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1217,7 +1217,7 @@ static int mtk_hdmi_bridge_mode_valid(struct drm_bridge *bridge, if (next_bridge) { struct drm_display_mode adjusted_mode; - drm_mode_copy(&adjusted_mode, mode); + drm_mode_init(&adjusted_mode, mode); if (!drm_bridge_chain_mode_fixup(next_bridge, mode, &adjusted_mode)) return MODE_BAD; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 2c14646661b7..0f71e8fe7be7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -237,12 +237,13 @@ static void dpu_encoder_phys_vid_setup_timing_engine( unsigned long lock_flags; struct dpu_hw_intf_cfg intf_cfg = { 0 }; + drm_mode_init(&mode, &phys_enc->cached_mode); + if (!phys_enc->hw_ctl->ops.setup_intf_cfg) { DPU_ERROR("invalid encoder %d\n", phys_enc != NULL); return; } - mode = phys_enc->cached_mode; if (!phys_enc->hw_intf->ops.setup_timing_gen) { DPU_ERROR("timing engine setup is not supported\n"); return; @@ -634,7 +635,9 @@ static int dpu_encoder_phys_vid_get_frame_count( { struct intf_status s = {0}; u32 fetch_start = 0; - struct drm_display_mode mode = phys_enc->cached_mode; + struct drm_display_mode mode; + + drm_mode_init(&mode, &phys_enc->cached_mode); if (!dpu_encoder_phys_vid_is_master(phys_enc)) return -EINVAL; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index bfd0aeff3f0d..39c9e55f07cc 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -857,7 +857,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); - dp->panel->dp_mode.drm_mode = mode->drm_mode; + drm_mode_copy(&dp->panel->dp_mode.drm_mode, &mode->drm_mode); dp->panel->dp_mode.bpp = mode->bpp; dp->panel->dp_mode.capabilities = mode->capabilities; dp_panel_init_panel_info(dp->panel); diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index a614582779ca..40409a29f5b6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -264,7 +264,11 @@ nva3_set_intensity(struct backlight_device *bd) u32 div, val; div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); - val = (bd->props.brightness * div) / 100; + + val = backlight_get_brightness(bd); + if (val) + val = (val * div) / 100; + if (div) { nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), val | diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 8e194dbc9506..3abc47521b2c 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -66,6 +66,8 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, struct drm_gem_object *obj = buffer->priv; int ret = 0; + dma_resv_assert_held(buffer->resv); + ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 6f6cc6662b2e..737edcdf9eef 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -306,6 +306,15 @@ config DRM_PANEL_NEC_NL8048HL11 panel (found on the Zoom2/3/3630 SDP boards). To compile this driver as a module, choose M here. +config DRM_PANEL_NEWVISION_NV3051D + tristate "NewVision NV3051D DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + This driver supports the NV3051D based panel found on the Anbernic + RG353P and RG353V. + config DRM_PANEL_NEWVISION_NV3052C tristate "NewVision NV3052C RGB/SPI panel" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index af0b1ebdbac8..f8f9d9f6a307 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o +obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3052C) += panel-newvision-nv3052c.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c new file mode 100644 index 000000000000..a07958038ffd --- /dev/null +++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c @@ -0,0 +1,504 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NV3051D MIPI-DSI panel driver for Anbernic RG353x + * Copyright (C) 2022 Chris Morgan + * + * based on + * + * Elida kd35t133 3.5" MIPI-DSI panel driver + * Copyright (C) Theobroma Systems 2020 + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/media-bus-format.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/consumer.h> + +#include <video/display_timing.h> +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +struct nv3051d_panel_info { + const struct drm_display_mode *display_modes; + unsigned int num_modes; + u16 width_mm, height_mm; + u32 bus_flags; +}; + +struct panel_nv3051d { + struct device *dev; + struct drm_panel panel; + struct gpio_desc *reset_gpio; + const struct nv3051d_panel_info *panel_info; + struct regulator *vdd; +}; + +static inline struct panel_nv3051d *panel_to_panelnv3051d(struct drm_panel *panel) +{ + return container_of(panel, struct panel_nv3051d, panel); +} + +static int panel_nv3051d_init_sequence(struct panel_nv3051d *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + /* + * Init sequence was supplied by device vendor with no + * documentation. + */ + + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xE3, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x03, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x04, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x24, 0x12); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0x1E); + mipi_dsi_dcs_write_seq(dsi, 0x26, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0x27, 0x52); + mipi_dsi_dcs_write_seq(dsi, 0x28, 0x57); + mipi_dsi_dcs_write_seq(dsi, 0x29, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x2A, 0xDF); + mipi_dsi_dcs_write_seq(dsi, 0x38, 0x9C); + mipi_dsi_dcs_write_seq(dsi, 0x39, 0xA7); + mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x53); + mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x49, 0x3C); + mipi_dsi_dcs_write_seq(dsi, 0x59, 0xFE); + mipi_dsi_dcs_write_seq(dsi, 0x5C, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x91, 0x77); + mipi_dsi_dcs_write_seq(dsi, 0x92, 0x77); + mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x55); + mipi_dsi_dcs_write_seq(dsi, 0xA1, 0x50); + mipi_dsi_dcs_write_seq(dsi, 0xA4, 0x9C); + mipi_dsi_dcs_write_seq(dsi, 0xA7, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0xA8, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xA9, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xAA, 0xFC); + mipi_dsi_dcs_write_seq(dsi, 0xAB, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0xAC, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0xAD, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0xAE, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0xAF, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33); + mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x0E); + mipi_dsi_dcs_write_seq(dsi, 0xD1, 0x0E); + mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x29); + mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x2B); + mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C); + mipi_dsi_dcs_write_seq(dsi, 0xD2, 0x0A); + mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0xD3, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0xD6, 0x0D); + mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x32); + mipi_dsi_dcs_write_seq(dsi, 0xD7, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xE1, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x0A); + mipi_dsi_dcs_write_seq(dsi, 0xD8, 0x0A); + mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xD9, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xBD, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0xDD, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0xBC, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0xDC, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0xBB, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xDB, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xDA, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xBE, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0xDE, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0xBF, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xDF, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xC0, 0x17); + mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x17); + mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x3B); + mipi_dsi_dcs_write_seq(dsi, 0xD5, 0x3C); + mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x0B); + mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0C); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x01, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x02, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x03, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x04, 0x61); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0xC7); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x08, 0x82); + mipi_dsi_dcs_write_seq(dsi, 0x09, 0x83); + mipi_dsi_dcs_write_seq(dsi, 0x30, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x31, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x32, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x33, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0x61); + mipi_dsi_dcs_write_seq(dsi, 0x35, 0xC5); + mipi_dsi_dcs_write_seq(dsi, 0x36, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x37, 0x23); + mipi_dsi_dcs_write_seq(dsi, 0x40, 0x82); + mipi_dsi_dcs_write_seq(dsi, 0x41, 0x83); + mipi_dsi_dcs_write_seq(dsi, 0x42, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x43, 0x81); + mipi_dsi_dcs_write_seq(dsi, 0x44, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x45, 0xF2); + mipi_dsi_dcs_write_seq(dsi, 0x46, 0xF1); + mipi_dsi_dcs_write_seq(dsi, 0x47, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x48, 0xF4); + mipi_dsi_dcs_write_seq(dsi, 0x49, 0xF3); + mipi_dsi_dcs_write_seq(dsi, 0x50, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x51, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x52, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x53, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x54, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x55, 0xF6); + mipi_dsi_dcs_write_seq(dsi, 0x56, 0xF5); + mipi_dsi_dcs_write_seq(dsi, 0x57, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x58, 0xF8); + mipi_dsi_dcs_write_seq(dsi, 0x59, 0xF7); + mipi_dsi_dcs_write_seq(dsi, 0x7E, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x7F, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x5A); + mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x0E); + mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xC7, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xCA, 0x0E); + mipi_dsi_dcs_write_seq(dsi, 0xCB, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0xCC, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0xCE, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0xCF, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0x81, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0x84, 0x0E); + mipi_dsi_dcs_write_seq(dsi, 0x85, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0x86, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0x87, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x88, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0x89, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x8A, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x97, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0x9A, 0x0E); + mipi_dsi_dcs_write_seq(dsi, 0x9B, 0x0F); + mipi_dsi_dcs_write_seq(dsi, 0x9C, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0x9D, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x9E, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0x9F, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x01, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x02, 0xDA); + mipi_dsi_dcs_write_seq(dsi, 0x03, 0xBA); + mipi_dsi_dcs_write_seq(dsi, 0x04, 0xA8); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x9A); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0x08, 0x91); + mipi_dsi_dcs_write_seq(dsi, 0x09, 0x90); + mipi_dsi_dcs_write_seq(dsi, 0x0A, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0x0B, 0x8F); + mipi_dsi_dcs_write_seq(dsi, 0x0C, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x0D, 0x58); + mipi_dsi_dcs_write_seq(dsi, 0x0E, 0x48); + mipi_dsi_dcs_write_seq(dsi, 0x0F, 0x38); + mipi_dsi_dcs_write_seq(dsi, 0x10, 0x2B); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); + mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x36, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x70); + + dev_dbg(ctx->dev, "Panel init sequence done\n"); + + return 0; +} + +static int panel_nv3051d_unprepare(struct drm_panel *panel) +{ + struct panel_nv3051d *ctx = panel_to_panelnv3051d(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) + dev_err(ctx->dev, "failed to set display off: %d\n", ret); + + msleep(20); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) { + dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); + return ret; + } + + usleep_range(10000, 15000); + + regulator_disable(ctx->vdd); + + return 0; +} + +static int panel_nv3051d_prepare(struct drm_panel *panel) +{ + struct panel_nv3051d *ctx = panel_to_panelnv3051d(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + dev_dbg(ctx->dev, "Resetting the panel\n"); + ret = regulator_enable(ctx->vdd); + if (ret < 0) { + dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret); + return ret; + } + + usleep_range(2000, 3000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(150); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); + + ret = panel_nv3051d_init_sequence(ctx); + if (ret < 0) { + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); + goto disable_vdd; + } + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); + goto disable_vdd; + } + + msleep(200); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set display on: %d\n", ret); + goto disable_vdd; + } + + usleep_range(10000, 15000); + + return 0; + +disable_vdd: + regulator_disable(ctx->vdd); + return ret; +} + +static int panel_nv3051d_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct panel_nv3051d *ctx = panel_to_panelnv3051d(panel); + const struct nv3051d_panel_info *panel_info = ctx->panel_info; + struct drm_display_mode *mode; + unsigned int i; + + for (i = 0; i < panel_info->num_modes; i++) { + mode = drm_mode_duplicate(connector->dev, + &panel_info->display_modes[i]); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER; + if (panel_info->num_modes == 1) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_probed_add(connector, mode); + } + + connector->display_info.bpc = 8; + connector->display_info.width_mm = panel_info->width_mm; + connector->display_info.height_mm = panel_info->height_mm; + connector->display_info.bus_flags = panel_info->bus_flags; + + return panel_info->num_modes; +} + +static const struct drm_panel_funcs panel_nv3051d_funcs = { + .unprepare = panel_nv3051d_unprepare, + .prepare = panel_nv3051d_prepare, + .get_modes = panel_nv3051d_get_modes, +}; + +static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct panel_nv3051d *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = dev; + + ctx->panel_info = of_device_get_match_data(dev); + if (!ctx->panel_info) + return -EINVAL; + + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) { + dev_err(dev, "cannot get reset gpio\n"); + return PTR_ERR(ctx->reset_gpio); + } + + ctx->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(ctx->vdd)) { + ret = PTR_ERR(ctx->vdd); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to request vdd regulator: %d\n", ret); + return ret; + } + + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + + drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return ret; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void panel_nv3051d_shutdown(struct mipi_dsi_device *dsi) +{ + struct panel_nv3051d *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = drm_panel_unprepare(&ctx->panel); + if (ret < 0) + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); + + ret = drm_panel_disable(&ctx->panel); + if (ret < 0) + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); +} + +static void panel_nv3051d_remove(struct mipi_dsi_device *dsi) +{ + struct panel_nv3051d *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + panel_nv3051d_shutdown(dsi); + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct drm_display_mode nv3051d_rgxx3_modes[] = { + { /* 120hz */ + .hdisplay = 640, + .hsync_start = 640 + 40, + .hsync_end = 640 + 40 + 2, + .htotal = 640 + 40 + 2 + 80, + .vdisplay = 480, + .vsync_start = 480 + 18, + .vsync_end = 480 + 18 + 2, + .vtotal = 480 + 18 + 2 + 28, + .clock = 48300, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + }, + { /* 100hz */ + .hdisplay = 640, + .hsync_start = 640 + 40, + .hsync_end = 640 + 40 + 2, + .htotal = 640 + 40 + 2 + 80, + .vdisplay = 480, + .vsync_start = 480 + 18, + .vsync_end = 480 + 18 + 2, + .vtotal = 480 + 18 + 2 + 28, + .clock = 40250, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + }, + { /* 60hz */ + .hdisplay = 640, + .hsync_start = 640 + 40, + .hsync_end = 640 + 40 + 2, + .htotal = 640 + 40 + 2 + 80, + .vdisplay = 480, + .vsync_start = 480 + 18, + .vsync_end = 480 + 18 + 2, + .vtotal = 480 + 18 + 2 + 28, + .clock = 24150, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + }, +}; + +static const struct nv3051d_panel_info nv3051d_rgxx3_info = { + .display_modes = nv3051d_rgxx3_modes, + .num_modes = ARRAY_SIZE(nv3051d_rgxx3_modes), + .width_mm = 70, + .height_mm = 57, + .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, +}; + +static const struct of_device_id newvision_nv3051d_of_match[] = { + { .compatible = "newvision,nv3051d", .data = &nv3051d_rgxx3_info }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, newvision_nv3051d_of_match); + +static struct mipi_dsi_driver newvision_nv3051d_driver = { + .driver = { + .name = "panel-newvision-nv3051d", + .of_match_table = newvision_nv3051d_of_match, + }, + .probe = panel_nv3051d_probe, + .remove = panel_nv3051d_remove, + .shutdown = panel_nv3051d_shutdown, +}; +module_mipi_dsi_driver(newvision_nv3051d_driver); + +MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>"); +MODULE_DESCRIPTION("DRM driver for Newvision NV3051D based MIPI DSI panels"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 518ee13b1d6f..8526dda91931 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -571,7 +571,7 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder, video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); - memcpy(&dp->mode, adjusted, sizeof(*mode)); + drm_mode_copy(&dp->mode, adjusted); } static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 87b2243ea23e..f51774866f41 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -499,7 +499,7 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, inno_hdmi_setup(hdmi, adj_mode); /* Store the display mode for plugin/DPMS poweron events */ - memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode)); + drm_mode_copy(&hdmi->previous_mode, adj_mode); } static void inno_hdmi_encoder_enable(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index cf2cf51091a3..90145ad96984 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -395,7 +395,7 @@ rk3066_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder); /* Store the display mode for plugin/DPMS poweron events. */ - memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode)); + drm_mode_copy(&hdmi->previous_mode, adj_mode); } static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index b6ee8a82e656..f3a5616b7daf 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -288,7 +288,7 @@ static void sti_dvo_set_mode(struct drm_bridge *bridge, DRM_DEBUG_DRIVER("\n"); - memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode)); + drm_mode_copy(&dvo->mode, mode); /* According to the path used (main or aux), the dvo clocks should * have a different parent clock. */ diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 03cc401ed593..ec6656b9ee7c 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -524,7 +524,7 @@ static void sti_hda_set_mode(struct drm_bridge *bridge, DRM_DEBUG_DRIVER("\n"); - memcpy(&hda->mode, mode, sizeof(struct drm_display_mode)); + drm_mode_copy(&hda->mode, mode); if (!hda_get_mode_idx(hda->mode, &mode_idx)) { DRM_ERROR("Undefined mode\n"); diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index cb82622877d2..fcc2194869d6 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -941,7 +941,7 @@ static void sti_hdmi_set_mode(struct drm_bridge *bridge, DRM_DEBUG_DRIVER("\n"); /* Copy the drm display mode in the connector local structure */ - memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode)); + drm_mode_copy(&hdmi->mode, mode); /* Update clock framerate according to the selected mode */ ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000); diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index b09b8ab40ae4..979e7bc902f6 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -694,6 +694,8 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) struct drm_gem_object *gem = buf->priv; int err; + dma_resv_assert_held(buf->resv); + err = drm_gem_mmap_obj(gem, gem->size, vma); if (err < 0) return err; diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile index 2d9f49b62ecb..b29ef1085cad 100644 --- a/drivers/gpu/drm/tests/Makefile +++ b/drivers/gpu/drm/tests/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \ drm_format_helper_test.o \ drm_format_test.o \ drm_framebuffer_test.o \ + drm_kunit_helpers.o \ drm_mm_test.o \ drm_plane_helper_test.o \ drm_rect_test.o diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c new file mode 100644 index 000000000000..362a5fbd82f5 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Maxime Ripard <mripard@kernel.org> + */ + +#include <kunit/test.h> + +#include <drm/drm_connector.h> +#include <drm/drm_edid.h> +#include <drm/drm_drv.h> +#include <drm/drm_modes.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_probe_helper.h> + +#include "drm_kunit_helpers.h" + +struct drm_client_modeset_test_priv { + struct drm_device *drm; + struct drm_connector connector; +}; + +static int drm_client_modeset_connector_get_modes(struct drm_connector *connector) +{ + return drm_add_modes_noedid(connector, 1920, 1200); +} + +static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = { + .get_modes = drm_client_modeset_connector_get_modes, +}; + +static const struct drm_connector_funcs drm_client_modeset_connector_funcs = { +}; + +static int drm_client_modeset_test_init(struct kunit *test) +{ + struct drm_client_modeset_test_priv *priv; + int ret; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, priv); + + test->priv = priv; + + priv->drm = drm_kunit_device_init(test, DRIVER_MODESET, "drm-client-modeset-test"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm); + + ret = drmm_connector_init(priv->drm, &priv->connector, + &drm_client_modeset_connector_funcs, + DRM_MODE_CONNECTOR_Unknown, + NULL); + KUNIT_ASSERT_EQ(test, ret, 0); + + drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs); + + return 0; +} + +static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test) +{ + struct drm_client_modeset_test_priv *priv = test->priv; + struct drm_device *drm = priv->drm; + struct drm_connector *connector = &priv->connector; + struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode; + struct drm_display_mode *expected_mode, *mode; + const char *cmdline = "1920x1080@60"; + int ret; + + expected_mode = drm_mode_find_dmt(priv->drm, 1920, 1080, 60, false); + KUNIT_ASSERT_NOT_NULL(test, expected_mode); + + KUNIT_ASSERT_TRUE(test, + drm_mode_parse_command_line_for_connector(cmdline, + connector, + cmdline_mode)); + + mutex_lock(&drm->mode_config.mutex); + ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080); + mutex_unlock(&drm->mode_config.mutex); + KUNIT_ASSERT_GT(test, ret, 0); + + mode = drm_connector_pick_cmdline_mode(connector); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode)); +} + +static struct kunit_case drm_test_pick_cmdline_tests[] = { + KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60), + {} +}; + +static struct kunit_suite drm_test_pick_cmdline_test_suite = { + .name = "drm_test_pick_cmdline", + .init = drm_client_modeset_test_init, + .test_cases = drm_test_pick_cmdline_tests +}; + +kunit_test_suite(drm_test_pick_cmdline_test_suite); diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c new file mode 100644 index 000000000000..f1662091f250 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <drm/drm_drv.h> +#include <drm/drm_managed.h> + +#include <kunit/resource.h> + +#include <linux/device.h> + +#include "drm_kunit_helpers.h" + +struct kunit_dev { + struct drm_device base; +}; + +static const struct drm_mode_config_funcs drm_mode_config_funcs = { +}; + +static int dev_init(struct kunit_resource *res, void *ptr) +{ + char *name = ptr; + struct device *dev; + + dev = root_device_register(name); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + res->data = dev; + return 0; +} + +static void dev_free(struct kunit_resource *res) +{ + struct device *dev = res->data; + + root_device_unregister(dev); +} + +struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name) +{ + struct kunit_dev *kdev; + struct drm_device *drm; + struct drm_driver *driver; + struct device *dev; + int ret; + + dev = kunit_alloc_resource(test, dev_init, dev_free, GFP_KERNEL, name); + if (!dev) + return ERR_PTR(-ENOMEM); + + driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL); + if (!driver) + return ERR_PTR(-ENOMEM); + + driver->driver_features = features; + kdev = devm_drm_dev_alloc(dev, driver, struct kunit_dev, base); + if (IS_ERR(kdev)) + return ERR_CAST(kdev); + + drm = &kdev->base; + drm->mode_config.funcs = &drm_mode_config_funcs; + + ret = drmm_mode_config_init(drm); + if (ret) + return ERR_PTR(ret); + + return drm; +} + +MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.h b/drivers/gpu/drm/tests/drm_kunit_helpers.h new file mode 100644 index 000000000000..20ab6eec4c89 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_kunit_helpers.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef DRM_KUNIT_HELPERS_H_ +#define DRM_KUNIT_HELPERS_H_ + +struct drm_device; +struct kunit; + +struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name); + +#endif // DRM_KUNIT_HELPERS_H_ diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index b8980440d137..96af1cb5202a 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -10,6 +10,7 @@ #include <linux/sched/signal.h> #include <linux/uaccess.h> +#include <drm/drm_managed.h> #include <drm/drm_syncobj.h> #include <uapi/drm/v3d_drm.h> @@ -1075,10 +1076,18 @@ v3d_gem_init(struct drm_device *dev) spin_lock_init(&v3d->mm_lock); spin_lock_init(&v3d->job_lock); - mutex_init(&v3d->bo_lock); - mutex_init(&v3d->reset_lock); - mutex_init(&v3d->sched_lock); - mutex_init(&v3d->cache_clean_lock); + ret = drmm_mutex_init(dev, &v3d->bo_lock); + if (ret) + return ret; + ret = drmm_mutex_init(dev, &v3d->reset_lock); + if (ret) + return ret; + ret = drmm_mutex_init(dev, &v3d->sched_lock); + if (ret) + return ret; + ret = drmm_mutex_init(dev, &v3d->cache_clean_lock); + if (ret) + return ret; /* Note: We don't allocate address 0. Various bits of HW * treat 0 as special, such as the occlusion query counters diff --git a/drivers/gpu/drm/v3d/v3d_perfmon.c b/drivers/gpu/drm/v3d/v3d_perfmon.c index 48aaaa972c49..e1be7368b87d 100644 --- a/drivers/gpu/drm/v3d/v3d_perfmon.c +++ b/drivers/gpu/drm/v3d/v3d_perfmon.c @@ -17,8 +17,10 @@ void v3d_perfmon_get(struct v3d_perfmon *perfmon) void v3d_perfmon_put(struct v3d_perfmon *perfmon) { - if (perfmon && refcount_dec_and_test(&perfmon->refcnt)) + if (perfmon && refcount_dec_and_test(&perfmon->refcnt)) { + mutex_destroy(&perfmon->lock); kfree(perfmon); + } } void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon) @@ -113,6 +115,7 @@ void v3d_perfmon_close_file(struct v3d_file_priv *v3d_priv) idr_for_each(&v3d_priv->perfmon.idr, v3d_perfmon_idr_del, NULL); idr_destroy(&v3d_priv->perfmon.idr); mutex_unlock(&v3d_priv->perfmon.lock); + mutex_destroy(&v3d_priv->perfmon.lock); } int v3d_perfmon_create_ioctl(struct drm_device *dev, void *data, @@ -154,6 +157,7 @@ int v3d_perfmon_create_ioctl(struct drm_device *dev, void *data, mutex_unlock(&v3d_priv->perfmon.lock); if (ret < 0) { + mutex_destroy(&perfmon->lock); kfree(perfmon); return ret; } diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 0d78c800ed51..6b223a5fcf6f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -124,9 +124,8 @@ static unsigned long long vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, unsigned int bpc, enum vc4_hdmi_output_format fmt); -static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder) +static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi) { - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_display_info *display = &vc4_hdmi->connector.display_info; lockdep_assert_held(&vc4_hdmi->mutex); @@ -319,9 +318,8 @@ out: static int vc4_hdmi_reset_link(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx) { - struct drm_device *drm = connector->dev; - struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); - struct drm_encoder *encoder = &vc4_hdmi->encoder.base; + struct drm_device *drm; + struct vc4_hdmi *vc4_hdmi; struct drm_connector_state *conn_state; struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; @@ -332,6 +330,7 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector, if (!connector) return 0; + drm = connector->dev; ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx); if (ret) return ret; @@ -349,7 +348,8 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector, if (!crtc_state->active) return 0; - if (!vc4_hdmi_supports_scrambling(encoder)) + vc4_hdmi = connector_to_vc4_hdmi(connector); + if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) return 0; scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode, @@ -867,7 +867,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) lockdep_assert_held(&vc4_hdmi->mutex); - if (!vc4_hdmi_supports_scrambling(encoder)) + if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) return; if (!vc4_hdmi_mode_needs_scrambling(mode, diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 555bd40fa472..7f45a62969f2 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -11,6 +11,7 @@ */ #include <linux/dma-buf.h> +#include <linux/dma-resv.h> #include <linux/module.h> #include <linux/refcount.h> #include <linux/scatterlist.h> @@ -455,6 +456,8 @@ static int vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf, struct iosys_map *map) static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf, struct vm_area_struct *vma) { + dma_resv_assert_held(dbuf->resv); + return vb2_dc_mmap(dbuf->priv, vma); } diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 36981a5b5c53..b7f39ee49ed8 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -10,6 +10,7 @@ * the Free Software Foundation. */ +#include <linux/dma-resv.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/refcount.h> @@ -495,6 +496,8 @@ static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf, static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf, struct vm_area_struct *vma) { + dma_resv_assert_held(dbuf->resv); + return vb2_dma_sg_mmap(dbuf->priv, vma); } diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 41db707e43a4..f9b665366365 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -10,6 +10,7 @@ * the Free Software Foundation. */ +#include <linux/dma-resv.h> #include <linux/io.h> #include <linux/module.h> #include <linux/mm.h> @@ -316,6 +317,8 @@ static int vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf, static int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf, struct vm_area_struct *vma) { + dma_resv_assert_held(dbuf->resv); + return vb2_vmalloc_mmap(dbuf->priv, vma); } diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 1ad580865525..0f467a71b069 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -6,6 +6,7 @@ #include <linux/device.h> #include <linux/dma-buf.h> #include <linux/dma-mapping.h> +#include <linux/dma-resv.h> #include <linux/idr.h> #include <linux/list.h> #include <linux/miscdevice.h> @@ -682,6 +683,8 @@ static int fastrpc_mmap(struct dma_buf *dmabuf, struct fastrpc_buf *buf = dmabuf->priv; size_t size = vma->vm_end - vma->vm_start; + dma_resv_assert_held(dmabuf->resv); + return dma_mmap_coherent(buf->dev, vma, buf->virt, FASTRPC_PHYS(buf->phys), size); } diff --git a/drivers/staging/sm750fb/Kconfig b/drivers/staging/sm750fb/Kconfig index 8c0d8a873d5b..acb6c08d09dc 100644 --- a/drivers/staging/sm750fb/Kconfig +++ b/drivers/staging/sm750fb/Kconfig @@ -6,6 +6,7 @@ config FB_SM750 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Frame buffer driver for the Silicon Motion SM750 chip with 2D accelearion and dual head support. diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 168ae2e9005d..effc7fcc3703 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -1168,6 +1168,9 @@ static int __init lynxfb_init(void) { char *option; + if (fb_modesetting_disabled("sm750fb")) + return -ENODEV; + #ifdef MODULE option = g_option; #else diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0587e21abad9..6d2fde6c5d11 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -11,6 +11,10 @@ config APERTURE_HELPERS Support tracking and hand-over of aperture ownership. Required by graphics drivers for firmware-provided framebuffers. +config VIDEO_NOMODESET + bool + default n + if HAS_IOMEM config HAVE_FB_ATMEL diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 5bb6b452cc83..a50eb528ed3c 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_APERTURE_HELPERS) += aperture.o obj-$(CONFIG_VGASTATE) += vgastate.o +obj-$(CONFIG_VIDEO_NOMODESET) += nomodeset.o obj-$(CONFIG_HDMI) += hdmi.o obj-$(CONFIG_VT) += console/ diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index a98987aa2784..71019b167f8b 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -227,6 +227,7 @@ config FB_CIRRUS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This enables support for Cirrus Logic GD542x/543x based boards on Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. @@ -245,6 +246,7 @@ config FB_PM2 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This is the frame buffer device driver for cards based on the 3D Labs Permedia, Permedia 2 and Permedia 2V chips. @@ -340,6 +342,7 @@ config FB_CYBER2000 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This enables support for the Integraphics CyberPro 20x0 and 5000 VGA chips used in the Rebel.com Netwinder and other machines. @@ -504,6 +507,7 @@ config FB_CT65550 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This is the frame buffer device driver for the Chips & Technologies 65550 graphics chip in PowerBooks. @@ -514,6 +518,7 @@ config FB_ASILIANT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This is the frame buffer device driver for the Asiliant 69030 chipset @@ -522,6 +527,7 @@ config FB_IMSTT depends on (FB = y) && PCI select FB_CFB_IMAGEBLIT select FB_MACMODES if PPC_PMAC + select VIDEO_NOMODESET help The IMS Twin Turbo is a PCI-based frame buffer card bundled with many Macintosh and compatible computers. @@ -585,6 +591,7 @@ config FB_TGA select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select BITREVERSE + select VIDEO_NOMODESET help This is the frame buffer device driver for generic TGA and SFB+ graphic cards. These include DEC ZLXp-E1, -E2 and -E3 PCI cards, @@ -777,6 +784,7 @@ config FB_XVR500 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This is the framebuffer device for the Sun XVR-500 and similar graphics cards based upon the 3DLABS Wildcat chipset. The driver @@ -790,6 +798,7 @@ config FB_XVR2500 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This is the framebuffer device for the Sun XVR-2500 and similar graphics cards based upon the 3DLABS Wildcat chipset. The driver @@ -816,6 +825,7 @@ config FB_PVR2 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Say Y here if you have a PowerVR 2 card in your box. If you plan to run linux on your Dreamcast, you will have to say Y here. @@ -881,6 +891,7 @@ config FB_NVIDIA select FB_CFB_IMAGEBLIT select BITREVERSE select VGASTATE + select VIDEO_NOMODESET help This driver supports graphics boards with the nVidia chips, TNT and newer. For very old chipsets, such as the RIVA128, then use @@ -928,6 +939,7 @@ config FB_RIVA select FB_CFB_IMAGEBLIT select BITREVERSE select VGASTATE + select VIDEO_NOMODESET help This driver supports graphics boards with the nVidia Riva/Geforce chips. @@ -972,6 +984,7 @@ config FB_I740 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select VGASTATE + select VIDEO_NOMODESET select FB_DDC help This driver supports graphics cards based on Intel740 chip. @@ -984,6 +997,7 @@ config FB_I810 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select VGASTATE + select VIDEO_NOMODESET help This driver supports the on-board graphics built in to the Intel 810 and 815 chipsets. Say Y if you have and plan to use such a board. @@ -1034,6 +1048,7 @@ config FB_LE80578 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This driver supports the LE80578 (Vermilion Range) chipset @@ -1051,6 +1066,7 @@ config FB_INTEL select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select BOOT_VESA_SUPPORT if FB_INTEL = y + select VIDEO_NOMODESET depends on !DRM_I915 help This driver supports the on-board graphics built in to the Intel @@ -1088,6 +1104,7 @@ config FB_MATROX select FB_CFB_IMAGEBLIT select FB_TILEBLITTING select FB_MACMODES if PPC_PMAC + select VIDEO_NOMODESET help Say Y here if you have a Matrox Millennium, Matrox Millennium II, Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox @@ -1208,6 +1225,7 @@ config FB_RADEON select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select FB_MACMODES if PPC + select VIDEO_NOMODESET help Choose this option if you want to use an ATI Radeon graphics card as a framebuffer device. There are both PCI and AGP versions. You @@ -1247,6 +1265,7 @@ config FB_ATY128 select FB_CFB_IMAGEBLIT select FB_BACKLIGHT if FB_ATY128_BACKLIGHT select FB_MACMODES if PPC_PMAC + select VIDEO_NOMODESET help This driver supports graphics boards with the ATI Rage128 chips. Say Y if you have such a graphics board and read @@ -1271,6 +1290,7 @@ config FB_ATY select FB_BACKLIGHT if FB_ATY_BACKLIGHT select FB_MACMODES if PPC select FB_ATY_CT if SPARC64 && PCI + select VIDEO_NOMODESET help This driver supports graphics boards with the ATI Mach64 chips. Say Y if you have such a graphics board. @@ -1321,6 +1341,7 @@ config FB_S3 select FB_TILEBLITTING select FB_SVGALIB select VGASTATE + select VIDEO_NOMODESET select FONT_8x16 if FRAMEBUFFER_CONSOLE help Driver for graphics boards with S3 Trio / S3 Virge chip. @@ -1341,6 +1362,7 @@ config FB_SAVAGE select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select VGASTATE + select VIDEO_NOMODESET help This driver supports notebooks and computers with S3 Savage PCI/AGP chips. @@ -1379,6 +1401,7 @@ config FB_SIS select FB_CFB_IMAGEBLIT select BOOT_VESA_SUPPORT if FB_SIS = y select FB_SIS_300 if !FB_SIS_315 + select VIDEO_NOMODESET help This is the frame buffer device driver for the SiS 300, 315, 330 and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. @@ -1408,6 +1431,7 @@ config FB_VIA select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select I2C_ALGOBIT + select VIDEO_NOMODESET help This is the frame buffer device driver for Graphics chips of VIA UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ @@ -1447,6 +1471,7 @@ config FB_NEOMAGIC select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select VGASTATE + select VIDEO_NOMODESET help This driver supports notebooks with NeoMagic PCI chips. Say Y if you have such a graphics card. @@ -1460,6 +1485,7 @@ config FB_KYRO select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Say Y here if you have a STG4000 / Kyro / PowerVR 3 based graphics board. @@ -1474,6 +1500,7 @@ config FB_3DFX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_MODE_HELPERS + select VIDEO_NOMODESET help This driver supports graphics boards with the 3Dfx Banshee, Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have @@ -1503,6 +1530,7 @@ config FB_VOODOO1 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or Voodoo2 (cvg) based graphics card. @@ -1524,6 +1552,7 @@ config FB_VT8623 select FB_TILEBLITTING select FB_SVGALIB select VGASTATE + select VIDEO_NOMODESET select FONT_8x16 if FRAMEBUFFER_CONSOLE help Driver for CastleRock integrated graphics core in the @@ -1537,6 +1566,7 @@ config FB_TRIDENT select FB_CFB_IMAGEBLIT select FB_DDC select FB_MODE_HELPERS + select VIDEO_NOMODESET help This is the frame buffer device driver for Trident PCI/AGP chipsets. Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D @@ -1560,6 +1590,7 @@ config FB_ARK select FB_TILEBLITTING select FB_SVGALIB select VGASTATE + select VIDEO_NOMODESET select FONT_8x16 if FRAMEBUFFER_CONSOLE help Driver for PCI graphics boards with ARK 2000PV chip @@ -1571,6 +1602,7 @@ config FB_PM3 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This is the frame buffer device driver for the 3DLabs Permedia3 chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & @@ -1583,6 +1615,7 @@ config FB_CARMINE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help This is the frame buffer device driver for the Fujitsu Carmine chip. The driver provides two independent frame buffer devices. @@ -1961,6 +1994,7 @@ config FB_IBM_GXT4500 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Say Y here to enable support for the IBM GXT4000P/6000P and GXT4500P/6500P display adaptor based on Raster Engine RC1000, @@ -2101,6 +2135,7 @@ config FB_MB862XX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers. @@ -2188,6 +2223,7 @@ config FB_HYPERV select FB_CFB_IMAGEBLIT select FB_DEFERRED_IO select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA + select VIDEO_NOMODESET help This framebuffer driver supports Microsoft Hyper-V Synthetic Video. @@ -2230,6 +2266,7 @@ config FB_SM712 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Frame buffer driver for the Silicon Motion SM710, SM712, SM721 and SM722 chips. diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c index 5f8fec9e5fd4..60a96fdb5dd8 100644 --- a/drivers/video/fbdev/arkfb.c +++ b/drivers/video/fbdev/arkfb.c @@ -1187,7 +1187,12 @@ static int __init arkfb_init(void) #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("arkfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("arkfb", &option)) return -ENODEV; diff --git a/drivers/video/fbdev/asiliantfb.c b/drivers/video/fbdev/asiliantfb.c index 3818437a8f69..8383468f5577 100644 --- a/drivers/video/fbdev/asiliantfb.c +++ b/drivers/video/fbdev/asiliantfb.c @@ -616,6 +616,9 @@ static struct pci_driver asiliantfb_driver = { static int __init asiliantfb_init(void) { + if (fb_modesetting_disabled("asiliantfb")) + return -ENODEV; + if (fb_get_options("asiliantfb", NULL)) return -ENODEV; diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index 57e398fe7a81..dd31b9d7d337 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -2503,7 +2503,12 @@ static int aty128fb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("aty128fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("aty128fb", &option)) return -ENODEV; aty128fb_setup(option); diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index b3463d137152..0ccf5d401ecb 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -3965,7 +3965,12 @@ static int __init atyfb_init(void) int err1 = 1, err2 = 1; #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("atyfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("atyfb", &option)) return -ENODEV; atyfb_setup(option); diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index 8b28c9bddd97..657064227de8 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -2607,7 +2607,12 @@ static int __init radeonfb_init (void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("radeonfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("radeonfb", &option)) return -ENODEV; radeonfb_setup(option); diff --git a/drivers/video/fbdev/carminefb.c b/drivers/video/fbdev/carminefb.c index 4651b48a87f9..4ae21dbdb8ca 100644 --- a/drivers/video/fbdev/carminefb.c +++ b/drivers/video/fbdev/carminefb.c @@ -773,6 +773,9 @@ static struct pci_driver carmine_pci_driver = { static int __init carminefb_init(void) { + if (fb_modesetting_disabled("carminefb")) + return -ENODEV; + if (!(fb_displays & (CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) { printk(KERN_ERR "If you disable both displays than you don't " diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index f1c1c95c1fdf..cc37ec3f8fc1 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -506,6 +506,9 @@ static struct pci_driver chipsfb_driver = { int __init chips_init(void) { + if (fb_modesetting_disabled("chipsfb")) + return -ENODEV; + if (fb_get_options("chipsfb", NULL)) return -ENODEV; diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c index b08bee43779a..ba45e2147c52 100644 --- a/drivers/video/fbdev/cirrusfb.c +++ b/drivers/video/fbdev/cirrusfb.c @@ -2359,7 +2359,12 @@ static int __init cirrusfb_init(void) #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("cirrusfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("cirrusfb", &option)) return -ENODEV; cirrusfb_setup(option); diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index c730253ab85c..dec678f72a42 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -332,3 +332,19 @@ void fb_deferred_io_cleanup(struct fb_info *info) mutex_destroy(&fbdefio->lock); } EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); + +void fb_deferred_io_schedule_flush(struct fb_info *info) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + + if (WARN_ON_ONCE(!fbdefio)) + return; /* bug in driver logic */ + + /* + * There's no requirement from callers to schedule the + * flush immediately. Rather schedule the worker with a + * delay and let a few more writes pile up. + */ + schedule_delayed_work(&info->deferred_work, fbdefio->delay); +} +EXPORT_SYMBOL_GPL(fb_deferred_io_schedule_flush); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 1e70d8c67653..3a6c8458eb8d 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -40,6 +40,7 @@ #include <asm/fb.h> +#include <video/nomodeset.h> #include <video/vga.h> /* @@ -1844,4 +1845,18 @@ int fb_new_modelist(struct fb_info *info) return 0; } +#if defined(CONFIG_VIDEO_NOMODESET) +bool fb_modesetting_disabled(const char *drvname) +{ + bool fwonly = video_firmware_drivers_only(); + + if (fwonly) + pr_warn("Driver %s not loading because of nomodeset parameter\n", + drvname); + + return fwonly; +} +EXPORT_SYMBOL(fb_modesetting_disabled); +#endif + MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/cyber2000fb.c b/drivers/video/fbdev/cyber2000fb.c index 585af90a68a5..f005db54371f 100644 --- a/drivers/video/fbdev/cyber2000fb.c +++ b/drivers/video/fbdev/cyber2000fb.c @@ -48,7 +48,6 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> - #ifdef __arm__ #include <asm/mach-types.h> #endif @@ -1876,7 +1875,12 @@ static int __init cyber2000fb_init(void) #ifndef MODULE char *option = NULL; +#endif + if (fb_modesetting_disabled("CyberPro")) + return -ENODEV; + +#ifndef MODULE if (fb_get_options("cyber2000fb", &option)) return -ENODEV; cyber2000fb_setup(option); diff --git a/drivers/video/fbdev/geode/Kconfig b/drivers/video/fbdev/geode/Kconfig index ac9c860592aa..2f8f0fb1dae2 100644 --- a/drivers/video/fbdev/geode/Kconfig +++ b/drivers/video/fbdev/geode/Kconfig @@ -15,6 +15,7 @@ config FB_GEODE_LX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Framebuffer driver for the display controller integrated into the AMD Geode LX processors. @@ -30,6 +31,7 @@ config FB_GEODE_GX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Framebuffer driver for the display controller integrated into the AMD Geode GX processors. @@ -45,6 +47,7 @@ config FB_GEODE_GX1 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEO_NOMODESET help Framebuffer driver for the display controller integrated into the AMD Geode GX1 processor. diff --git a/drivers/video/fbdev/geode/gx1fb_core.c b/drivers/video/fbdev/geode/gx1fb_core.c index 1514c653a84f..9c942001ac10 100644 --- a/drivers/video/fbdev/geode/gx1fb_core.c +++ b/drivers/video/fbdev/geode/gx1fb_core.c @@ -446,7 +446,12 @@ static int __init gx1fb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("gx1fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("gx1fb", &option)) return -ENODEV; gx1fb_setup(option); diff --git a/drivers/video/fbdev/geode/gxfb_core.c b/drivers/video/fbdev/geode/gxfb_core.c index 2527bd80ec5f..8e05e76de075 100644 --- a/drivers/video/fbdev/geode/gxfb_core.c +++ b/drivers/video/fbdev/geode/gxfb_core.c @@ -511,7 +511,12 @@ static int __init gxfb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("gxfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("gxfb", &option)) return -ENODEV; diff --git a/drivers/video/fbdev/geode/lxfb_core.c b/drivers/video/fbdev/geode/lxfb_core.c index 9d26592dbfce..8130e9eee2b4 100644 --- a/drivers/video/fbdev/geode/lxfb_core.c +++ b/drivers/video/fbdev/geode/lxfb_core.c @@ -647,7 +647,12 @@ static int __init lxfb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("lxfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("lxfb", &option)) return -ENODEV; diff --git a/drivers/video/fbdev/gxt4500.c b/drivers/video/fbdev/gxt4500.c index 0dcef4bec8d7..5f42d3d9d6ce 100644 --- a/drivers/video/fbdev/gxt4500.c +++ b/drivers/video/fbdev/gxt4500.c @@ -779,6 +779,9 @@ static struct pci_driver gxt4500_driver = { static int gxt4500_init(void) { + if (fb_modesetting_disabled("gxt4500")) + return -ENODEV; + #ifndef MODULE if (fb_get_options("gxt4500", &mode_option)) return -ENODEV; diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 072ce07ba9e0..d8edb5635f77 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -59,7 +59,6 @@ #include <linux/hyperv.h> - /* Hyper-V Synthetic Video Protocol definitions and structures */ #define MAX_VMBUS_PKT_SIZE 0x4000 @@ -1363,6 +1362,9 @@ static int __init hvfb_drv_init(void) { int ret; + if (fb_modesetting_disabled("hyper_fb")) + return -ENODEV; + ret = vmbus_driver_register(&hvfb_drv); if (ret != 0) return ret; diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c index b795f6503cb6..3860b137b86a 100644 --- a/drivers/video/fbdev/i740fb.c +++ b/drivers/video/fbdev/i740fb.c @@ -1285,7 +1285,12 @@ static int __init i740fb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("i740fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("i740fb", &option)) return -ENODEV; i740fb_setup(option); diff --git a/drivers/video/fbdev/i810/i810_main.c b/drivers/video/fbdev/i810/i810_main.c index ff09f8c20bfc..85abb65f07d7 100644 --- a/drivers/video/fbdev/i810/i810_main.c +++ b/drivers/video/fbdev/i810/i810_main.c @@ -2143,6 +2143,9 @@ static int i810fb_init(void) { char *option = NULL; + if (fb_modesetting_disabled("i810fb")) + return -ENODEV; + if (fb_get_options("i810fb", &option)) return -ENODEV; i810fb_setup(option); @@ -2159,6 +2162,9 @@ static int i810fb_init(void) static int i810fb_init(void) { + if (fb_modesetting_disabled("i810fb")) + return -ENODEV; + hsync1 *= 1000; hsync2 *= 1000; diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c index d7edb9c5d3a3..bea45647184e 100644 --- a/drivers/video/fbdev/imsttfb.c +++ b/drivers/video/fbdev/imsttfb.c @@ -1617,7 +1617,12 @@ static int __init imsttfb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("imsttfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("imsttfb", &option)) return -ENODEV; diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c index d4a2891a9a7a..0a9e5067b201 100644 --- a/drivers/video/fbdev/intelfb/intelfbdrv.c +++ b/drivers/video/fbdev/intelfb/intelfbdrv.c @@ -389,6 +389,9 @@ static int __init intelfb_init(void) if (idonly) return -ENODEV; + if (fb_modesetting_disabled("intelfb")) + return -ENODEV; + #ifndef MODULE if (fb_get_options("intelfb", &option)) return -ENODEV; diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c index b4b93054c520..0596573ef140 100644 --- a/drivers/video/fbdev/kyro/fbdev.c +++ b/drivers/video/fbdev/kyro/fbdev.c @@ -789,7 +789,12 @@ static int __init kyrofb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("kyrofb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("kyrofb", &option)) return -ENODEV; kyrofb_setup(option); diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index 775d34115e2d..0d3cee7ae726 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -2314,6 +2314,9 @@ static void __init matroxfb_init_params(void) { static int __init matrox_init(void) { int err; + if (fb_modesetting_disabled("matroxfb")) + return -ENODEV; + matroxfb_init_params(); err = pci_register_driver(&matroxfb_driver); dev = -1; /* accept all new devices... */ diff --git a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c index 90c79e8c1157..a236fc910148 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c @@ -1181,6 +1181,9 @@ static int mb862xxfb_init(void) { int ret = -ENODEV; + if (fb_modesetting_disabled(DRV_NAME)) + return -ENODEV; + #if defined(CONFIG_FB_MB862XX_LIME) ret = platform_driver_register(&of_platform_mb862xxfb_driver); #endif diff --git a/drivers/video/fbdev/neofb.c b/drivers/video/fbdev/neofb.c index 93a2d2d1abe8..39d8cdef5c97 100644 --- a/drivers/video/fbdev/neofb.c +++ b/drivers/video/fbdev/neofb.c @@ -2209,7 +2209,12 @@ static int __init neofb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("neofb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("neofb", &option)) return -ENODEV; neofb_setup(option); diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index 329e2e8133c6..1960916098d4 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -1521,7 +1521,12 @@ static int nvidiafb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("nvidiafb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("nvidiafb", &option)) return -ENODEV; nvidiafb_setup(option); diff --git a/drivers/video/fbdev/pm2fb.c b/drivers/video/fbdev/pm2fb.c index 7da715d31a93..0823c9de859a 100644 --- a/drivers/video/fbdev/pm2fb.c +++ b/drivers/video/fbdev/pm2fb.c @@ -1799,7 +1799,12 @@ static int __init pm2fb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("pm2fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("pm2fb", &option)) return -ENODEV; pm2fb_setup(option); diff --git a/drivers/video/fbdev/pm3fb.c b/drivers/video/fbdev/pm3fb.c index ba69846d444f..b46a471df9ae 100644 --- a/drivers/video/fbdev/pm3fb.c +++ b/drivers/video/fbdev/pm3fb.c @@ -1540,7 +1540,12 @@ static int __init pm3fb_init(void) */ #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("pm3fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("pm3fb", &option)) return -ENODEV; pm3fb_setup(option); diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index b73ad14efa20..6888127a5eb8 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -1082,7 +1082,12 @@ static int __init pvr2fb_init(void) #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("pvr2fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("pvr2fb", &option)) return -ENODEV; pvr2fb_setup(option); diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index 0ea74e28f915..644278146d3b 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -2165,7 +2165,12 @@ static int rivafb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("rivafb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("rivafb", &option)) return -ENODEV; rivafb_setup(option); diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index 7713274bd04c..7d257489edcc 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -1558,7 +1558,12 @@ static int __init s3fb_init(void) #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("s3fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("s3fb", &option)) return -ENODEV; s3fb_setup(option); diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c index b7818b652698..4a27b68798bf 100644 --- a/drivers/video/fbdev/savage/savagefb_driver.c +++ b/drivers/video/fbdev/savage/savagefb_driver.c @@ -2556,6 +2556,9 @@ static int __init savagefb_init(void) DBG("savagefb_init"); + if (fb_modesetting_disabled("savagefb")) + return -ENODEV; + if (fb_get_options("savagefb", &option)) return -ENODEV; diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c index 1c197c3f9538..cfba776afcea 100644 --- a/drivers/video/fbdev/sis/sis_main.c +++ b/drivers/video/fbdev/sis/sis_main.c @@ -6588,7 +6588,12 @@ static int __init sisfb_init(void) { #ifndef MODULE char *options = NULL; +#endif + + if (fb_modesetting_disabled("sisfb")) + return -ENODEV; +#ifndef MODULE if(fb_get_options("sisfb", &options)) return -ENODEV; diff --git a/drivers/video/fbdev/skeletonfb.c b/drivers/video/fbdev/skeletonfb.c index a10f1057293b..40c130ab6b38 100644 --- a/drivers/video/fbdev/skeletonfb.c +++ b/drivers/video/fbdev/skeletonfb.c @@ -987,7 +987,12 @@ static int __init xxxfb_init(void) */ #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("xxxfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("xxxfb", &option)) return -ENODEV; xxxfb_setup(option); diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index 3baf33635e65..b528776c7612 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -1756,6 +1756,9 @@ static int __init sm712fb_init(void) { char *option = NULL; + if (fb_modesetting_disabled("sm712fb")) + return -ENODEV; + if (fb_get_options("sm712fb", &option)) return -ENODEV; if (option && *option) diff --git a/drivers/video/fbdev/sstfb.c b/drivers/video/fbdev/sstfb.c index a56b24288566..da296b2ab54a 100644 --- a/drivers/video/fbdev/sstfb.c +++ b/drivers/video/fbdev/sstfb.c @@ -1503,6 +1503,9 @@ static int sstfb_init(void) { char *option = NULL; + if (fb_modesetting_disabled("sstfb")) + return -ENODEV; + if (fb_get_options("sstfb", &option)) return -ENODEV; sstfb_setup(option); diff --git a/drivers/video/fbdev/sunxvr2500.c b/drivers/video/fbdev/sunxvr2500.c index f4059529c602..2cab4b9be68a 100644 --- a/drivers/video/fbdev/sunxvr2500.c +++ b/drivers/video/fbdev/sunxvr2500.c @@ -247,6 +247,9 @@ static struct pci_driver s3d_driver = { static int __init s3d_init(void) { + if (fb_modesetting_disabled("s3d")) + return -ENODEV; + if (fb_get_options("s3d", NULL)) return -ENODEV; diff --git a/drivers/video/fbdev/sunxvr500.c b/drivers/video/fbdev/sunxvr500.c index b0c8cf0c535a..6ec358af1256 100644 --- a/drivers/video/fbdev/sunxvr500.c +++ b/drivers/video/fbdev/sunxvr500.c @@ -430,6 +430,9 @@ static struct pci_driver e3d_driver = { static int __init e3d_init(void) { + if (fb_modesetting_disabled("e3d")) + return -ENODEV; + if (fb_get_options("e3d", NULL)) return -ENODEV; diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c index 592a913d0718..d17e5e1472aa 100644 --- a/drivers/video/fbdev/tdfxfb.c +++ b/drivers/video/fbdev/tdfxfb.c @@ -1632,7 +1632,12 @@ static int __init tdfxfb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("tdfxfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("tdfxfb", &option)) return -ENODEV; diff --git a/drivers/video/fbdev/tgafb.c b/drivers/video/fbdev/tgafb.c index 251dbd282f5e..14d37c49633c 100644 --- a/drivers/video/fbdev/tgafb.c +++ b/drivers/video/fbdev/tgafb.c @@ -1597,7 +1597,12 @@ static int tgafb_init(void) int status; #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("tgafb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("tgafb", &option)) return -ENODEV; tgafb_setup(option); diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 219ce7292337..6099b9768ba1 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -1811,7 +1811,12 @@ static int __init tridentfb_init(void) { #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("tridentfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("tridentfb", &option)) return -ENODEV; tridentfb_setup(option); diff --git a/drivers/video/fbdev/vermilion/vermilion.c b/drivers/video/fbdev/vermilion/vermilion.c index 82b36dbb5b1a..1465fb7b619e 100644 --- a/drivers/video/fbdev/vermilion/vermilion.c +++ b/drivers/video/fbdev/vermilion/vermilion.c @@ -1057,7 +1057,12 @@ static int __init vmlfb_init(void) #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("vmlfb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options(MODULE_NAME, &option)) return -ENODEV; #endif diff --git a/drivers/video/fbdev/via/via-core.c b/drivers/video/fbdev/via/via-core.c index 2ee8fcae08df..32a6399b080b 100644 --- a/drivers/video/fbdev/via/via-core.c +++ b/drivers/video/fbdev/via/via-core.c @@ -725,6 +725,9 @@ static int __init via_core_init(void) { int ret; + if (fb_modesetting_disabled("viafb")) + return -ENODEV; + ret = viafb_init(); if (ret) return ret; diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c index 49b9f148d3a1..034333ee6e45 100644 --- a/drivers/video/fbdev/vt8623fb.c +++ b/drivers/video/fbdev/vt8623fb.c @@ -920,7 +920,12 @@ static int __init vt8623fb_init(void) #ifndef MODULE char *option = NULL; +#endif + + if (fb_modesetting_disabled("vt8623fb")) + return -ENODEV; +#ifndef MODULE if (fb_get_options("vt8623fb", &option)) return -ENODEV; diff --git a/drivers/gpu/drm/drm_nomodeset.c b/drivers/video/nomodeset.c index f3978d5bd3a1..13cc8b719697 100644 --- a/drivers/gpu/drm/drm_nomodeset.c +++ b/drivers/video/nomodeset.c @@ -3,17 +3,19 @@ #include <linux/module.h> #include <linux/types.h> -static bool drm_nomodeset; +#include <video/nomodeset.h> -bool drm_firmware_drivers_only(void) +static bool video_nomodeset; + +bool video_firmware_drivers_only(void) { - return drm_nomodeset; + return video_nomodeset; } -EXPORT_SYMBOL(drm_firmware_drivers_only); +EXPORT_SYMBOL(video_firmware_drivers_only); static int __init disable_modeset(char *str) { - drm_nomodeset = true; + video_nomodeset = true; pr_warn("Booted with the nomodeset parameter. Only the system framebuffer will be available\n"); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index b5fe710a3365..565cf9d3c550 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1219,6 +1219,13 @@ struct drm_cmdline_mode { bool bpp_specified; /** + * @pixel_clock: + * + * Pixel Clock in kHz. Optional. + */ + unsigned int pixel_clock; + + /** * @xres: * * Active resolution on the X axis, in pixels. diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index f6159acb8856..700d3857e088 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -30,6 +30,8 @@ #include <linux/list.h> #include <linux/irqreturn.h> +#include <video/nomodeset.h> + #include <drm/drm_device.h> struct drm_file; @@ -602,6 +604,10 @@ static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev) int drm_dev_set_unique(struct drm_device *dev, const char *name); -extern bool drm_firmware_drivers_only(void); +/* TODO: Inline drm_firmware_drivers_only() in all its callers. */ +static inline bool drm_firmware_drivers_only(void) +{ + return video_firmware_drivers_only(); +} #endif diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index b111dc7ada78..455f6c2b8117 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -116,7 +116,6 @@ struct drm_fb_helper_funcs { * @damage_clip: clip rectangle used with deferred_io to accumulate damage to * the screen buffer * @damage_lock: spinlock protecting @damage_clip - * @damage_work: worker used to flush the framebuffer * @resume_work: worker used during resume if the console lock is already taken * * This is the main structure used by the fbdev helpers. Drivers supporting @@ -146,7 +145,6 @@ struct drm_fb_helper { u32 pseudo_palette[17]; struct drm_clip_rect damage_clip; spinlock_t damage_lock; - struct work_struct damage_work; struct work_struct resume_work; /** diff --git a/include/linux/fb.h b/include/linux/fb.h index 0aff76bcbb00..8dc9635f5bc1 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -663,6 +663,7 @@ extern void fb_deferred_io_open(struct fb_info *info, struct inode *inode, struct file *file); extern void fb_deferred_io_cleanup(struct fb_info *info); +extern void fb_deferred_io_schedule_flush(struct fb_info *info); extern int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync); @@ -803,6 +804,15 @@ extern int fb_find_mode(struct fb_var_screeninfo *var, const struct fb_videomode *default_mode, unsigned int default_bpp); +#if defined(CONFIG_VIDEO_NOMODESET) +bool fb_modesetting_disabled(const char *drvname); +#else +bool fb_modesetting_disabled(const char *drvname) +{ + return false; +} +#endif + /* Convenience logging macros */ #define fb_err(fb_info, fmt, ...) \ pr_err("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__) diff --git a/include/video/nomodeset.h b/include/video/nomodeset.h new file mode 100644 index 000000000000..8f8688b8beab --- /dev/null +++ b/include/video/nomodeset.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef VIDEO_NOMODESET_H +#define VIDEO_NOMODESET_H + +bool video_firmware_drivers_only(void); + +#endif |