diff --git a/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml b/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml index 9f61ebdfefa8..4ed7a799ba26 100644 --- a/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml +++ b/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml @@ -70,7 +70,9 @@ properties: samsung,burst-clock-frequency: $ref: /schemas/types.yaml#/definitions/uint32 description: - DSIM high speed burst mode frequency. + DSIM high speed burst mode frequency. If absent, + the pixel clock from the attached device or bridge + will be used instead. samsung,esc-clock-frequency: $ref: /schemas/types.yaml#/definitions/uint32 @@ -80,7 +82,8 @@ properties: samsung,pll-clock-frequency: $ref: /schemas/types.yaml#/definitions/uint32 description: - DSIM oscillator clock frequency. + DSIM oscillator clock frequency. If absent, the clock frequency + of sclk_mipi will be used instead. phys: maxItems: 1 @@ -100,7 +103,8 @@ properties: specified. port@1: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false description: DSI output port node to the panel or the next bridge in the chain. @@ -134,9 +138,7 @@ required: - compatible - interrupts - reg - - samsung,burst-clock-frequency - samsung,esc-clock-frequency - - samsung,pll-clock-frequency allOf: - $ref: ../dsi-controller.yaml# diff --git a/Documentation/devicetree/bindings/display/connector/hdmi-connector.yaml b/Documentation/devicetree/bindings/display/connector/hdmi-connector.yaml index 83c0d008265b..3ee8f9225984 100644 --- a/Documentation/devicetree/bindings/display/connector/hdmi-connector.yaml +++ b/Documentation/devicetree/bindings/display/connector/hdmi-connector.yaml @@ -36,6 +36,9 @@ properties: description: GPIO signal to enable DDC bus maxItems: 1 + hdmi-pwr-supply: + description: Power supply for the HDMI +5V Power pin + port: $ref: /schemas/graph.yaml#/properties/port description: Connection to controller providing HDMI signals diff --git a/Documentation/devicetree/bindings/display/fsl,lcdif.yaml b/Documentation/devicetree/bindings/display/fsl,lcdif.yaml index 75b4efd70ba8..fc11ab5fc465 100644 --- a/Documentation/devicetree/bindings/display/fsl,lcdif.yaml +++ b/Documentation/devicetree/bindings/display/fsl,lcdif.yaml @@ -21,6 +21,7 @@ properties: - fsl,imx28-lcdif - fsl,imx6sx-lcdif - fsl,imx8mp-lcdif + - fsl,imx93-lcdif - items: - enum: - fsl,imx6sl-lcdif @@ -88,7 +89,9 @@ allOf: properties: compatible: contains: - const: fsl,imx8mp-lcdif + enum: + - fsl,imx8mp-lcdif + - fsl,imx93-lcdif then: properties: clocks: @@ -107,6 +110,7 @@ allOf: enum: - fsl,imx6sx-lcdif - fsl,imx8mp-lcdif + - fsl,imx93-lcdif then: properties: clocks: @@ -123,6 +127,7 @@ allOf: - fsl,imx8mm-lcdif - fsl,imx8mn-lcdif - fsl,imx8mp-lcdif + - fsl,imx93-lcdif then: required: - power-domains diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 733e47da36e8..f7c45e38d4b7 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -33,6 +33,8 @@ properties: - ampire,am-1280800n3tzqw-t00h # Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel - ampire,am-480272h3tmqw-t01h + # Ampire AM-800480L1TMQW-T00H 5" WVGA TFT LCD panel + - ampire,am-800480l1tmqw-t00h # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel - ampire,am800480r3tmqwa1h # Ampire AM-800600P5TMQW-TB8H 8.0" SVGA TFT LCD panel diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst index b46327356e80..fe35a291ff3e 100644 --- a/Documentation/gpu/drm-usage-stats.rst +++ b/Documentation/gpu/drm-usage-stats.rst @@ -24,7 +24,7 @@ File format specification - All keys shall be prefixed with `drm-`. - Whitespace between the delimiter and first non-whitespace character shall be ignored when parsing. -- Neither keys or values are allowed to contain whitespace characters. +- Keys are not allowed to contain whitespace characters. - Numerical key value pairs can end with optional unit string. - Data type of the value is fixed as defined in the specification. @@ -39,12 +39,13 @@ Data types ---------- - - Unsigned integer without defining the maximum value. -- - String excluding any above defined reserved characters or whitespace. +- - String excluding any above defined reserved characters or whitespace. +- - String. Mandatory fully standardised keys --------------------------------- -- drm-driver: +- drm-driver: String shall contain the name this driver registered as via the respective `struct drm_driver` data structure. @@ -52,6 +53,9 @@ String shall contain the name this driver registered as via the respective Optional fully standardised keys -------------------------------- +Identification +^^^^^^^^^^^^^^ + - drm-pdev: For PCI devices this should contain the PCI slot address of the device in @@ -69,10 +73,13 @@ scope of each device, in which case `drm-pdev` shall be present as well. Userspace should make sure to not double account any usage statistics by using the above described criteria in order to associate data to individual clients. -- drm-engine-: ns +Utilization +^^^^^^^^^^^ + +- drm-engine-: ns GPUs usually contain multiple execution engines. Each shall be given a stable -and unique name (str), with possible values documented in the driver specific +and unique name (keystr), with possible values documented in the driver specific documentation. Value shall be in specified time units which the respective GPU engine spent @@ -84,31 +91,19 @@ larger value within a reasonable period. Upon observing a value lower than what was previously read, userspace is expected to stay with that larger previous value until a monotonic update is seen. -- drm-engine-capacity-: +- drm-engine-capacity-: Engine identifier string must be the same as the one specified in the -drm-engine- tag and shall contain a greater than zero number in case the +drm-engine- tag and shall contain a greater than zero number in case the exported engine corresponds to a group of identical hardware engines. In the absence of this tag parser shall assume capacity of one. Zero capacity is not allowed. -- drm-memory-: [KiB|MiB] - -Each possible memory type which can be used to store buffer objects by the -GPU in question shall be given a stable and unique name to be returned as the -string here. - -Value shall reflect the amount of storage currently consumed by the buffer -object belong to this client, in the respective memory region. - -Default unit shall be bytes with optional unit specifiers of 'KiB' or 'MiB' -indicating kibi- or mebi-bytes. - -- drm-cycles- +- drm-cycles-: Engine identifier string must be the same as the one specified in the -drm-engine- tag and shall contain the number of busy cycles for the given +drm-engine- tag and shall contain the number of busy cycles for the given engine. Values are not required to be constantly monotonic if it makes the driver @@ -117,16 +112,60 @@ larger value within a reasonable period. Upon observing a value lower than what was previously read, userspace is expected to stay with that larger previous value until a monotonic update is seen. -- drm-maxfreq- [Hz|MHz|KHz] +- drm-maxfreq-: [Hz|MHz|KHz] Engine identifier string must be the same as the one specified in the -drm-engine- tag and shall contain the maximum frequency for the given -engine. Taken together with drm-cycles-, this can be used to calculate -percentage utilization of the engine, whereas drm-engine- only reflects +drm-engine- tag and shall contain the maximum frequency for the given +engine. Taken together with drm-cycles-, this can be used to calculate +percentage utilization of the engine, whereas drm-engine- only reflects time active without considering what frequency the engine is operating as a percentage of it's maximum frequency. +Memory +^^^^^^ + +- drm-memory-: [KiB|MiB] + +Each possible memory type which can be used to store buffer objects by the +GPU in question shall be given a stable and unique name to be returned as the +string here. The name "memory" is reserved to refer to normal system memory. + +Value shall reflect the amount of storage currently consumed by the buffer +objects belong to this client, in the respective memory region. + +Default unit shall be bytes with optional unit specifiers of 'KiB' or 'MiB' +indicating kibi- or mebi-bytes. + +- drm-shared-: [KiB|MiB] + +The total size of buffers that are shared with another file (ie. have more +than a single handle). + +- drm-total-: [KiB|MiB] + +The total size of buffers that including shared and private memory. + +- drm-resident-: [KiB|MiB] + +The total size of buffers that are resident in the specified region. + +- drm-purgeable-: [KiB|MiB] + +The total size of buffers that are purgeable. + +- drm-active-: [KiB|MiB] + +The total size of buffers that are active on one or more engines. + +Implementation Details +====================== + +Drivers should use drm_show_fdinfo() in their `struct file_operations`, and +implement &drm_driver.show_fdinfo if they wish to provide any stats which +are not provided by drm_show_fdinfo(). But even driver specific stats should +be documented above and where possible, aligned with other drivers. + Driver specific implementations -=============================== +------------------------------- :ref:`i915-usage-stats` diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ba3fb04bb691..bb2e48cc6cd6 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -95,6 +95,7 @@ config DRM_KUNIT_TEST config DRM_KMS_HELPER tristate depends on DRM + select FB_SYS_HELPERS_DEFERRED if DRM_FBDEV_EMULATION help CRTC helpers for KMS drivers. @@ -132,14 +133,6 @@ config DRM_FBDEV_EMULATION bool "Enable legacy fbdev support for your modesetting driver" depends on DRM_KMS_HELPER depends on FB=y || FB=DRM_KMS_HELPER - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_DEFERRED_IO - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT select FRAMEBUFFER_CONSOLE if !EXPERT select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE default y @@ -223,6 +216,7 @@ config DRM_TTM_HELPER config DRM_GEM_DMA_HELPER tristate depends on DRM + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION help Choose this if you need the GEM DMA helper functions diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index b1ca1ab6d6ad..c9a41c997c6c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2747,7 +2747,7 @@ static const struct file_operations amdgpu_driver_kms_fops = { .compat_ioctl = amdgpu_kms_compat_ioctl, #endif #ifdef CONFIG_PROC_FS - .show_fdinfo = amdgpu_show_fdinfo + .show_fdinfo = drm_show_fdinfo, #endif }; @@ -2802,6 +2802,9 @@ static const struct drm_driver amdgpu_kms_driver = { .dumb_map_offset = amdgpu_mode_dumb_mmap, .fops = &amdgpu_driver_kms_fops, .release = &amdgpu_driver_release_kms, +#ifdef CONFIG_PROC_FS + .show_fdinfo = amdgpu_show_fdinfo, +#endif .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c index c57252f004e8..13d7413d4ca3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c @@ -53,9 +53,8 @@ static const char *amdgpu_ip_name[AMDGPU_HW_IP_NUM] = { [AMDGPU_HW_IP_VCN_JPEG] = "jpeg", }; -void amdgpu_show_fdinfo(struct seq_file *m, struct file *f) +void amdgpu_show_fdinfo(struct drm_printer *p, struct drm_file *file) { - struct drm_file *file = f->private_data; struct amdgpu_device *adev = drm_to_adev(file->minor->dev); struct amdgpu_fpriv *fpriv = file->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; @@ -87,31 +86,30 @@ void amdgpu_show_fdinfo(struct seq_file *m, struct file *f) * ****************************************************************** */ - seq_printf(m, "pasid:\t%u\n", fpriv->vm.pasid); - seq_printf(m, "drm-driver:\t%s\n", file->minor->dev->driver->name); - seq_printf(m, "drm-pdev:\t%04x:%02x:%02x.%d\n", domain, bus, dev, fn); - seq_printf(m, "drm-client-id:\t%Lu\n", vm->immediate.fence_context); - seq_printf(m, "drm-memory-vram:\t%llu KiB\n", stats.vram/1024UL); - seq_printf(m, "drm-memory-gtt: \t%llu KiB\n", stats.gtt/1024UL); - seq_printf(m, "drm-memory-cpu: \t%llu KiB\n", stats.cpu/1024UL); - seq_printf(m, "amd-memory-visible-vram:\t%llu KiB\n", + drm_printf(p, "pasid:\t%u\n", fpriv->vm.pasid); + drm_printf(p, "drm-driver:\t%s\n", file->minor->dev->driver->name); + drm_printf(p, "drm-pdev:\t%04x:%02x:%02x.%d\n", domain, bus, dev, fn); + drm_printf(p, "drm-client-id:\t%Lu\n", vm->immediate.fence_context); + drm_printf(p, "drm-memory-vram:\t%llu KiB\n", stats.vram/1024UL); + drm_printf(p, "drm-memory-gtt: \t%llu KiB\n", stats.gtt/1024UL); + drm_printf(p, "drm-memory-cpu: \t%llu KiB\n", stats.cpu/1024UL); + drm_printf(p, "amd-memory-visible-vram:\t%llu KiB\n", stats.visible_vram/1024UL); - seq_printf(m, "amd-evicted-vram:\t%llu KiB\n", + drm_printf(p, "amd-evicted-vram:\t%llu KiB\n", stats.evicted_vram/1024UL); - seq_printf(m, "amd-evicted-visible-vram:\t%llu KiB\n", + drm_printf(p, "amd-evicted-visible-vram:\t%llu KiB\n", stats.evicted_visible_vram/1024UL); - seq_printf(m, "amd-requested-vram:\t%llu KiB\n", + drm_printf(p, "amd-requested-vram:\t%llu KiB\n", stats.requested_vram/1024UL); - seq_printf(m, "amd-requested-visible-vram:\t%llu KiB\n", + drm_printf(p, "amd-requested-visible-vram:\t%llu KiB\n", stats.requested_visible_vram/1024UL); - seq_printf(m, "amd-requested-gtt:\t%llu KiB\n", + drm_printf(p, "amd-requested-gtt:\t%llu KiB\n", stats.requested_gtt/1024UL); - for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { if (!usage[hw_ip]) continue; - seq_printf(m, "drm-engine-%s:\t%Ld ns\n", amdgpu_ip_name[hw_ip], + drm_printf(p, "drm-engine-%s:\t%Ld ns\n", amdgpu_ip_name[hw_ip], ktime_to_ns(usage[hw_ip])); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h index e86834bfea1d..0398f5a159ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h @@ -37,6 +37,6 @@ #include "amdgpu_ids.h" uint32_t amdgpu_get_ip_count(struct amdgpu_device *adev, int id); -void amdgpu_show_fdinfo(struct seq_file *m, struct file *f); +void amdgpu_show_fdinfo(struct drm_printer *p, struct drm_file *file); #endif diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig index f5c66d89ba99..5afade25e217 100644 --- a/drivers/gpu/drm/armada/Kconfig +++ b/drivers/gpu/drm/armada/Kconfig @@ -3,6 +3,7 @@ config DRM_ARMADA tristate "DRM support for Marvell Armada SoCs" depends on DRM && HAVE_CLK && ARM && MMU select DRM_KMS_HELPER + select FB_IO_HELPERS if DRM_FBDEV_EMULATION help Support the "LCD" controllers found on the Marvell Armada 510 devices. There are two controllers on the device, each controller diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 0a5fd1aa86eb..3943e89cc06c 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -33,12 +34,8 @@ static void armada_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops armada_fb_ops = { .owner = THIS_MODULE, + FB_DEFAULT_IO_OPS, DRM_FB_HELPER_DEFAULT_OPS, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_destroy = armada_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index f076a09afac0..82c68b042444 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -227,6 +227,7 @@ config DRM_SAMSUNG_DSIM select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY_MIPI_DPHY help The Samsung MIPI DSIM bridge controller driver. This MIPI DSIM bridge can be found it on Exynos SoCs and diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index ddceafa7b637..2254457ab5d0 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1393,7 +1393,7 @@ static struct i2c_driver adv7511_driver = { .of_match_table = adv7511_of_ids, }, .id_table = adv7511_i2c_ids, - .probe_new = adv7511_probe, + .probe = adv7511_probe, .remove = adv7511_remove, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index 3577c532abb4..72ab2ab77081 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -815,7 +815,7 @@ static struct i2c_driver anx6345_driver = { .name = "anx6345", .of_match_table = of_match_ptr(anx6345_match_table), }, - .probe_new = anx6345_i2c_probe, + .probe = anx6345_i2c_probe, .remove = anx6345_i2c_remove, .id_table = anx6345_id, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index a3a38bbe2786..06a3e3243e19 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -1389,7 +1389,7 @@ static struct i2c_driver anx78xx_driver = { .name = "anx7814", .of_match_table = of_match_ptr(anx78xx_match_table), }, - .probe_new = anx78xx_i2c_probe, + .probe = anx78xx_i2c_probe, .remove = anx78xx_i2c_remove, .id_table = anx78xx_id, }; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index c86531f7b072..8b985efdc086 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -2800,7 +2800,7 @@ static struct i2c_driver anx7625_driver = { .of_match_table = anx_match_table, .pm = &anx7625_pm_ops, }, - .probe_new = anx7625_i2c_probe, + .probe = anx7625_i2c_probe, .remove = anx7625_i2c_remove, .id_table = anx7625_id, diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index 0e37840cd7a8..8bfce21d6b90 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -795,7 +795,7 @@ static struct i2c_device_id chipone_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, chipone_i2c_id); static struct i2c_driver chipone_i2c_driver = { - .probe_new = chipone_i2c_probe, + .probe = chipone_i2c_probe, .id_table = chipone_i2c_id, .driver = { .name = "chipone-icn6211-i2c", diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index 339b759e4c81..a854eb84e399 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -603,7 +603,7 @@ static const struct i2c_device_id ch7033_ids[] = { MODULE_DEVICE_TABLE(i2c, ch7033_ids); static struct i2c_driver ch7033_driver = { - .probe_new = ch7033_probe, + .probe = ch7033_probe, .remove = ch7033_remove, .driver = { .name = "ch7033", diff --git a/drivers/gpu/drm/bridge/cros-ec-anx7688.c b/drivers/gpu/drm/bridge/cros-ec-anx7688.c index fa91bdeddef0..c8abd9920fee 100644 --- a/drivers/gpu/drm/bridge/cros-ec-anx7688.c +++ b/drivers/gpu/drm/bridge/cros-ec-anx7688.c @@ -173,7 +173,7 @@ static const struct of_device_id cros_ec_anx7688_bridge_match_table[] = { MODULE_DEVICE_TABLE(of, cros_ec_anx7688_bridge_match_table); static struct i2c_driver cros_ec_anx7688_bridge_driver = { - .probe_new = cros_ec_anx7688_bridge_probe, + .probe = cros_ec_anx7688_bridge_probe, .remove = cros_ec_anx7688_bridge_remove, .driver = { .name = "cros-ec-anx7688-bridge", diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index 56ae511367b1..f7f436cf96e0 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -24,7 +24,7 @@ struct display_connector { struct gpio_desc *hpd_gpio; int hpd_irq; - struct regulator *dp_pwr; + struct regulator *supply; struct gpio_desc *ddc_en; }; @@ -191,6 +191,18 @@ static irqreturn_t display_connector_hpd_irq(int irq, void *arg) return IRQ_HANDLED; } +static int display_connector_get_supply(struct platform_device *pdev, + struct display_connector *conn, + const char *name) +{ + conn->supply = devm_regulator_get_optional(&pdev->dev, name); + + if (conn->supply == ERR_PTR(-ENODEV)) + conn->supply = NULL; + + return PTR_ERR_OR_ZERO(conn->supply); +} + static int display_connector_probe(struct platform_device *pdev) { struct display_connector *conn; @@ -316,36 +328,15 @@ static int display_connector_probe(struct platform_device *pdev) if (type == DRM_MODE_CONNECTOR_DisplayPort) { int ret; - conn->dp_pwr = devm_regulator_get_optional(&pdev->dev, "dp-pwr"); - - if (IS_ERR(conn->dp_pwr)) { - ret = PTR_ERR(conn->dp_pwr); - - switch (ret) { - case -ENODEV: - conn->dp_pwr = NULL; - break; - - case -EPROBE_DEFER: - return -EPROBE_DEFER; - - default: - dev_err(&pdev->dev, "failed to get DP PWR regulator: %d\n", ret); - return ret; - } - } - - if (conn->dp_pwr) { - ret = regulator_enable(conn->dp_pwr); - if (ret) { - dev_err(&pdev->dev, "failed to enable DP PWR regulator: %d\n", ret); - return ret; - } - } + ret = display_connector_get_supply(pdev, conn, "dp-pwr"); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to get DP PWR regulator\n"); } /* enable DDC */ if (type == DRM_MODE_CONNECTOR_HDMIA) { + int ret; + conn->ddc_en = devm_gpiod_get_optional(&pdev->dev, "ddc-en", GPIOD_OUT_HIGH); @@ -353,6 +344,18 @@ static int display_connector_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Couldn't get ddc-en gpio\n"); return PTR_ERR(conn->ddc_en); } + + ret = display_connector_get_supply(pdev, conn, "hdmi-pwr"); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to get HDMI +5V Power regulator\n"); + } + + if (conn->supply) { + ret = regulator_enable(conn->supply); + if (ret) { + dev_err(&pdev->dev, "failed to enable PWR regulator: %d\n", ret); + return ret; + } } conn->bridge.funcs = &display_connector_bridge_funcs; @@ -386,8 +389,8 @@ static void display_connector_remove(struct platform_device *pdev) if (conn->ddc_en) gpiod_set_value(conn->ddc_en, 0); - if (conn->dp_pwr) - regulator_disable(conn->dp_pwr); + if (conn->supply) + regulator_disable(conn->supply); drm_bridge_remove(&conn->bridge); diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 45f579c365e7..504d51c42f79 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -3479,7 +3479,7 @@ static struct i2c_driver it6505_i2c_driver = { .of_match_table = it6505_of_match, .pm = &it6505_bridge_pm_ops, }, - .probe_new = it6505_i2c_probe, + .probe = it6505_i2c_probe, .remove = it6505_i2c_remove, .shutdown = it6505_shutdown, .id_table = it6505_id, diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c index a2d723d6a4be..466641c77fe9 100644 --- a/drivers/gpu/drm/bridge/ite-it66121.c +++ b/drivers/gpu/drm/bridge/ite-it66121.c @@ -1640,7 +1640,7 @@ static struct i2c_driver it66121_driver = { .name = "it66121", .of_match_table = it66121_dt_match, }, - .probe_new = it66121_probe, + .probe = it66121_probe, .remove = it66121_remove, .id_table = it66121_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 13c131ade268..4eaea67fb71c 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -773,7 +773,7 @@ static struct i2c_driver lt8912_i2c_driver = { .name = "lt8912", .of_match_table = lt8912_dt_match, }, - .probe_new = lt8912_probe, + .probe = lt8912_probe, .remove = lt8912_remove, .id_table = lt8912_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c index 00db68151238..aa8d47e7f40d 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9211.c +++ b/drivers/gpu/drm/bridge/lontium-lt9211.c @@ -787,7 +787,7 @@ static const struct of_device_id lt9211_match_table[] = { MODULE_DEVICE_TABLE(of, lt9211_match_table); static struct i2c_driver lt9211_driver = { - .probe_new = lt9211_probe, + .probe = lt9211_probe, .remove = lt9211_remove, .id_table = lt9211_id, .driver = { diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 151efe92711c..5163e5224aad 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -1192,7 +1192,7 @@ static struct i2c_driver lt9611_driver = { .name = "lt9611", .of_match_table = lt9611_match_table, }, - .probe_new = lt9611_probe, + .probe = lt9611_probe, .remove = lt9611_remove, .id_table = lt9611_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 583daacf3705..2a57e804ea02 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -1011,7 +1011,7 @@ static struct i2c_driver lt9611uxc_driver = { .of_match_table = lt9611uxc_match_table, .dev_groups = lt9611uxc_attr_groups, }, - .probe_new = lt9611uxc_probe, + .probe = lt9611uxc_probe, .remove = lt9611uxc_remove, .id_table = lt9611uxc_id, }; diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index 4fc494d9084b..460db3c8a08c 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -375,7 +375,7 @@ MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match); static struct i2c_driver stdp4028_ge_b850v3_fw_driver = { .id_table = stdp4028_ge_b850v3_fw_i2c_table, - .probe_new = stdp4028_ge_b850v3_fw_probe, + .probe = stdp4028_ge_b850v3_fw_probe, .remove = stdp4028_ge_b850v3_fw_remove, .driver = { .name = "stdp4028-ge-b850v3-fw", @@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match); static struct i2c_driver stdp2690_ge_b850v3_fw_driver = { .id_table = stdp2690_ge_b850v3_fw_i2c_table, - .probe_new = stdp2690_ge_b850v3_fw_probe, + .probe = stdp2690_ge_b850v3_fw_probe, .remove = stdp2690_ge_b850v3_fw_remove, .driver = { .name = "stdp2690-ge-b850v3-fw", diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index cd292a2f894c..d81920227a8a 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -335,7 +335,7 @@ MODULE_DEVICE_TABLE(of, ptn3460_match); static struct i2c_driver ptn3460_driver = { .id_table = ptn3460_i2c_table, - .probe_new = ptn3460_probe, + .probe = ptn3460_probe, .remove = ptn3460_remove, .driver = { .name = "nxp,ptn3460", diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index efa80e309b98..c9b6cb7678e3 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table); static struct i2c_driver ps8622_driver = { .id_table = ps8622_i2c_table, - .probe_new = ps8622_probe, + .probe = ps8622_probe, .remove = ps8622_remove, .driver = { .name = "ps8622", diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index c3eb45179405..8801cdd033b5 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -791,7 +791,7 @@ static const struct of_device_id ps8640_match[] = { MODULE_DEVICE_TABLE(of, ps8640_match); static struct i2c_driver ps8640_driver = { - .probe_new = ps8640_probe, + .probe = ps8640_probe, .remove = ps8640_remove, .driver = { .name = "ps8640", diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 0f3f6846beea..043b8109e64a 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -220,6 +220,8 @@ #define OLD_SCLK_MIPI_CLK_NAME "pll_clk" +#define PS_TO_CYCLE(ps, hz) DIV64_U64_ROUND_CLOSEST(((ps) * (hz)), 1000000000000ULL) + static const char *const clk_names[5] = { "bus_clk", "sclk_mipi", @@ -407,6 +409,9 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { @@ -420,6 +425,9 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { @@ -431,6 +439,9 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { @@ -443,6 +454,9 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5433_reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { @@ -455,6 +469,9 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5422_reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { @@ -471,6 +488,9 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { */ .pll_p_offset = 14, .reg_values = imx8mm_dsim_reg_values, + .m_min = 64, + .m_max = 1023, + .min_freq = 1050, }; static const struct samsung_dsim_driver_data * @@ -549,12 +569,12 @@ static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi, tmp = (u64)fout * (_p << _s); do_div(tmp, fin); _m = tmp; - if (_m < 41 || _m > 125) + if (_m < driver_data->m_min || _m > driver_data->m_max) continue; tmp = (u64)_m * fin; do_div(tmp, _p); - if (tmp < 500 * MHZ || + if (tmp < driver_data->min_freq * MHZ || tmp > driver_data->max_freq * MHZ) continue; @@ -640,16 +660,28 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); } while ((reg & DSIM_PLL_STABLE) == 0); + dsi->hs_clock = fout; + return fout; } static int samsung_dsim_enable_clock(struct samsung_dsim *dsi) { - unsigned long hs_clk, byte_clk, esc_clk; + unsigned long hs_clk, byte_clk, esc_clk, pix_clk; unsigned long esc_div; u32 reg; + struct drm_display_mode *m = &dsi->mode; + int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); + + /* m->clock is in KHz */ + pix_clk = m->clock * 1000; + + /* Use burst_clk_rate if available, otherwise use the pix_clk */ + if (dsi->burst_clk_rate) + hs_clk = samsung_dsim_set_pll(dsi, dsi->burst_clk_rate); + else + hs_clk = samsung_dsim_set_pll(dsi, DIV_ROUND_UP(pix_clk * bpp, dsi->lanes)); - hs_clk = samsung_dsim_set_pll(dsi, dsi->burst_clk_rate); if (!hs_clk) { dev_err(dsi->dev, "failed to configure DSI PLL\n"); return -EFAULT; @@ -687,13 +719,47 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; const unsigned int *reg_values = driver_data->reg_values; u32 reg; + struct phy_configure_opts_mipi_dphy cfg; + int clk_prepare, lpx, clk_zero, clk_post, clk_trail; + int hs_exit, hs_prepare, hs_zero, hs_trail; + unsigned long long byte_clock = dsi->hs_clock / 8; if (driver_data->has_freqband) return; + phy_mipi_dphy_get_default_config_for_hsclk(dsi->hs_clock, + dsi->lanes, &cfg); + + /* + * TODO: + * The tech Applications Processor manuals for i.MX8M Mini, Nano, + * and Plus don't state what the definition of the PHYTIMING + * bits are beyond their address and bit position. + * After reviewing NXP's downstream code, it appears + * that the various PHYTIMING registers take the number + * of cycles and use various dividers on them. This + * calculation does not result in an exact match to the + * downstream code, but it is very close to the values + * generated by their lookup table, and it appears + * to sync at a variety of resolutions. If someone + * can get a more accurate mathematical equation needed + * for these registers, this should be updated. + */ + + lpx = PS_TO_CYCLE(cfg.lpx, byte_clock); + hs_exit = PS_TO_CYCLE(cfg.hs_exit, byte_clock); + clk_prepare = PS_TO_CYCLE(cfg.clk_prepare, byte_clock); + clk_zero = PS_TO_CYCLE(cfg.clk_zero, byte_clock); + clk_post = PS_TO_CYCLE(cfg.clk_post, byte_clock); + clk_trail = PS_TO_CYCLE(cfg.clk_trail, byte_clock); + hs_prepare = PS_TO_CYCLE(cfg.hs_prepare, byte_clock); + hs_zero = PS_TO_CYCLE(cfg.hs_zero, byte_clock); + hs_trail = PS_TO_CYCLE(cfg.hs_trail, byte_clock); + /* B D-PHY: D-PHY Master & Slave Analog Block control */ reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] | reg_values[PHYCTRL_SLEW_UP]; + samsung_dsim_write(dsi, DSIM_PHYCTRL_REG, reg); /* @@ -701,7 +767,9 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) * T HS-EXIT: Time that the transmitter drives LP-11 following a HS * burst */ - reg = reg_values[PHYTIMING_LPX] | reg_values[PHYTIMING_HS_EXIT]; + + reg = DSIM_PHYTIMING_LPX(lpx) | DSIM_PHYTIMING_HS_EXIT(hs_exit); + samsung_dsim_write(dsi, DSIM_PHYTIMING_REG, reg); /* @@ -717,10 +785,11 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after * the last payload clock bit of a HS transmission burst */ - reg = reg_values[PHYTIMING_CLK_PREPARE] | - reg_values[PHYTIMING_CLK_ZERO] | - reg_values[PHYTIMING_CLK_POST] | - reg_values[PHYTIMING_CLK_TRAIL]; + + reg = DSIM_PHYTIMING1_CLK_PREPARE(clk_prepare) | + DSIM_PHYTIMING1_CLK_ZERO(clk_zero) | + DSIM_PHYTIMING1_CLK_POST(clk_post) | + DSIM_PHYTIMING1_CLK_TRAIL(clk_trail); samsung_dsim_write(dsi, DSIM_PHYTIMING1_REG, reg); @@ -733,8 +802,11 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) * T HS-TRAIL: Time that the transmitter drives the flipped differential * state after last payload data bit of a HS transmission burst */ - reg = reg_values[PHYTIMING_HS_PREPARE] | reg_values[PHYTIMING_HS_ZERO] | - reg_values[PHYTIMING_HS_TRAIL]; + + reg = DSIM_PHYTIMING2_HS_PREPARE(hs_prepare) | + DSIM_PHYTIMING2_HS_ZERO(hs_zero) | + DSIM_PHYTIMING2_HS_TRAIL(hs_trail); + samsung_dsim_write(dsi, DSIM_PHYTIMING2_REG, reg); } @@ -866,6 +938,10 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); reg &= ~DSIM_STOP_STATE_CNT_MASK; reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); + + if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) + reg |= DSIM_FORCE_STOP_STATE; + samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); @@ -881,17 +957,29 @@ static void samsung_dsim_set_display_mode(struct samsung_dsim *dsi) u32 reg; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { + int byte_clk_khz = dsi->hs_clock / 1000 / 8; + int hfp = (m->hsync_start - m->hdisplay) * byte_clk_khz / m->clock; + int hbp = (m->htotal - m->hsync_end) * byte_clk_khz / m->clock; + int hsa = (m->hsync_end - m->hsync_start) * byte_clk_khz / m->clock; + + /* remove packet overhead when possible */ + hfp = max(hfp - 6, 0); + hbp = max(hbp - 6, 0); + hsa = max(hsa - 6, 0); + + dev_dbg(dsi->dev, "calculated hfp: %u, hbp: %u, hsa: %u", + hfp, hbp, hsa); + reg = DSIM_CMD_ALLOW(0xf) | DSIM_STABLE_VFP(m->vsync_start - m->vdisplay) | DSIM_MAIN_VBP(m->vtotal - m->vsync_end); samsung_dsim_write(dsi, DSIM_MVPORCH_REG, reg); - reg = DSIM_MAIN_HFP(m->hsync_start - m->hdisplay) - | DSIM_MAIN_HBP(m->htotal - m->hsync_end); + reg = DSIM_MAIN_HFP(hfp) | DSIM_MAIN_HBP(hbp); samsung_dsim_write(dsi, DSIM_MHPORCH_REG, reg); reg = DSIM_MAIN_VSA(m->vsync_end - m->vsync_start) - | DSIM_MAIN_HSA(m->hsync_end - m->hsync_start); + | DSIM_MAIN_HSA(hsa); samsung_dsim_write(dsi, DSIM_MSYNC_REG, reg); } reg = DSIM_MAIN_HRESOL(m->hdisplay, num_bits_resol) | @@ -1347,6 +1435,9 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge, ret = samsung_dsim_init(dsi); if (ret) return; + + samsung_dsim_set_display_mode(dsi); + samsung_dsim_set_display_enable(dsi, true); } } @@ -1354,9 +1445,16 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct samsung_dsim *dsi = bridge_to_dsi(bridge); + u32 reg; - samsung_dsim_set_display_mode(dsi); - samsung_dsim_set_display_enable(dsi, true); + if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { + samsung_dsim_set_display_mode(dsi); + samsung_dsim_set_display_enable(dsi, true); + } else { + reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); + reg &= ~DSIM_FORCE_STOP_STATE; + samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); + } dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1365,10 +1463,17 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct samsung_dsim *dsi = bridge_to_dsi(bridge); + u32 reg; if (!(dsi->state & DSIM_STATE_ENABLED)) return; + if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { + reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); + reg |= DSIM_FORCE_STOP_STATE; + samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); + } + dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1689,11 +1794,11 @@ static const struct mipi_dsi_host_ops samsung_dsim_ops = { }; static int samsung_dsim_of_read_u32(const struct device_node *np, - const char *propname, u32 *out_value) + const char *propname, u32 *out_value, bool optional) { int ret = of_property_read_u32(np, propname, out_value); - if (ret < 0) + if (ret < 0 && !optional) pr_err("%pOF: failed to get '%s' property\n", np, propname); return ret; @@ -1706,19 +1811,30 @@ static int samsung_dsim_parse_dt(struct samsung_dsim *dsi) u32 lane_polarities[5] = { 0 }; struct device_node *endpoint; int i, nr_lanes, ret; + struct clk *pll_clk; ret = samsung_dsim_of_read_u32(node, "samsung,pll-clock-frequency", - &dsi->pll_clk_rate); - if (ret < 0) - return ret; + &dsi->pll_clk_rate, 1); + /* If it doesn't exist, read it from the clock instead of failing */ + if (ret < 0) { + dev_dbg(dev, "Using sclk_mipi for pll clock frequency\n"); + pll_clk = devm_clk_get(dev, "sclk_mipi"); + if (!IS_ERR(pll_clk)) + dsi->pll_clk_rate = clk_get_rate(pll_clk); + else + return PTR_ERR(pll_clk); + } + /* If it doesn't exist, use pixel clock instead of failing */ ret = samsung_dsim_of_read_u32(node, "samsung,burst-clock-frequency", - &dsi->burst_clk_rate); - if (ret < 0) - return ret; + &dsi->burst_clk_rate, 1); + if (ret < 0) { + dev_dbg(dev, "Using pixel clock for HS clock frequency\n"); + dsi->burst_clk_rate = 0; + } ret = samsung_dsim_of_read_u32(node, "samsung,esc-clock-frequency", - &dsi->esc_clk_rate); + &dsi->esc_clk_rate, 0); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index ef66461e7f7c..aac239729a1d 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1151,7 +1151,7 @@ static const struct i2c_device_id sii902x_i2c_ids[] = { MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids); static struct i2c_driver sii902x_driver = { - .probe_new = sii902x_probe, + .probe = sii902x_probe, .remove = sii902x_remove, .driver = { .name = "sii902x", diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index 2d17f227867b..d8373d918324 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -955,7 +955,7 @@ static struct i2c_driver sii9234_driver = { .name = "sii9234", .of_match_table = sii9234_dt_match, }, - .probe_new = sii9234_probe, + .probe = sii9234_probe, .remove = sii9234_remove, .id_table = sii9234_id, }; diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index b96d03cd878d..79b09ccd1353 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2378,7 +2378,7 @@ static struct i2c_driver sii8620_driver = { .name = "sii8620", .of_match_table = of_match_ptr(sii8620_dt_match), }, - .probe_new = sii8620_probe, + .probe = sii8620_probe, .remove = sii8620_remove, .id_table = sii8620_id, }; diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index d6349af4f1b6..65dc842e31f0 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1781,7 +1781,200 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = { static bool tc_readable_reg(struct device *dev, unsigned int reg) { - return reg != SYSCTRL; + switch (reg) { + /* DSI D-PHY Layer */ + case 0x004: + case 0x020: + case 0x024: + case 0x028: + case 0x02c: + case 0x030: + case 0x038: + case 0x040: + case 0x044: + case 0x048: + case 0x04c: + case 0x050: + case 0x054: + /* DSI PPI Layer */ + case PPI_STARTPPI: + case 0x108: + case 0x110: + case PPI_LPTXTIMECNT: + case PPI_LANEENABLE: + case PPI_TX_RX_TA: + case 0x140: + case PPI_D0S_ATMR: + case PPI_D1S_ATMR: + case 0x14c: + case 0x150: + case PPI_D0S_CLRSIPOCOUNT: + case PPI_D1S_CLRSIPOCOUNT: + case PPI_D2S_CLRSIPOCOUNT: + case PPI_D3S_CLRSIPOCOUNT: + case 0x180: + case 0x184: + case 0x188: + case 0x18c: + case 0x190: + case 0x1a0: + case 0x1a4: + case 0x1a8: + case 0x1ac: + case 0x1b0: + case 0x1c0: + case 0x1c4: + case 0x1c8: + case 0x1cc: + case 0x1d0: + case 0x1e0: + case 0x1e4: + case 0x1f0: + case 0x1f4: + /* DSI Protocol Layer */ + case DSI_STARTDSI: + case 0x208: + case DSI_LANEENABLE: + case 0x214: + case 0x218: + case 0x220: + case 0x224: + case 0x228: + case 0x230: + /* DSI General */ + case 0x300: + /* DSI Application Layer */ + case 0x400: + case 0x404: + /* DPI */ + case DPIPXLFMT: + /* Parallel Output */ + case POCTRL: + /* Video Path0 Configuration */ + case VPCTRL0: + case HTIM01: + case HTIM02: + case VTIM01: + case VTIM02: + case VFUEN0: + /* System */ + case TC_IDREG: + case 0x504: + case SYSSTAT: + case SYSRSTENB: + case SYSCTRL: + /* I2C */ + case 0x520: + /* GPIO */ + case GPIOM: + case GPIOC: + case GPIOO: + case GPIOI: + /* Interrupt */ + case INTCTL_G: + case INTSTS_G: + case 0x570: + case 0x574: + case INT_GP0_LCNT: + case INT_GP1_LCNT: + /* DisplayPort Control */ + case DP0CTL: + /* DisplayPort Clock */ + case DP0_VIDMNGEN0: + case DP0_VIDMNGEN1: + case DP0_VMNGENSTATUS: + case 0x628: + case 0x62c: + case 0x630: + /* DisplayPort Main Channel */ + case DP0_SECSAMPLE: + case DP0_VIDSYNCDELAY: + case DP0_TOTALVAL: + case DP0_STARTVAL: + case DP0_ACTIVEVAL: + case DP0_SYNCVAL: + case DP0_MISC: + /* DisplayPort Aux Channel */ + case DP0_AUXCFG0: + case DP0_AUXCFG1: + case DP0_AUXADDR: + case 0x66c: + case 0x670: + case 0x674: + case 0x678: + case 0x67c: + case 0x680: + case 0x684: + case 0x688: + case DP0_AUXSTATUS: + case DP0_AUXI2CADR: + /* DisplayPort Link Training */ + case DP0_SRCCTRL: + case DP0_LTSTAT: + case DP0_SNKLTCHGREQ: + case DP0_LTLOOPCTRL: + case DP0_SNKLTCTRL: + case 0x6e8: + case 0x6ec: + case 0x6f0: + case 0x6f4: + /* DisplayPort Audio */ + case 0x700: + case 0x704: + case 0x708: + case 0x70c: + case 0x710: + case 0x714: + case 0x718: + case 0x71c: + case 0x720: + /* DisplayPort Source Control */ + case DP1_SRCCTRL: + /* DisplayPort PHY */ + case DP_PHY_CTRL: + case 0x810: + case 0x814: + case 0x820: + case 0x840: + /* I2S */ + case 0x880: + case 0x888: + case 0x88c: + case 0x890: + case 0x894: + case 0x898: + case 0x89c: + case 0x8a0: + case 0x8a4: + case 0x8a8: + case 0x8ac: + case 0x8b0: + case 0x8b4: + /* PLL */ + case DP0_PLLCTRL: + case DP1_PLLCTRL: + case PXL_PLLCTRL: + case PXL_PLLPARAM: + case SYS_PLLPARAM: + /* HDCP */ + case 0x980: + case 0x984: + case 0x988: + case 0x98c: + case 0x990: + case 0x994: + case 0x998: + case 0x99c: + case 0x9a0: + case 0x9a4: + case 0x9a8: + case 0x9ac: + /* Debug */ + case TSTCTL: + case PLL_DBG: + return true; + } + return false; } static const struct regmap_range tc_volatile_ranges[] = { @@ -2209,7 +2402,7 @@ static struct i2c_driver tc358767_driver = { .of_match_table = tc358767_of_ids, }, .id_table = tc358767_i2c_ids, - .probe_new = tc_probe, + .probe = tc_probe, .remove = tc_remove, }; module_i2c_driver(tc358767_driver); diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index 97ae3a9c90da..819a4b6ec2a0 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -1134,7 +1134,7 @@ static struct i2c_driver tc358768_driver = { .of_match_table = tc358768_of_ids, }, .id_table = tc358768_i2c_ids, - .probe_new = tc358768_i2c_probe, + .probe = tc358768_i2c_probe, .remove = tc358768_i2c_remove, }; module_i2c_driver(tc358768_driver); diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c index 19316994ddd1..90a89d70d832 100644 --- a/drivers/gpu/drm/bridge/tc358775.c +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -728,7 +728,7 @@ static struct i2c_driver tc358775_driver = { .of_match_table = tc358775_of_ids, }, .id_table = tc358775_i2c_ids, - .probe_new = tc_probe, + .probe = tc_probe, .remove = tc_remove, }; module_i2c_driver(tc358775_driver); diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c index 186a9e2ff24d..b65632ec7e7d 100644 --- a/drivers/gpu/drm/bridge/ti-dlpc3433.c +++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c @@ -400,7 +400,7 @@ static const struct of_device_id dlpc3433_match_table[] = { MODULE_DEVICE_TABLE(of, dlpc3433_match_table); static struct i2c_driver dlpc3433_driver = { - .probe_new = dlpc3433_probe, + .probe = dlpc3433_probe, .remove = dlpc3433_remove, .id_table = dlpc3433_id, .driver = { diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 1f5c07989e2b..7e9f4ec8e780 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -321,8 +321,8 @@ static u8 sn65dsi83_get_dsi_div(struct sn65dsi83 *ctx) return dsi_div - 1; } -static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); struct drm_atomic_state *state = old_bridge_state->base.state; @@ -485,11 +485,22 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, /* Trigger reset after CSR register update. */ regmap_write(ctx->regmap, REG_RC_RESET, REG_RC_RESET_SOFT_RESET); + /* Wait for 10ms after soft reset as specified in datasheet */ + usleep_range(10000, 12000); +} + +static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); + unsigned int pval; + /* Clear all errors that got asserted during initialization. */ regmap_read(ctx->regmap, REG_IRQ_STAT, &pval); regmap_write(ctx->regmap, REG_IRQ_STAT, pval); - usleep_range(10000, 12000); + /* Wait for 1ms and check for errors in status register */ + usleep_range(1000, 1100); regmap_read(ctx->regmap, REG_IRQ_STAT, &pval); if (pval) dev_err(ctx->dev, "Unexpected link status 0x%02x\n", pval); @@ -556,6 +567,7 @@ static const struct drm_bridge_funcs sn65dsi83_funcs = { .attach = sn65dsi83_attach, .detach = sn65dsi83_detach, .atomic_enable = sn65dsi83_atomic_enable, + .atomic_pre_enable = sn65dsi83_atomic_pre_enable, .atomic_disable = sn65dsi83_atomic_disable, .mode_valid = sn65dsi83_mode_valid, @@ -698,6 +710,7 @@ static int sn65dsi83_probe(struct i2c_client *client) ctx->bridge.funcs = &sn65dsi83_funcs; ctx->bridge.of_node = dev->of_node; + ctx->bridge.pre_enable_prev_first = true; drm_bridge_add(&ctx->bridge); ret = sn65dsi83_host_attach(ctx); @@ -735,7 +748,7 @@ static const struct of_device_id sn65dsi83_match_table[] = { MODULE_DEVICE_TABLE(of, sn65dsi83_match_table); static struct i2c_driver sn65dsi83_driver = { - .probe_new = sn65dsi83_probe, + .probe = sn65dsi83_probe, .remove = sn65dsi83_remove, .id_table = sn65dsi83_id, .driver = { diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 260cad1fd1da..597ceb7024e0 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1970,7 +1970,7 @@ static struct i2c_driver ti_sn65dsi86_driver = { .of_match_table = ti_sn65dsi86_match_table, .pm = &ti_sn65dsi86_pm_ops, }, - .probe_new = ti_sn65dsi86_probe, + .probe = ti_sn65dsi86_probe, .id_table = ti_sn65dsi86_id, }; diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index ab63225cd635..c06390da9ffd 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -408,7 +408,7 @@ static struct i2c_driver tfp410_i2c_driver = { .of_match_table = of_match_ptr(tfp410_match), }, .id_table = tfp410_i2c_ids, - .probe_new = tfp410_i2c_probe, + .probe = tfp410_i2c_probe, .remove = tfp410_i2c_remove, }; #endif /* IS_ENABLED(CONFIG_I2C) */ diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index f0e9549b6bd7..9978147bbc8a 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -670,6 +670,28 @@ static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, drm_rect_init(clip, x1, y1, x2 - x1, y2 - y1); } +/* Don't use in new code. */ +void drm_fb_helper_damage_range(struct fb_info *info, off_t off, size_t len) +{ + struct drm_fb_helper *fb_helper = info->par; + struct drm_rect damage_area; + + drm_fb_helper_memory_range_to_clip(info, off, len, &damage_area); + drm_fb_helper_damage(fb_helper, damage_area.x1, damage_area.y1, + drm_rect_width(&damage_area), + drm_rect_height(&damage_area)); +} +EXPORT_SYMBOL(drm_fb_helper_damage_range); + +/* Don't use in new code. */ +void drm_fb_helper_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) +{ + struct drm_fb_helper *fb_helper = info->par; + + drm_fb_helper_damage(fb_helper, x, y, width, height); +} +EXPORT_SYMBOL(drm_fb_helper_damage_area); + /** * drm_fb_helper_deferred_io() - fbdev deferred_io callback function * @info: fb_info struct pointer @@ -714,220 +736,6 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagerefli } EXPORT_SYMBOL(drm_fb_helper_deferred_io); -/** - * drm_fb_helper_sys_read - Implements struct &fb_ops.fb_read for system memory - * @info: fb_info struct pointer - * @buf: userspace buffer to read from framebuffer memory - * @count: number of bytes to read from framebuffer memory - * @ppos: read offset within framebuffer memory - * - * Returns: - * The number of bytes read on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos) -{ - return fb_sys_read(info, buf, count, ppos); -} -EXPORT_SYMBOL(drm_fb_helper_sys_read); - -/** - * drm_fb_helper_sys_write - Implements struct &fb_ops.fb_write for system memory - * @info: fb_info struct pointer - * @buf: userspace buffer to write to framebuffer memory - * @count: number of bytes to write to framebuffer memory - * @ppos: write offset within framebuffer memory - * - * Returns: - * The number of bytes written on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct drm_fb_helper *helper = info->par; - loff_t pos = *ppos; - ssize_t ret; - struct drm_rect damage_area; - - ret = fb_sys_write(info, buf, count, ppos); - if (ret <= 0) - return ret; - - if (helper->funcs->fb_dirty) { - drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); - drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1, - drm_rect_width(&damage_area), - drm_rect_height(&damage_area)); - } - - return ret; -} -EXPORT_SYMBOL(drm_fb_helper_sys_write); - -/** - * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect - * @info: fbdev registered by the helper - * @rect: info about rectangle to fill - * - * A wrapper around sys_fillrect implemented by fbdev core - */ -void drm_fb_helper_sys_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct drm_fb_helper *helper = info->par; - - sys_fillrect(info, rect); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, rect->dx, rect->dy, rect->width, rect->height); -} -EXPORT_SYMBOL(drm_fb_helper_sys_fillrect); - -/** - * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea - * @info: fbdev registered by the helper - * @area: info about area to copy - * - * A wrapper around sys_copyarea implemented by fbdev core - */ -void drm_fb_helper_sys_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct drm_fb_helper *helper = info->par; - - sys_copyarea(info, area); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, area->dx, area->dy, area->width, area->height); -} -EXPORT_SYMBOL(drm_fb_helper_sys_copyarea); - -/** - * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit - * @info: fbdev registered by the helper - * @image: info about image to blit - * - * A wrapper around sys_imageblit implemented by fbdev core - */ -void drm_fb_helper_sys_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct drm_fb_helper *helper = info->par; - - sys_imageblit(info, image); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, image->dx, image->dy, image->width, image->height); -} -EXPORT_SYMBOL(drm_fb_helper_sys_imageblit); - -/** - * drm_fb_helper_cfb_read - Implements struct &fb_ops.fb_read for I/O memory - * @info: fb_info struct pointer - * @buf: userspace buffer to read from framebuffer memory - * @count: number of bytes to read from framebuffer memory - * @ppos: read offset within framebuffer memory - * - * Returns: - * The number of bytes read on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos) -{ - return fb_io_read(info, buf, count, ppos); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_read); - -/** - * drm_fb_helper_cfb_write - Implements struct &fb_ops.fb_write for I/O memory - * @info: fb_info struct pointer - * @buf: userspace buffer to write to framebuffer memory - * @count: number of bytes to write to framebuffer memory - * @ppos: write offset within framebuffer memory - * - * Returns: - * The number of bytes written on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct drm_fb_helper *helper = info->par; - loff_t pos = *ppos; - ssize_t ret; - struct drm_rect damage_area; - - ret = fb_io_write(info, buf, count, ppos); - if (ret <= 0) - return ret; - - if (helper->funcs->fb_dirty) { - drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); - drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1, - drm_rect_width(&damage_area), - drm_rect_height(&damage_area)); - } - - return ret; -} -EXPORT_SYMBOL(drm_fb_helper_cfb_write); - -/** - * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect - * @info: fbdev registered by the helper - * @rect: info about rectangle to fill - * - * A wrapper around cfb_fillrect implemented by fbdev core - */ -void drm_fb_helper_cfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct drm_fb_helper *helper = info->par; - - cfb_fillrect(info, rect); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, rect->dx, rect->dy, rect->width, rect->height); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect); - -/** - * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea - * @info: fbdev registered by the helper - * @area: info about area to copy - * - * A wrapper around cfb_copyarea implemented by fbdev core - */ -void drm_fb_helper_cfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct drm_fb_helper *helper = info->par; - - cfb_copyarea(info, area); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, area->dx, area->dy, area->width, area->height); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea); - -/** - * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit - * @info: fbdev registered by the helper - * @image: info about image to blit - * - * A wrapper around cfb_imageblit implemented by fbdev core - */ -void drm_fb_helper_cfb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct drm_fb_helper *helper = info->par; - - cfb_imageblit(info, image); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, image->dx, image->dy, image->width, image->height); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); - /** * drm_fb_helper_set_suspend - wrapper around fb_set_suspend * @fb_helper: driver-allocated fbdev helper, can be NULL diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c index 728deffcc0d9..d86773fa8ab0 100644 --- a/drivers/gpu/drm/drm_fbdev_dma.c +++ b/drivers/gpu/drm/drm_fbdev_dma.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT +#include + #include #include #include @@ -64,14 +66,11 @@ static const struct fb_ops drm_fbdev_dma_fb_ops = { .owner = THIS_MODULE, .fb_open = drm_fbdev_dma_fb_open, .fb_release = drm_fbdev_dma_fb_release, - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, + __FB_DEFAULT_SYS_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_destroy = drm_fbdev_dma_fb_destroy, + __FB_DEFAULT_SYS_OPS_DRAW, .fb_mmap = drm_fbdev_dma_fb_mmap, + .fb_destroy = drm_fbdev_dma_fb_destroy, }; /* diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c index 8e5148bf40bb..98ae703848a0 100644 --- a/drivers/gpu/drm/drm_fbdev_generic.c +++ b/drivers/gpu/drm/drm_fbdev_generic.c @@ -34,6 +34,10 @@ static int drm_fbdev_generic_fb_release(struct fb_info *info, int user) return 0; } +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(drm_fbdev_generic, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area); + static void drm_fbdev_generic_fb_destroy(struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; @@ -56,13 +60,8 @@ static const struct fb_ops drm_fbdev_generic_fb_ops = { .owner = THIS_MODULE, .fb_open = drm_fbdev_generic_fb_open, .fb_release = drm_fbdev_generic_fb_release, - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, + FB_DEFAULT_DEFERRED_OPS(drm_fbdev_generic), DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_mmap = fb_deferred_io_mmap, .fb_destroy = drm_fbdev_generic_fb_destroy, }; diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index c1018c470047..883d83bc0e3d 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include "drm_crtc_internal.h" @@ -148,6 +149,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) */ struct drm_file *drm_file_alloc(struct drm_minor *minor) { + static atomic64_t ident = ATOMIC_INIT(0); struct drm_device *dev = minor->dev; struct drm_file *file; int ret; @@ -156,6 +158,8 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor) if (!file) return ERR_PTR(-ENOMEM); + /* Get a unique identifier for fdinfo: */ + file->client_id = atomic64_inc_return(&ident); file->pid = get_pid(task_tgid(current)); file->minor = minor; @@ -868,6 +872,134 @@ void drm_send_event(struct drm_device *dev, struct drm_pending_event *e) } EXPORT_SYMBOL(drm_send_event); +static void print_size(struct drm_printer *p, const char *stat, + const char *region, u64 sz) +{ + const char *units[] = {"", " KiB", " MiB"}; + unsigned u; + + for (u = 0; u < ARRAY_SIZE(units) - 1; u++) { + if (sz < SZ_1K) + break; + sz = div_u64(sz, SZ_1K); + } + + drm_printf(p, "drm-%s-%s:\t%llu%s\n", stat, region, sz, units[u]); +} + +/** + * drm_print_memory_stats - A helper to print memory stats + * @p: The printer to print output to + * @stats: The collected memory stats + * @supported_status: Bitmask of optional stats which are available + * @region: The memory region + * + */ +void drm_print_memory_stats(struct drm_printer *p, + const struct drm_memory_stats *stats, + enum drm_gem_object_status supported_status, + const char *region) +{ + print_size(p, "total", region, stats->private + stats->shared); + print_size(p, "shared", region, stats->shared); + print_size(p, "active", region, stats->active); + + if (supported_status & DRM_GEM_OBJECT_RESIDENT) + print_size(p, "resident", region, stats->resident); + + if (supported_status & DRM_GEM_OBJECT_PURGEABLE) + print_size(p, "purgeable", region, stats->purgeable); +} +EXPORT_SYMBOL(drm_print_memory_stats); + +/** + * drm_show_memory_stats - Helper to collect and show standard fdinfo memory stats + * @p: the printer to print output to + * @file: the DRM file + * + * Helper to iterate over GEM objects with a handle allocated in the specified + * file. + */ +void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) +{ + struct drm_gem_object *obj; + struct drm_memory_stats status = {}; + enum drm_gem_object_status supported_status; + int id; + + spin_lock(&file->table_lock); + idr_for_each_entry (&file->object_idr, obj, id) { + enum drm_gem_object_status s = 0; + + if (obj->funcs && obj->funcs->status) { + s = obj->funcs->status(obj); + supported_status = DRM_GEM_OBJECT_RESIDENT | + DRM_GEM_OBJECT_PURGEABLE; + } + + if (obj->handle_count > 1) { + status.shared += obj->size; + } else { + status.private += obj->size; + } + + if (s & DRM_GEM_OBJECT_RESIDENT) { + status.resident += obj->size; + } else { + /* If already purged or not yet backed by pages, don't + * count it as purgeable: + */ + s &= ~DRM_GEM_OBJECT_PURGEABLE; + } + + if (!dma_resv_test_signaled(obj->resv, dma_resv_usage_rw(true))) { + status.active += obj->size; + + /* If still active, don't count as purgeable: */ + s &= ~DRM_GEM_OBJECT_PURGEABLE; + } + + if (s & DRM_GEM_OBJECT_PURGEABLE) + status.purgeable += obj->size; + } + spin_unlock(&file->table_lock); + + drm_print_memory_stats(p, &status, supported_status, "memory"); +} +EXPORT_SYMBOL(drm_show_memory_stats); + +/** + * drm_show_fdinfo - helper for drm file fops + * @m: output stream + * @f: the device file instance + * + * Helper to implement fdinfo, for userspace to query usage stats, etc, of a + * process using the GPU. See also &drm_driver.show_fdinfo. + * + * For text output format description please see Documentation/gpu/drm-usage-stats.rst + */ +void drm_show_fdinfo(struct seq_file *m, struct file *f) +{ + struct drm_file *file = f->private_data; + struct drm_device *dev = file->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); + + drm_printf(&p, "drm-driver:\t%s\n", dev->driver->name); + drm_printf(&p, "drm-client-id:\t%llu\n", file->client_id); + + if (dev_is_pci(dev->dev)) { + struct pci_dev *pdev = to_pci_dev(dev->dev); + + drm_printf(&p, "drm-pdev:\t%04x:%02x:%02x.%d\n", + pci_domain_nr(pdev->bus), pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + } + + if (dev->driver->show_fdinfo) + dev->driver->show_fdinfo(&p, file); +} +EXPORT_SYMBOL(drm_show_fdinfo); + /** * mock_drm_getfile - Create a new struct file for the drm device * @minor: drm minor to wrap (e.g. #drm_device.primary) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 0cb92d651ff1..7ca7e1dab52c 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -7,6 +7,7 @@ config DRM_EXYNOS select DRM_DISPLAY_HELPER if DRM_EXYNOS_DP select DRM_KMS_HELPER select VIDEOMODE_HELPERS + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select SND_SOC_HDMI_CODEC if SND_SOC help Choose this option if you have a Samsung SoC Exynos chipset. diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index ea4b3d248aac..fdf65587f1fe 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -8,6 +8,8 @@ * Seung-Woo Kim */ +#include + #include #include #include @@ -47,13 +49,10 @@ static void exynos_drm_fb_destroy(struct fb_info *info) static const struct fb_ops exynos_drm_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_IO_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, + __FB_DEFAULT_IO_OPS_DRAW, .fb_mmap = exynos_drm_fb_mmap, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_destroy = exynos_drm_fb_destroy, }; diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index 2efc0eb41c64..cd3d92725ed4 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -3,6 +3,7 @@ config DRM_GMA500 tristate "Intel GMA500/600/3600/3650 KMS Framebuffer" depends on DRM && PCI && X86 && MMU select DRM_KMS_HELPER + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select I2C select I2C_ALGOBIT # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c index 4f0309548b2b..955cbe9f05a7 100644 --- a/drivers/gpu/drm/gma500/fbdev.c +++ b/drivers/gpu/drm/gma500/fbdev.c @@ -5,6 +5,7 @@ * **************************************************************************/ +#include #include #include @@ -134,13 +135,10 @@ static void psb_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops psb_fbdev_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_IO_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, .fb_setcolreg = psb_fbdev_fb_setcolreg, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, + __FB_DEFAULT_IO_OPS_DRAW, .fb_mmap = psb_fbdev_fb_mmap, .fb_destroy = psb_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/i2c/tda9950.c b/drivers/gpu/drm/i2c/tda9950.c index b8c143e573e0..82d618c40dce 100644 --- a/drivers/gpu/drm/i2c/tda9950.c +++ b/drivers/gpu/drm/i2c/tda9950.c @@ -492,7 +492,7 @@ static struct i2c_device_id tda9950_ids[] = { MODULE_DEVICE_TABLE(i2c, tda9950_ids); static struct i2c_driver tda9950_driver = { - .probe_new = tda9950_probe, + .probe = tda9950_probe, .remove = tda9950_remove, .driver = { .name = "tda9950", diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index db5c9343a3d2..40bcd9067e69 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -2099,7 +2099,7 @@ static const struct i2c_device_id tda998x_ids[] = { MODULE_DEVICE_TABLE(i2c, tda998x_ids); static struct i2c_driver tda998x_driver = { - .probe_new = tda998x_probe, + .probe = tda998x_probe, .remove = tda998x_remove, .driver = { .name = "tda998x", diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index e4f4d2e3fdfe..01b5a8272a27 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -17,6 +17,7 @@ config DRM_I915 select DRM_KMS_HELPER select DRM_PANEL select DRM_MIPI_DSI + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select RELAY select I2C select I2C_ALGOBIT diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index aab1ae74a8f7..eccaceaf8b9d 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,10 @@ static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev) intel_frontbuffer_invalidate(to_frontbuffer(ifbdev), ORIGIN_CPU); } +FB_GEN_DEFAULT_DEFERRED_IO_OPS(intel_fbdev, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area) + static int intel_fbdev_set_par(struct fb_info *info) { struct intel_fbdev *ifbdev = to_intel_fbdev(info->par); @@ -132,15 +137,12 @@ static int intel_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) static const struct fb_ops intelfb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_DEFERRED_OPS_RDWR(intel_fbdev), DRM_FB_HELPER_DEFAULT_OPS, .fb_set_par = intel_fbdev_set_par, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_pan_display = intel_fbdev_pan_display, .fb_blank = intel_fbdev_blank, + .fb_pan_display = intel_fbdev_pan_display, + __FB_DEFAULT_DEFERRED_OPS_DRAW(intel_fbdev), .fb_mmap = intel_fbdev_mmap, }; diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 85f5ab1d552c..a78662bd6273 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -21,6 +21,7 @@ config DRM_MSM select DRM_BRIDGE select DRM_PANEL_BRIDGE select DRM_SCHED + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION select SHMEM select TMPFS select QCOM_SCM diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 060c7689a739..58264ff2c4b1 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1057,23 +1057,23 @@ static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW), }; -static void msm_fop_show_fdinfo(struct seq_file *m, struct file *f) +static void msm_show_fdinfo(struct drm_printer *p, struct drm_file *file) { - struct drm_file *file = f->private_data; struct drm_device *dev = file->minor->dev; struct msm_drm_private *priv = dev->dev_private; - struct drm_printer p = drm_seq_file_printer(m); if (!priv->gpu) return; - msm_gpu_show_fdinfo(priv->gpu, file->driver_priv, &p); + msm_gpu_show_fdinfo(priv->gpu, file->driver_priv, p); + + drm_show_memory_stats(p, file); } static const struct file_operations fops = { .owner = THIS_MODULE, DRM_GEM_FOPS, - .show_fdinfo = msm_fop_show_fdinfo, + .show_fdinfo = drm_show_fdinfo, }; static const struct drm_driver msm_driver = { @@ -1083,7 +1083,7 @@ static const struct drm_driver msm_driver = { DRIVER_MODESET | DRIVER_SYNCOBJ, .open = msm_open, - .postclose = msm_postclose, + .postclose = msm_postclose, .dumb_create = msm_gem_dumb_create, .dumb_map_offset = msm_gem_dumb_map_offset, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, @@ -1093,6 +1093,7 @@ static const struct drm_driver msm_driver = { #ifdef CONFIG_DEBUG_FS .debugfs_init = msm_debugfs_init, #endif + .show_fdinfo = msm_show_fdinfo, .ioctls = msm_ioctls, .num_ioctls = ARRAY_SIZE(msm_ioctls), .fops = &fops, diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index ce0ba6d1979a..fa9c1cbffae3 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -4,6 +4,8 @@ * Author: Rob Clark */ +#include + #include #include #include @@ -23,6 +25,10 @@ module_param(fbdev, bool, 0600); * fbdev funcs, to implement legacy fbdev interface on top of drm driver */ +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(msm_fbdev, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area) + static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par; @@ -52,16 +58,9 @@ static void msm_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops msm_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_DEFERRED_OPS_RDWR(msm_fbdev), DRM_FB_HELPER_DEFAULT_OPS, - - /* Note: to properly handle manual update displays, we wrap the - * basic fbdev ops which write to the framebuffer - */ - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, + __FB_DEFAULT_DEFERRED_OPS_DRAW(msm_fbdev), .fb_mmap = msm_fbdev_mmap, .fb_destroy = msm_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index db6c4e281d75..c32264234ea1 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1096,6 +1096,20 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, return ret; } +static enum drm_gem_object_status msm_gem_status(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + enum drm_gem_object_status status = 0; + + if (msm_obj->pages) + status |= DRM_GEM_OBJECT_RESIDENT; + + if (msm_obj->madv == MSM_MADV_DONTNEED) + status |= DRM_GEM_OBJECT_PURGEABLE; + + return status; +} + static const struct vm_operations_struct vm_ops = { .fault = msm_gem_fault, .open = drm_gem_vm_open, @@ -1110,6 +1124,7 @@ static const struct drm_gem_object_funcs msm_gem_object_funcs = { .vmap = msm_gem_prime_vmap, .vunmap = msm_gem_prime_vunmap, .mmap = msm_gem_object_mmap, + .status = msm_gem_status, .vm_ops = &vm_ops, }; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 26ebda40be4f..c403912d13ab 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -151,8 +151,6 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) void msm_gpu_show_fdinfo(struct msm_gpu *gpu, struct msm_file_private *ctx, struct drm_printer *p) { - drm_printf(p, "drm-driver:\t%s\n", gpu->dev->driver->name); - drm_printf(p, "drm-client-id:\t%u\n", ctx->seqno); drm_printf(p, "drm-engine-gpu:\t%llu ns\n", ctx->elapsed_ns); drm_printf(p, "drm-cycles-gpu:\t%llu\n", ctx->cycles); drm_printf(p, "drm-maxfreq-gpu:\t%u Hz\n", gpu->fast_rate); diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c index 6fb5b469ee5a..c9d8cbb21407 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_drv.c +++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c @@ -9,13 +9,16 @@ #include #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -38,21 +41,70 @@ static const struct drm_mode_config_helper_funcs lcdif_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; +static const struct drm_encoder_funcs lcdif_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + static int lcdif_attach_bridge(struct lcdif_drm_private *lcdif) { - struct drm_device *drm = lcdif->drm; + struct device *dev = lcdif->drm->dev; + struct device_node *ep; struct drm_bridge *bridge; int ret; - bridge = devm_drm_of_get_bridge(drm->dev, drm->dev->of_node, 0, 0); - if (IS_ERR(bridge)) - return PTR_ERR(bridge); + for_each_endpoint_of_node(dev->of_node, ep) { + struct device_node *remote; + struct of_endpoint of_ep; + struct drm_encoder *encoder; - ret = drm_bridge_attach(&lcdif->encoder, bridge, NULL, 0); - if (ret) - return dev_err_probe(drm->dev, ret, "Failed to attach bridge\n"); + remote = of_graph_get_remote_port_parent(ep); + if (!of_device_is_available(remote)) { + of_node_put(remote); + continue; + } + of_node_put(remote); - lcdif->bridge = bridge; + ret = of_graph_parse_endpoint(ep, &of_ep); + if (ret < 0) { + dev_err(dev, "Failed to parse endpoint %pOF\n", ep); + of_node_put(ep); + return ret; + } + + bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, of_ep.id); + if (IS_ERR(bridge)) { + of_node_put(ep); + return dev_err_probe(dev, PTR_ERR(bridge), + "Failed to get bridge for endpoint%u\n", + of_ep.id); + } + + encoder = devm_kzalloc(dev, sizeof(*encoder), GFP_KERNEL); + if (!encoder) { + dev_err(dev, "Failed to allocate encoder for endpoint%u\n", + of_ep.id); + of_node_put(ep); + return -ENOMEM; + } + + encoder->possible_crtcs = drm_crtc_mask(&lcdif->crtc); + ret = drm_encoder_init(lcdif->drm, encoder, &lcdif_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) { + dev_err(dev, "Failed to initialize encoder for endpoint%u: %d\n", + of_ep.id, ret); + of_node_put(ep); + return ret; + } + + ret = drm_bridge_attach(encoder, bridge, NULL, 0); + if (ret) { + of_node_put(ep); + return dev_err_probe(dev, ret, + "Failed to attach bridge for endpoint%u\n", + of_ep.id); + } + } return 0; } @@ -199,6 +251,7 @@ static const struct drm_driver lcdif_driver = { static const struct of_device_id lcdif_dt_ids[] = { { .compatible = "fsl,imx8mp-lcdif" }, + { .compatible = "fsl,imx93-lcdif" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, lcdif_dt_ids); diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.h b/drivers/gpu/drm/mxsfb/lcdif_drv.h index 6cdba6e20c02..61483a4e058d 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_drv.h +++ b/drivers/gpu/drm/mxsfb/lcdif_drv.h @@ -11,7 +11,6 @@ #include #include #include -#include #include struct clk; @@ -30,8 +29,6 @@ struct lcdif_drm_private { /* i.MXRT does support overlay planes, add them here. */ } planes; struct drm_crtc crtc; - struct drm_encoder encoder; - struct drm_bridge *bridge; }; static inline struct lcdif_drm_private * diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index 262bc43b1079..2541d2de4e45 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,18 @@ #include "lcdif_drv.h" #include "lcdif_regs.h" +struct lcdif_crtc_state { + struct drm_crtc_state base; /* always be the first member */ + u32 bus_format; + u32 bus_flags; +}; + +static inline struct lcdif_crtc_state * +to_lcdif_crtc_state(struct drm_crtc_state *s) +{ + return container_of(s, struct lcdif_crtc_state, base); +} + /* ----------------------------------------------------------------------------- * CRTC */ @@ -385,48 +398,108 @@ static void lcdif_reset_block(struct lcdif_drm_private *lcdif) readl(lcdif->base + LCDC_V8_CTRL); } -static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, - struct drm_plane_state *plane_state, - struct drm_bridge_state *bridge_state, - const u32 bus_format) +static void lcdif_crtc_mode_set_nofb(struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) { - struct drm_device *drm = lcdif->crtc.dev; - struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode; - u32 bus_flags = 0; - - if (lcdif->bridge && lcdif->bridge->timings) - bus_flags = lcdif->bridge->timings->input_bus_flags; - else if (bridge_state) - bus_flags = bridge_state->input_bus_cfg.flags; + struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state); + struct drm_device *drm = crtc_state->crtc->dev; + struct lcdif_drm_private *lcdif = to_lcdif_drm_private(drm); + struct drm_display_mode *m = &crtc_state->adjusted_mode; DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", m->crtc_clock, (int)(clk_get_rate(lcdif->clk) / 1000)); DRM_DEV_DEBUG_DRIVER(drm->dev, "Bridge bus_flags: 0x%08X\n", - bus_flags); + lcdif_crtc_state->bus_flags); DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); /* Mandatory eLCDIF reset as per the Reference Manual */ lcdif_reset_block(lcdif); - lcdif_set_formats(lcdif, plane_state, bus_format); + lcdif_set_formats(lcdif, plane_state, lcdif_crtc_state->bus_format); - lcdif_set_mode(lcdif, bus_flags); + lcdif_set_mode(lcdif, lcdif_crtc_state->bus_flags); } static int lcdif_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { + struct drm_device *drm = crtc->dev; struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state); bool has_primary = crtc_state->plane_mask & drm_plane_mask(crtc->primary); + struct drm_connector_state *connector_state; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_bridge_state *bridge_state; + struct drm_bridge *bridge; + u32 bus_format, bus_flags; + bool format_set = false, flags_set = false; + int ret, i; /* The primary plane has to be enabled when the CRTC is active. */ if (crtc_state->active && !has_primary) return -EINVAL; - return drm_atomic_add_affected_planes(state, crtc); + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + + /* Try to find consistent bus format and flags across first bridges. */ + for_each_new_connector_in_state(state, connector, connector_state, i) { + if (!connector_state->crtc) + continue; + + encoder = connector_state->best_encoder; + + bridge = drm_bridge_chain_get_first_bridge(encoder); + if (!bridge) + continue; + + bridge_state = drm_atomic_get_new_bridge_state(state, bridge); + if (!bridge_state) + bus_format = MEDIA_BUS_FMT_FIXED; + else + bus_format = bridge_state->input_bus_cfg.format; + + if (bus_format == MEDIA_BUS_FMT_FIXED) { + dev_warn(drm->dev, + "[ENCODER:%d:%s]'s bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n" + "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n", + encoder->base.id, encoder->name); + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + } else if (!bus_format) { + /* If all else fails, default to RGB888_1X24 */ + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + } + + if (!format_set) { + lcdif_crtc_state->bus_format = bus_format; + format_set = true; + } else if (lcdif_crtc_state->bus_format != bus_format) { + DRM_DEV_DEBUG_DRIVER(drm->dev, "inconsistent bus format\n"); + return -EINVAL; + } + + if (bridge->timings) + bus_flags = bridge->timings->input_bus_flags; + else if (bridge_state) + bus_flags = bridge_state->input_bus_cfg.flags; + else + bus_flags = 0; + + if (!flags_set) { + lcdif_crtc_state->bus_flags = bus_flags; + flags_set = true; + } else if (lcdif_crtc_state->bus_flags != bus_flags) { + DRM_DEV_DEBUG_DRIVER(drm->dev, "inconsistent bus flags\n"); + return -EINVAL; + } + } + + return 0; } static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc, @@ -458,41 +531,18 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev); + struct drm_crtc_state *new_cstate = drm_atomic_get_new_crtc_state(state, crtc); struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state, crtc->primary); struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode; - struct drm_bridge_state *bridge_state = NULL; struct drm_device *drm = lcdif->drm; - u32 bus_format = 0; dma_addr_t paddr; - /* If there is a bridge attached to the LCDIF, use its bus format */ - if (lcdif->bridge) { - bridge_state = - drm_atomic_get_new_bridge_state(state, - lcdif->bridge); - if (!bridge_state) - bus_format = MEDIA_BUS_FMT_FIXED; - else - bus_format = bridge_state->input_bus_cfg.format; - - if (bus_format == MEDIA_BUS_FMT_FIXED) { - dev_warn_once(drm->dev, - "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n" - "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n"); - bus_format = MEDIA_BUS_FMT_RGB888_1X24; - } - } - - /* If all else fails, default to RGB888_1X24 */ - if (!bus_format) - bus_format = MEDIA_BUS_FMT_RGB888_1X24; - clk_set_rate(lcdif->clk, m->crtc_clock * 1000); pm_runtime_get_sync(drm->dev); - lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format); + lcdif_crtc_mode_set_nofb(new_cstate, new_pstate); /* Write cur_buf as well to avoid an initial corrupt frame */ paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); @@ -529,6 +579,48 @@ static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc, pm_runtime_put_sync(drm->dev); } +static void lcdif_crtc_atomic_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + __drm_atomic_helper_crtc_destroy_state(state); + kfree(to_lcdif_crtc_state(state)); +} + +static void lcdif_crtc_reset(struct drm_crtc *crtc) +{ + struct lcdif_crtc_state *state; + + if (crtc->state) + lcdif_crtc_atomic_destroy_state(crtc, crtc->state); + + crtc->state = NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_crtc_reset(crtc, &state->base); +} + +static struct drm_crtc_state * +lcdif_crtc_atomic_duplicate_state(struct drm_crtc *crtc) +{ + struct lcdif_crtc_state *old = to_lcdif_crtc_state(crtc->state); + struct lcdif_crtc_state *new; + + if (WARN_ON(!crtc->state)) + return NULL; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &new->base); + + new->bus_format = old->bus_format; + new->bus_flags = old->bus_flags; + + return &new->base; +} + static int lcdif_crtc_enable_vblank(struct drm_crtc *crtc) { struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev); @@ -557,24 +649,16 @@ static const struct drm_crtc_helper_funcs lcdif_crtc_helper_funcs = { }; static const struct drm_crtc_funcs lcdif_crtc_funcs = { - .reset = drm_atomic_helper_crtc_reset, + .reset = lcdif_crtc_reset, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .atomic_duplicate_state = lcdif_crtc_atomic_duplicate_state, + .atomic_destroy_state = lcdif_crtc_atomic_destroy_state, .enable_vblank = lcdif_crtc_enable_vblank, .disable_vblank = lcdif_crtc_disable_vblank, }; -/* ----------------------------------------------------------------------------- - * Encoder - */ - -static const struct drm_encoder_funcs lcdif_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - /* ----------------------------------------------------------------------------- * Planes */ @@ -667,7 +751,6 @@ int lcdif_kms_init(struct lcdif_drm_private *lcdif) BIT(DRM_COLOR_YCBCR_BT2020); const u32 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | BIT(DRM_COLOR_YCBCR_FULL_RANGE); - struct drm_encoder *encoder = &lcdif->encoder; struct drm_crtc *crtc = &lcdif->crtc; int ret; @@ -691,13 +774,7 @@ int lcdif_kms_init(struct lcdif_drm_private *lcdif) return ret; drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs); - ret = drm_crtc_init_with_planes(lcdif->drm, crtc, - &lcdif->planes.primary, NULL, - &lcdif_crtc_funcs, NULL); - if (ret) - return ret; - - encoder->possible_crtcs = drm_crtc_mask(crtc); - return drm_encoder_init(lcdif->drm, encoder, &lcdif_encoder_funcs, - DRM_MODE_ENCODER_NONE, NULL); + return drm_crtc_init_with_planes(lcdif->drm, crtc, + &lcdif->planes.primary, NULL, + &lcdif_crtc_funcs, NULL); } diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 76ded1568bd0..b4ac76c9f31b 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -4,6 +4,7 @@ config DRM_OMAP depends on DRM && OF depends on ARCH_OMAP2PLUS select DRM_KMS_HELPER + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION select VIDEOMODE_HELPERS select HDMI default n diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index b950e93b3846..b7ccce0704a3 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -4,6 +4,8 @@ * Author: Rob Clark */ +#include + #include #include #include @@ -95,20 +97,13 @@ static void omap_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, - + FB_DEFAULT_SYS_OPS, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_setcmap = drm_fb_helper_setcmap, .fb_blank = drm_fb_helper_blank, .fb_pan_display = omap_fbdev_pan_display, .fb_ioctl = drm_fb_helper_ioctl, - - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_destroy = omap_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index e23ddab2126e..fbd114b4f0be 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -903,7 +903,7 @@ err_finished_ddc_init: return err; } -static int panel_edp_remove(struct device *dev) +static void panel_edp_remove(struct device *dev) { struct panel_edp *panel = dev_get_drvdata(dev); @@ -918,8 +918,6 @@ static int panel_edp_remove(struct device *dev) kfree(panel->edid); panel->edid = NULL; - - return 0; } static void panel_edp_shutdown(struct device *dev) @@ -1934,9 +1932,9 @@ static int panel_edp_platform_probe(struct platform_device *pdev) return panel_edp_probe(&pdev->dev, id->data, NULL); } -static int panel_edp_platform_remove(struct platform_device *pdev) +static void panel_edp_platform_remove(struct platform_device *pdev) { - return panel_edp_remove(&pdev->dev); + panel_edp_remove(&pdev->dev); } static void panel_edp_platform_shutdown(struct platform_device *pdev) @@ -1957,7 +1955,7 @@ static struct platform_driver panel_edp_platform_driver = { .pm = &panel_edp_pm_ops, }, .probe = panel_edp_platform_probe, - .remove = panel_edp_platform_remove, + .remove_new = panel_edp_platform_remove, .shutdown = panel_edp_platform_shutdown, }; diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c index aba556c98300..4819ada69482 100644 --- a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c +++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c @@ -308,7 +308,7 @@ static struct i2c_driver lcd_olinuxino_driver = { .name = "lcd_olinuxino", .of_match_table = lcd_olinuxino_of_ids, }, - .probe_new = lcd_olinuxino_probe, + .probe = lcd_olinuxino_probe, .remove = lcd_olinuxino_remove, }; diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c index 11d6ca276c1e..90ea91e4311d 100644 --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -489,7 +489,7 @@ static struct i2c_driver rpi_touchscreen_driver = { .name = "rpi_touchscreen", .of_match_table = rpi_touchscreen_of_ids, }, - .probe_new = rpi_touchscreen_probe, + .probe = rpi_touchscreen_probe, .remove = rpi_touchscreen_remove, }; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5778824dffd4..754c09c6d4c1 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -759,8 +759,8 @@ static const struct panel_desc ampire_am_480272h3tmqw_t01h = { .num_modes = 1, .bpc = 8, .size = { - .width = 105, - .height = 67, + .width = 99, + .height = 58, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; @@ -778,6 +778,36 @@ static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = { .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, }; +static const struct display_timing ampire_am_800480l1tmqw_t00h_timing = { + .pixelclock = { 29930000, 33260000, 36590000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 1, 40, 168 }, + .hback_porch = { 88, 88, 88 }, + .hsync_len = { 1, 128, 128 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 1, 35, 37 }, + .vback_porch = { 8, 8, 8 }, + .vsync_len = { 1, 2, 2 }, + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | + DISPLAY_FLAGS_SYNC_POSEDGE, +}; + +static const struct panel_desc ampire_am_800480l1tmqw_t00h = { + .timings = &ire_am_800480l1tmqw_t00h_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 111, + .height = 67, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; + static const struct panel_desc ampire_am800480r3tmqwa1h = { .modes = &ire_am800480r3tmqwa1h_mode, .num_modes = 1, @@ -3993,6 +4023,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "ampire,am-480272h3tmqw-t01h", .data = &ire_am_480272h3tmqw_t01h, + }, { + .compatible = "ampire,am-800480l1tmqw-t00h", + .data = &ire_am_800480l1tmqw_t00h, }, { .compatible = "ampire,am800480r3tmqwa1h", .data = &ire_am800480r3tmqwa1h, diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index e19d77d58810..fe498c8af1bb 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -11,6 +11,7 @@ config DRM_RADEON select DRM_SUBALLOC_HELPER select DRM_TTM select DRM_TTM_HELPER + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select SND_HDA_COMPONENT if SND_HDA_CORE select POWER_SUPPLY select HWMON diff --git a/drivers/gpu/drm/radeon/radeon_fbdev.c b/drivers/gpu/drm/radeon/radeon_fbdev.c index fe76e29910ef..28212c2d6c98 100644 --- a/drivers/gpu/drm/radeon/radeon_fbdev.c +++ b/drivers/gpu/drm/radeon/radeon_fbdev.c @@ -24,6 +24,7 @@ * David Airlie */ +#include #include #include #include @@ -190,14 +191,10 @@ static void radeon_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops radeon_fbdev_fb_ops = { .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, .fb_open = radeon_fbdev_fb_open, .fb_release = radeon_fbdev_fb_release, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, + FB_DEFAULT_IO_OPS, + DRM_FB_HELPER_DEFAULT_OPS, .fb_destroy = radeon_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/solomon/ssd130x-i2c.c b/drivers/gpu/drm/solomon/ssd130x-i2c.c index ddfa0bb5d9c9..b4eb2d64bf6e 100644 --- a/drivers/gpu/drm/solomon/ssd130x-i2c.c +++ b/drivers/gpu/drm/solomon/ssd130x-i2c.c @@ -100,7 +100,7 @@ static struct i2c_driver ssd130x_i2c_driver = { .name = DRIVER_NAME, .of_match_table = ssd130x_of_match, }, - .probe_new = ssd130x_i2c_probe, + .probe = ssd130x_i2c_probe, .remove = ssd130x_i2c_remove, .shutdown = ssd130x_i2c_shutdown, }; diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 89897d5f5c72..1750b6a25e87 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -444,15 +444,13 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dw_mipi_dsi_stm *dsi; struct clk *pclk; - struct resource *res; int ret; dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); if (!dsi) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dsi->base = devm_ioremap_resource(dev, res); + dsi->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dsi->base)) { ret = PTR_ERR(dsi->base); DRM_ERROR("Unable to get dsi registers %d\n", ret); diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 03c6becda795..b8be4c1db423 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -1145,7 +1145,7 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source) { - struct ltdc_device *ldev = crtc_to_ltdc(crtc); + struct ltdc_device *ldev; int ret; DRM_DEBUG_DRIVER("\n"); @@ -1153,6 +1153,8 @@ static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source) if (!crtc) return -ENODEV; + ldev = crtc_to_ltdc(crtc); + if (source && strcmp(source, "auto") == 0) { ldev->crc_active = true; ret = regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_CRCEN); diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 56453ca277c2..498313778175 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -12,6 +12,7 @@ config DRM_TEGRA select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION select TEGRA_HOST1X select INTERCONNECT select IOMMU_IOVA diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c index dca9eccae466..e74d9be981c7 100644 --- a/drivers/gpu/drm/tegra/fbdev.c +++ b/drivers/gpu/drm/tegra/fbdev.c @@ -8,6 +8,7 @@ */ #include +#include #include #include @@ -58,12 +59,9 @@ static void tegra_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_SYS_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, + __FB_DEFAULT_SYS_OPS_DRAW, .fb_mmap = tegra_fb_mmap, .fb_destroy = tegra_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index ab725d9d14a6..1ce4b36ab33b 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -137,7 +137,6 @@ static void ttm_tt_init_fields(struct ttm_tt *ttm, unsigned long extra_pages) { ttm->num_pages = (PAGE_ALIGN(bo->base.size) >> PAGE_SHIFT) + extra_pages; - ttm->caching = ttm_cached; ttm->page_flags = page_flags; ttm->dma_address = NULL; ttm->swap_storage = NULL; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 485e8c35d5c6..6e4b6ad9d8e6 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -158,6 +158,27 @@ config FB_DEFERRED_IO bool depends on FB +config FB_IO_HELPERS + bool + depends on FB + select FB_CFB_COPYAREA + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + +config FB_SYS_HELPERS + bool + depends on FB + select FB_SYS_COPYAREA + select FB_SYS_FILLRECT + select FB_SYS_FOPS + select FB_SYS_IMAGEBLIT + +config FB_SYS_HELPERS_DEFERRED + bool + depends on FB + select FB_DEFERRED_IO + select FB_SYS_HELPERS + config FB_HECUBA tristate depends on FB diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 6a37d1e079bf..05100e91ecb9 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -54,11 +54,14 @@ struct samsung_dsim_driver_data { unsigned int has_freqband:1; unsigned int has_clklane_stop:1; unsigned int num_clks; + unsigned int min_freq; unsigned int max_freq; unsigned int wait_for_reset; unsigned int num_bits_resol; unsigned int pll_p_offset; const unsigned int *reg_values; + u16 m_min; + u16 m_max; }; struct samsung_dsim_host_ops { @@ -90,6 +93,7 @@ struct samsung_dsim { u32 pll_clk_rate; u32 burst_clk_rate; + u32 hs_clock; u32 esc_clk_rate; u32 lanes; u32 mode_flags; diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index b419c59c4bef..89e2706cac56 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -401,6 +401,13 @@ struct drm_driver { struct drm_device *dev, uint32_t handle, uint64_t *offset); + /** + * @show_fdinfo: + * + * Print device specific fdinfo. See Documentation/gpu/drm-usage-stats.rst. + */ + void (*show_fdinfo)(struct drm_printer *p, struct drm_file *f); + /** @major: driver major number */ int major; /** @minor: driver minor number */ diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 72032c354a30..4863b0f8299e 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -253,32 +253,11 @@ void drm_fb_helper_fill_info(struct fb_info *info, struct drm_fb_helper *fb_helper, struct drm_fb_helper_surface_size *sizes); +void drm_fb_helper_damage_range(struct fb_info *info, off_t off, size_t len); +void drm_fb_helper_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height); + void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist); -ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos); -ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos); - -void drm_fb_helper_sys_fillrect(struct fb_info *info, - const struct fb_fillrect *rect); -void drm_fb_helper_sys_copyarea(struct fb_info *info, - const struct fb_copyarea *area); -void drm_fb_helper_sys_imageblit(struct fb_info *info, - const struct fb_image *image); - -ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos); -ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos); - -void drm_fb_helper_cfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect); -void drm_fb_helper_cfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area); -void drm_fb_helper_cfb_imageblit(struct fb_info *info, - const struct fb_image *image); - void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend); void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, bool suspend); @@ -394,62 +373,6 @@ static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper) return -ENODEV; } -static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info, - char __user *buf, size_t count, - loff_t *ppos) -{ - return -ENODEV; -} - -static inline ssize_t drm_fb_helper_sys_write(struct fb_info *info, - const char __user *buf, - size_t count, loff_t *ppos) -{ - return -ENODEV; -} - -static inline void drm_fb_helper_sys_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ -} - -static inline void drm_fb_helper_sys_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ -} - -static inline void drm_fb_helper_sys_imageblit(struct fb_info *info, - const struct fb_image *image) -{ -} - -static inline ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos) -{ - return -ENODEV; -} - -static inline ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - return -ENODEV; -} - -static inline void drm_fb_helper_cfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ -} - -static inline void drm_fb_helper_cfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ -} - -static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ -} - static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend) { diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index ecffe24e2b1b..966912053cb0 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -41,6 +41,7 @@ struct dma_fence; struct drm_file; struct drm_device; +struct drm_printer; struct device; struct file; @@ -258,6 +259,9 @@ struct drm_file { /** @pid: Process that opened this file. */ struct pid *pid; + /** @client_id: A unique id for fdinfo */ + u64 client_id; + /** @magic: Authentication magic, see @authenticated. */ drm_magic_t magic; @@ -439,6 +443,34 @@ void drm_send_event_timestamp_locked(struct drm_device *dev, struct drm_pending_event *e, ktime_t timestamp); +/** + * struct drm_memory_stats - GEM object stats associated + * @shared: Total size of GEM objects shared between processes + * @private: Total size of GEM objects + * @resident: Total size of GEM objects backing pages + * @purgeable: Total size of GEM objects that can be purged (resident and not active) + * @active: Total size of GEM objects active on one or more engines + * + * Used by drm_print_memory_stats() + */ +struct drm_memory_stats { + u64 shared; + u64 private; + u64 resident; + u64 purgeable; + u64 active; +}; + +enum drm_gem_object_status; + +void drm_print_memory_stats(struct drm_printer *p, + const struct drm_memory_stats *stats, + enum drm_gem_object_status supported_status, + const char *region); + +void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file); +void drm_show_fdinfo(struct seq_file *m, struct file *f); + struct file *mock_drm_getfile(struct drm_minor *minor, unsigned int flags); #endif /* _DRM_FILE_H_ */ diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index b8efd836edef..bbc721870c13 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -42,6 +42,25 @@ struct iosys_map; struct drm_gem_object; +/** + * enum drm_gem_object_status - bitmask of object state for fdinfo reporting + * @DRM_GEM_OBJECT_RESIDENT: object is resident in memory (ie. not unpinned) + * @DRM_GEM_OBJECT_PURGEABLE: object marked as purgeable by userspace + * + * Bitmask of status used for fdinfo memory stats, see &drm_gem_object_funcs.status + * and drm_show_fdinfo(). Note that an object can DRM_GEM_OBJECT_PURGEABLE if + * it still active or not resident, in which case drm_show_fdinfo() will not + * account for it as purgeable. So drivers do not need to check if the buffer + * is idle and resident to return this bit. (Ie. userspace can mark a buffer + * as purgeable even while it is still busy on the GPU.. it does not _actually_ + * become puregeable until it becomes idle. The status gem object func does + * not need to consider this.) + */ +enum drm_gem_object_status { + DRM_GEM_OBJECT_RESIDENT = BIT(0), + DRM_GEM_OBJECT_PURGEABLE = BIT(1), +}; + /** * struct drm_gem_object_funcs - GEM object functions */ @@ -174,6 +193,19 @@ struct drm_gem_object_funcs { */ int (*evict)(struct drm_gem_object *obj); + /** + * @status: + * + * The optional status callback can return additional object state + * which determines which stats the object is counted against. The + * callback is called under table_lock. Racing against object status + * change is "harmless", and the callback can expect to not race + * against object destruction. + * + * Called by drm_show_memory_stats(). + */ + enum drm_gem_object_status (*status)(struct drm_gem_object *obj); + /** * @vm_ops: * diff --git a/include/linux/fb.h b/include/linux/fb.h index 2cf8efcb9e32..ce6823e157e6 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -538,9 +538,31 @@ extern ssize_t fb_io_read(struct fb_info *info, char __user *buf, extern ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos); +/* + * Initializes struct fb_ops for framebuffers in I/O memory. + */ + +#define __FB_DEFAULT_IO_OPS_RDWR \ + .fb_read = fb_io_read, \ + .fb_write = fb_io_write + +#define __FB_DEFAULT_IO_OPS_DRAW \ + .fb_fillrect = cfb_fillrect, \ + .fb_copyarea = cfb_copyarea, \ + .fb_imageblit = cfb_imageblit + +#define __FB_DEFAULT_IO_OPS_MMAP \ + .fb_mmap = NULL // default implementation + +#define FB_DEFAULT_IO_OPS \ + __FB_DEFAULT_IO_OPS_RDWR, \ + __FB_DEFAULT_IO_OPS_DRAW, \ + __FB_DEFAULT_IO_OPS_MMAP + /* * Drawing operations where framebuffer is in system RAM */ + extern void sys_fillrect(struct fb_info *info, const struct fb_fillrect *rect); extern void sys_copyarea(struct fb_info *info, const struct fb_copyarea *area); extern void sys_imageblit(struct fb_info *info, const struct fb_image *image); @@ -549,6 +571,27 @@ extern ssize_t fb_sys_read(struct fb_info *info, char __user *buf, extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos); +/* + * Initializes struct fb_ops for framebuffers in system memory. + */ + +#define __FB_DEFAULT_SYS_OPS_RDWR \ + .fb_read = fb_sys_read, \ + .fb_write = fb_sys_write + +#define __FB_DEFAULT_SYS_OPS_DRAW \ + .fb_fillrect = sys_fillrect, \ + .fb_copyarea = sys_copyarea, \ + .fb_imageblit = sys_imageblit + +#define __FB_DEFAULT_SYS_OPS_MMAP \ + .fb_mmap = NULL // default implementation + +#define FB_DEFAULT_SYS_OPS \ + __FB_DEFAULT_SYS_OPS_RDWR, \ + __FB_DEFAULT_SYS_OPS_DRAW, \ + __FB_DEFAULT_SYS_OPS_MMAP + /* drivers/video/fbmem.c */ extern int register_framebuffer(struct fb_info *fb_info); extern void unregister_framebuffer(struct fb_info *fb_info); @@ -604,6 +647,75 @@ extern void fb_deferred_io_cleanup(struct fb_info *info); extern int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync); +/* + * Generate callbacks for deferred I/O + */ + +#define __FB_GEN_DEFAULT_DEFERRED_OPS_RDWR(__prefix, __damage_range, __mode) \ + static ssize_t __prefix ## _defio_read(struct fb_info *info, char __user *buf, \ + size_t count, loff_t *ppos) \ + { \ + return fb_ ## __mode ## _read(info, buf, count, ppos); \ + } \ + static ssize_t __prefix ## _defio_write(struct fb_info *info, const char __user *buf, \ + size_t count, loff_t *ppos) \ + { \ + unsigned long offset = *ppos; \ + ssize_t ret = fb_ ## __mode ## _write(info, buf, count, ppos); \ + if (ret > 0) \ + __damage_range(info, offset, ret); \ + return ret; \ + } + +#define __FB_GEN_DEFAULT_DEFERRED_OPS_DRAW(__prefix, __damage_area, __mode) \ + static void __prefix ## _defio_fillrect(struct fb_info *info, \ + const struct fb_fillrect *rect) \ + { \ + __mode ## _fillrect(info, rect); \ + __damage_area(info, rect->dx, rect->dy, rect->width, rect->height); \ + } \ + static void __prefix ## _defio_copyarea(struct fb_info *info, \ + const struct fb_copyarea *area) \ + { \ + __mode ## _copyarea(info, area); \ + __damage_area(info, area->dx, area->dy, area->width, area->height); \ + } \ + static void __prefix ## _defio_imageblit(struct fb_info *info, \ + const struct fb_image *image) \ + { \ + __mode ## _imageblit(info, image); \ + __damage_area(info, image->dx, image->dy, image->width, image->height); \ + } + +#define FB_GEN_DEFAULT_DEFERRED_IO_OPS(__prefix, __damage_range, __damage_area) \ + __FB_GEN_DEFAULT_DEFERRED_OPS_RDWR(__prefix, __damage_range, io) \ + __FB_GEN_DEFAULT_DEFERRED_OPS_DRAW(__prefix, __damage_area, cfb) + +#define FB_GEN_DEFAULT_DEFERRED_SYS_OPS(__prefix, __damage_range, __damage_area) \ + __FB_GEN_DEFAULT_DEFERRED_OPS_RDWR(__prefix, __damage_range, sys) \ + __FB_GEN_DEFAULT_DEFERRED_OPS_DRAW(__prefix, __damage_area, sys) + +/* + * Initializes struct fb_ops for deferred I/O. + */ + +#define __FB_DEFAULT_DEFERRED_OPS_RDWR(__prefix) \ + .fb_read = __prefix ## _defio_read, \ + .fb_write = __prefix ## _defio_write + +#define __FB_DEFAULT_DEFERRED_OPS_DRAW(__prefix) \ + .fb_fillrect = __prefix ## _defio_fillrect, \ + .fb_copyarea = __prefix ## _defio_copyarea, \ + .fb_imageblit = __prefix ## _defio_imageblit + +#define __FB_DEFAULT_DEFERRED_OPS_MMAP(__prefix) \ + .fb_mmap = fb_deferred_io_mmap + +#define FB_DEFAULT_DEFERRED_OPS(__prefix) \ + __FB_DEFAULT_DEFERRED_OPS_RDWR(__prefix), \ + __FB_DEFAULT_DEFERRED_OPS_DRAW(__prefix), \ + __FB_DEFAULT_DEFERRED_OPS_MMAP(__prefix) + static inline bool fb_be_math(struct fb_info *info) { #ifdef CONFIG_FB_FOREIGN_ENDIAN