diff options
author | Dave Airlie <airlied@redhat.com> | 2020-01-03 11:43:31 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2020-01-03 11:43:44 +1000 |
commit | f5c547efa16c0ea5abff0596e829f502be11902e (patch) | |
tree | 1c8aedb783cf543d499c4f23db6c563289e81103 | |
parent | 3ae3271443b337c1cd421a9b73d51c5c2de52977 (diff) | |
parent | 1ce0d5162b98bf6120db1b259d0f0706e69f15fd (diff) |
Merge tag 'drm-misc-next-2020-01-02' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v5.6:
UAPI Changes:
- Commandline parser: Add support for panel orientation, and per-mode options.
- Fix IOCTL naming for dma-buf heaps.
Cross-subsystem Changes:
- Rename DMA_HEAP_IOC_ALLOC to DMA_HEAP_IOCTL_ALLOC before it becomes abi.
- Change DMA-BUF system-heap's name to system.
- Fix leak in error handling in dma_heap_ioctl(), and make a symbol static.
- Fix udma-buf cpu access.
- Fix ti devicetree bindings.
Core Changes:
- Add CTA-861-G modes with VIC >= 193.
- Change error handling and remove bug_on in *drm_dev_init.
- Export drm_panel_of_backlight() correctly once more.
- Add support for lvds decoders.
- Convert drm/client and drm/(gem-,)fb-helper to drm-device based logging and update logging todo.
Driver Changes:
- Add support for dsi/px30 to rockchip.
- Add fb damage support to virtio.
- Use dma_resv locking wrappers in vc4, msm, etnaviv.
- Make functions in virtio static, and perform some simplifications.
- Add suspend support to sun4i.
- Add A64 mipi dsi support to sun4i.
- Add runtime pm suspend to komeda.
- Associated driver fixes.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/efc11139-1653-86bc-1b0f-0aefde219850@linux.intel.com
67 files changed, 1645 insertions, 824 deletions
diff --git a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml index 0f7074977c04..9e90c2b00960 100644 --- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml +++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml @@ -15,7 +15,9 @@ properties: "#size-cells": true compatible: - const: allwinner,sun6i-a31-mipi-dsi + enum: + - allwinner,sun6i-a31-mipi-dsi + - allwinner,sun50i-a64-mipi-dsi reg: maxItems: 1 @@ -24,6 +26,8 @@ properties: maxItems: 1 clocks: + minItems: 1 + maxItems: 2 items: - description: Bus Clock - description: Module Clock @@ -63,13 +67,38 @@ required: - reg - interrupts - clocks - - clock-names - phys - phy-names - resets - vcc-dsi-supply - port +allOf: + - if: + properties: + compatible: + contains: + const: allwinner,sun6i-a31-mipi-dsi + + then: + properties: + clocks: + minItems: 2 + + required: + - clock-names + + - if: + properties: + compatible: + contains: + const: allwinner,sun50i-a64-mipi-dsi + + then: + properties: + clocks: + minItems: 1 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml new file mode 100644 index 000000000000..8f373029f5d2 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/lvds-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Transparent LVDS encoders and decoders + +maintainers: + - Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> + +description: | + This binding supports transparent LVDS encoders and decoders that don't + require any configuration. + + LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple + incompatible data link layers have been used over time to transmit image data + to LVDS panels. This binding targets devices compatible with the following + specifications only. + + [JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February + 1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) + [LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National + Semiconductor + [VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video + Electronics Standards Association (VESA) + + Those devices have been marketed under the FPD-Link and FlatLink brand names + among others. + +properties: + compatible: + oneOf: + - items: + - enum: + - ti,ds90c185 # For the TI DS90C185 FPD-Link Serializer + - ti,ds90c187 # For the TI DS90C187 FPD-Link Serializer + - ti,sn75lvds83 # For the TI SN75LVDS83 FlatLink transmitter + - const: lvds-encoder # Generic LVDS encoder compatible fallback + - items: + - enum: + - ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver + - const: lvds-decoder # Generic LVDS decoders compatible fallback + - enum: + - thine,thc63lvdm83d # For the THC63LVDM83D LVDS serializer + + ports: + type: object + description: | + This device has two video ports. Their connections are modeled using the + OF graph bindings specified in Documentation/devicetree/bindings/graph.txt + properties: + port@0: + type: object + description: | + For LVDS encoders, port 0 is the parallel input + For LVDS decoders, port 0 is the LVDS input + + port@1: + type: object + description: | + For LVDS encoders, port 1 is the LVDS output + For LVDS decoders, port 1 is the parallel output + + required: + - port@0 + - port@1 + + powerdown-gpios: + description: + The GPIO used to control the power down line of this device. + maxItems: 1 + +required: + - compatible + - ports + +examples: + - | + lvds-encoder { + compatible = "ti,ds90c185", "lvds-encoder"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_enc_in: endpoint { + remote-endpoint = <&display_out_rgb>; + }; + }; + + port@1 { + reg = <1>; + + lvds_enc_out: endpoint { + remote-endpoint = <&lvds_panel_in>; + }; + }; + }; + }; + + - | + lvds-decoder { + compatible = "ti,ds90cf384a", "lvds-decoder"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_dec_in: endpoint { + remote-endpoint = <&display_out_lvds>; + }; + }; + + port@1 { + reg = <1>; + + lvds_dec_out: endpoint { + remote-endpoint = <&rgb_panel_in>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt deleted file mode 100644 index 60091db5dfa5..000000000000 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ /dev/null @@ -1,66 +0,0 @@ -Parallel to LVDS Encoder ------------------------- - -This binding supports the parallel to LVDS encoders that don't require any -configuration. - -LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple -incompatible data link layers have been used over time to transmit image data -to LVDS panels. This binding targets devices compatible with the following -specifications only. - -[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February -1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) -[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National -Semiconductor -[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video -Electronics Standards Association (VESA) - -Those devices have been marketed under the FPD-Link and FlatLink brand names -among others. - - -Required properties: - -- compatible: Must be "lvds-encoder" - - Any encoder compatible with this generic binding, but with additional - properties not listed here, must list a device specific compatible first - followed by this generic compatible. - -Required nodes: - -This device has two video ports. Their connections are modeled using the OF -graph bindings specified in Documentation/devicetree/bindings/graph.txt. - -- Video port 0 for parallel input -- Video port 1 for LVDS output - - -Example -------- - -lvds-encoder { - compatible = "lvds-encoder"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_enc_in: endpoint { - remote-endpoint = <&display_out_rgb>; - }; - }; - - port@1 { - reg = <1>; - - lvds_enc_out: endpoint { - remote-endpoint = <&lvds_panel_in>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt b/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt deleted file mode 100644 index fee3c88e1a17..000000000000 --- a/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt +++ /dev/null @@ -1,50 +0,0 @@ -THine Electronics THC63LVDM83D LVDS serializer ----------------------------------------------- - -The THC63LVDM83D is an LVDS serializer designed to support pixel data -transmission between a host and a flat panel. - -Required properties: - -- compatible: Should be "thine,thc63lvdm83d" - -Optional properties: - -- powerdown-gpios: Power down control GPIO (the /PWDN pin, active low). - -Required nodes: - -The THC63LVDM83D has two video ports. Their connections are modeled using the -OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt. - -- Video port 0 for CMOS/TTL input -- Video port 1 for LVDS output - - -Example -------- - - lvds_enc: encoder@0 { - compatible = "thine,thc63lvdm83d"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_enc_in: endpoint@0 { - remote-endpoint = <&rgb_out>; - }; - }; - - port@1 { - reg = <1>; - - lvds_enc_out: endpoint@0 { - remote-endpoint = <&panel_in>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt b/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt deleted file mode 100644 index e575f996959a..000000000000 --- a/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt +++ /dev/null @@ -1,55 +0,0 @@ -Texas Instruments FPD-Link (LVDS) Serializer --------------------------------------------- - -The DS90C185 and DS90C187 are low-power serializers for portable -battery-powered applications that reduces the size of the RGB -interface between the host GPU and the display. - -Required properties: - -- compatible: Should be - "ti,ds90c185", "lvds-encoder" for the TI DS90C185 FPD-Link Serializer - "ti,ds90c187", "lvds-encoder" for the TI DS90C187 FPD-Link Serializer - -Optional properties: - -- powerdown-gpios: Power down control GPIO (the PDB pin, active-low) - -Required nodes: - -The devices have two video ports. Their connections are modeled using the OF -graph bindings specified in Documentation/devicetree/bindings/graph.txt. - -- Video port 0 for parallel input -- Video port 1 for LVDS output - - -Example -------- - -lvds-encoder { - compatible = "ti,ds90c185", "lvds-encoder"; - - powerdown-gpios = <&gpio 17 GPIO_ACTIVE_LOW>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_enc_in: endpoint { - remote-endpoint = <&lcdc_out_rgb>; - }; - }; - - port@1 { - reg = <1>; - - lvds_enc_out: endpoint { - remote-endpoint = <&lvds_panel_in>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index ce4c1fc9116c..151be3bba06f 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -4,13 +4,16 @@ Rockchip specific extensions to the Synopsys Designware MIPI DSI Required properties: - #address-cells: Should be <1>. - #size-cells: Should be <0>. -- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". - "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi". +- compatible: one of + "rockchip,px30-mipi-dsi", "snps,dw-mipi-dsi" + "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi" + "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi" - reg: Represent the physical address range of the controller. - interrupts: Represent the controller's interrupt to the CPU(s). - clocks, clock-names: Phandles to the controller's pll reference - clock(ref) and APB clock(pclk). For RK3399, a phy config clock - (phy_cfg) and a grf clock(grf) are required. As described in [1]. + clock(ref) when using an internal dphy and APB clock(pclk). + For RK3399, a phy config clock (phy_cfg) and a grf clock(grf) + are required. As described in [1]. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - ports: contain a port node with endpoint definitions as defined in [2]. For vopb,set the reg = <0> and set the reg = <1> for vopl. @@ -18,6 +21,8 @@ Required properties: - video port 1 for either a panel or subsequent encoder Optional properties: +- phys: from general PHY binding: the phandle for the PHY device. +- phy-names: Should be "dphy" if phys references an external phy. - power-domains: a phandle to mipi dsi power domain node. - resets: list of phandle + reset specifier pairs, as described in [3]. - reset-names: string reset name, must be "apb". diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml index 230d74f22136..d0b541a461f3 100644 --- a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml @@ -15,7 +15,11 @@ properties: const: 0 compatible: - const: allwinner,sun6i-a31-mipi-dphy + oneOf: + - const: allwinner,sun6i-a31-mipi-dphy + - items: + - const: allwinner,sun50i-a64-mipi-dphy + - const: allwinner,sun6i-a31-mipi-dphy reg: maxItems: 1 diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 9c4e3fd39e6d..624d08fd2856 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -65,6 +65,9 @@ Valid options are:: - reflect_y (boolean): Perform an axial symmetry on the Y axis - rotate (integer): Rotate the initial framebuffer by x degrees. Valid values are 0, 90, 180 and 270. + - panel_orientation, one of "normal", "upside_down", "left_side_up", or + "right_side_up". For KMS drivers only, this sets the "panel orientation" + property on the kms connector as hint for kms users. ----------------------------------------------------------------------------- diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 2d85f37284a1..bc869b23fc39 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -142,14 +142,14 @@ Contact: Daniel Vetter, respective driver maintainers Level: Advanced -Convert instances of dev_info/dev_err/dev_warn to their DRM_DEV_* equivalent ----------------------------------------------------------------------------- +Convert logging to drm_* functions with drm_device paramater +------------------------------------------------------------ For drivers which could have multiple instances, it is necessary to differentiate between which is which in the logs. Since DRM_INFO/WARN/ERROR don't do this, drivers used dev_info/warn/err to make this differentiation. We -now have DRM_DEV_* variants of the drm print macros, so we can start to convert -those drivers back to using drm-formwatted specific log messages. +now have drm_* variants of the drm print functions, so we can start to convert +those drivers back to using drm-formatted specific log messages. Before you start this conversion please contact the relevant maintainers to make sure your work will be merged - not everyone agrees that the DRM dmesg macros diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c index 4f04d104ae61..afd22c9dbdcf 100644 --- a/drivers/dma-buf/dma-heap.c +++ b/drivers/dma-buf/dma-heap.c @@ -106,8 +106,8 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data) return 0; } -unsigned int dma_heap_ioctl_cmds[] = { - DMA_HEAP_IOC_ALLOC, +static unsigned int dma_heap_ioctl_cmds[] = { + DMA_HEAP_IOCTL_ALLOC, }; static long dma_heap_ioctl(struct file *file, unsigned int ucmd, @@ -153,11 +153,12 @@ static long dma_heap_ioctl(struct file *file, unsigned int ucmd, memset(kdata + in_size, 0, ksize - in_size); switch (kcmd) { - case DMA_HEAP_IOC_ALLOC: + case DMA_HEAP_IOCTL_ALLOC: ret = dma_heap_ioctl_allocate(file, kdata); break; default: - return -ENOTTY; + ret = -ENOTTY; + goto err; } if (copy_to_user((void __user *)arg, kdata, out_size) != 0) diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index 1aa01e98c595..0bf688e3c023 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -109,7 +109,7 @@ static int system_heap_create(void) struct dma_heap_export_info exp_info; int ret = 0; - exp_info.name = "system_heap"; + exp_info.name = "system"; exp_info.ops = &system_heap_ops; exp_info.priv = NULL; diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 61b0a2cff874..acb26c627d27 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -122,9 +122,8 @@ static int begin_cpu_udmabuf(struct dma_buf *buf, if (IS_ERR(ubuf->sg)) return PTR_ERR(ubuf->sg); } else { - dma_sync_sg_for_device(dev, ubuf->sg->sgl, - ubuf->sg->nents, - direction); + dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents, + direction); } return 0; @@ -139,7 +138,7 @@ static int end_cpu_udmabuf(struct dma_buf *buf, if (!ubuf->sg) return -EINVAL; - dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents, direction); + dma_sync_sg_for_device(dev, ubuf->sg->sgl, ubuf->sg->nents, direction); return 0; } diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c index dd1ecf4276d3..00fa56c29b3e 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c @@ -20,8 +20,10 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline) evts |= KOMEDA_EVENT_IBSY; if (raw_status & LPU_IRQ_EOW) evts |= KOMEDA_EVENT_EOW; + if (raw_status & LPU_IRQ_OVR) + evts |= KOMEDA_EVENT_OVR; - if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY)) { + if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY | LPU_IRQ_OVR)) { u32 restore = 0, tbu_status; /* Check error of LPU status */ status = malidp_read32(reg, BLK_STATUS); @@ -45,6 +47,15 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline) restore |= LPU_STATUS_ACE3; evts |= KOMEDA_ERR_ACE3; } + if (status & LPU_STATUS_FEMPTY) { + restore |= LPU_STATUS_FEMPTY; + evts |= KOMEDA_EVENT_EMPTY; + } + if (status & LPU_STATUS_FFULL) { + restore |= LPU_STATUS_FFULL; + evts |= KOMEDA_EVENT_FULL; + } + if (restore != 0) malidp_write32_mask(reg, BLK_STATUS, restore, 0); diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h index 81de6a23e7f3..e80172a0b320 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h @@ -175,6 +175,7 @@ #define TBU_DOUTSTDCAPB_MASK 0x3F /* LPU_IRQ_BITS */ +#define LPU_IRQ_OVR BIT(9) #define LPU_IRQ_IBSY BIT(10) #define LPU_IRQ_ERR BIT(11) #define LPU_IRQ_EOW BIT(12) @@ -185,6 +186,8 @@ #define LPU_STATUS_AXIE BIT(4) #define LPU_STATUS_AXIRP BIT(5) #define LPU_STATUS_AXIWP BIT(6) +#define LPU_STATUS_FEMPTY BIT(11) +#define LPU_STATUS_FFULL BIT(14) #define LPU_STATUS_ACE0 BIT(16) #define LPU_STATUS_ACE1 BIT(17) #define LPU_STATUS_ACE2 BIT(18) diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 1c452ea75999..56bd938961ee 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -5,6 +5,7 @@ * */ #include <linux/clk.h> +#include <linux/pm_runtime.h> #include <linux/spinlock.h> #include <drm/drm_atomic.h> @@ -274,6 +275,7 @@ static void komeda_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old) { + pm_runtime_get_sync(crtc->dev->dev); komeda_crtc_prepare(to_kcrtc(crtc)); drm_crtc_vblank_on(crtc); WARN_ON(drm_crtc_vblank_get(crtc)); @@ -372,6 +374,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc, drm_crtc_vblank_put(crtc); drm_crtc_vblank_off(crtc); komeda_crtc_unprepare(kcrtc); + pm_runtime_put(crtc->dev->dev); } static void diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c index 38b832804bad..1d767473ba8a 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c @@ -10,6 +10,7 @@ #include <linux/of_graph.h> #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/dma-mapping.h> #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h> @@ -27,12 +28,16 @@ static int komeda_register_show(struct seq_file *sf, void *x) seq_puts(sf, "\n====== Komeda register dump =========\n"); + pm_runtime_get_sync(mdev->dev); + if (mdev->funcs->dump_register) mdev->funcs->dump_register(mdev, sf); for (i = 0; i < mdev->n_pipelines; i++) komeda_pipeline_dump_register(mdev->pipelines[i], sf); + pm_runtime_put(mdev->dev); + return 0; } @@ -263,15 +268,6 @@ struct komeda_dev *komeda_dev_create(struct device *dev) if (!mdev->iommu) DRM_INFO("continue without IOMMU support!\n"); - if (mdev->iommu && mdev->funcs->connect_iommu) { - err = mdev->funcs->connect_iommu(mdev); - if (err) { - DRM_ERROR("connect iommu failed.\n"); - mdev->iommu = NULL; - goto disable_clk; - } - } - clk_disable_unprepare(mdev->aclk); err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group); @@ -310,11 +306,6 @@ void komeda_dev_destroy(struct komeda_dev *mdev) if (mdev->aclk) clk_prepare_enable(mdev->aclk); - if (mdev->iommu && mdev->funcs->disconnect_iommu) - if (mdev->funcs->disconnect_iommu(mdev)) - DRM_ERROR("disconnect iommu failed.\n"); - mdev->iommu = NULL; - for (i = 0; i < mdev->n_pipelines; i++) { komeda_pipeline_destroy(mdev, mdev->pipelines[i]); mdev->pipelines[i] = NULL; @@ -343,44 +334,26 @@ void komeda_dev_destroy(struct komeda_dev *mdev) int komeda_dev_resume(struct komeda_dev *mdev) { - int ret = 0; - clk_prepare_enable(mdev->aclk); - if (mdev->iommu && mdev->funcs->connect_iommu) { - ret = mdev->funcs->connect_iommu(mdev); - if (ret < 0) { - DRM_ERROR("connect iommu failed.\n"); - goto disable_clk; - } - } - - ret = mdev->funcs->enable_irq(mdev); + mdev->funcs->enable_irq(mdev); -disable_clk: - clk_disable_unprepare(mdev->aclk); + if (mdev->iommu && mdev->funcs->connect_iommu) + if (mdev->funcs->connect_iommu(mdev)) + DRM_ERROR("connect iommu failed.\n"); - return ret; + return 0; } int komeda_dev_suspend(struct komeda_dev *mdev) { - int ret = 0; - - clk_prepare_enable(mdev->aclk); - - if (mdev->iommu && mdev->funcs->disconnect_iommu) { - ret = mdev->funcs->disconnect_iommu(mdev); - if (ret < 0) { + if (mdev->iommu && mdev->funcs->disconnect_iommu) + if (mdev->funcs->disconnect_iommu(mdev)) DRM_ERROR("disconnect iommu failed.\n"); - goto disable_clk; - } - } - ret = mdev->funcs->disable_irq(mdev); + mdev->funcs->disable_irq(mdev); -disable_clk: clk_disable_unprepare(mdev->aclk); - return ret; + return 0; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h index 4a67a80d5fcf..ce27f2f27c24 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h @@ -20,6 +20,8 @@ #define KOMEDA_EVENT_OVR BIT_ULL(4) #define KOMEDA_EVENT_EOW BIT_ULL(5) #define KOMEDA_EVENT_MODE BIT_ULL(6) +#define KOMEDA_EVENT_FULL BIT_ULL(7) +#define KOMEDA_EVENT_EMPTY BIT_ULL(8) #define KOMEDA_ERR_TETO BIT_ULL(14) #define KOMEDA_ERR_TEMR BIT_ULL(15) @@ -49,7 +51,8 @@ KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\ KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF) -#define KOMEDA_WARN_EVENTS KOMEDA_ERR_CSCE +#define KOMEDA_WARN_EVENTS \ + (KOMEDA_ERR_CSCE | KOMEDA_EVENT_FULL | KOMEDA_EVENT_EMPTY) #define KOMEDA_INFO_EVENTS (0 \ | KOMEDA_EVENT_VSYNC \ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index ad38bbc7431e..ea5cd1e17304 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -33,6 +33,12 @@ static void komeda_unbind(struct device *dev) return; komeda_kms_detach(mdrv->kms); + + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + else + komeda_dev_suspend(mdrv->mdev); + komeda_dev_destroy(mdrv->mdev); dev_set_drvdata(dev, NULL); @@ -54,6 +60,10 @@ static int komeda_bind(struct device *dev) goto free_mdrv; } + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) + komeda_dev_resume(mdrv->mdev); + mdrv->kms = komeda_kms_attach(mdrv->mdev); if (IS_ERR(mdrv->kms)) { err = PTR_ERR(mdrv->kms); @@ -65,6 +75,11 @@ static int komeda_bind(struct device *dev) return 0; destroy_mdev: + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + else + komeda_dev_suspend(mdrv->mdev); + komeda_dev_destroy(mdrv->mdev); free_mdrv: @@ -131,15 +146,29 @@ static const struct of_device_id komeda_of_match[] = { MODULE_DEVICE_TABLE(of, komeda_of_match); +static int komeda_rt_pm_suspend(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + + return komeda_dev_suspend(mdrv->mdev); +} + +static int komeda_rt_pm_resume(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + + return komeda_dev_resume(mdrv->mdev); +} + static int __maybe_unused komeda_pm_suspend(struct device *dev) { struct komeda_drv *mdrv = dev_get_drvdata(dev); - struct drm_device *drm = &mdrv->kms->base; int res; - res = drm_mode_config_helper_suspend(drm); + res = drm_mode_config_helper_suspend(&mdrv->kms->base); - komeda_dev_suspend(mdrv->mdev); + if (!pm_runtime_status_suspended(dev)) + komeda_dev_suspend(mdrv->mdev); return res; } @@ -147,15 +176,16 @@ static int __maybe_unused komeda_pm_suspend(struct device *dev) static int __maybe_unused komeda_pm_resume(struct device *dev) { struct komeda_drv *mdrv = dev_get_drvdata(dev); - struct drm_device *drm = &mdrv->kms->base; - komeda_dev_resume(mdrv->mdev); + if (!pm_runtime_status_suspended(dev)) + komeda_dev_resume(mdrv->mdev); - return drm_mode_config_helper_resume(drm); + return drm_mode_config_helper_resume(&mdrv->kms->base); } static const struct dev_pm_ops komeda_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) + SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL) }; static struct platform_driver komeda_platform_driver = { diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_event.c b/drivers/gpu/drm/arm/display/komeda/komeda_event.c index 977c38d516da..53f944e66dfc 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_event.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_event.c @@ -78,6 +78,8 @@ static void evt_str(struct komeda_str *str, u64 events) /* LPU errors or events */ evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|"); + evt_sprintf(str, events & KOMEDA_EVENT_EMPTY, "EMPTY|"); + evt_sprintf(str, events & KOMEDA_EVENT_FULL, "FULL|"); evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|"); evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|"); evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|"); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 2368a0aab83d..442d4656150a 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -308,10 +308,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) if (err) goto free_component_binding; - err = mdev->funcs->enable_irq(mdev); - if (err) - goto free_component_binding; - drm->irq_enabled = true; drm_kms_helper_poll_init(drm); @@ -325,7 +321,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) free_interrupts: drm_kms_helper_poll_fini(drm); drm->irq_enabled = false; - mdev->funcs->disable_irq(mdev); free_component_binding: component_unbind_all(mdev->dev, drm); cleanup_mode_config: @@ -347,7 +342,6 @@ void komeda_kms_detach(struct komeda_kms_dev *kms) drm_kms_helper_poll_fini(drm); drm_atomic_helper_shutdown(drm); drm->irq_enabled = false; - mdev->funcs->disable_irq(mdev); component_unbind_all(mdev->dev, drm); drm_mode_config_cleanup(drm); komeda_kms_cleanup_private_objs(kms); diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 3c70a53813bf..37715cc6064e 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -512,7 +512,7 @@ static int malidp_de_plane_check(struct drm_plane *plane, int i, ret; unsigned int block_w, block_h; - if (!state->crtc || !state->fb) + if (!state->crtc || WARN_ON(!state->fb)) return 0; fb = state->fb; diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c index e567bdfa2ab8..b615b7dfdd9d 100644 --- a/drivers/gpu/drm/bochs/bochs_hw.c +++ b/drivers/gpu/drm/bochs/bochs_hw.c @@ -255,7 +255,7 @@ void bochs_hw_setformat(struct bochs_device *bochs, DRM_ERROR("%s: Huh? Got framebuffer format 0x%x", __func__, format->format); break; - }; + } } void bochs_hw_setbase(struct bochs_device *bochs, diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index ccc698c44f58..0b9ca5862455 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -35,14 +35,14 @@ config DRM_DUMB_VGA_DAC Support for non-programmable RGB to VGA DAC bridges, such as ADI ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs. -config DRM_LVDS_ENCODER - tristate "Transparent parallel to LVDS encoder support" +config DRM_LVDS_CODEC + tristate "Transparent LVDS encoders and decoders support" depends on OF select DRM_KMS_HELPER select DRM_PANEL_BRIDGE help - Support for transparent parallel to LVDS encoders that don't require - any configuration. + Support for transparent LVDS encoders and decoders that don't + require any configuration. config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw" diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index a6c7dd7727ea..cd16ce830270 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o -obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o +obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c new file mode 100644 index 000000000000..5f04cc11227e --- /dev/null +++ b/drivers/gpu/drm/bridge/lvds-codec.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Renesas Electronics Corporation + * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> + +#include <drm/drm_bridge.h> +#include <drm/drm_panel.h> + +struct lvds_codec { + struct drm_bridge bridge; + struct drm_bridge *panel_bridge; + struct gpio_desc *powerdown_gpio; + u32 connector_type; +}; + +static int lvds_codec_attach(struct drm_bridge *bridge) +{ + struct lvds_codec *lvds_codec = container_of(bridge, + struct lvds_codec, bridge); + + return drm_bridge_attach(bridge->encoder, lvds_codec->panel_bridge, + bridge); +} + +static void lvds_codec_enable(struct drm_bridge *bridge) +{ + struct lvds_codec *lvds_codec = container_of(bridge, + struct lvds_codec, bridge); + + if (lvds_codec->powerdown_gpio) + gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0); +} + +static void lvds_codec_disable(struct drm_bridge *bridge) +{ + struct lvds_codec *lvds_codec = container_of(bridge, + struct lvds_codec, bridge); + + if (lvds_codec->powerdown_gpio) + gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1); +} + +static struct drm_bridge_funcs funcs = { + .attach = lvds_codec_attach, + .enable = lvds_codec_enable, + .disable = lvds_codec_disable, +}; + +static int lvds_codec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *panel_node; + struct drm_panel *panel; + struct lvds_codec *lvds_codec; + + lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL); + if (!lvds_codec) + return -ENOMEM; + + lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev); + lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(lvds_codec->powerdown_gpio)) { + int err = PTR_ERR(lvds_codec->powerdown_gpio); + + if (err != -EPROBE_DEFER) + dev_err(dev, "powerdown GPIO failure: %d\n", err); + return err; + } + + /* Locate the panel DT node. */ + panel_node = of_graph_get_remote_node(dev->of_node, 1, 0); + if (!panel_node) { + dev_dbg(dev, "panel DT node not found\n"); + return -ENXIO; + } + + panel = of_drm_find_panel(panel_node); + of_node_put(panel_node); + if (IS_ERR(panel)) { + dev_dbg(dev, "panel not found, deferring probe\n"); + return PTR_ERR(panel); + } + + lvds_codec->panel_bridge = + devm_drm_panel_bridge_add_typed(dev, panel, + lvds_codec->connector_type); + if (IS_ERR(lvds_codec->panel_bridge)) + return PTR_ERR(lvds_codec->panel_bridge); + + /* + * The panel_bridge bridge is attached to the panel's of_node, + * but we need a bridge attached to our of_node for our user + * to look up. + */ + lvds_codec->bridge.of_node = dev->of_node; + lvds_codec->bridge.funcs = &funcs; + drm_bridge_add(&lvds_codec->bridge); + + platform_set_drvdata(pdev, lvds_codec); + + return 0; +} + +static int lvds_codec_remove(struct platform_device *pdev) +{ + struct lvds_codec *lvds_codec = platform_get_drvdata(pdev); + + drm_bridge_remove(&lvds_codec->bridge); + + return 0; +} + +static const struct of_device_id lvds_codec_match[] = { + { + .compatible = "lvds-decoder", + .data = (void *)DRM_MODE_CONNECTOR_DPI, + }, + { + .compatible = "lvds-encoder", + .data = (void *)DRM_MODE_CONNECTOR_LVDS, + }, + { + .compatible = "thine,thc63lvdm83d", + .data = (void *)DRM_MODE_CONNECTOR_LVDS, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, lvds_codec_match); + +static struct platform_driver lvds_codec_driver = { + .probe = lvds_codec_probe, + .remove = lvds_codec_remove, + .driver = { + .name = "lvds-codec", + .of_match_table = lvds_codec_match, + }, +}; +module_platform_driver(lvds_codec_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("LVDS encoders and decoders"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c deleted file mode 100644 index e2132a8d5106..000000000000 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> - */ - -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_graph.h> -#include <linux/platform_device.h> - -#include <drm/drm_bridge.h> -#include <drm/drm_panel.h> - -struct lvds_encoder { - struct drm_bridge bridge; - struct drm_bridge *panel_bridge; - struct gpio_desc *powerdown_gpio; -}; - -static int lvds_encoder_attach(struct drm_bridge *bridge) -{ - struct lvds_encoder *lvds_encoder = container_of(bridge, - struct lvds_encoder, - bridge); - - return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge, - bridge); -} - -static void lvds_encoder_enable(struct drm_bridge *bridge) -{ - struct lvds_encoder *lvds_encoder = container_of(bridge, - struct lvds_encoder, - bridge); - - if (lvds_encoder->powerdown_gpio) - gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0); -} - -static void lvds_encoder_disable(struct drm_bridge *bridge) -{ - struct lvds_encoder *lvds_encoder = container_of(bridge, - struct lvds_encoder, - bridge); - - if (lvds_encoder->powerdown_gpio) - gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); -} - -static struct drm_bridge_funcs funcs = { - .attach = lvds_encoder_attach, - .enable = lvds_encoder_enable, - .disable = lvds_encoder_disable, -}; - -static int lvds_encoder_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *port; - struct device_node *endpoint; - struct device_node *panel_node; - struct drm_panel *panel; - struct lvds_encoder *lvds_encoder; - - lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL); - if (!lvds_encoder) - return -ENOMEM; - - lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", - GPIOD_OUT_HIGH); - if (IS_ERR(lvds_encoder->powerdown_gpio)) { - int err = PTR_ERR(lvds_encoder->powerdown_gpio); - - if (err != -EPROBE_DEFER) - dev_err(dev, "powerdown GPIO failure: %d\n", err); - return err; - } - - /* Locate the panel DT node. */ - port = of_graph_get_port_by_id(dev->of_node, 1); - if (!port) { - dev_dbg(dev, "port 1 not found\n"); - return -ENXIO; - } - - endpoint = of_get_child_by_name(port, "endpoint"); - of_node_put(port); - if (!endpoint) { - dev_dbg(dev, "no endpoint for port 1\n"); - return -ENXIO; - } - - panel_node = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!panel_node) { - dev_dbg(dev, "no remote endpoint for port 1\n"); - return -ENXIO; - } - - panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); - if (IS_ERR(panel)) { - dev_dbg(dev, "panel not found, deferring probe\n"); - return PTR_ERR(panel); - } - - lvds_encoder->panel_bridge = - devm_drm_panel_bridge_add_typed(dev, panel, - DRM_MODE_CONNECTOR_LVDS); - if (IS_ERR(lvds_encoder->panel_bridge)) - return PTR_ERR(lvds_encoder->panel_bridge); - - /* The panel_bridge bridge is attached to the panel's of_node, - * but we need a bridge attached to our of_node for our user - * to look up. - */ - lvds_encoder->bridge.of_node = dev->of_node; - lvds_encoder->bridge.funcs = &funcs; - drm_bridge_add(&lvds_encoder->bridge); - - platform_set_drvdata(pdev, lvds_encoder); - - return 0; -} - -static int lvds_encoder_remove(struct platform_device *pdev) -{ - struct lvds_encoder *lvds_encoder = platform_get_drvdata(pdev); - - drm_bridge_remove(&lvds_encoder->bridge); - - return 0; -} - -static const struct of_device_id lvds_encoder_match[] = { - { .compatible = "lvds-encoder" }, - { .compatible = "thine,thc63lvdm83d" }, - {}, -}; -MODULE_DEVICE_TABLE(of, lvds_encoder_match); - -static struct platform_driver lvds_encoder_driver = { - .probe = lvds_encoder_probe, - .remove = lvds_encoder_remove, - .driver = { - .name = "lvds-encoder", - .of_match_table = lvds_encoder_match, - }, -}; -module_platform_driver(lvds_encoder_driver); - -MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); -MODULE_DESCRIPTION("Transparent parallel to LVDS encoder"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index b6e793bb653c..b18351b6760a 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -719,7 +719,15 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) { + const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; + struct dw_mipi_dsi_dphy_timing timing; u32 hw_version; + int ret; + + ret = phy_ops->get_timing(dsi->plat_data->priv_data, + dsi->lane_mbps, &timing); + if (ret) + DRM_DEV_ERROR(dsi->dev, "Retrieving phy timings failed\n"); /* * TODO dw drv improvements @@ -732,16 +740,20 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; if (hw_version >= HWVER_131) { - dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) | - PHY_LP2HS_TIME_V131(0x40)); + dsi_write(dsi, DSI_PHY_TMR_CFG, + PHY_HS2LP_TIME_V131(timing.data_hs2lp) | + PHY_LP2HS_TIME_V131(timing.data_lp2hs)); dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); } else { - dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | - PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); + dsi_write(dsi, DSI_PHY_TMR_CFG, + PHY_HS2LP_TIME(timing.data_hs2lp) | + PHY_LP2HS_TIME(timing.data_lp2hs) | + MAX_RD_TIME(10000)); } - dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) - | PHY_CLKLP2HS_TIME(0x40)); + dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, + PHY_CLKHS2LP_TIME(timing.clk_hs2lp) | + PHY_CLKLP2HS_TIME(timing.clk_lp2hs)); } static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) @@ -798,9 +810,6 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; - if (phy_ops->power_off) - phy_ops->power_off(dsi->plat_data->priv_data); - /* * Switch to command mode before panel-bridge post_disable & * panel unprepare. @@ -817,6 +826,9 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) */ dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); + if (phy_ops->power_off) + phy_ops->power_off(dsi->plat_data->priv_data); + if (dsi->slave) { dw_mipi_dsi_disable(dsi->slave); clk_disable_unprepare(dsi->slave->pclk); @@ -883,6 +895,9 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ dw_mipi_dsi_set_mode(dsi, 0); + + if (phy_ops->power_on) + phy_ops->power_on(dsi->plat_data->priv_data); } static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, @@ -899,15 +914,11 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) { struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); - const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; /* Switch to video mode for panel-bridge enable & panel enable */ dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); if (dsi->slave) dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO); - - if (phy_ops->power_on) - phy_ops->power_on(dsi->plat_data->priv_data); } static enum drm_mode_status @@ -991,7 +1002,8 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, dsi->dev = dev; dsi->plat_data = plat_data; - if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps) { + if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps || + !plat_data->phy_ops->get_timing) { DRM_ERROR("Phy not properly configured\n"); return ERR_PTR(-ENODEV); } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index ab4508f25986..d33691512a8e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -251,7 +251,7 @@ EXPORT_SYMBOL(drm_atomic_state_clear); * @ref: This atomic state to deallocate * * This frees all memory associated with an atomic state, including all the - * per-object state for planes, crtcs and connectors. + * per-object state for planes, CRTCs and connectors. */ void __drm_atomic_state_free(struct kref *ref) { @@ -272,12 +272,12 @@ void __drm_atomic_state_free(struct kref *ref) EXPORT_SYMBOL(__drm_atomic_state_free); /** - * drm_atomic_get_crtc_state - get crtc state + * drm_atomic_get_crtc_state - get CRTC state * @state: global atomic state object - * @crtc: crtc to get state object for + * @crtc: CRTC to get state object for * - * This function returns the crtc state for the given crtc, allocating it if - * needed. It will also grab the relevant crtc lock to make sure that the state + * This function returns the CRTC state for the given CRTC, allocating it if + * needed. It will also grab the relevant CRTC lock to make sure that the state * is consistent. * * Returns: @@ -1018,14 +1018,14 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, } /** - * drm_atomic_add_affected_connectors - add connectors for crtc + * drm_atomic_add_affected_connectors - add connectors for CRTC * @state: atomic state - * @crtc: DRM crtc + * @crtc: DRM CRTC * * This function walks the current configuration and adds all connectors * currently using @crtc to the atomic configuration @state. Note that this * function must acquire the connection mutex. This can potentially cause - * unneeded seralization if the update is just for the planes on one crtc. Hence + * unneeded seralization if the update is just for the planes on one CRTC. Hence * drivers and helpers should only call this when really needed (e.g. when a * full modeset needs to happen due to some change). * @@ -1078,9 +1078,9 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_add_affected_connectors); /** - * drm_atomic_add_affected_planes - add planes for crtc + * drm_atomic_add_affected_planes - add planes for CRTC * @state: atomic state - * @crtc: DRM crtc + * @crtc: DRM CRTC * * This function walks the current configuration and adds all planes * currently used by @crtc to the atomic configuration @state. This is useful diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bcc9ca240638..4511c2e07bb9 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -150,8 +150,8 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, * is not set, an error is returned. Userspace can provide a solution * through the atomic ioctl. * - * If the flag is set conflicting connectors are removed from the crtc - * and the crtc is disabled if no encoder is left. This preserves + * If the flag is set conflicting connectors are removed from the CRTC + * and the CRTC is disabled if no encoder is left. This preserves * compatibility with the legacy set_config behavior. */ drm_connector_list_iter_begin(state->dev, &conn_iter); @@ -220,7 +220,7 @@ set_best_encoder(struct drm_atomic_state *state, crtc = conn_state->connector->state->crtc; /* A NULL crtc is an error here because we should have - * duplicated a NULL best_encoder when crtc was NULL. + * duplicated a NULL best_encoder when crtc was NULL. * As an exception restoring duplicated atomic state * during resume is allowed, so don't warn when * best_encoder is equal to encoder we intend to set. @@ -561,27 +561,27 @@ mode_valid(struct drm_atomic_state *state) * @state: the driver state object * * Check the state object to see if the requested state is physically possible. - * This does all the crtc and connector related computations for an atomic + * This does all the CRTC and connector related computations for an atomic * update and adds any additional connectors needed for full modesets. It calls * the various per-object callbacks in the follow order: * * 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder. * 2. &drm_connector_helper_funcs.atomic_check to validate the connector state. - * 3. If it's determined a modeset is needed then all connectors on the affected crtc - * crtc are added and &drm_connector_helper_funcs.atomic_check is run on them. + * 3. If it's determined a modeset is needed then all connectors on the affected + * CRTC are added and &drm_connector_helper_funcs.atomic_check is run on them. * 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and * &drm_crtc_helper_funcs.mode_valid are called on the affected components. * 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges. * 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state. - * This function is only called when the encoder will be part of a configured crtc, + * This function is only called when the encoder will be part of a configured CRTC, * it must not be used for implementing connector property validation. * If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called * instead. - * 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints. + * 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with CRTC constraints. * * &drm_crtc_state.mode_changed is set when the input mode is changed. * &drm_crtc_state.connectors_changed is set when a connector is added or - * removed from the crtc. &drm_crtc_state.active_changed is set when + * removed from the CRTC. &drm_crtc_state.active_changed is set when * &drm_crtc_state.active changes, which is used for DPMS. * See also: drm_atomic_crtc_needs_modeset() * @@ -692,7 +692,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, /* * After all the routing has been prepared we need to add in any - * connector which is itself unchanged, but whose crtc changes its + * connector which is itself unchanged, but whose CRTC changes its * configuration. This must be done before calling mode_fixup in case a * crtc only changed its mode but has the same set of connectors. */ @@ -741,13 +741,13 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); /** * drm_atomic_helper_check_plane_state() - Check plane state for validity * @plane_state: plane state to check - * @crtc_state: crtc state to check + * @crtc_state: CRTC state to check * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point * @can_position: is it legal to position the plane such that it - * doesn't cover the entire crtc? This will generally + * doesn't cover the entire CRTC? This will generally * only be false for primary planes. - * @can_update_disabled: can the plane be updated while the crtc + * @can_update_disabled: can the plane be updated while the CRTC * is disabled? * * Checks that a desired plane update is valid, and updates various @@ -844,7 +844,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_plane_state); * &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check * hooks provided by the driver. * - * It also sets &drm_crtc_state.planes_changed to indicate that a crtc has + * It also sets &drm_crtc_state.planes_changed to indicate that a CRTC has * updated planes. * * RETURNS: @@ -908,7 +908,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes); * @state: the driver state object * * Check the state object to see if the requested state is physically possible. - * Only crtcs and planes have check callbacks, so for any additional (global) + * Only CRTCs and planes have check callbacks, so for any additional (global) * checking that a driver needs it can simply wrap that around this function. * Drivers without such needs can directly use this as their * &drm_mode_config_funcs.atomic_check callback. @@ -961,14 +961,14 @@ crtc_needs_disable(struct drm_crtc_state *old_state, struct drm_crtc_state *new_state) { /* - * No new_state means the crtc is off, so the only criteria is whether + * No new_state means the CRTC is off, so the only criteria is whether * it's currently active or in self refresh mode. */ if (!new_state) return drm_atomic_crtc_effectively_active(old_state); /* - * We need to run through the crtc_funcs->disable() function if the crtc + * We need to run through the crtc_funcs->disable() function if the CRTC * is currently on, if it's transitioning to self refresh mode, or if * it's in self refresh mode and needs to be fully disabled. */ @@ -1087,7 +1087,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) * @old_state: atomic state object with old state structures * * This function updates all the various legacy modeset state pointers in - * connectors, encoders and crtcs. It also updates the timestamping constants + * connectors, encoders and CRTCs. It also updates the timestamping constants * used for precise vblank timestamps by calling * drm_calc_timestamping_constants(). * @@ -1236,7 +1236,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) * This function shuts down all the outputs that need to be shut down and * prepares them (if required) with the new mode. * - * For compatibility with legacy crtc helpers this should be called before + * For compatibility with legacy CRTC helpers this should be called before * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime @@ -1282,7 +1282,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, * This function enables all the outputs with the new configuration which had to * be turned off for the update. * - * For compatibility with legacy crtc helpers this should be called after + * For compatibility with legacy CRTC helpers this should be called after * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime @@ -1414,12 +1414,12 @@ int drm_atomic_helper_wait_for_fences(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences); /** - * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs + * drm_atomic_helper_wait_for_vblanks - wait for vblank on CRTCs * @dev: DRM device * @old_state: atomic state object with old state structures * - * Helper to, after atomic commit, wait for vblanks on all effected - * crtcs (ie. before cleaning up old framebuffers using + * Helper to, after atomic commit, wait for vblanks on all affected + * CRTCs (ie. before cleaning up old framebuffers using * drm_atomic_helper_cleanup_planes()). It will only wait on CRTCs where the * framebuffers have actually changed to optimize for the legacy cursor and * plane update use-case. @@ -1478,10 +1478,10 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); * @dev: DRM device * @old_state: atomic state object with old state structures * - * Helper to, after atomic commit, wait for page flips on all effected + * Helper to, after atomic commit, wait for page flips on all affected * crtcs (ie. before cleaning up old framebuffers using * drm_atomic_helper_cleanup_planes()). Compared to - * drm_atomic_helper_wait_for_vblanks() this waits for the completion of on all + * drm_atomic_helper_wait_for_vblanks() this waits for the completion on all * CRTCs, assuming that cursors-only updates are signalling their completion * immediately (or using a different path). * @@ -2208,7 +2208,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); * drm_atomic_helper_fake_vblank - fake VBLANK events if needed * @old_state: atomic state object with old state structures * - * This function walks all CRTCs and fake VBLANK events on those with + * This function walks all CRTCs and fakes VBLANK events on those with * &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL. * The primary use of this function is writeback connectors working in oneshot * mode and faking VBLANK events. In this case they only fake the VBLANK event @@ -2404,7 +2404,7 @@ static bool plane_crtc_active(const struct drm_plane_state *state) * @flags: flags for committing plane state * * This function commits the new plane state using the plane and atomic helper - * functions for planes and crtcs. It assumes that the atomic state has already + * functions for planes and CRTCs. It assumes that the atomic state has already * been pushed into the relevant object state pointers, since this step can no * longer fail. * @@ -2525,15 +2525,15 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_commit_planes); /** - * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a crtc - * @old_crtc_state: atomic state object with the old crtc state + * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a CRTC + * @old_crtc_state: atomic state object with the old CRTC state * * This function commits the new plane state using the plane and atomic helper - * functions for planes on the specific crtc. It assumes that the atomic state + * functions for planes on the specific CRTC. It assumes that the atomic state * has already been pushed into the relevant object state pointers, since this * step can no longer fail. * - * This function is useful when plane updates should be done crtc-by-crtc + * This function is useful when plane updates should be done CRTC-by-CRTC * instead of one global step like drm_atomic_helper_commit_planes() does. * * This function can only be savely used when planes are not allowed to move @@ -2823,10 +2823,10 @@ EXPORT_SYMBOL(drm_atomic_helper_swap_state); * @plane: plane object to update * @crtc: owning CRTC of owning plane * @fb: framebuffer to flip onto plane - * @crtc_x: x offset of primary plane on crtc - * @crtc_y: y offset of primary plane on crtc - * @crtc_w: width of primary plane rectangle on crtc - * @crtc_h: height of primary plane rectangle on crtc + * @crtc_x: x offset of primary plane on @crtc + * @crtc_y: y offset of primary plane on @crtc + * @crtc_w: width of primary plane rectangle on @crtc + * @crtc_h: height of primary plane rectangle on @crtc * @src_x: x offset of @fb for panning * @src_y: y offset of @fb for panning * @src_w: width of source rectangle in @fb @@ -2932,7 +2932,7 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_plane); * @set: mode set configuration * @ctx: lock acquisition context * - * Provides a default crtc set_config handler using the atomic driver interface. + * Provides a default CRTC set_config handler using the atomic driver interface. * * NOTE: For backwards compatibility with old userspace this automatically * resets the "link-status" property to GOOD, to force any link @@ -3345,7 +3345,7 @@ static int page_flip_common(struct drm_atomic_state *state, /** * drm_atomic_helper_page_flip - execute a legacy page flip - * @crtc: DRM crtc + * @crtc: DRM CRTC * @fb: DRM framebuffer * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates @@ -3389,7 +3389,7 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip); /** * drm_atomic_helper_page_flip_target - do page flip on target vblank period. - * @crtc: DRM crtc + * @crtc: DRM CRTC * @fb: DRM framebuffer * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 0d466d3b0809..a1e5e262bae2 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -160,12 +160,12 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); /** - * drm_atomic_set_crtc_for_plane - set crtc for plane + * drm_atomic_set_crtc_for_plane - set CRTC for plane * @plane_state: the plane whose incoming state to update - * @crtc: crtc to use for the plane + * @crtc: CRTC to use for the plane * - * Changing the assigned crtc for a plane requires us to grab the lock and state - * for the new crtc, as needed. This function takes care of all these details + * Changing the assigned CRTC for a plane requires us to grab the lock and state + * for the new CRTC, as needed. This function takes care of all these details * besides updating the pointer in the state object itself. * * Returns: @@ -279,12 +279,12 @@ drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, EXPORT_SYMBOL(drm_atomic_set_fence_for_plane); /** - * drm_atomic_set_crtc_for_connector - set crtc for connector + * drm_atomic_set_crtc_for_connector - set CRTC for connector * @conn_state: atomic state object for the connector - * @crtc: crtc to use for the connector + * @crtc: CRTC to use for the connector * - * Changing the assigned crtc for a connector requires us to grab the lock and - * state for the new crtc, as needed. This function takes care of all these + * Changing the assigned CRTC for a connector requires us to grab the lock and + * state for the new CRTC, as needed. This function takes care of all these * details besides updating the pointer in the state object itself. * * Returns: diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index d9a2e3695525..b031b45aa8ef 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -150,7 +150,7 @@ void drm_client_release(struct drm_client_dev *client) { struct drm_device *dev = client->dev; - DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name); + drm_dbg_kms(dev, "%s\n", client->name); drm_client_modeset_free(client); drm_client_close(client); @@ -203,7 +203,7 @@ void drm_client_dev_hotplug(struct drm_device *dev) continue; ret = client->funcs->hotplug(client); - DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); } mutex_unlock(&dev->clientlist_mutex); } @@ -223,7 +223,7 @@ void drm_client_dev_restore(struct drm_device *dev) continue; ret = client->funcs->restore(client); - DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); if (!ret) /* The first one to return zero gets the privilege to restore */ break; } @@ -351,8 +351,8 @@ static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer) ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file); if (ret) - DRM_DEV_ERROR(buffer->client->dev->dev, - "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret); + drm_err(buffer->client->dev, + "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret); buffer->fb = NULL; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 1b9b40a1c7c9..7c18a980cd4b 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -622,7 +622,8 @@ int drm_dev_init(struct drm_device *dev, return -ENODEV; } - BUG_ON(!parent); + if (WARN_ON(!parent)) + return -EINVAL; kref_init(&dev->ref); dev->dev = get_device(parent); @@ -725,7 +726,7 @@ int devm_drm_dev_init(struct device *parent, { int ret; - if (WARN_ON(!parent || !driver->release)) + if (WARN_ON(!driver->release)) return -EINVAL; ret = drm_dev_init(dev, driver, parent); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5b33b7cfd645..99769d6c9f84 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -710,14 +710,11 @@ static const struct minimode extra_modes[] = { }; /* - * Probably taken from CEA-861 spec. - * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c. + * From CEA/CTA-861 spec. * - * Index using the VIC. + * Do not access directly, instead always use cea_mode_for_vic(). */ -static const struct drm_display_mode edid_cea_modes[] = { - /* 0 - dummy, VICs start at 1 */ - { }, +static const struct drm_display_mode edid_cea_modes_1[] = { /* 1 - 640x480@60Hz 4:3 */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, @@ -1381,6 +1378,149 @@ static const struct drm_display_mode edid_cea_modes[] = { }; /* + * From CEA/CTA-861 spec. + * + * Do not access directly, instead always use cea_mode_for_vic(). + */ +static const struct drm_display_mode edid_cea_modes_193[] = { + /* 193 - 5120x2160@120Hz 64:27 */ + { DRM_MODE("5120x2160", DRM_MODE_TYPE_DRIVER, 1485000, 5120, 5284, + 5372, 5500, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 194 - 7680x4320@24Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 195 - 7680x4320@25Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 196 - 7680x4320@30Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 197 - 7680x4320@48Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 198 - 7680x4320@50Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 199 - 7680x4320@60Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 200 - 7680x4320@100Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792, + 9968, 10560, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 201 - 7680x4320@120Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032, + 8208, 8800, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 202 - 7680x4320@24Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 203 - 7680x4320@25Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 204 - 7680x4320@30Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 205 - 7680x4320@48Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 206 - 7680x4320@50Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 207 - 7680x4320@60Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 208 - 7680x4320@100Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792, + 9968, 10560, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 209 - 7680x4320@120Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032, + 8208, 8800, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 210 - 10240x4320@24Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 11732, + 11908, 12500, 0, 4320, 4336, 4356, 4950, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 211 - 10240x4320@25Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 12732, + 12908, 13500, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 212 - 10240x4320@30Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 10528, + 10704, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 213 - 10240x4320@48Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 11732, + 11908, 12500, 0, 4320, 4336, 4356, 4950, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 214 - 10240x4320@50Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 12732, + 12908, 13500, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 215 - 10240x4320@60Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 10528, + 10704, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 216 - 10240x4320@100Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 12432, + 12608, 13200, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 217 - 10240x4320@120Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 10528, + 10704, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 218 - 4096x2160@100Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4896, + 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, + /* 219 - 4096x2160@120Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4184, + 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, +}; + +/* * HDMI 1.4 4k modes. Index using the VIC. */ static const struct drm_display_mode edid_4k_modes[] = { @@ -3071,6 +3211,30 @@ static u8 *drm_find_cea_extension(const struct edid *edid) return cea; } +static const struct drm_display_mode *cea_mode_for_vic(u8 vic) +{ + BUILD_BUG_ON(1 + ARRAY_SIZE(edid_cea_modes_1) - 1 != 127); + BUILD_BUG_ON(193 + ARRAY_SIZE(edid_cea_modes_193) - 1 != 219); + + if (vic >= 1 && vic < 1 + ARRAY_SIZE(edid_cea_modes_1)) + return &edid_cea_modes_1[vic - 1]; + if (vic >= 193 && vic < 193 + ARRAY_SIZE(edid_cea_modes_193)) + return &edid_cea_modes_193[vic - 193]; + return NULL; +} + +static u8 cea_num_vics(void) +{ + return 193 + ARRAY_SIZE(edid_cea_modes_193); +} + +static u8 cea_next_vic(u8 vic) +{ + if (++vic == 1 + ARRAY_SIZE(edid_cea_modes_1)) + vic = 193; + return vic; +} + /* * Calculate the alternate clock for the CEA mode * (60Hz vs. 59.94Hz etc.) @@ -3108,14 +3272,14 @@ cea_mode_alternate_timings(u8 vic, struct drm_display_mode *mode) * get the other variants by simply increasing the * vertical front porch length. */ - BUILD_BUG_ON(edid_cea_modes[8].vtotal != 262 || - edid_cea_modes[9].vtotal != 262 || - edid_cea_modes[12].vtotal != 262 || - edid_cea_modes[13].vtotal != 262 || - edid_cea_modes[23].vtotal != 312 || - edid_cea_modes[24].vtotal != 312 || - edid_cea_modes[27].vtotal != 312 || - edid_cea_modes[28].vtotal != 312); + BUILD_BUG_ON(cea_mode_for_vic(8)->vtotal != 262 || + cea_mode_for_vic(9)->vtotal != 262 || + cea_mode_for_vic(12)->vtotal != 262 || + cea_mode_for_vic(13)->vtotal != 262 || + cea_mode_for_vic(23)->vtotal != 312 || + cea_mode_for_vic(24)->vtotal != 312 || + cea_mode_for_vic(27)->vtotal != 312 || + cea_mode_for_vic(28)->vtotal != 312); if (((vic == 8 || vic == 9 || vic == 12 || vic == 13) && mode->vtotal < 263) || @@ -3143,8 +3307,8 @@ static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_m if (to_match->picture_aspect_ratio) match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; - for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { - struct drm_display_mode cea_mode = edid_cea_modes[vic]; + for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) { + struct drm_display_mode cea_mode = *cea_mode_for_vic(vic); unsigned int clock1, clock2; /* Check both 60Hz and 59.94Hz */ @@ -3182,8 +3346,8 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) if (to_match->picture_aspect_ratio) match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; - for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { - struct drm_display_mode cea_mode = edid_cea_modes[vic]; + for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) { + struct drm_display_mode cea_mode = *cea_mode_for_vic(vic); unsigned int clock1, clock2; /* Check both 60Hz and 59.94Hz */ @@ -3206,12 +3370,17 @@ EXPORT_SYMBOL(drm_match_cea_mode); static bool drm_valid_cea_vic(u8 vic) { - return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes); + return cea_mode_for_vic(vic) != NULL; } static enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) { - return edid_cea_modes[video_code].picture_aspect_ratio; + const struct drm_display_mode *mode = cea_mode_for_vic(video_code); + + if (mode) + return mode->picture_aspect_ratio; + + return HDMI_PICTURE_ASPECT_NONE; } static enum hdmi_picture_aspect drm_get_hdmi_aspect_ratio(const u8 video_code) @@ -3323,7 +3492,7 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) unsigned int clock1, clock2; if (drm_valid_cea_vic(vic)) { - cea_mode = &edid_cea_modes[vic]; + cea_mode = cea_mode_for_vic(vic); clock2 = cea_mode_alternate_clock(cea_mode); } else { vic = drm_match_hdmi_mode(mode); @@ -3398,7 +3567,7 @@ drm_display_mode_from_vic_index(struct drm_connector *connector, if (!drm_valid_cea_vic(vic)) return NULL; - newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]); + newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic)); if (!newmode) return NULL; @@ -3432,7 +3601,7 @@ static int do_y420vdb_modes(struct drm_connector *connector, if (!drm_valid_cea_vic(vic)) continue; - newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]); + newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic)); if (!newmode) break; bitmap_set(hdmi->y420_vdb_modes, vic, 1); @@ -4001,7 +4170,7 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) vic = drm_match_cea_mode_clock_tolerance(mode, 5); if (drm_valid_cea_vic(vic)) { type = "CEA"; - cea_mode = &edid_cea_modes[vic]; + cea_mode = cea_mode_for_vic(vic); clock1 = cea_mode->clock; clock2 = cea_mode_alternate_clock(cea_mode); } else { @@ -4577,7 +4746,7 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, if (scdc->supported) { scdc->scrambling.supported = true; - /* Few sinks support scrambling for cloks < 340M */ + /* Few sinks support scrambling for clocks < 340M */ if ((hf_vsdb[6] & 0x8)) scdc->scrambling.low_rates = true; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index fb9bff0f4581..f8e905192608 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -191,6 +191,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) { struct drm_fb_helper *helper = info->par; struct drm_client_dev *client = &helper->client; + struct drm_device *dev = helper->dev; struct drm_crtc *crtc; const struct drm_crtc_helper_funcs *funcs; struct drm_mode_set *mode_set; @@ -209,7 +210,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) continue; if (!fb) { - DRM_ERROR("no fb to restore??\n"); + drm_err(dev, "no fb to restore?\n"); continue; } @@ -1248,12 +1249,13 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, { struct drm_fb_helper *fb_helper = info->par; struct drm_framebuffer *fb = fb_helper->fb; + struct drm_device *dev = fb_helper->dev; if (in_dbg_master()) return -EINVAL; if (var->pixclock != 0) { - DRM_DEBUG("fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n"); + drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n"); var->pixclock = 0; } @@ -1268,7 +1270,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, if (var->bits_per_pixel != fb->format->cpp[0] * 8 || var->xres > fb->width || var->yres > fb->height || var->xres_virtual > fb->width || var->yres_virtual > fb->height) { - DRM_DEBUG("fb requested width/height/bpp can't fit in current fb " + drm_dbg_kms(dev, "fb requested width/height/bpp can't fit in current fb " "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, var->xres_virtual, var->yres_virtual, @@ -1295,7 +1297,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, * so reject all pixel format changing requests. */ if (!drm_fb_pixel_format_equal(var, &info->var)) { - DRM_DEBUG("fbdev emulation doesn't support changing the pixel format\n"); + drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel format\n"); return -EINVAL; } @@ -1320,7 +1322,7 @@ int drm_fb_helper_set_par(struct fb_info *info) return -EBUSY; if (var->pixclock != 0) { - DRM_ERROR("PIXEL CLOCK SET\n"); + drm_err(fb_helper->dev, "PIXEL CLOCK SET\n"); return -EINVAL; } @@ -1430,6 +1432,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, int preferred_bpp) { struct drm_client_dev *client = &fb_helper->client; + struct drm_device *dev = fb_helper->dev; int ret = 0; int crtc_count = 0; struct drm_connector_list_iter conn_iter; @@ -1493,7 +1496,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, struct drm_plane *plane = crtc->primary; int j; - DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc)); + drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc)); for (j = 0; j < plane->format_count; j++) { const struct drm_format_info *fmt; @@ -1526,7 +1529,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } } if (sizes.surface_depth != best_depth && best_depth) { - DRM_INFO("requested bpp %d, scaled depth down to %d", + drm_info(dev, "requested bpp %d, scaled depth down to %d", sizes.surface_bpp, best_depth); sizes.surface_depth = best_depth; } @@ -1574,7 +1577,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, mutex_unlock(&client->modeset_mutex); if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { - DRM_INFO("Cannot find any crtc or sizes\n"); + drm_info(dev, "Cannot find any crtc or sizes\n"); /* First time: disable all crtc's.. */ if (!fb_helper->deferred_setup) @@ -1889,7 +1892,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) drm_master_internal_release(fb_helper->dev); - DRM_DEBUG_KMS("\n"); + drm_dbg_kms(fb_helper->dev, "\n"); drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height); drm_setup_crtcs_fb(fb_helper); @@ -2026,15 +2029,16 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, struct drm_fb_helper_surface_size *sizes) { struct drm_client_dev *client = &fb_helper->client; + struct drm_device *dev = fb_helper->dev; struct drm_client_buffer *buffer; struct drm_framebuffer *fb; struct fb_info *fbi; u32 format; void *vaddr; - DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", - sizes->surface_width, sizes->surface_height, - sizes->surface_bpp); + drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n", + sizes->surface_width, sizes->surface_height, + sizes->surface_bpp); format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); buffer = drm_client_framebuffer_create(client, sizes->surface_width, @@ -2118,7 +2122,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) return drm_fb_helper_hotplug_event(dev->fb_helper); if (!dev->mode_config.num_connector) { - DRM_DEV_DEBUG(dev->dev, "No connectors found, will not create framebuffer!\n"); + drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n"); return 0; } @@ -2143,7 +2147,7 @@ err: fb_helper->dev = NULL; fb_helper->fbdev = NULL; - DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret); + drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret); return ret; } @@ -2200,7 +2204,7 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs); if (ret) { kfree(fb_helper); - DRM_DEV_ERROR(dev->dev, "Failed to register client: %d\n", ret); + drm_err(dev, "Failed to register client: %d\n", ret); return ret; } @@ -2212,7 +2216,7 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) ret = drm_fbdev_client_hotplug(&fb_helper->client); if (ret) - DRM_DEV_DEBUG(dev->dev, "client hotplug ret=%d\n", ret); + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); drm_client_register(&fb_helper->client); diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index b9bcd310ca2d..3a7ace19a902 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -74,8 +74,7 @@ drm_gem_fb_alloc(struct drm_device *dev, ret = drm_framebuffer_init(dev, fb, funcs); if (ret) { - DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n", - ret); + drm_err(dev, "Failed to init framebuffer: %d\n", ret); kfree(fb); return ERR_PTR(ret); } @@ -160,7 +159,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file, objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); if (!objs[i]) { - DRM_DEBUG_KMS("Failed to lookup GEM object\n"); + drm_dbg_kms(dev, "Failed to lookup GEM object\n"); ret = -ENOENT; goto err_gem_object_put; } diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 88232698d7a0..2a4eb619d7ad 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1568,33 +1568,76 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, return 0; } -static int drm_mode_parse_cmdline_options(char *str, size_t len, +static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret) +{ + const char *value; + char *endp; + + /* + * delim must point to the '=', otherwise it is a syntax error and + * if delim points to the terminating zero, then delim + 1 wil point + * past the end of the string. + */ + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + *int_ret = simple_strtol(value, &endp, 10); + + /* Make sure we have parsed something */ + if (endp == value) + return -EINVAL; + + return 0; +} + +static int drm_mode_parse_panel_orientation(const char *delim, + struct drm_cmdline_mode *mode) +{ + const char *value; + + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + delim = strchr(value, ','); + if (!delim) + delim = value + strlen(value); + + if (!strncmp(value, "normal", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; + else if (!strncmp(value, "upside_down", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; + else if (!strncmp(value, "left_side_up", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; + else if (!strncmp(value, "right_side_up", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; + else + return -EINVAL; + + return 0; +} + +static int drm_mode_parse_cmdline_options(const char *str, + bool freestanding, const struct drm_connector *connector, struct drm_cmdline_mode *mode) { - unsigned int rotation = 0; - char *sep = str; + unsigned int deg, margin, rotation = 0; + const char *delim, *option, *sep; - while ((sep = strchr(sep, ','))) { - char *delim, *option; - - option = sep + 1; + option = str; + do { delim = strchr(option, '='); if (!delim) { delim = strchr(option, ','); if (!delim) - delim = str + len; + delim = option + strlen(option); } if (!strncmp(option, "rotate", delim - option)) { - const char *value = delim + 1; - unsigned int deg; - - deg = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, °)) return -EINVAL; switch (deg) { @@ -1619,58 +1662,40 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len, } } else if (!strncmp(option, "reflect_x", delim - option)) { rotation |= DRM_MODE_REFLECT_X; - sep = delim; } else if (!strncmp(option, "reflect_y", delim - option)) { rotation |= DRM_MODE_REFLECT_Y; - sep = delim; } else if (!strncmp(option, "margin_right", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.right = margin; } else if (!strncmp(option, "margin_left", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.left = margin; } else if (!strncmp(option, "margin_top", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.top = margin; } else if (!strncmp(option, "margin_bottom", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.bottom = margin; + } else if (!strncmp(option, "panel_orientation", delim - option)) { + if (drm_mode_parse_panel_orientation(delim, mode)) + return -EINVAL; } else { return -EINVAL; } - } + sep = strchr(delim, ','); + option = sep + 1; + } while (sep); + + if (rotation && freestanding) + return -EINVAL; mode->rotation_reflection = rotation; @@ -1682,17 +1707,6 @@ static const char * const drm_named_modes_whitelist[] = { "PAL", }; -static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) - if (!strncmp(mode, drm_named_modes_whitelist[i], size)) - return true; - - return false; -} - /** * drm_mode_parse_command_line_for_connector - parse command line modeline for connector * @mode_option: optional per connector mode option @@ -1723,72 +1737,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, struct drm_cmdline_mode *mode) { const char *name; - bool named_mode = false, parse_extras = false; + bool freestanding = false, parse_extras = false; unsigned int bpp_off = 0, refresh_off = 0, options_off = 0; unsigned int mode_end = 0; - char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; - char *options_ptr = NULL; + 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 ret; + int i, len, ret; -#ifdef CONFIG_FB - if (!mode_option) - mode_option = fb_mode_option; -#endif + memset(mode, 0, sizeof(*mode)); + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; - if (!mode_option) { - mode->specified = false; + if (!mode_option) return false; - } name = mode_option; - /* - * This is a bit convoluted. To differentiate between the - * named modes and poorly formatted resolutions, we need a - * bunch of things: - * - We need to make sure that the first character (which - * would be our resolution in X) is a digit. - * - If not, then it's either a named mode or a force on/off. - * To distinguish between the two, we need to run the - * extra parsing function, and if not, then we consider it - * a named mode. - * - * If this isn't enough, we should add more heuristics here, - * and matching unit-tests. - */ - if (!isdigit(name[0]) && name[0] != 'x') { - unsigned int namelen = strlen(name); - - /* - * Only the force on/off options can be in that case, - * and they all take a single character. - */ - if (namelen == 1) { - ret = drm_mode_parse_cmdline_extra(name, namelen, true, - connector, mode); - if (!ret) - return true; - } - - named_mode = true; - } - /* Try to locate the bpp and refresh specifiers, if any */ bpp_ptr = strchr(name, '-'); - if (bpp_ptr) { + if (bpp_ptr) bpp_off = bpp_ptr - name; - mode->bpp_specified = true; - } refresh_ptr = strchr(name, '@'); - if (refresh_ptr) { - if (named_mode) - return false; - + if (refresh_ptr) refresh_off = refresh_ptr - name; - mode->refresh_specified = true; - } /* Locate the start of named options */ options_ptr = strchr(name, ','); @@ -1802,33 +1774,58 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, mode_end = refresh_off; } else if (options_ptr) { mode_end = options_off; + parse_extras = true; } else { mode_end = strlen(name); parse_extras = true; } - if (named_mode) { - if (mode_end + 1 > DRM_DISPLAY_MODE_LEN) - return false; + /* 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 (!drm_named_mode_is_in_whitelist(name, mode_end)) - return false; + strcpy(mode->name, drm_named_modes_whitelist[i]); + mode->specified = true; + break; + } + } - strscpy(mode->name, name, mode_end + 1); - } else { + /* No named mode? Check for a normal mode argument, e.g. 1024x768 */ + if (!mode->specified && isdigit(name[0])) { ret = drm_mode_parse_cmdline_res_mode(name, mode_end, parse_extras, connector, mode); if (ret) return false; + + mode->specified = true; + } + + /* No mode? Check for freestanding extras and/or options */ + if (!mode->specified) { + unsigned int len = strlen(mode_option); + + if (bpp_ptr || refresh_ptr) + return false; /* syntax error */ + + if (len == 1 || (len >= 2 && mode_option[1] == ',')) + extra_ptr = mode_option; + else + options_ptr = mode_option - 1; + + freestanding = true; } - mode->specified = true; if (bpp_ptr) { ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode); if (ret) return false; + + mode->bpp_specified = true; } if (refresh_ptr) { @@ -1836,6 +1833,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, &refresh_end_ptr, mode); if (ret) return false; + + mode->refresh_specified = true; } /* @@ -1849,20 +1848,21 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, else if (refresh_ptr) extra_ptr = refresh_end_ptr; - if (extra_ptr && - extra_ptr != options_ptr) { - int len = strlen(name) - (extra_ptr - name); + if (extra_ptr) { + if (options_ptr) + len = options_ptr - extra_ptr; + else + len = strlen(extra_ptr); - ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false, + ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding, connector, mode); if (ret) return false; } if (options_ptr) { - int len = strlen(name) - (options_ptr - name); - - ret = drm_mode_parse_cmdline_options(options_ptr, len, + ret = drm_mode_parse_cmdline_options(options_ptr + 1, + freestanding, connector, mode); if (ret) return false; diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 79ff3fdf6f6e..8c7bac85a793 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -302,7 +302,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) EXPORT_SYMBOL(of_drm_find_panel); #endif -#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) +#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) /** * drm_panel_of_backlight - use backlight device node for backlight * @panel: DRM panel diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index aa3e4c3b063a..3b0afa156d92 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -113,7 +113,7 @@ static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i) if (submit->bos[i].flags & BO_LOCKED) { struct drm_gem_object *obj = &submit->bos[i].obj->base; - ww_mutex_unlock(&obj->resv->lock); + dma_resv_unlock(obj->resv); submit->bos[i].flags &= ~BO_LOCKED; } } @@ -133,8 +133,7 @@ retry: contended = i; if (!(submit->bos[i].flags & BO_LOCKED)) { - ret = ww_mutex_lock_interruptible(&obj->resv->lock, - ticket); + ret = dma_resv_lock_interruptible(obj->resv, ticket); if (ret == -EALREADY) DRM_ERROR("BO at index %u already on submit list\n", i); @@ -161,8 +160,7 @@ fail: obj = &submit->bos[contended].obj->base; /* we lost out in a seqno race, lock and retry.. */ - ret = ww_mutex_lock_slow_interruptible(&obj->resv->lock, - ticket); + ret = dma_resv_lock_slow_interruptible(obj->resv, ticket); if (!ret) { submit->bos[contended].flags |= BO_LOCKED; slow_locked = contended; diff --git a/drivers/gpu/drm/gma500/accel_2d.c b/drivers/gpu/drm/gma500/accel_2d.c index b9e5a38632f7..adc0507545bf 100644 --- a/drivers/gpu/drm/gma500/accel_2d.c +++ b/drivers/gpu/drm/gma500/accel_2d.c @@ -228,8 +228,8 @@ static void psbfb_copyarea_accel(struct fb_info *info, { struct drm_fb_helper *fb_helper = info->par; struct drm_framebuffer *fb = fb_helper->fb; - struct drm_device *dev = fb->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_device *dev; + struct drm_psb_private *dev_priv; uint32_t offset; uint32_t stride; uint32_t src_format; @@ -238,6 +238,8 @@ static void psbfb_copyarea_accel(struct fb_info *info, if (!fb) return; + dev = fb->dev; + dev_priv = dev->dev_private; offset = to_gtt_range(fb->obj[0])->offset; stride = fb->pitches[0]; diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index d76106743f84..bb6528b01cd0 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -388,13 +388,14 @@ void mcde_dsi_te_request(struct mipi_dsi_device *mdsi) static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, const struct drm_display_mode *mode) { - u8 bpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format); + /* cpp, characters per pixel, number of bytes per pixel */ + u8 cpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format) / 8; + u64 pclk; u64 bpl; - u32 hfp; - u32 hbp; - u32 hsa; + int hfp; + int hbp; + int hsa; u32 blkline_pck, line_duration; - u32 blkeol_pck, blkeol_duration; u32 val; val = 0; @@ -431,11 +432,21 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, return; } - /* TODO: TVG could be enabled here */ + /* TODO: TVG (test video generator) could be enabled here */ - /* Send blanking packet */ + /* + * During vertical blanking: go to LP mode + * Like with the EOL setting, if this is not set, the EOL area will be + * filled with NULL or blanking packets in the vblank area. + * FIXME: some Samsung phones and display panels such as s6e63m0 use + * DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_BLANKING here instead, + * figure out how to properly configure that from the panel. + */ val |= DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0; - /* Send EOL packet */ + /* + * During EOL: go to LP mode. If this is not set, the EOL area will be + * filled with NULL or blanking packets. + */ val |= DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0; /* Recovery mode 1 */ val |= 1 << DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT; @@ -443,13 +454,13 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, writel(val, d->regs + DSI_VID_MAIN_CTL); /* Vertical frame parameters are pretty straight-forward */ - val = mode->vdisplay << DSI_VID_VSIZE_VSA_LENGTH_SHIFT; + val = mode->vdisplay << DSI_VID_VSIZE_VACT_LENGTH_SHIFT; /* vertical front porch */ val |= (mode->vsync_start - mode->vdisplay) << DSI_VID_VSIZE_VFP_LENGTH_SHIFT; /* vertical sync active */ val |= (mode->vsync_end - mode->vsync_start) - << DSI_VID_VSIZE_VACT_LENGTH_SHIFT; + << DSI_VID_VSIZE_VSA_LENGTH_SHIFT; /* vertical back porch */ val |= (mode->vtotal - mode->vsync_end) << DSI_VID_VSIZE_VBP_LENGTH_SHIFT; @@ -457,36 +468,54 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, /* * Horizontal frame parameters: - * horizontal resolution is given in pixels and must be re-calculated - * into bytes since this is what the hardware expects. + * horizontal resolution is given in pixels but must be re-calculated + * into bytes since this is what the hardware expects, these registers + * define the payload size of the packet. + * + * hfp = horizontal front porch in bytes + * hbp = horizontal back porch in bytes + * hsa = horizontal sync active in bytes * * 6 + 2 is HFP header + checksum */ - hfp = (mode->hsync_start - mode->hdisplay) * bpp - 6 - 2; + hfp = (mode->hsync_start - mode->hdisplay) * cpp - 6 - 2; if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { /* + * Use sync pulse for sync: explicit HSA time * 6 is HBP header + checksum * 4 is RGB header + checksum */ - hbp = (mode->htotal - mode->hsync_end) * bpp - 4 - 6; + hbp = (mode->htotal - mode->hsync_end) * cpp - 4 - 6; /* * 6 is HBP header + checksum * 4 is HSW packet bytes * 4 is RGB header + checksum */ - hsa = (mode->hsync_end - mode->hsync_start) * bpp - 4 - 4 - 6; + hsa = (mode->hsync_end - mode->hsync_start) * cpp - 4 - 4 - 6; } else { /* - * HBP includes both back porch and sync + * Use event for sync: HBP includes both back porch and sync * 6 is HBP header + checksum * 4 is HSW packet bytes * 4 is RGB header + checksum */ - hbp = (mode->htotal - mode->hsync_start) * bpp - 4 - 4 - 6; - /* HSA is not considered in this mode and set to 0 */ + hbp = (mode->htotal - mode->hsync_start) * cpp - 4 - 4 - 6; + /* HSA is not present in this mode and set to 0 */ + hsa = 0; + } + if (hfp < 0) { + dev_info(d->dev, "hfp negative, set to 0\n"); + hfp = 0; + } + if (hbp < 0) { + dev_info(d->dev, "hbp negative, set to 0\n"); + hbp = 0; + } + if (hsa < 0) { + dev_info(d->dev, "hsa negative, set to 0\n"); hsa = 0; } - dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u\n", + dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u bytes\n", hfp, hbp, hsa); /* Frame parameters: horizontal sync active */ @@ -497,71 +526,185 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, val |= hfp << DSI_VID_HSIZE1_HFP_LENGTH_SHIFT; writel(val, d->regs + DSI_VID_HSIZE1); - /* RGB data length (bytes on one scanline) */ - val = mode->hdisplay * (bpp / 8); + /* RGB data length (visible bytes on one scanline) */ + val = mode->hdisplay * cpp; writel(val, d->regs + DSI_VID_HSIZE2); + dev_dbg(d->dev, "RGB length, visible area on a line: %u bytes\n", val); - /* TODO: further adjustments for TVG mode here */ + /* + * Calculate the time between two pixels in picoseconds using + * the supplied refresh rate and total resolution including + * porches and sync. + */ + /* (ps/s) / (pixels/s) = ps/pixels */ + pclk = DIV_ROUND_UP_ULL(1000000000000, + (mode->vrefresh * mode->htotal * mode->vtotal)); + dev_dbg(d->dev, "picoseconds between two pixels: %llu\n", + pclk); /* - * EOL packet length from bits per line calculations: pixel clock - * is given in kHz, calculate the time between two pixels in - * picoseconds. + * How many bytes per line will this update frequency yield? + * + * Calculate the number of picoseconds for one scanline (1), then + * divide by 1000000000000 (2) to get in pixels per second we + * want to output. + * + * Multiply with number of bytes per second at this video display + * frequency (3) to get number of bytes transferred during this + * time. Notice that we use the frequency the display wants, + * not what we actually get from the DSI PLL, which is hs_freq. + * + * These arithmetics are done in a different order to avoid + * overflow. */ - bpl = mode->clock * mode->htotal; - bpl *= (d->hs_freq / 8); - do_div(bpl, 1000000); /* microseconds */ - do_div(bpl, 1000000); /* seconds */ + bpl = pclk * mode->htotal; /* (1) picoseconds per line */ + dev_dbg(d->dev, "picoseconds per line: %llu\n", bpl); + /* Multiply with bytes per second (3) */ + bpl *= (d->mdsi->hs_rate / 8); + /* Pixels per second (2) */ + bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* microseconds */ + bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* seconds */ + /* parallel transactions in all lanes */ bpl *= d->mdsi->lanes; - dev_dbg(d->dev, "calculated bytes per line: %llu\n", bpl); + dev_dbg(d->dev, + "calculated bytes per line: %llu @ %d Hz with HS %lu Hz\n", + bpl, mode->vrefresh, d->mdsi->hs_rate); + /* * 6 is header + checksum, header = 4 bytes, checksum = 2 bytes * 4 is short packet for vsync/hsync */ if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { - /* Fixme: isn't the hsync width in pixels? */ + /* Set the event packet size to 0 (not used) */ + writel(0, d->regs + DSI_VID_BLKSIZE1); + /* + * FIXME: isn't the hsync width in pixels? The porch and + * sync area size is in pixels here, but this -6 + * seems to be for bytes. It looks like this in the vendor + * code though. Is it completely untested? + */ blkline_pck = bpl - (mode->hsync_end - mode->hsync_start) - 6; val = blkline_pck << DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT; writel(val, d->regs + DSI_VID_BLKSIZE2); } else { + /* Set the sync pulse packet size to 0 (not used) */ + writel(0, d->regs + DSI_VID_BLKSIZE2); + /* Specifying payload size in bytes (-4-6 from manual) */ blkline_pck = bpl - 4 - 6; + if (blkline_pck > 0x1FFF) + dev_err(d->dev, "blkline_pck too big %d bytes\n", + blkline_pck); val = blkline_pck << DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT; + val &= DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_MASK; writel(val, d->regs + DSI_VID_BLKSIZE1); } - line_duration = (blkline_pck + 6) / d->mdsi->lanes; - dev_dbg(d->dev, "line duration %u\n", line_duration); + /* + * The line duration is used to scale back the frequency from + * the max frequency supported by the HS clock to the desired + * update frequency in vrefresh. + */ + line_duration = blkline_pck + 6; + /* + * The datasheet contains this complex condition to decreasing + * the line duration by 1 under very specific circumstances. + * Here we also imply that LP is used during burst EOL. + */ + if (d->mdsi->lanes == 2 && (hsa & 0x01) && (hfp & 0x01) + && (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) + line_duration--; + line_duration = DIV_ROUND_CLOSEST(line_duration, d->mdsi->lanes); + dev_dbg(d->dev, "line duration %u bytes\n", line_duration); val = line_duration << DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT; /* * This is the time to perform LP->HS on D-PHY * FIXME: nowhere to get this from: DT property on the DSI? + * The manual says this is "system dependent". + * values like 48 and 72 seen in the vendor code. */ - val |= 0 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT; + val |= 48 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT; writel(val, d->regs + DSI_VID_DPHY_TIME); - /* Calculate block end of line */ - blkeol_pck = bpl - mode->hdisplay * bpp - 6; - blkeol_duration = (blkeol_pck + 6) / d->mdsi->lanes; - dev_dbg(d->dev, "blkeol pck: %u, duration: %u\n", - blkeol_pck, blkeol_duration); - + /* + * See the manual figure 657 page 2203 for understanding the impact + * of the different burst mode settings. + */ if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { - /* Set up EOL clock for burst mode */ + int blkeol_pck, blkeol_duration; + /* + * Packet size at EOL for burst mode, this is only used + * if DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is NOT set, + * but we instead send NULL or blanking packets at EOL. + * This is given in number of bytes. + * + * See the manual page 2198 for the 13 reg_blkeol_pck bits. + */ + blkeol_pck = bpl - (mode->htotal * cpp) - 6; + if (blkeol_pck < 0) { + dev_err(d->dev, "video block does not fit on line!\n"); + dev_err(d->dev, + "calculated bytes per line: %llu @ %d Hz\n", + bpl, mode->vrefresh); + dev_err(d->dev, + "bytes per line (blkline_pck) %u bytes\n", + blkline_pck); + dev_err(d->dev, + "blkeol_pck becomes %d bytes\n", blkeol_pck); + return; + } + dev_dbg(d->dev, "BLKEOL packet: %d bytes\n", blkeol_pck); + val = readl(d->regs + DSI_VID_BLKSIZE1); + val &= ~DSI_VID_BLKSIZE1_BLKEOL_PCK_MASK; val |= blkeol_pck << DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT; writel(val, d->regs + DSI_VID_BLKSIZE1); - writel(blkeol_pck, d->regs + DSI_VID_VCA_SETTING2); - - writel(blkeol_duration, d->regs + DSI_VID_PCK_TIME); - writel(blkeol_duration - 6, d->regs + DSI_VID_VCA_SETTING1); + /* Use the same value for exact burst limit */ + val = blkeol_pck << + DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT; + val &= DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_MASK; + writel(val, d->regs + DSI_VID_VCA_SETTING2); + /* + * This BLKEOL duration is claimed to be the duration in clock + * cycles of the BLLP end-of-line (EOL) period for each line if + * DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is set. + * + * It is hard to trust the manuals' claim that this is in clock + * cycles as we mimic the behaviour of the vendor code, which + * appears to write a number of bytes that would have been + * transferred on a single lane. + * + * See the manual figure 657 page 2203 and page 2198 for the 13 + * reg_blkeol_duration bits. + * + * FIXME: should this also be set up also for non-burst mode + * according to figure 565 page 2202? + */ + blkeol_duration = DIV_ROUND_CLOSEST(blkeol_pck + 6, + d->mdsi->lanes); + dev_dbg(d->dev, "BLKEOL duration: %d clock cycles\n", + blkeol_duration); + + val = readl(d->regs + DSI_VID_PCK_TIME); + val &= ~DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK; + val |= blkeol_duration << + DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT; + writel(val, d->regs + DSI_VID_PCK_TIME); + + /* Max burst limit, this is given in bytes */ + val = readl(d->regs + DSI_VID_VCA_SETTING1); + val &= ~DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_MASK; + val |= (blkeol_pck - 6) << + DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT; + writel(val, d->regs + DSI_VID_VCA_SETTING1); } /* Maximum line limit */ val = readl(d->regs + DSI_VID_VCA_SETTING2); - val |= blkline_pck << - DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT; + val &= ~DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_MASK; + val |= (blkline_pck - 6) << + DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_SHIFT; writel(val, d->regs + DSI_VID_VCA_SETTING2); - + dev_dbg(d->dev, "blkline pck: %d bytes\n", blkline_pck - 6); } static void mcde_dsi_start(struct mcde_dsi *d) diff --git a/drivers/gpu/drm/mcde/mcde_dsi_regs.h b/drivers/gpu/drm/mcde/mcde_dsi_regs.h index 8089db805c57..16551af1089e 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi_regs.h +++ b/drivers/gpu/drm/mcde/mcde_dsi_regs.h @@ -228,6 +228,7 @@ #define DSI_VID_PCK_TIME 0x000000A8 #define DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT 0 +#define DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK 0x00000FFF #define DSI_VID_DPHY_TIME 0x000000AC #define DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT 0 diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 540ef2faa40a..f0b0325381e0 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -94,7 +94,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, if (!fb) return 0; - if (!state->crtc) + if (WARN_ON(!state->crtc)) return 0; ret = mtk_drm_crtc_plane_check(state->crtc, plane, diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 7d04c47d0023..385d4965a8d0 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -157,7 +157,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, msm_gem_unpin_iova(&msm_obj->base, submit->aspace); if (submit->bos[i].flags & BO_LOCKED) - ww_mutex_unlock(&msm_obj->base.resv->lock); + dma_resv_unlock(msm_obj->base.resv); if (backoff && !(submit->bos[i].flags & BO_VALID)) submit->bos[i].iova = 0; @@ -180,8 +180,8 @@ retry: contended = i; if (!(submit->bos[i].flags & BO_LOCKED)) { - ret = ww_mutex_lock_interruptible(&msm_obj->base.resv->lock, - &submit->ticket); + ret = dma_resv_lock_interruptible(msm_obj->base.resv, + &submit->ticket); if (ret) goto fail; submit->bos[i].flags |= BO_LOCKED; @@ -202,8 +202,8 @@ fail: if (ret == -EDEADLK) { struct msm_gem_object *msm_obj = submit->bos[contended].obj; /* we lost out in a seqno race, lock and retry.. */ - ret = ww_mutex_lock_slow_interruptible(&msm_obj->base.resv->lock, - &submit->ticket); + ret = dma_resv_lock_slow_interruptible(msm_obj->base.resv, + &submit->ticket); if (!ret) { submit->bos[contended].flags |= BO_LOCKED; slow_locked = contended; diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c index 20235ff0bbc4..b262b53dbd85 100644 --- a/drivers/gpu/drm/panel/panel-lg-lg4573.c +++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c @@ -42,7 +42,7 @@ static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data) struct spi_transfer xfer = { .len = 2, }; - u16 temp = cpu_to_be16(data); + __be16 temp = cpu_to_be16(data); struct spi_message msg; dev_dbg(ctx->panel.dev, "writing data: %x\n", data); diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 1670a5cae3c7..310aa1546893 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -46,6 +46,7 @@ config ROCKCHIP_DW_HDMI config ROCKCHIP_DW_MIPI_DSI bool "Rockchip specific extensions for Synopsys DW MIPI DSI" + select GENERIC_PHY_MIPI_DPHY help This selects support for Rockchip SoC specific extensions for the Synopsys DesignWare HDMI driver. If you want to diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 5f23cf702cb4..6e1270e45f97 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -12,6 +12,7 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/phy/phy.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -139,6 +140,12 @@ #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0) #define DW_MIPI_NEEDS_GRF_CLK BIT(1) +#define PX30_GRF_PD_VO_CON1 0x0438 +#define PX30_DSI_FORCETXSTOPMODE (0xf << 7) +#define PX30_DSI_FORCERXMODE BIT(6) +#define PX30_DSI_TURNDISABLE BIT(5) +#define PX30_DSI_LCDC_SEL BIT(0) + #define RK3288_GRF_SOC_CON6 0x025c #define RK3288_DSI0_LCDC_SEL BIT(6) #define RK3288_DSI1_LCDC_SEL BIT(9) @@ -223,6 +230,10 @@ struct dw_mipi_dsi_rockchip { bool is_slave; struct dw_mipi_dsi_rockchip *slave; + /* optional external dphy */ + struct phy *phy; + union phy_configure_opts phy_opts; + unsigned int lane_mbps; /* per lane */ u16 input_div; u16 feedback_div; @@ -359,6 +370,9 @@ static int dw_mipi_dsi_phy_init(void *priv_data) struct dw_mipi_dsi_rockchip *dsi = priv_data; int ret, i, vco; + if (dsi->phy) + return 0; + /* * Get vco from frequency(lane_mbps) * vco frequency table @@ -467,6 +481,28 @@ static int dw_mipi_dsi_phy_init(void *priv_data) return ret; } +static void dw_mipi_dsi_phy_power_on(void *priv_data) +{ + struct dw_mipi_dsi_rockchip *dsi = priv_data; + int ret; + + ret = phy_set_mode(dsi->phy, PHY_MODE_MIPI_DPHY); + if (ret) { + DRM_DEV_ERROR(dsi->dev, "failed to set phy mode: %d\n", ret); + return; + } + + phy_configure(dsi->phy, &dsi->phy_opts); + phy_power_on(dsi->phy); +} + +static void dw_mipi_dsi_phy_power_off(void *priv_data) +{ + struct dw_mipi_dsi_rockchip *dsi = priv_data; + + phy_power_off(dsi->phy); +} + static int dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, @@ -504,6 +540,17 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, "DPHY clock frequency is out of range\n"); } + /* for external phy only a the mipi_dphy_config is necessary */ + if (dsi->phy) { + phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 8, + bpp, lanes, + &dsi->phy_opts.mipi_dphy); + dsi->lane_mbps = target_mbps; + *lane_mbps = dsi->lane_mbps; + + return 0; + } + fin = clk_get_rate(dsi->pllref_clk); fout = target_mbps * USEC_PER_SEC; @@ -559,9 +606,89 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, return 0; } +struct hstt { + unsigned int maxfreq; + struct dw_mipi_dsi_dphy_timing timing; +}; + +#define HSTT(_maxfreq, _c_lp2hs, _c_hs2lp, _d_lp2hs, _d_hs2lp) \ +{ \ + .maxfreq = _maxfreq, \ + .timing = { \ + .clk_lp2hs = _c_lp2hs, \ + .clk_hs2lp = _c_hs2lp, \ + .data_lp2hs = _d_lp2hs, \ + .data_hs2lp = _d_hs2lp, \ + } \ +} + +/* Table A-3 High-Speed Transition Times */ +struct hstt hstt_table[] = { + HSTT( 90, 32, 20, 26, 13), + HSTT( 100, 35, 23, 28, 14), + HSTT( 110, 32, 22, 26, 13), + HSTT( 130, 31, 20, 27, 13), + HSTT( 140, 33, 22, 26, 14), + HSTT( 150, 33, 21, 26, 14), + HSTT( 170, 32, 20, 27, 13), + HSTT( 180, 36, 23, 30, 15), + HSTT( 200, 40, 22, 33, 15), + HSTT( 220, 40, 22, 33, 15), + HSTT( 240, 44, 24, 36, 16), + HSTT( 250, 48, 24, 38, 17), + HSTT( 270, 48, 24, 38, 17), + HSTT( 300, 50, 27, 41, 18), + HSTT( 330, 56, 28, 45, 18), + HSTT( 360, 59, 28, 48, 19), + HSTT( 400, 61, 30, 50, 20), + HSTT( 450, 67, 31, 55, 21), + HSTT( 500, 73, 31, 59, 22), + HSTT( 550, 79, 36, 63, 24), + HSTT( 600, 83, 37, 68, 25), + HSTT( 650, 90, 38, 73, 27), + HSTT( 700, 95, 40, 77, 28), + HSTT( 750, 102, 40, 84, 28), + HSTT( 800, 106, 42, 87, 30), + HSTT( 850, 113, 44, 93, 31), + HSTT( 900, 118, 47, 98, 32), + HSTT( 950, 124, 47, 102, 34), + HSTT(1000, 130, 49, 107, 35), + HSTT(1050, 135, 51, 111, 37), + HSTT(1100, 139, 51, 114, 38), + HSTT(1150, 146, 54, 120, 40), + HSTT(1200, 153, 57, 125, 41), + HSTT(1250, 158, 58, 130, 42), + HSTT(1300, 163, 58, 135, 44), + HSTT(1350, 168, 60, 140, 45), + HSTT(1400, 172, 64, 144, 47), + HSTT(1450, 176, 65, 148, 48), + HSTT(1500, 181, 66, 153, 50) +}; + +static int +dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, + struct dw_mipi_dsi_dphy_timing *timing) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hstt_table); i++) + if (lane_mbps < hstt_table[i].maxfreq) + break; + + if (i == ARRAY_SIZE(hstt_table)) + i--; + + *timing = hstt_table[i].timing; + + return 0; +} + static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = { .init = dw_mipi_dsi_phy_init, + .power_on = dw_mipi_dsi_phy_power_on, + .power_off = dw_mipi_dsi_phy_power_off, .get_lane_mbps = dw_mipi_dsi_get_lane_mbps, + .get_timing = dw_mipi_dsi_phy_get_timing, }; static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi, @@ -920,12 +1047,29 @@ static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev) return -EINVAL; } + /* try to get a possible external dphy */ + dsi->phy = devm_phy_optional_get(dev, "dphy"); + if (IS_ERR(dsi->phy)) { + ret = PTR_ERR(dsi->phy); + DRM_DEV_ERROR(dev, "failed to get mipi dphy: %d\n", ret); + return ret; + } + dsi->pllref_clk = devm_clk_get(dev, "ref"); if (IS_ERR(dsi->pllref_clk)) { - ret = PTR_ERR(dsi->pllref_clk); - DRM_DEV_ERROR(dev, - "Unable to get pll reference clock: %d\n", ret); - return ret; + if (dsi->phy) { + /* + * if external phy is present, pll will be + * generated there. + */ + dsi->pllref_clk = NULL; + } else { + ret = PTR_ERR(dsi->pllref_clk); + DRM_DEV_ERROR(dev, + "Unable to get pll reference clock: %d\n", + ret); + return ret; + } } if (dsi->cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) { @@ -989,6 +1133,24 @@ static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev) return 0; } +static const struct rockchip_dw_dsi_chip_data px30_chip_data[] = { + { + .reg = 0xff450000, + .lcdsel_grf_reg = PX30_GRF_PD_VO_CON1, + .lcdsel_big = HIWORD_UPDATE(0, PX30_DSI_LCDC_SEL), + .lcdsel_lit = HIWORD_UPDATE(PX30_DSI_LCDC_SEL, + PX30_DSI_LCDC_SEL), + + .lanecfg1_grf_reg = PX30_GRF_PD_VO_CON1, + .lanecfg1 = HIWORD_UPDATE(0, PX30_DSI_TURNDISABLE | + PX30_DSI_FORCERXMODE | + PX30_DSI_FORCETXSTOPMODE), + + .max_data_lanes = 4, + }, + { /* sentinel */ } +}; + static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = { { .reg = 0xff960000, @@ -1057,6 +1219,9 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { { + .compatible = "rockchip,px30-mipi-dsi", + .data = &px30_chip_data, + }, { .compatible = "rockchip,rk3288-mipi-dsi", .data = &rk3288_chip_data, }, { diff --git a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h index 6d61a0eb5d64..ceac7af9a172 100644 --- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h +++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h @@ -60,3 +60,8 @@ cmdline_test(drm_cmdline_test_vmirror) cmdline_test(drm_cmdline_test_margin_options) cmdline_test(drm_cmdline_test_multiple_options) cmdline_test(drm_cmdline_test_invalid_option) +cmdline_test(drm_cmdline_test_bpp_extra_and_option) +cmdline_test(drm_cmdline_test_extra_and_option) +cmdline_test(drm_cmdline_test_freestanding_options) +cmdline_test(drm_cmdline_test_freestanding_force_e_and_options) +cmdline_test(drm_cmdline_test_panel_orientation) diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c index 013de9d27c35..520f3e66a384 100644 --- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c +++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c @@ -992,6 +992,128 @@ static int drm_cmdline_test_invalid_option(void *ignored) return 0; } +static int drm_cmdline_test_bpp_extra_and_option(void *ignored) +{ + struct drm_cmdline_mode mode = { }; + + FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24e,rotate=180", + &no_connector, + &mode)); + FAIL_ON(!mode.specified); + FAIL_ON(mode.xres != 720); + FAIL_ON(mode.yres != 480); + FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180); + + FAIL_ON(mode.refresh_specified); + + FAIL_ON(!mode.bpp_specified); + FAIL_ON(mode.bpp != 24); + + FAIL_ON(mode.rb); + FAIL_ON(mode.cvt); + FAIL_ON(mode.interlace); + FAIL_ON(mode.margins); + FAIL_ON(mode.force != DRM_FORCE_ON); + + return 0; +} + +static int drm_cmdline_test_extra_and_option(void *ignored) +{ + struct drm_cmdline_mode mode = { }; + + FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480e,rotate=180", + &no_connector, + &mode)); + FAIL_ON(!mode.specified); + FAIL_ON(mode.xres != 720); + FAIL_ON(mode.yres != 480); + FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180); + + FAIL_ON(mode.refresh_specified); + FAIL_ON(mode.bpp_specified); + + FAIL_ON(mode.rb); + FAIL_ON(mode.cvt); + FAIL_ON(mode.interlace); + FAIL_ON(mode.margins); + FAIL_ON(mode.force != DRM_FORCE_ON); + + return 0; +} + +static int drm_cmdline_test_freestanding_options(void *ignored) +{ + struct drm_cmdline_mode mode = { }; + + FAIL_ON(!drm_mode_parse_command_line_for_connector("margin_right=14,margin_left=24,margin_bottom=36,margin_top=42", + &no_connector, + &mode)); + FAIL_ON(mode.specified); + FAIL_ON(mode.refresh_specified); + FAIL_ON(mode.bpp_specified); + + FAIL_ON(mode.tv_margins.right != 14); + FAIL_ON(mode.tv_margins.left != 24); + FAIL_ON(mode.tv_margins.bottom != 36); + FAIL_ON(mode.tv_margins.top != 42); + + FAIL_ON(mode.rb); + FAIL_ON(mode.cvt); + FAIL_ON(mode.interlace); + FAIL_ON(mode.margins); + FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); + + return 0; +} + +static int drm_cmdline_test_freestanding_force_e_and_options(void *ignored) +{ + struct drm_cmdline_mode mode = { }; + + FAIL_ON(!drm_mode_parse_command_line_for_connector("e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42", + &no_connector, + &mode)); + FAIL_ON(mode.specified); + FAIL_ON(mode.refresh_specified); + FAIL_ON(mode.bpp_specified); + + FAIL_ON(mode.tv_margins.right != 14); + FAIL_ON(mode.tv_margins.left != 24); + FAIL_ON(mode.tv_margins.bottom != 36); + FAIL_ON(mode.tv_margins.top != 42); + + FAIL_ON(mode.rb); + FAIL_ON(mode.cvt); + FAIL_ON(mode.interlace); + FAIL_ON(mode.margins); + FAIL_ON(mode.force != DRM_FORCE_ON); + + return 0; +} + +static int drm_cmdline_test_panel_orientation(void *ignored) +{ + struct drm_cmdline_mode mode = { }; + + FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down", + &no_connector, + &mode)); + FAIL_ON(mode.specified); + FAIL_ON(mode.refresh_specified); + FAIL_ON(mode.bpp_specified); + + FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP); + + FAIL_ON(mode.rb); + FAIL_ON(mode.cvt); + FAIL_ON(mode.interlace); + FAIL_ON(mode.margins); + FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); + + return 0; +} + #include "drm_selftest.c" static int __init test_drm_cmdline_init(void) diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 514efefb0016..4b165635b2d4 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -309,11 +309,24 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, return 0; } +static int +dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, + struct dw_mipi_dsi_dphy_timing *timing) +{ + timing->clk_hs2lp = 0x40; + timing->clk_lp2hs = 0x40; + timing->data_hs2lp = 0x40; + timing->data_lp2hs = 0x40; + + return 0; +} + static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { .init = dw_mipi_dsi_phy_init, .power_on = dw_mipi_dsi_phy_power_on, .power_off = dw_mipi_dsi_phy_power_off, .get_lane_mbps = dw_mipi_dsi_get_lane_mbps, + .get_timing = dw_mipi_dsi_phy_get_timing, }; static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = { diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 5b51298921cf..c2815e8ae1da 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -437,9 +437,6 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, /* Commit shadow registers = update planes at next vblank */ reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); - /* Enable LTDC */ - reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); - drm_crtc_vblank_on(crtc); } @@ -453,9 +450,6 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, drm_crtc_vblank_off(crtc); - /* disable LTDC */ - reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); - /* disable IRQ */ reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); @@ -1044,9 +1038,13 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = { static void ltdc_encoder_disable(struct drm_encoder *encoder) { struct drm_device *ddev = encoder->dev; + struct ltdc_device *ldev = ddev->dev_private; DRM_DEBUG_DRIVER("\n"); + /* Disable LTDC */ + reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); + /* Set to sleep state the pinctrl whatever type of encoder */ pinctrl_pm_select_sleep_state(ddev->dev); } @@ -1054,6 +1052,19 @@ static void ltdc_encoder_disable(struct drm_encoder *encoder) static void ltdc_encoder_enable(struct drm_encoder *encoder) { struct drm_device *ddev = encoder->dev; + struct ltdc_device *ldev = ddev->dev_private; + + DRM_DEBUG_DRIVER("\n"); + + /* Enable LTDC */ + reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); +} + +static void ltdc_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *ddev = encoder->dev; DRM_DEBUG_DRIVER("\n"); @@ -1069,6 +1080,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder) static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = { .disable = ltdc_encoder_disable, .enable = ltdc_encoder_enable, + .mode_set = ltdc_encoder_mode_set, }; static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index a5757b11b730..5ae67d526b1d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -346,6 +346,27 @@ static int sun4i_drv_add_endpoints(struct device *dev, return count; } +#ifdef CONFIG_PM_SLEEP +static int sun4i_drv_drm_sys_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(drm); +} + +static int sun4i_drv_drm_sys_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(drm); +} +#endif + +static const struct dev_pm_ops sun4i_drv_drm_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sun4i_drv_drm_sys_suspend, + sun4i_drv_drm_sys_resume) +}; + static int sun4i_drv_probe(struct platform_device *pdev) { struct component_match *match = NULL; @@ -418,6 +439,7 @@ static struct platform_driver sun4i_drv_platform_driver = { .driver = { .name = "sun4i-drm", .of_match_table = sun4i_drv_of_table, + .pm = &sun4i_drv_drm_pm_ops, }, }; module_platform_driver(sun4i_drv_platform_driver); diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 4e8f634cc2db..a75fcb113172 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -1081,6 +1081,7 @@ static const struct component_ops sun6i_dsi_ops = { static int sun6i_dsi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const char *bus_clk_name = NULL; struct sun6i_dsi *dsi; struct resource *res; void __iomem *base; @@ -1094,6 +1095,10 @@ static int sun6i_dsi_probe(struct platform_device *pdev) dsi->host.ops = &sun6i_dsi_host_ops; dsi->host.dev = dev; + if (of_device_is_compatible(dev->of_node, + "allwinner,sun6i-a31-mipi-dsi")) + bus_clk_name = "bus"; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) { @@ -1107,23 +1112,36 @@ static int sun6i_dsi_probe(struct platform_device *pdev) return PTR_ERR(dsi->regulator); } - dsi->regs = devm_regmap_init_mmio_clk(dev, "bus", base, - &sun6i_dsi_regmap_config); - if (IS_ERR(dsi->regs)) { - dev_err(dev, "Couldn't create the DSI encoder regmap\n"); - return PTR_ERR(dsi->regs); - } - dsi->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(dsi->reset)) { dev_err(dev, "Couldn't get our reset line\n"); return PTR_ERR(dsi->reset); } - dsi->mod_clk = devm_clk_get(dev, "mod"); - if (IS_ERR(dsi->mod_clk)) { - dev_err(dev, "Couldn't get the DSI mod clock\n"); - return PTR_ERR(dsi->mod_clk); + dsi->regs = devm_regmap_init_mmio(dev, base, &sun6i_dsi_regmap_config); + if (IS_ERR(dsi->regs)) { + dev_err(dev, "Couldn't init regmap\n"); + return PTR_ERR(dsi->regs); + } + + dsi->bus_clk = devm_clk_get(dev, bus_clk_name); + if (IS_ERR(dsi->bus_clk)) { + dev_err(dev, "Couldn't get the DSI bus clock\n"); + return PTR_ERR(dsi->bus_clk); + } + + ret = regmap_mmio_attach_clk(dsi->regs, dsi->bus_clk); + if (ret) + return ret; + + if (of_device_is_compatible(dev->of_node, + "allwinner,sun6i-a31-mipi-dsi")) { + dsi->mod_clk = devm_clk_get(dev, "mod"); + if (IS_ERR(dsi->mod_clk)) { + dev_err(dev, "Couldn't get the DSI mod clock\n"); + ret = PTR_ERR(dsi->mod_clk); + goto err_attach_clk; + } } /* @@ -1161,6 +1179,9 @@ err_pm_disable: pm_runtime_disable(dev); err_unprotect_clk: clk_rate_exclusive_put(dsi->mod_clk); +err_attach_clk: + if (!IS_ERR(dsi->bus_clk)) + regmap_mmio_detach_clk(dsi->regs); return ret; } @@ -1174,6 +1195,9 @@ static int sun6i_dsi_remove(struct platform_device *pdev) pm_runtime_disable(dev); clk_rate_exclusive_put(dsi->mod_clk); + if (!IS_ERR(dsi->bus_clk)) + regmap_mmio_detach_clk(dsi->regs); + return 0; } @@ -1232,6 +1256,7 @@ static const struct dev_pm_ops sun6i_dsi_pm_ops = { static const struct of_device_id sun6i_dsi_of_table[] = { { .compatible = "allwinner,sun6i-a31-mipi-dsi" }, + { .compatible = "allwinner,sun50i-a64-mipi-dsi" }, { } }; MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table); diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 7a06cb6e31c5..e1cfc3ccd05a 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -568,7 +568,7 @@ vc4_unlock_bo_reservations(struct drm_device *dev, for (i = 0; i < exec->bo_count; i++) { struct drm_gem_object *bo = &exec->bo[i]->base; - ww_mutex_unlock(&bo->resv->lock); + dma_resv_unlock(bo->resv); } ww_acquire_fini(acquire_ctx); @@ -595,8 +595,7 @@ vc4_lock_bo_reservations(struct drm_device *dev, retry: if (contended_lock != -1) { bo = &exec->bo[contended_lock]->base; - ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, - acquire_ctx); + ret = dma_resv_lock_slow_interruptible(bo->resv, acquire_ctx); if (ret) { ww_acquire_done(acquire_ctx); return ret; @@ -609,19 +608,19 @@ retry: bo = &exec->bo[i]->base; - ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx); + ret = dma_resv_lock_interruptible(bo->resv, acquire_ctx); if (ret) { int j; for (j = 0; j < i; j++) { bo = &exec->bo[j]->base; - ww_mutex_unlock(&bo->resv->lock); + dma_resv_unlock(bo->resv); } if (contended_lock != -1 && contended_lock >= i) { bo = &exec->bo[contended_lock]->base; - ww_mutex_unlock(&bo->resv->lock); + dma_resv_unlock(bo->resv); } if (ret == -EDEADLK) { diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index e622485ae826..0966208ec30d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -43,6 +43,9 @@ #define XRES_MAX 8192 #define YRES_MAX 8192 +#define drm_connector_to_virtio_gpu_output(x) \ + container_of(x, struct virtio_gpu_output, conn) + static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, @@ -59,7 +62,7 @@ static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = { .dirty = drm_atomic_helper_dirtyfb, }; -int +static int virtio_gpu_framebuffer_init(struct drm_device *dev, struct virtio_gpu_framebuffer *vgfb, const struct drm_mode_fb_cmd2 *mode_cmd, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index eedae2a7b532..7e69c06e168e 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -103,8 +103,6 @@ struct virtio_gpu_fence { struct virtio_gpu_fence_driver *drv; struct list_head node; }; -#define to_virtio_fence(x) \ - container_of(x, struct virtio_gpu_fence, f) struct virtio_gpu_vbuffer { char *buf; @@ -135,10 +133,6 @@ struct virtio_gpu_output { }; #define drm_crtc_to_virtio_gpu_output(x) \ container_of(x, struct virtio_gpu_output, crtc) -#define drm_connector_to_virtio_gpu_output(x) \ - container_of(x, struct virtio_gpu_output, conn) -#define drm_encoder_to_virtio_gpu_output(x) \ - container_of(x, struct virtio_gpu_output, enc) struct virtio_gpu_framebuffer { struct drm_framebuffer base; @@ -183,6 +177,9 @@ struct virtio_gpu_device { struct kmem_cache *vbufs; bool vqs_ready; + bool disable_notify; + bool pending_notify; + struct ida resource_ida; wait_queue_head_t resp_wq; @@ -335,11 +332,10 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work); void virtio_gpu_dequeue_cursor_func(struct work_struct *work); void virtio_gpu_dequeue_fence_func(struct work_struct *work); +void virtio_gpu_disable_notify(struct virtio_gpu_device *vgdev); +void virtio_gpu_enable_notify(struct virtio_gpu_device *vgdev); + /* virtio_gpu_display.c */ -int virtio_gpu_framebuffer_init(struct drm_device *dev, - struct virtio_gpu_framebuffer *vgfb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); @@ -350,7 +346,6 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, int index); /* virtio_gpu_fence.c */ -bool virtio_fence_signaled(struct dma_fence *f); struct virtio_gpu_fence *virtio_gpu_fence_alloc( struct virtio_gpu_device *vgdev); void virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, @@ -366,18 +361,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, struct virtio_gpu_object_params *params, struct virtio_gpu_object **bo_ptr, struct virtio_gpu_fence *fence); - /* virtgpu_prime.c */ struct drm_gem_object *virtgpu_gem_prime_import_sg_table( struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); -static inline u64 virtio_gpu_object_mmap_offset(struct virtio_gpu_object *bo) -{ - return drm_vma_node_offset_addr(&bo->base.base.vma_node); -} - -/* virgl debufs */ +/* virgl debugfs */ int virtio_gpu_debugfs_init(struct drm_minor *minor); #endif diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index a4b9881ca1d3..5b2a4146c5bd 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c @@ -27,6 +27,9 @@ #include "virtgpu_drv.h" +#define to_virtio_fence(x) \ + container_of(x, struct virtio_gpu_fence, f) + static const char *virtio_get_driver_name(struct dma_fence *f) { return "virtio_gpu"; @@ -37,7 +40,7 @@ static const char *virtio_get_timeline_name(struct dma_fence *f) return "controlq"; } -bool virtio_fence_signaled(struct dma_fence *f) +static bool virtio_fence_signaled(struct dma_fence *f) { struct virtio_gpu_fence *fence = to_virtio_fence(f); diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c index 4c1f579edfb3..0a2b62279647 100644 --- a/drivers/gpu/drm/virtio/virtgpu_gem.c +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c @@ -96,14 +96,12 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv, uint32_t handle, uint64_t *offset_p) { struct drm_gem_object *gobj; - struct virtio_gpu_object *obj; BUG_ON(!offset_p); gobj = drm_gem_object_lookup(file_priv, handle); if (gobj == NULL) return -ENOENT; - obj = gem_to_virtio_gpu_obj(gobj); - *offset_p = virtio_gpu_object_mmap_offset(obj); + *offset_p = drm_vma_node_offset_addr(&gobj->vma_node); drm_gem_object_put_unlocked(gobj); return 0; } diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index bc4bc4475a8c..ac42c84d2d7f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -24,6 +24,7 @@ */ #include <drm/drm_atomic_helper.h> +#include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_plane_helper.h> @@ -88,7 +89,7 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, struct drm_crtc_state *crtc_state; int ret; - if (!state->fb || !state->crtc) + if (!state->fb || WARN_ON(!state->crtc)) return 0; crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); @@ -103,22 +104,26 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, } static void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev, - struct virtio_gpu_object *bo, - struct drm_plane_state *state) + struct drm_plane_state *state, + struct drm_rect *rect) { + struct virtio_gpu_object *bo = + gem_to_virtio_gpu_obj(state->fb->obj[0]); struct virtio_gpu_object_array *objs; + uint32_t w = rect->x2 - rect->x1; + uint32_t h = rect->y2 - rect->y1; + uint32_t x = rect->x1; + uint32_t y = rect->y1; + uint32_t off = x * state->fb->format->cpp[0] + + y * state->fb->pitches[0]; objs = virtio_gpu_array_alloc(1); if (!objs) return; virtio_gpu_array_add_obj(objs, &bo->base.base); - virtio_gpu_cmd_transfer_to_host_2d - (vgdev, 0, - state->src_w >> 16, - state->src_h >> 16, - state->src_x >> 16, - state->src_y >> 16, - objs, NULL); + + virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y, + objs, NULL); } static void virtio_gpu_primary_plane_update(struct drm_plane *plane, @@ -127,8 +132,8 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, struct drm_device *dev = plane->dev; struct virtio_gpu_device *vgdev = dev->dev_private; struct virtio_gpu_output *output = NULL; - struct virtio_gpu_framebuffer *vgfb; struct virtio_gpu_object *bo; + struct drm_rect rect; if (plane->state->crtc) output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); @@ -146,30 +151,43 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, return; } - vgfb = to_virtio_gpu_framebuffer(plane->state->fb); - bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); + if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect)) + return; + + virtio_gpu_disable_notify(vgdev); + + bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]); if (bo->dumb) - virtio_gpu_update_dumb_bo(vgdev, bo, plane->state); - - DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", - bo->hw_res_handle, - plane->state->crtc_w, plane->state->crtc_h, - plane->state->crtc_x, plane->state->crtc_y, - plane->state->src_w >> 16, - plane->state->src_h >> 16, - plane->state->src_x >> 16, - plane->state->src_y >> 16); - virtio_gpu_cmd_set_scanout(vgdev, output->index, - bo->hw_res_handle, - plane->state->src_w >> 16, - plane->state->src_h >> 16, - plane->state->src_x >> 16, - plane->state->src_y >> 16); + virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect); + + if (plane->state->fb != old_state->fb || + plane->state->src_w != old_state->src_w || + plane->state->src_h != old_state->src_h || + plane->state->src_x != old_state->src_x || + plane->state->src_y != old_state->src_y) { + DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", + bo->hw_res_handle, + plane->state->crtc_w, plane->state->crtc_h, + plane->state->crtc_x, plane->state->crtc_y, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->src_x >> 16, + plane->state->src_y >> 16); + virtio_gpu_cmd_set_scanout(vgdev, output->index, + bo->hw_res_handle, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->src_x >> 16, + plane->state->src_y >> 16); + } + virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, - plane->state->src_x >> 16, - plane->state->src_y >> 16, - plane->state->src_w >> 16, - plane->state->src_h >> 16); + rect.x1, + rect.y1, + rect.x2 - rect.x1, + rect.y2 - rect.y1); + + virtio_gpu_enable_notify(vgdev); } static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 9274c4063c70..5914e79d3429 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -404,8 +404,12 @@ again: } notify = virtio_gpu_queue_ctrl_buffer_locked(vgdev, vbuf, vout); spin_unlock(&vgdev->ctrlq.qlock); - if (notify) - virtqueue_notify(vgdev->ctrlq.vq); + if (notify) { + if (vgdev->disable_notify) + vgdev->pending_notify = true; + else + virtqueue_notify(vgdev->ctrlq.vq); + } if (sgt) { sg_free_table(sgt); @@ -413,6 +417,21 @@ again: } } +void virtio_gpu_disable_notify(struct virtio_gpu_device *vgdev) +{ + vgdev->disable_notify = true; +} + +void virtio_gpu_enable_notify(struct virtio_gpu_device *vgdev) +{ + vgdev->disable_notify = false; + + if (!vgdev->pending_notify) + return; + vgdev->pending_notify = false; + virtqueue_notify(vgdev->ctrlq.vq); +} + static void virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf) { diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index 94cc64a342e1..b0e390b3288e 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -19,6 +19,13 @@ struct dw_mipi_dsi; struct mipi_dsi_device; struct platform_device; +struct dw_mipi_dsi_dphy_timing { + u16 data_hs2lp; + u16 data_lp2hs; + u16 clk_hs2lp; + u16 clk_lp2hs; +}; + struct dw_mipi_dsi_phy_ops { int (*init)(void *priv_data); void (*power_on)(void *priv_data); @@ -27,6 +34,8 @@ struct dw_mipi_dsi_phy_ops { const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, unsigned int *lane_mbps); + int (*get_timing)(void *priv_data, unsigned int lane_mbps, + struct dw_mipi_dsi_dphy_timing *timing); }; struct dw_mipi_dsi_host_ops { diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 5923819dcd68..951dfb15c27b 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -35,7 +35,7 @@ * struct drm_crtc_commit - track modeset commits on a CRTC * * This structure is used to track pending modeset changes and atomic commit on - * a per-CRTC basis. Since updating the list should never block this structure + * a per-CRTC basis. Since updating the list should never block, this structure * is reference counted to allow waiters to safely wait on an event to complete, * without holding any locks. * @@ -363,7 +363,7 @@ struct drm_atomic_state { * When a connector or plane is not bound to any CRTC, it's still important * to preserve linearity to prevent the atomic states from being freed to early. * - * This commit (if set) is not bound to any crtc, but will be completed when + * This commit (if set) is not bound to any CRTC, but will be completed when * drm_atomic_helper_commit_hw_done() is called. */ struct drm_crtc_commit *fake_commit; @@ -476,12 +476,12 @@ drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state, struct drm_encoder *encoder); /** - * drm_atomic_get_existing_crtc_state - get crtc state, if it exists + * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the crtc state for the given crtc, or NULL - * if the crtc is not part of the global atomic state. + * This function returns the CRTC state for the given CRTC, or NULL + * if the CRTC is not part of the global atomic state. * * This function is deprecated, @drm_atomic_get_old_crtc_state or * @drm_atomic_get_new_crtc_state should be used instead. @@ -494,12 +494,12 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state, } /** - * drm_atomic_get_old_crtc_state - get old crtc state, if it exists + * drm_atomic_get_old_crtc_state - get old CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the old crtc state for the given crtc, or - * NULL if the crtc is not part of the global atomic state. + * This function returns the old CRTC state for the given CRTC, or + * NULL if the CRTC is not part of the global atomic state. */ static inline struct drm_crtc_state * drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, @@ -508,12 +508,12 @@ drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, return state->crtcs[drm_crtc_index(crtc)].old_state; } /** - * drm_atomic_get_new_crtc_state - get new crtc state, if it exists + * drm_atomic_get_new_crtc_state - get new CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the new crtc state for the given crtc, or - * NULL if the crtc is not part of the global atomic state. + * This function returns the new CRTC state for the given CRTC, or + * NULL if the CRTC is not part of the global atomic state. */ static inline struct drm_crtc_state * drm_atomic_get_new_crtc_state(struct drm_atomic_state *state, @@ -978,11 +978,11 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state) } /** - * drm_atomic_crtc_effectively_active - compute whether crtc is actually active + * drm_atomic_crtc_effectively_active - compute whether CRTC is actually active * @state: &drm_crtc_state for the CRTC * * When in self refresh mode, the crtc_state->active value will be false, since - * the crtc is off. However in some cases we're interested in whether the crtc + * the CRTC is off. However in some cases we're interested in whether the CRTC * is active, or effectively active (ie: it's connected to an active display). * In these cases, use this function instead of just checking active. */ diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index bf4e07141d81..9db3cac48f4f 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -152,7 +152,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, /** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC * @plane: the loop cursor - * @crtc: the crtc whose planes are iterated + * @crtc: the CRTC whose planes are iterated * * This iterates over the current state, useful (for example) when applying * atomic state after it has been checked and swapped. To iterate over the @@ -166,7 +166,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, /** * drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state * @plane: the loop cursor - * @crtc_state: the incoming crtc-state + * @crtc_state: the incoming CRTC state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * attached if the specified state is applied. Useful during for example @@ -180,7 +180,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * drm_crtc_atomic_state_for_each_plane_state - iterate over attached planes in new state * @plane: the loop cursor * @plane_state: loop cursor for the plane's state, must be const - * @crtc_state: the incoming crtc-state + * @crtc_state: the incoming CRTC state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * attached if the specified state is applied. Useful during for example @@ -189,7 +189,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * * Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a * const plane_state. This is useful when a driver just wants to peek at other - * active planes on this crtc, but does not need to change it. + * active planes on this CRTC, but does not need to change it. */ #define drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) \ drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) \ diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 17b728d9c73d..221910948b37 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1070,6 +1070,14 @@ struct drm_cmdline_mode { unsigned int rotation_reflection; /** + * @panel_orientation: + * + * drm-connector "panel orientation" property override value, + * DRM_MODE_PANEL_ORIENTATION_UNKNOWN if not set. + */ + enum drm_panel_orientation panel_orientation; + + /** * @tv_margins: TV margins to apply to the mode. */ struct drm_connector_tv_margins tv_margins; diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 5f27b693e1a0..121f7aabccd1 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -198,7 +198,7 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np) } #endif -#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) +#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) int drm_panel_of_backlight(struct drm_panel *panel); #else static inline int drm_panel_of_backlight(struct drm_panel *panel) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 085a9685270c..8f99d389792d 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -322,6 +322,8 @@ static inline bool drm_debug_enabled(enum drm_debug_category category) /* * struct device based logging + * + * Prefer drm_device based logging over device or prink based logging. */ __printf(3, 4) @@ -418,7 +420,70 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, fmt, ##__VA_ARGS__) /* + * struct drm_device based logging + * + * Prefer drm_device based logging over device or prink based logging. + */ + +/* Helper for struct drm_device based logging. */ +#define __drm_printk(drm, level, type, fmt, ...) \ + dev_##level##type((drm)->dev, "[drm] " fmt, ##__VA_ARGS__) + + +#define drm_info(drm, fmt, ...) \ + __drm_printk((drm), info,, fmt, ##__VA_ARGS__) + +#define drm_notice(drm, fmt, ...) \ + __drm_printk((drm), notice,, fmt, ##__VA_ARGS__) + +#define drm_warn(drm, fmt, ...) \ + __drm_printk((drm), warn,, fmt, ##__VA_ARGS__) + +#define drm_err(drm, fmt, ...) \ + __drm_printk((drm), err,, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_info_once(drm, fmt, ...) \ + __drm_printk((drm), info, _once, fmt, ##__VA_ARGS__) + +#define drm_notice_once(drm, fmt, ...) \ + __drm_printk((drm), notice, _once, fmt, ##__VA_ARGS__) + +#define drm_warn_once(drm, fmt, ...) \ + __drm_printk((drm), warn, _once, fmt, ##__VA_ARGS__) + +#define drm_err_once(drm, fmt, ...) \ + __drm_printk((drm), err, _once, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_err_ratelimited(drm, fmt, ...) \ + __drm_printk((drm), err, _ratelimited, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_dbg_core(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_CORE, fmt, ##__VA_ARGS__) +#define drm_dbg(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) +#define drm_dbg_kms(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_KMS, fmt, ##__VA_ARGS__) +#define drm_dbg_prime(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__) +#define drm_dbg_atomic(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) +#define drm_dbg_vbl(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_VBL, fmt, ##__VA_ARGS__) +#define drm_dbg_state(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_STATE, fmt, ##__VA_ARGS__) +#define drm_dbg_lease(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_LEASE, fmt, ##__VA_ARGS__) +#define drm_dbg_dp(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_DP, fmt, ##__VA_ARGS__) + + +/* * printk based logging + * + * Prefer drm_device based logging over device or prink based logging. */ __printf(2, 3) diff --git a/include/uapi/linux/dma-heap.h b/include/uapi/linux/dma-heap.h index 73e7f66c1cae..6f84fa08e074 100644 --- a/include/uapi/linux/dma-heap.h +++ b/include/uapi/linux/dma-heap.h @@ -42,12 +42,12 @@ struct dma_heap_allocation_data { #define DMA_HEAP_IOC_MAGIC 'H' /** - * DOC: DMA_HEAP_IOC_ALLOC - allocate memory from pool + * DOC: DMA_HEAP_IOCTL_ALLOC - allocate memory from pool * * Takes a dma_heap_allocation_data struct and returns it with the fd field * populated with the dmabuf handle of the allocation. */ -#define DMA_HEAP_IOC_ALLOC _IOWR(DMA_HEAP_IOC_MAGIC, 0x0,\ +#define DMA_HEAP_IOCTL_ALLOC _IOWR(DMA_HEAP_IOC_MAGIC, 0x0,\ struct dma_heap_allocation_data) #endif /* _UAPI_LINUX_DMABUF_POOL_H */ diff --git a/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c b/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c index 3e53ad331bdc..cd5e1f602ac9 100644 --- a/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c +++ b/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c @@ -116,7 +116,7 @@ static int dmabuf_heap_alloc_fdflags(int fd, size_t len, unsigned int fd_flags, if (!dmabuf_fd) return -EINVAL; - ret = ioctl(fd, DMA_HEAP_IOC_ALLOC, &data); + ret = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &data); if (ret < 0) return ret; *dmabuf_fd = (int)data.fd; |