diff options
181 files changed, 3767 insertions, 1611 deletions
@@ -327,6 +327,7 @@ Mauro Carvalho Chehab <mchehab@kernel.org> <m.chehab@samsung.com> Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@s-opensource.com> Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@mellanox.com> Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@nvidia.com> +Maxime Ripard <mripard@kernel.org> <maxime@cerno.tech> Maxime Ripard <mripard@kernel.org> <maxime.ripard@bootlin.com> Maxime Ripard <mripard@kernel.org> <maxime.ripard@free-electrons.com> Mayuresh Janorkar <mayur@ti.com> diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-g12a-dw-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-g12a-dw-mipi-dsi.yaml new file mode 100644 index 000000000000..a3428f012005 --- /dev/null +++ b/Documentation/devicetree/bindings/display/amlogic,meson-g12a-dw-mipi-dsi.yaml @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2020 BayLibre, SAS +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/amlogic,meson-g12a-dw-mipi-dsi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic specific extensions to the Synopsys Designware MIPI DSI Host Controller + +maintainers: + - Neil Armstrong <neil.armstrong@linaro.org> + +description: | + The Amlogic Meson Synopsys Designware Integration is composed of + - A Synopsys DesignWare MIPI DSI Host Controller IP + - A TOP control block controlling the Clocks & Resets of the IP + +allOf: + - $ref: dsi-controller.yaml# + +properties: + compatible: + enum: + - amlogic,meson-g12a-dw-mipi-dsi + + reg: + maxItems: 1 + + clocks: + minItems: 3 + maxItems: 4 + + clock-names: + minItems: 3 + items: + - const: pclk + - const: bit + - const: px + - const: meas + + resets: + maxItems: 1 + + reset-names: + items: + - const: top + + phys: + maxItems: 1 + + phy-names: + items: + - const: dphy + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Input node to receive pixel data. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: DSI output node to panel. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - phys + - phy-names + - ports + +unevaluatedProperties: false + +examples: + - | + dsi@6000 { + compatible = "amlogic,meson-g12a-dw-mipi-dsi"; + reg = <0x6000 0x400>; + resets = <&reset_top>; + reset-names = "top"; + clocks = <&clk_pclk>, <&bit_clk>, <&clk_px>; + clock-names = "pclk", "bit", "px"; + phys = <&mipi_dphy>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + mipi_dsi_venc_port: port@0 { + reg = <0>; + + mipi_dsi_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + /* DSI Output */ + mipi_dsi_panel_port: port@1 { + reg = <1>; + + mipi_out_panel: endpoint { + remote-endpoint = <&mipi_in_panel>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml index 0c72120acc4f..cb0a90f02321 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml @@ -96,6 +96,11 @@ properties: description: A port node pointing to the HDMI-TX port node. + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: + A port node pointing to the DPI port node (e.g. DSI or LVDS transceiver). + "#address-cells": const: 1 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/bridge/toshiba,tc358762.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml index 81ca3cbc7abe..6c1de0b21722 100644 --- a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml @@ -21,6 +21,9 @@ properties: maxItems: 1 description: virtual channel number of a DSI peripheral + reset-gpios: + maxItems: 1 + vddc-supply: description: Regulator for 1.2V internal core power. 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/boe,tv101wum-nl6.yaml b/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml index aed55608ebf6..906ef62709b8 100644 --- a/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml +++ b/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml @@ -32,6 +32,10 @@ properties: - innolux,hj110iz-01a # STARRY 2081101QFH032011-53G 10.1" WUXGA TFT LCD panel - starry,2081101qfh032011-53g + # STARRY himax83102-j02 10.51" WUXGA TFT LCD panel + - starry,himax83102-j02 + # STARRY ili9882t 10.51" WUXGA TFT LCD panel + - starry,ili9882t reg: description: the virtual channel number of a DSI peripheral diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 733e47da36e8..1d4936fc5182 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 @@ -284,6 +286,8 @@ properties: - rocktech,rk101ii01d-ct # Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel - rocktech,rk070er9427 + # Rocktech Display Ltd. RK043FN48H 4.3" 480x272 LCD-TFT panel + - rocktech,rk043fn48h # Samsung 13.3" FHD (1920x1080 pixels) eDP AMOLED panel - samsung,atna33xc20 # Samsung 12.2" (2560x1600 pixels) 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 ---------- - <uint> - Unsigned integer without defining the maximum value. -- <str> - String excluding any above defined reserved characters or whitespace. +- <keystr> - String excluding any above defined reserved characters or whitespace. +- <valstr> - String. Mandatory fully standardised keys --------------------------------- -- drm-driver: <str> +- drm-driver: <valstr> 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: <aaaa:bb.cc.d> 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-<str>: <uint> ns +Utilization +^^^^^^^^^^^ + +- drm-engine-<keystr>: <uint> 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-<str>: <uint> +- drm-engine-capacity-<keystr>: <uint> Engine identifier string must be the same as the one specified in the -drm-engine-<str> tag and shall contain a greater than zero number in case the +drm-engine-<keystr> 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-<str>: <uint> [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-<str> <uint> +- drm-cycles-<keystr>: <uint> Engine identifier string must be the same as the one specified in the -drm-engine-<str> tag and shall contain the number of busy cycles for the given +drm-engine-<keystr> 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-<str> <uint> [Hz|MHz|KHz] +- drm-maxfreq-<keystr>: <uint> [Hz|MHz|KHz] Engine identifier string must be the same as the one specified in the -drm-engine-<str> tag and shall contain the maximum frequency for the given -engine. Taken together with drm-cycles-<str>, this can be used to calculate -percentage utilization of the engine, whereas drm-engine-<str> only reflects +drm-engine-<keystr> tag and shall contain the maximum frequency for the given +engine. Taken together with drm-cycles-<keystr>, this can be used to calculate +percentage utilization of the engine, whereas drm-engine-<keystr> only reflects time active without considering what frequency the engine is operating as a percentage of it's maximum frequency. +Memory +^^^^^^ + +- drm-memory-<region>: <uint> [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-<region>: <uint> [KiB|MiB] + +The total size of buffers that are shared with another file (ie. have more +than a single handle). + +- drm-total-<region>: <uint> [KiB|MiB] + +The total size of buffers that including shared and private memory. + +- drm-resident-<region>: <uint> [KiB|MiB] + +The total size of buffers that are resident in the specified region. + +- drm-purgeable-<region>: <uint> [KiB|MiB] + +The total size of buffers that are purgeable. + +- drm-active-<region>: <uint> [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/MAINTAINERS b/MAINTAINERS index b344e1318ac3..4a53d061eebd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6981,8 +6981,7 @@ F: Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.yaml F: Documentation/devicetree/bindings/display/bridge/renesas,lvds.yaml F: Documentation/devicetree/bindings/display/renesas,du.yaml -F: drivers/gpu/drm/rcar-du/ -F: drivers/gpu/drm/shmobile/ +F: drivers/gpu/drm/renesas/ F: include/linux/platform_data/shmob_drm.h DRM DRIVERS FOR ROCKCHIP @@ -17388,6 +17387,8 @@ F: include/dt-bindings/clock/qcom,* QUALCOMM CLOUD AI (QAIC) DRIVER M: Jeffrey Hugo <quic_jhugo@quicinc.com> +R: Carl Vanderlip <quic_carlv@quicinc.com> +R: Pranjal Ramajor Asha Kanojiya <quic_pkanojiy@quicinc.com> L: linux-arm-msm@vger.kernel.org L: dri-devel@lists.freedesktop.org S: Supported diff --git a/drivers/accel/habanalabs/common/command_buffer.c b/drivers/accel/habanalabs/common/command_buffer.c index 6e09f48750a0..08f7aee42624 100644 --- a/drivers/accel/habanalabs/common/command_buffer.c +++ b/drivers/accel/habanalabs/common/command_buffer.c @@ -27,12 +27,6 @@ static int cb_map_mem(struct hl_ctx *ctx, struct hl_cb *cb) return -EINVAL; } - if (!hdev->mmu_enable) { - dev_err_ratelimited(hdev->dev, - "Cannot map CB because MMU is disabled\n"); - return -EINVAL; - } - if (cb->is_mmu_mapped) return 0; diff --git a/drivers/accel/habanalabs/common/command_submission.c b/drivers/accel/habanalabs/common/command_submission.c index af9d2e22c6e7..c23829dab97a 100644 --- a/drivers/accel/habanalabs/common/command_submission.c +++ b/drivers/accel/habanalabs/common/command_submission.c @@ -280,14 +280,8 @@ bool cs_needs_timeout(struct hl_cs *cs) static bool is_cb_patched(struct hl_device *hdev, struct hl_cs_job *job) { - /* - * Patched CB is created for external queues jobs, and for H/W queues - * jobs if the user CB was allocated by driver and MMU is disabled. - */ - return (job->queue_type == QUEUE_TYPE_EXT || - (job->queue_type == QUEUE_TYPE_HW && - job->is_kernel_allocated_cb && - !hdev->mmu_enable)); + /* Patched CB is created for external queues jobs */ + return (job->queue_type == QUEUE_TYPE_EXT); } /* @@ -363,14 +357,13 @@ static void hl_complete_job(struct hl_device *hdev, struct hl_cs_job *job) } } - /* For H/W queue jobs, if a user CB was allocated by driver and MMU is - * enabled, the user CB isn't released in cs_parser() and thus should be + /* For H/W queue jobs, if a user CB was allocated by driver, + * the user CB isn't released in cs_parser() and thus should be * released here. This is also true for INT queues jobs which were * allocated by driver. */ - if ((job->is_kernel_allocated_cb && - ((job->queue_type == QUEUE_TYPE_HW && hdev->mmu_enable) || - job->queue_type == QUEUE_TYPE_INT))) { + if (job->is_kernel_allocated_cb && + (job->queue_type == QUEUE_TYPE_HW || job->queue_type == QUEUE_TYPE_INT)) { atomic_dec(&job->user_cb->cs_cnt); hl_cb_put(job->user_cb); } @@ -804,12 +797,14 @@ out: static void cs_timedout(struct work_struct *work) { + struct hl_cs *cs = container_of(work, struct hl_cs, work_tdr.work); + bool skip_reset_on_timeout, device_reset = false; struct hl_device *hdev; u64 event_mask = 0x0; + uint timeout_sec; int rc; - struct hl_cs *cs = container_of(work, struct hl_cs, - work_tdr.work); - bool skip_reset_on_timeout = cs->skip_reset_on_timeout, device_reset = false; + + skip_reset_on_timeout = cs->skip_reset_on_timeout; rc = cs_get_unless_zero(cs); if (!rc) @@ -840,29 +835,31 @@ static void cs_timedout(struct work_struct *work) event_mask |= HL_NOTIFIER_EVENT_CS_TIMEOUT; } + timeout_sec = jiffies_to_msecs(hdev->timeout_jiffies) / 1000; + switch (cs->type) { case CS_TYPE_SIGNAL: dev_err(hdev->dev, - "Signal command submission %llu has not finished in time!\n", - cs->sequence); + "Signal command submission %llu has not finished in %u seconds!\n", + cs->sequence, timeout_sec); break; case CS_TYPE_WAIT: dev_err(hdev->dev, - "Wait command submission %llu has not finished in time!\n", - cs->sequence); + "Wait command submission %llu has not finished in %u seconds!\n", + cs->sequence, timeout_sec); break; case CS_TYPE_COLLECTIVE_WAIT: dev_err(hdev->dev, - "Collective Wait command submission %llu has not finished in time!\n", - cs->sequence); + "Collective Wait command submission %llu has not finished in %u seconds!\n", + cs->sequence, timeout_sec); break; default: dev_err(hdev->dev, - "Command submission %llu has not finished in time!\n", - cs->sequence); + "Command submission %llu has not finished in %u seconds!\n", + cs->sequence, timeout_sec); break; } @@ -1139,11 +1136,10 @@ static void force_complete_cs(struct hl_device *hdev) spin_unlock(&hdev->cs_mirror_lock); } -void hl_abort_waitings_for_completion(struct hl_device *hdev) +void hl_abort_waiting_for_cs_completions(struct hl_device *hdev) { force_complete_cs(hdev); force_complete_multi_cs(hdev); - hl_release_pending_user_interrupts(hdev); } static void job_wq_completion(struct work_struct *work) @@ -1948,8 +1944,7 @@ static int cs_ioctl_signal_wait_create_jobs(struct hl_device *hdev, else cb_size = hdev->asic_funcs->get_signal_cb_size(hdev); - cb = hl_cb_kernel_create(hdev, cb_size, - q_type == QUEUE_TYPE_HW && hdev->mmu_enable); + cb = hl_cb_kernel_create(hdev, cb_size, q_type == QUEUE_TYPE_HW); if (!cb) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&cntr->out_of_mem_drop_cnt); @@ -2152,7 +2147,7 @@ static int cs_ioctl_unreserve_signals(struct hl_fpriv *hpriv, u32 handle_id) hdev->asic_funcs->hw_queues_unlock(hdev); rc = -EINVAL; - goto out; + goto out_unlock; } /* @@ -2167,15 +2162,21 @@ static int cs_ioctl_unreserve_signals(struct hl_fpriv *hpriv, u32 handle_id) /* Release the id and free allocated memory of the handle */ idr_remove(&mgr->handles, handle_id); + + /* unlock before calling ctx_put, where we might sleep */ + spin_unlock(&mgr->lock); hl_ctx_put(encaps_sig_hdl->ctx); kfree(encaps_sig_hdl); + goto out; } else { rc = -EINVAL; dev_err(hdev->dev, "failed to unreserve signals, cannot find handler\n"); } -out: + +out_unlock: spin_unlock(&mgr->lock); +out: return rc; } diff --git a/drivers/accel/habanalabs/common/debugfs.c b/drivers/accel/habanalabs/common/debugfs.c index 22dd17c077c0..9e84a47a21dc 100644 --- a/drivers/accel/habanalabs/common/debugfs.c +++ b/drivers/accel/habanalabs/common/debugfs.c @@ -255,9 +255,6 @@ static int vm_show(struct seq_file *s, void *data) u64 j; int i; - if (!dev_entry->hdev->mmu_enable) - return 0; - mutex_lock(&dev_entry->ctx_mem_hash_mutex); list_for_each_entry(ctx, &dev_entry->ctx_mem_hash_list, debugfs_list) { @@ -436,9 +433,6 @@ static int mmu_show(struct seq_file *s, void *data) u64 virt_addr = dev_entry->mmu_addr, phys_addr; int i; - if (!hdev->mmu_enable) - return 0; - if (dev_entry->mmu_asid == HL_KERNEL_ASID_ID) ctx = hdev->kernel_ctx; else @@ -496,9 +490,6 @@ static ssize_t mmu_asid_va_write(struct file *file, const char __user *buf, char *c; ssize_t rc; - if (!hdev->mmu_enable) - return count; - if (count > sizeof(kbuf) - 1) goto err; if (copy_from_user(kbuf, buf, count)) @@ -535,9 +526,6 @@ static int mmu_ack_error(struct seq_file *s, void *data) struct hl_device *hdev = dev_entry->hdev; int rc; - if (!hdev->mmu_enable) - return 0; - if (!dev_entry->mmu_cap_mask) { dev_err(hdev->dev, "mmu_cap_mask is not set\n"); goto err; @@ -563,9 +551,6 @@ static ssize_t mmu_ack_error_value_write(struct file *file, char kbuf[MMU_KBUF_SIZE]; ssize_t rc; - if (!hdev->mmu_enable) - return count; - if (count > sizeof(kbuf) - 1) goto err; @@ -661,9 +646,6 @@ static bool hl_is_device_va(struct hl_device *hdev, u64 addr) { struct asic_fixed_properties *prop = &hdev->asic_prop; - if (!hdev->mmu_enable) - goto out; - if (prop->dram_supports_virtual_memory && (addr >= prop->dmmu.start_addr && addr < prop->dmmu.end_addr)) return true; @@ -675,7 +657,7 @@ static bool hl_is_device_va(struct hl_device *hdev, u64 addr) if (addr >= prop->pmmu_huge.start_addr && addr < prop->pmmu_huge.end_addr) return true; -out: + return false; } @@ -685,9 +667,6 @@ static bool hl_is_device_internal_memory_va(struct hl_device *hdev, u64 addr, struct asic_fixed_properties *prop = &hdev->asic_prop; u64 dram_start_addr, dram_end_addr; - if (!hdev->mmu_enable) - return false; - if (prop->dram_supports_virtual_memory) { dram_start_addr = prop->dmmu.start_addr; dram_end_addr = prop->dmmu.end_addr; @@ -1756,17 +1735,15 @@ static void add_files_to_device(struct hl_device *hdev, struct hl_dbg_device_ent } } -void hl_debugfs_add_device(struct hl_device *hdev) +int hl_debugfs_device_init(struct hl_device *hdev) { struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs; int count = ARRAY_SIZE(hl_debugfs_list); dev_entry->hdev = hdev; - dev_entry->entry_arr = kmalloc_array(count, - sizeof(struct hl_debugfs_entry), - GFP_KERNEL); + dev_entry->entry_arr = kmalloc_array(count, sizeof(struct hl_debugfs_entry), GFP_KERNEL); if (!dev_entry->entry_arr) - return; + return -ENOMEM; dev_entry->data_dma_blob_desc.size = 0; dev_entry->data_dma_blob_desc.data = NULL; @@ -1787,21 +1764,14 @@ void hl_debugfs_add_device(struct hl_device *hdev) spin_lock_init(&dev_entry->userptr_spinlock); mutex_init(&dev_entry->ctx_mem_hash_mutex); - dev_entry->root = debugfs_create_dir(dev_name(hdev->dev), - hl_debug_root); - - add_files_to_device(hdev, dev_entry, dev_entry->root); - if (!hdev->asic_prop.fw_security_enabled) - add_secured_nodes(dev_entry, dev_entry->root); + return 0; } -void hl_debugfs_remove_device(struct hl_device *hdev) +void hl_debugfs_device_fini(struct hl_device *hdev) { struct hl_dbg_device_entry *entry = &hdev->hl_debugfs; int i; - debugfs_remove_recursive(entry->root); - mutex_destroy(&entry->ctx_mem_hash_mutex); mutex_destroy(&entry->file_mutex); @@ -1814,6 +1784,24 @@ void hl_debugfs_remove_device(struct hl_device *hdev) kfree(entry->entry_arr); } +void hl_debugfs_add_device(struct hl_device *hdev) +{ + struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs; + + dev_entry->root = debugfs_create_dir(dev_name(hdev->dev), hl_debug_root); + + add_files_to_device(hdev, dev_entry, dev_entry->root); + if (!hdev->asic_prop.fw_security_enabled) + add_secured_nodes(dev_entry, dev_entry->root); +} + +void hl_debugfs_remove_device(struct hl_device *hdev) +{ + struct hl_dbg_device_entry *entry = &hdev->hl_debugfs; + + debugfs_remove_recursive(entry->root); +} + void hl_debugfs_add_file(struct hl_fpriv *hpriv) { struct hl_dbg_device_entry *dev_entry = &hpriv->hdev->hl_debugfs; diff --git a/drivers/accel/habanalabs/common/device.c b/drivers/accel/habanalabs/common/device.c index fabfc501ef54..b97339d1f7c6 100644 --- a/drivers/accel/habanalabs/common/device.c +++ b/drivers/accel/habanalabs/common/device.c @@ -674,7 +674,7 @@ static int device_init_cdev(struct hl_device *hdev, struct class *class, return 0; } -static int device_cdev_sysfs_add(struct hl_device *hdev) +static int cdev_sysfs_debugfs_add(struct hl_device *hdev) { int rc; @@ -699,7 +699,9 @@ static int device_cdev_sysfs_add(struct hl_device *hdev) goto delete_ctrl_cdev_device; } - hdev->cdev_sysfs_created = true; + hl_debugfs_add_device(hdev); + + hdev->cdev_sysfs_debugfs_created = true; return 0; @@ -710,11 +712,12 @@ delete_cdev_device: return rc; } -static void device_cdev_sysfs_del(struct hl_device *hdev) +static void cdev_sysfs_debugfs_remove(struct hl_device *hdev) { - if (!hdev->cdev_sysfs_created) + if (!hdev->cdev_sysfs_debugfs_created) goto put_devices; + hl_debugfs_remove_device(hdev); hl_sysfs_fini(hdev); cdev_device_del(&hdev->cdev_ctrl, hdev->dev_ctrl); cdev_device_del(&hdev->cdev, hdev->dev); @@ -981,6 +984,18 @@ static void device_early_fini(struct hl_device *hdev) hdev->asic_funcs->early_fini(hdev); } +static bool is_pci_link_healthy(struct hl_device *hdev) +{ + u16 vendor_id; + + if (!hdev->pdev) + return false; + + pci_read_config_word(hdev->pdev, PCI_VENDOR_ID, &vendor_id); + + return (vendor_id == PCI_VENDOR_ID_HABANALABS); +} + static void hl_device_heartbeat(struct work_struct *work) { struct hl_device *hdev = container_of(work, struct hl_device, @@ -995,7 +1010,8 @@ static void hl_device_heartbeat(struct work_struct *work) goto reschedule; if (hl_device_operational(hdev, NULL)) - dev_err(hdev->dev, "Device heartbeat failed!\n"); + dev_err(hdev->dev, "Device heartbeat failed! PCI link is %s\n", + is_pci_link_healthy(hdev) ? "healthy" : "broken"); info.err_type = HL_INFO_FW_HEARTBEAT_ERR; info.event_mask = &event_mask; @@ -1157,6 +1173,16 @@ static void take_release_locks(struct hl_device *hdev) mutex_unlock(&hdev->fpriv_ctrl_list_lock); } +static void hl_abort_waiting_for_completions(struct hl_device *hdev) +{ + hl_abort_waiting_for_cs_completions(hdev); + + /* Release all pending user interrupts, each pending user interrupt + * holds a reference to a user context. + */ + hl_release_pending_user_interrupts(hdev); +} + static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_reset, bool skip_wq_flush) { @@ -1176,10 +1202,7 @@ static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_r /* flush the MMU prefetch workqueue */ flush_workqueue(hdev->prefetch_wq); - /* Release all pending user interrupts, each pending user interrupt - * holds a reference to user context - */ - hl_release_pending_user_interrupts(hdev); + hl_abort_waiting_for_completions(hdev); } /* @@ -1921,7 +1944,7 @@ out: hl_ctx_put(ctx); - hl_abort_waitings_for_completion(hdev); + hl_abort_waiting_for_completions(hdev); return 0; @@ -2034,7 +2057,7 @@ out_err: int hl_device_init(struct hl_device *hdev) { int i, rc, cq_cnt, user_interrupt_cnt, cq_ready_cnt; - bool add_cdev_sysfs_on_err = false; + bool expose_interfaces_on_err = false; rc = create_cdev(hdev); if (rc) @@ -2150,16 +2173,22 @@ int hl_device_init(struct hl_device *hdev) hdev->device_release_watchdog_timeout_sec = HL_DEVICE_RELEASE_WATCHDOG_TIMEOUT_SEC; hdev->memory_scrub_val = MEM_SCRUB_DEFAULT_VAL; - hl_debugfs_add_device(hdev); - /* debugfs nodes are created in hl_ctx_init so it must be called after - * hl_debugfs_add_device. + rc = hl_debugfs_device_init(hdev); + if (rc) { + dev_err(hdev->dev, "failed to initialize debugfs entry structure\n"); + kfree(hdev->kernel_ctx); + goto mmu_fini; + } + + /* The debugfs entry structure is accessed in hl_ctx_init(), so it must be called after + * hl_debugfs_device_init(). */ rc = hl_ctx_init(hdev, hdev->kernel_ctx, true); if (rc) { dev_err(hdev->dev, "failed to initialize kernel context\n"); kfree(hdev->kernel_ctx); - goto remove_device_from_debugfs; + goto debugfs_device_fini; } rc = hl_cb_pool_init(hdev); @@ -2175,11 +2204,10 @@ int hl_device_init(struct hl_device *hdev) } /* - * From this point, override rc (=0) in case of an error to allow - * debugging (by adding char devices and create sysfs nodes as part of - * the error flow). + * From this point, override rc (=0) in case of an error to allow debugging + * (by adding char devices and creating sysfs/debugfs files as part of the error flow). */ - add_cdev_sysfs_on_err = true; + expose_interfaces_on_err = true; /* Device is now enabled as part of the initialization requires * communication with the device firmware to get information that @@ -2221,15 +2249,13 @@ int hl_device_init(struct hl_device *hdev) } /* - * Expose devices and sysfs nodes to user. - * From here there is no need to add char devices and create sysfs nodes - * in case of an error. + * Expose devices and sysfs/debugfs files to user. + * From here there is no need to expose them in case of an error. */ - add_cdev_sysfs_on_err = false; - rc = device_cdev_sysfs_add(hdev); + expose_interfaces_on_err = false; + rc = cdev_sysfs_debugfs_add(hdev); if (rc) { - dev_err(hdev->dev, - "Failed to add char devices and sysfs nodes\n"); + dev_err(hdev->dev, "Failed to add char devices and sysfs/debugfs files\n"); rc = 0; goto out_disabled; } @@ -2275,8 +2301,8 @@ release_ctx: if (hl_ctx_put(hdev->kernel_ctx) != 1) dev_err(hdev->dev, "kernel ctx is still alive on initialization failure\n"); -remove_device_from_debugfs: - hl_debugfs_remove_device(hdev); +debugfs_device_fini: + hl_debugfs_device_fini(hdev); mmu_fini: hl_mmu_fini(hdev); eq_fini: @@ -2300,15 +2326,11 @@ free_dev: put_device(hdev->dev); out_disabled: hdev->disabled = true; - if (add_cdev_sysfs_on_err) - device_cdev_sysfs_add(hdev); - if (hdev->pdev) - dev_err(&hdev->pdev->dev, - "Failed to initialize hl%d. Device %s is NOT usable !\n", - hdev->cdev_idx, dev_name(&(hdev)->pdev->dev)); - else - pr_err("Failed to initialize hl%d. Device %s is NOT usable !\n", - hdev->cdev_idx, dev_name(&(hdev)->pdev->dev)); + if (expose_interfaces_on_err) + cdev_sysfs_debugfs_add(hdev); + dev_err(&hdev->pdev->dev, + "Failed to initialize hl%d. Device %s is NOT usable !\n", + hdev->cdev_idx, dev_name(&hdev->pdev->dev)); return rc; } @@ -2427,8 +2449,6 @@ void hl_device_fini(struct hl_device *hdev) if ((hdev->kernel_ctx) && (hl_ctx_put(hdev->kernel_ctx) != 1)) dev_err(hdev->dev, "kernel ctx is still alive\n"); - hl_debugfs_remove_device(hdev); - hl_dec_fini(hdev); hl_vm_fini(hdev); @@ -2453,8 +2473,10 @@ void hl_device_fini(struct hl_device *hdev) device_early_fini(hdev); - /* Hide devices and sysfs nodes from user */ - device_cdev_sysfs_del(hdev); + /* Hide devices and sysfs/debugfs files from user */ + cdev_sysfs_debugfs_remove(hdev); + + hl_debugfs_device_fini(hdev); pr_info("removed device successfully\n"); } @@ -2667,3 +2689,11 @@ void hl_handle_fw_err(struct hl_device *hdev, struct hl_info_fw_err_info *info) if (info->event_mask) *info->event_mask |= HL_NOTIFIER_EVENT_CRITICL_FW_ERR; } + +void hl_enable_err_info_capture(struct hl_error_info *captured_err_info) +{ + vfree(captured_err_info->page_fault_info.user_mappings); + memset(captured_err_info, 0, sizeof(struct hl_error_info)); + atomic_set(&captured_err_info->cs_timeout.write_enable, 1); + captured_err_info->undef_opcode.write_enable = true; +} diff --git a/drivers/accel/habanalabs/common/firmware_if.c b/drivers/accel/habanalabs/common/firmware_if.c index 59f61ec66445..acbc1a6b5cb1 100644 --- a/drivers/accel/habanalabs/common/firmware_if.c +++ b/drivers/accel/habanalabs/common/firmware_if.c @@ -71,38 +71,124 @@ free_fw_ver: return NULL; } -static int hl_get_preboot_major_minor(struct hl_device *hdev, char *preboot_ver) +/** + * extract_u32_until_given_char() - given a string of the format "<u32><char>*", extract the u32. + * @str: the given string + * @ver_num: the pointer to the extracted u32 to be returned to the caller. + * @given_char: the given char at the end of the u32 in the string + * + * Return: Upon success, return a pointer to the given_char in the string. Upon failure, return NULL + */ +static char *extract_u32_until_given_char(char *str, u32 *ver_num, char given_char) { - char major[8], minor[8], *first_dot, *second_dot; - int rc; + char num_str[8] = {}, *ch; - first_dot = strnstr(preboot_ver, ".", 10); - if (first_dot) { - strscpy(major, preboot_ver, first_dot - preboot_ver + 1); - rc = kstrtou32(major, 10, &hdev->fw_major_version); - } else { - rc = -EINVAL; + ch = strchrnul(str, given_char); + if (*ch == '\0' || ch == str || ch - str >= sizeof(num_str)) + return NULL; + + memcpy(num_str, str, ch - str); + if (kstrtou32(num_str, 10, ver_num)) + return NULL; + return ch; +} + +/** + * hl_get_sw_major_minor_subminor() - extract the FW's SW version major, minor, sub-minor + * from the version string + * @hdev: pointer to the hl_device + * @fw_str: the FW's version string + * + * The extracted version is set in the hdev fields: fw_sw_{major/minor/sub_minor}_ver. + * + * fw_str is expected to have one of two possible formats, examples: + * 1) 'Preboot version hl-gaudi2-1.9.0-fw-42.0.1-sec-3' + * 2) 'Preboot version hl-gaudi2-1.9.0-rc-fw-42.0.1-sec-3' + * In those examples, the SW major,minor,subminor are correspondingly: 1,9,0. + * + * Return: 0 for success or a negative error code for failure. + */ +static int hl_get_sw_major_minor_subminor(struct hl_device *hdev, const char *fw_str) +{ + char *end, *start; + + end = strnstr(fw_str, "-rc-", VERSION_MAX_LEN); + if (end == fw_str) + return -EINVAL; + + if (!end) + end = strnstr(fw_str, "-fw-", VERSION_MAX_LEN); + + if (end == fw_str) + return -EINVAL; + + if (!end) + return -EINVAL; + + for (start = end - 1; start != fw_str; start--) { + if (*start == '-') + break; } - if (rc) { - dev_err(hdev->dev, "Error %d parsing preboot major version\n", rc); - return rc; + if (start == fw_str) + return -EINVAL; + + /* start/end point each to the starting and ending hyphen of the sw version e.g. -1.9.0- */ + start++; + start = extract_u32_until_given_char(start, &hdev->fw_sw_major_ver, '.'); + if (!start) + goto err_zero_ver; + + start++; + start = extract_u32_until_given_char(start, &hdev->fw_sw_minor_ver, '.'); + if (!start) + goto err_zero_ver; + + start++; + start = extract_u32_until_given_char(start, &hdev->fw_sw_sub_minor_ver, '-'); + if (!start) + goto err_zero_ver; + + return 0; + +err_zero_ver: + hdev->fw_sw_major_ver = 0; + hdev->fw_sw_minor_ver = 0; + hdev->fw_sw_sub_minor_ver = 0; + return -EINVAL; +} + +/** + * hl_get_preboot_major_minor() - extract the FW's version major, minor from the version string. + * @hdev: pointer to the hl_device + * @preboot_ver: the FW's version string + * + * preboot_ver is expected to be the format of <major>.<minor>.<sub minor>*, e.g: 42.0.1-sec-3 + * The extracted version is set in the hdev fields: fw_inner_{major/minor}_ver. + * + * Return: 0 on success, negative error code for failure. + */ +static int hl_get_preboot_major_minor(struct hl_device *hdev, char *preboot_ver) +{ + preboot_ver = extract_u32_until_given_char(preboot_ver, &hdev->fw_inner_major_ver, '.'); + if (!preboot_ver) { + dev_err(hdev->dev, "Error parsing preboot major version\n"); + goto err_zero_ver; } - /* skip the first dot */ - first_dot++; + preboot_ver++; - second_dot = strnstr(first_dot, ".", 10); - if (second_dot) { - strscpy(minor, first_dot, second_dot - first_dot + 1); - rc = kstrtou32(minor, 10, &hdev->fw_minor_version); - } else { - rc = -EINVAL; + preboot_ver = extract_u32_until_given_char(preboot_ver, &hdev->fw_inner_minor_ver, '.'); + if (!preboot_ver) { + dev_err(hdev->dev, "Error parsing preboot minor version\n"); + goto err_zero_ver; } + return 0; - if (rc) - dev_err(hdev->dev, "Error %d parsing preboot minor version\n", rc); - return rc; +err_zero_ver: + hdev->fw_inner_major_ver = 0; + hdev->fw_inner_minor_ver = 0; + return -EINVAL; } static int hl_request_fw(struct hl_device *hdev, @@ -505,6 +591,20 @@ void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size, size); } +int hl_fw_send_soft_reset(struct hl_device *hdev) +{ + struct cpucp_packet pkt; + int rc; + + memset(&pkt, 0, sizeof(pkt)); + pkt.ctl = cpu_to_le32(CPUCP_PACKET_SOFT_RESET << CPUCP_PKT_CTL_OPCODE_SHIFT); + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL); + if (rc) + dev_err(hdev->dev, "failed to send soft-reset msg (err = %d)\n", rc); + + return rc; +} + int hl_fw_send_device_activity(struct hl_device *hdev, bool open) { struct cpucp_packet pkt; @@ -1268,8 +1368,10 @@ void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev) void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev) { - struct static_fw_load_mgr *static_loader = - &hdev->fw_loader.static_loader; + struct fw_load_mgr *fw_loader = &hdev->fw_loader; + u32 status, cpu_boot_status_reg, cpu_timeout; + struct static_fw_load_mgr *static_loader; + struct pre_fw_load_props *pre_fw_load; int rc; if (hdev->device_cpu_is_halted) @@ -1277,12 +1379,28 @@ void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev) /* Stop device CPU to make sure nothing bad happens */ if (hdev->asic_prop.dynamic_fw_load) { + pre_fw_load = &fw_loader->pre_fw_load; + cpu_timeout = fw_loader->cpu_timeout; + cpu_boot_status_reg = pre_fw_load->cpu_boot_status_reg; + rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, - COMMS_GOTO_WFE, 0, false, - hdev->fw_loader.cpu_timeout); - if (rc) + COMMS_GOTO_WFE, 0, false, cpu_timeout); + if (rc) { dev_err(hdev->dev, "Failed sending COMMS_GOTO_WFE\n"); + } else { + rc = hl_poll_timeout( + hdev, + cpu_boot_status_reg, + status, + status == CPU_BOOT_STATUS_IN_WFE, + hdev->fw_poll_interval_usec, + cpu_timeout); + if (rc) + dev_err(hdev->dev, "Current status=%u. Timed-out updating to WFE\n", + status); + } } else { + static_loader = &hdev->fw_loader.static_loader; WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_GOTO_WFE); msleep(static_loader->cpu_reset_wait_msec); @@ -2151,6 +2269,7 @@ static int hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev, struct asic_fixed_properties *prop = &hdev->asic_prop; char *preboot_ver, *boot_ver; char btl_ver[32]; + int rc; switch (fwc) { case FW_COMP_BOOT_FIT: @@ -2164,20 +2283,20 @@ static int hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev, break; case FW_COMP_PREBOOT: strscpy(prop->preboot_ver, fw_version, VERSION_MAX_LEN); - preboot_ver = strnstr(prop->preboot_ver, "Preboot", - VERSION_MAX_LEN); + preboot_ver = strnstr(prop->preboot_ver, "Preboot", VERSION_MAX_LEN); + dev_info(hdev->dev, "preboot full version: '%s'\n", preboot_ver); + if (preboot_ver && preboot_ver != prop->preboot_ver) { strscpy(btl_ver, prop->preboot_ver, min((int) (preboot_ver - prop->preboot_ver), 31)); dev_info(hdev->dev, "%s\n", btl_ver); } + rc = hl_get_sw_major_minor_subminor(hdev, preboot_ver); + if (rc) + return rc; preboot_ver = extract_fw_ver_from_str(prop->preboot_ver); if (preboot_ver) { - int rc; - - dev_info(hdev->dev, "preboot version %s\n", preboot_ver); - rc = hl_get_preboot_major_minor(hdev, preboot_ver); kfree(preboot_ver); if (rc) @@ -2367,16 +2486,6 @@ static int hl_fw_dynamic_load_image(struct hl_device *hdev, if (rc) goto release_fw; - /* update state according to boot stage */ - if (cur_fwc == FW_COMP_BOOT_FIT) { - struct cpu_dyn_regs *dyn_regs; - - dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; - hl_fw_boot_fit_update_state(hdev, - le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), - le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); - } - /* copy boot fit to space allocated by FW */ rc = hl_fw_dynamic_copy_image(hdev, fw, fw_loader); if (rc) @@ -2679,6 +2788,14 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, goto protocol_err; } + rc = hl_fw_dynamic_wait_for_boot_fit_active(hdev, fw_loader); + if (rc) + goto protocol_err; + + hl_fw_boot_fit_update_state(hdev, + le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), + le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); + /* * when testing FW load (without Linux) on PLDM we don't want to * wait until boot fit is active as it may take several hours. @@ -2688,10 +2805,6 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, if (hdev->pldm && !(hdev->fw_components & FW_TYPE_LINUX)) return 0; - rc = hl_fw_dynamic_wait_for_boot_fit_active(hdev, fw_loader); - if (rc) - goto protocol_err; - /* Enable DRAM scrambling before Linux boot and after successful * UBoot */ @@ -2725,7 +2838,8 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, if (rc) goto protocol_err; - hl_fw_linux_update_state(hdev, le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), + hl_fw_linux_update_state(hdev, + le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); hl_fw_dynamic_update_linux_interrupt_if(hdev); diff --git a/drivers/accel/habanalabs/common/habanalabs.h b/drivers/accel/habanalabs/common/habanalabs.h index eaae69a9f817..d92ba2e30e31 100644 --- a/drivers/accel/habanalabs/common/habanalabs.h +++ b/drivers/accel/habanalabs/common/habanalabs.h @@ -36,6 +36,8 @@ struct hl_device; struct hl_fpriv; +#define PCI_VENDOR_ID_HABANALABS 0x1da3 + /* Use upper bits of mmap offset to store habana driver specific information. * bits[63:59] - Encode mmap type * bits[45:0] - mmap offset value @@ -113,18 +115,6 @@ enum hl_mmu_page_table_location { MMU_NUM_PGT_LOCATIONS /* num of PGT locations */ }; -/** - * enum hl_mmu_enablement - what mmu modules to enable - * @MMU_EN_NONE: mmu disabled. - * @MMU_EN_ALL: enable all. - * @MMU_EN_PMMU_ONLY: Enable only the PMMU leaving the DMMU disabled. - */ -enum hl_mmu_enablement { - MMU_EN_NONE = 0, - MMU_EN_ALL = 1, - MMU_EN_PMMU_ONLY = 3, /* N/A for Goya/Gaudi */ -}; - /* * HL_RSVD_SOBS 'sync stream' reserved sync objects per QMAN stream * HL_RSVD_MONS 'sync stream' reserved monitors per QMAN stream @@ -2568,12 +2558,7 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val); ktime_t __timeout; \ u32 __elbi_read; \ int __rc = 0; \ - if (hdev->pdev) \ - __timeout = ktime_add_us(ktime_get(), timeout_us); \ - else \ - __timeout = ktime_add_us(ktime_get(),\ - min((u64)(timeout_us * 10), \ - (u64) HL_SIM_MAX_TIMEOUT_US)); \ + __timeout = ktime_add_us(ktime_get(), timeout_us); \ might_sleep_if(sleep_us); \ for (;;) { \ if (elbi) { \ @@ -2625,13 +2610,7 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val); u8 __arr_idx; \ int __rc = 0; \ \ - if (hdev->pdev) \ - __timeout = ktime_add_us(ktime_get(), timeout_us); \ - else \ - __timeout = ktime_add_us(ktime_get(),\ - min(((u64)timeout_us * 10), \ - (u64) HL_SIM_MAX_TIMEOUT_US)); \ - \ + __timeout = ktime_add_us(ktime_get(), timeout_us); \ might_sleep_if(sleep_us); \ if (arr_size >= 64) \ __rc = -EINVAL; \ @@ -2689,12 +2668,8 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val); mem_written_by_device) \ ({ \ ktime_t __timeout; \ - if (hdev->pdev) \ - __timeout = ktime_add_us(ktime_get(), timeout_us); \ - else \ - __timeout = ktime_add_us(ktime_get(),\ - min((u64)(timeout_us * 100), \ - (u64) HL_SIM_MAX_TIMEOUT_US)); \ + \ + __timeout = ktime_add_us(ktime_get(), timeout_us); \ might_sleep_if(sleep_us); \ for (;;) { \ /* Verify we read updates done by other cores or by device */ \ @@ -3225,8 +3200,11 @@ struct hl_reset_info { * @captured_err_info: holds information about errors. * @reset_info: holds current device reset information. * @stream_master_qid_arr: pointer to array with QIDs of master streams. - * @fw_major_version: major version of current loaded preboot. - * @fw_minor_version: minor version of current loaded preboot. + * @fw_inner_major_ver: the major of current loaded preboot inner version. + * @fw_inner_minor_ver: the minor of current loaded preboot inner version. + * @fw_sw_major_ver: the major of current loaded preboot SW version. + * @fw_sw_minor_ver: the minor of current loaded preboot SW version. + * @fw_sw_sub_minor_ver: the sub-minor of current loaded preboot SW version. * @dram_used_mem: current DRAM memory consumption. * @memory_scrub_val: the value to which the dram will be scrubbed to using cb scrub_device_dram * @timeout_jiffies: device CS timeout value. @@ -3287,7 +3265,7 @@ struct hl_reset_info { * @in_debug: whether the device is in a state where the profiling/tracing infrastructure * can be used. This indication is needed because in some ASICs we need to do * specific operations to enable that infrastructure. - * @cdev_sysfs_created: were char devices and sysfs nodes created. + * @cdev_sysfs_debugfs_created: were char devices and sysfs/debugfs files created. * @stop_on_err: true if engines should stop on error. * @supports_sync_stream: is sync stream supported. * @sync_stream_queue_idx: helper index for sync stream queues initialization. @@ -3314,7 +3292,7 @@ struct hl_reset_info { * @nic_ports_mask: Controls which NIC ports are enabled. Used only for testing. * @fw_components: Controls which f/w components to load to the device. There are multiple f/w * stages and sometimes we want to stop at a certain stage. Used only for testing. - * @mmu_enable: Whether to enable or disable the device MMU(s). Used only for testing. + * @mmu_disable: Disable the device MMU(s). Used only for testing. * @cpu_queues_enable: Whether to enable queues communication vs. the f/w. Used only for testing. * @pldm: Whether we are running in Palladium environment. Used only for testing. * @hard_reset_on_fw_events: Whether to do device hard-reset when a fatal event is received from @@ -3412,8 +3390,11 @@ struct hl_device { struct hl_reset_info reset_info; u32 *stream_master_qid_arr; - u32 fw_major_version; - u32 fw_minor_version; + u32 fw_inner_major_ver; + u32 fw_inner_minor_ver; + u32 fw_sw_major_ver; + u32 fw_sw_minor_ver; + u32 fw_sw_sub_minor_ver; atomic64_t dram_used_mem; u64 memory_scrub_val; u64 timeout_jiffies; @@ -3451,7 +3432,7 @@ struct hl_device { u8 init_done; u8 device_cpu_disabled; u8 in_debug; - u8 cdev_sysfs_created; + u8 cdev_sysfs_debugfs_created; u8 stop_on_err; u8 supports_sync_stream; u8 sync_stream_queue_idx; @@ -3474,7 +3455,7 @@ struct hl_device { /* Parameters for bring-up to be upstreamed */ u64 nic_ports_mask; u64 fw_components; - u8 mmu_enable; + u8 mmu_disable; u8 cpu_queues_enable; u8 pldm; u8 hard_reset_on_fw_events; @@ -3547,9 +3528,15 @@ struct hl_ioctl_desc { hl_ioctl_t *func; }; -static inline bool hl_is_fw_ver_below_1_9(struct hl_device *hdev) +static inline bool hl_is_fw_sw_ver_below(struct hl_device *hdev, u32 fw_sw_major, u32 fw_sw_minor) { - return (hdev->fw_major_version < 42); + if (hdev->fw_sw_major_ver < fw_sw_major) + return true; + if (hdev->fw_sw_major_ver > fw_sw_major) + return false; + if (hdev->fw_sw_minor_ver < fw_sw_minor) + return true; + return false; } /* @@ -3813,8 +3800,6 @@ struct pgt_info *hl_mmu_hr_get_alloc_next_hop(struct hl_ctx *ctx, u64 curr_pte, bool *is_new_hop); int hl_mmu_hr_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr, struct hl_mmu_hop_info *hops, struct hl_hr_mmu_funcs *hr_func); -void hl_mmu_swap_out(struct hl_ctx *ctx); -void hl_mmu_swap_in(struct hl_ctx *ctx); int hl_mmu_if_set_funcs(struct hl_device *hdev); void hl_mmu_v1_set_funcs(struct hl_device *hdev, struct hl_mmu_funcs *mmu); void hl_mmu_v2_hr_set_funcs(struct hl_device *hdev, struct hl_mmu_funcs *mmu); @@ -3872,6 +3857,7 @@ int hl_fw_dram_replaced_row_get(struct hl_device *hdev, int hl_fw_dram_pending_row_get(struct hl_device *hdev, u32 *pend_rows_num); int hl_fw_cpucp_engine_core_asid_set(struct hl_device *hdev, u32 asid); int hl_fw_send_device_activity(struct hl_device *hdev, bool open); +int hl_fw_send_soft_reset(struct hl_device *hdev); int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3], bool is_wc[3]); int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data); @@ -3921,7 +3907,7 @@ void hl_dec_fini(struct hl_device *hdev); void hl_dec_ctx_fini(struct hl_ctx *ctx); void hl_release_pending_user_interrupts(struct hl_device *hdev); -void hl_abort_waitings_for_completion(struct hl_device *hdev); +void hl_abort_waiting_for_cs_completions(struct hl_device *hdev); int hl_cs_signal_sob_wraparound_handler(struct hl_device *hdev, u32 q_idx, struct hl_hw_sob **hw_sob, u32 count, bool encaps_sig); @@ -3958,11 +3944,14 @@ void hl_handle_page_fault(struct hl_device *hdev, u64 addr, u16 eng_id, bool is_ u64 *event_mask); void hl_handle_critical_hw_err(struct hl_device *hdev, u16 event_id, u64 *event_mask); void hl_handle_fw_err(struct hl_device *hdev, struct hl_info_fw_err_info *info); +void hl_enable_err_info_capture(struct hl_error_info *captured_err_info); #ifdef CONFIG_DEBUG_FS void hl_debugfs_init(void); void hl_debugfs_fini(void); +int hl_debugfs_device_init(struct hl_device *hdev); +void hl_debugfs_device_fini(struct hl_device *hdev); void hl_debugfs_add_device(struct hl_device *hdev); void hl_debugfs_remove_device(struct hl_device *hdev); void hl_debugfs_add_file(struct hl_fpriv *hpriv); diff --git a/drivers/accel/habanalabs/common/habanalabs_drv.c b/drivers/accel/habanalabs/common/habanalabs_drv.c index d9df64e75f33..7263e84c1a4d 100644 --- a/drivers/accel/habanalabs/common/habanalabs_drv.c +++ b/drivers/accel/habanalabs/common/habanalabs_drv.c @@ -13,6 +13,7 @@ #include <linux/pci.h> #include <linux/module.h> +#include <linux/vmalloc.h> #define CREATE_TRACE_POINTS #include <trace/events/habanalabs.h> @@ -54,8 +55,6 @@ module_param(boot_error_status_mask, ulong, 0444); MODULE_PARM_DESC(boot_error_status_mask, "Mask of the error status during device CPU boot (If bitX is cleared then error X is masked. Default all 1's)"); -#define PCI_VENDOR_ID_HABANALABS 0x1da3 - #define PCI_IDS_GOYA 0x0001 #define PCI_IDS_GAUDI 0x1000 #define PCI_IDS_GAUDI_SEC 0x1010 @@ -220,9 +219,7 @@ int hl_device_open(struct inode *inode, struct file *filp) hl_debugfs_add_file(hpriv); - memset(&hdev->captured_err_info, 0, sizeof(hdev->captured_err_info)); - atomic_set(&hdev->captured_err_info.cs_timeout.write_enable, 1); - hdev->captured_err_info.undef_opcode.write_enable = true; + hl_enable_err_info_capture(&hdev->captured_err_info); hdev->open_counter++; hdev->last_successful_open_jif = jiffies; @@ -307,7 +304,6 @@ static void set_driver_behavior_per_device(struct hl_device *hdev) { hdev->nic_ports_mask = 0; hdev->fw_components = FW_TYPE_ALL_TYPES; - hdev->mmu_enable = MMU_EN_ALL; hdev->cpu_queues_enable = 1; hdev->pldm = 0; hdev->hard_reset_on_fw_events = 1; @@ -382,7 +378,6 @@ static int fixup_device_params(struct hl_device *hdev) /* If CPU queues not enabled, no way to do heartbeat */ if (!hdev->cpu_queues_enable) hdev->heartbeat = 0; - fixup_device_params_per_asic(hdev, tmp_timeout); return 0; diff --git a/drivers/accel/habanalabs/common/habanalabs_ioctl.c b/drivers/accel/habanalabs/common/habanalabs_ioctl.c index 203ee857810c..6a45a92344e9 100644 --- a/drivers/accel/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/accel/habanalabs/common/habanalabs_ioctl.c @@ -62,7 +62,7 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args) hw_ip.device_id = hdev->asic_funcs->get_pci_id(hdev); hw_ip.sram_base_address = prop->sram_user_base_address; hw_ip.dram_base_address = - hdev->mmu_enable && prop->dram_supports_virtual_memory ? + prop->dram_supports_virtual_memory ? prop->dmmu.start_addr : prop->dram_user_base_address; hw_ip.tpc_enabled_mask = prop->tpc_enabled_mask & 0xFF; hw_ip.tpc_enabled_mask_ext = prop->tpc_enabled_mask; @@ -71,11 +71,8 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args) dram_available_size = prop->dram_size - dram_kmd_size; - if (hdev->mmu_enable == MMU_EN_ALL) - hw_ip.dram_size = DIV_ROUND_DOWN_ULL(dram_available_size, - prop->dram_page_size) * prop->dram_page_size; - else - hw_ip.dram_size = dram_available_size; + hw_ip.dram_size = DIV_ROUND_DOWN_ULL(dram_available_size, prop->dram_page_size) * + prop->dram_page_size; if (hw_ip.dram_size > PAGE_SIZE) hw_ip.dram_enabled = 1; @@ -842,15 +839,15 @@ static int hw_err_info(struct hl_fpriv *hpriv, struct hl_info_args *args) struct hw_err_info *info; int rc; - if ((!user_buf_size) || (!user_buf)) + if (!user_buf) return -EINVAL; - if (user_buf_size < sizeof(struct hl_info_hw_err_event)) - return -ENOMEM; - info = &hdev->captured_err_info.hw_err; if (!info->event_info_available) - return -ENOENT; + return 0; + + if (user_buf_size < sizeof(struct hl_info_hw_err_event)) + return -ENOMEM; rc = copy_to_user(user_buf, &info->event, sizeof(struct hl_info_hw_err_event)); return rc ? -EFAULT : 0; @@ -864,15 +861,15 @@ static int fw_err_info(struct hl_fpriv *hpriv, struct hl_info_args *args) struct fw_err_info *info; int rc; - if ((!user_buf_size) || (!user_buf)) + if (!user_buf) return -EINVAL; - if (user_buf_size < sizeof(struct hl_info_fw_err_event)) - return -ENOMEM; - info = &hdev->captured_err_info.fw_err; if (!info->event_info_available) - return -ENOENT; + return 0; + + if (user_buf_size < sizeof(struct hl_info_fw_err_event)) + return -ENOMEM; rc = copy_to_user(user_buf, &info->event, sizeof(struct hl_info_fw_err_event)); return rc ? -EFAULT : 0; @@ -1198,7 +1195,7 @@ static long _hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg, out_err: if (retcode) - dev_dbg(dev, "error in ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n", + dev_dbg_ratelimited(dev, "error in ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n", task_pid_nr(current), cmd, nr); if (kdata != stack_kdata) @@ -1222,7 +1219,7 @@ long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) if ((nr >= HL_COMMAND_START) && (nr < HL_COMMAND_END)) { ioctl = &hl_ioctls[nr]; } else { - dev_err(hdev->dev, "invalid ioctl: pid=%d, nr=0x%02x\n", + dev_dbg_ratelimited(hdev->dev, "invalid ioctl: pid=%d, nr=0x%02x\n", task_pid_nr(current), nr); return -ENOTTY; } @@ -1245,7 +1242,7 @@ long hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg) if (nr == _IOC_NR(HL_IOCTL_INFO)) { ioctl = &hl_ioctls_control[nr]; } else { - dev_err(hdev->dev_ctrl, "invalid ioctl: pid=%d, nr=0x%02x\n", + dev_dbg_ratelimited(hdev->dev_ctrl, "invalid ioctl: pid=%d, nr=0x%02x\n", task_pid_nr(current), nr); return -ENOTTY; } diff --git a/drivers/accel/habanalabs/common/irq.c b/drivers/accel/habanalabs/common/irq.c index c67895b1cdeb..b1010d206c2e 100644 --- a/drivers/accel/habanalabs/common/irq.c +++ b/drivers/accel/habanalabs/common/irq.c @@ -430,7 +430,7 @@ irqreturn_t hl_irq_handler_eq(int irq, void *arg) cur_eqe_index = FIELD_GET(EQ_CTL_INDEX_MASK, cur_eqe); if ((hdev->event_queue.check_eqe_index) && (((eq->prev_eqe_index + 1) & EQ_CTL_INDEX_MASK) != cur_eqe_index)) { - dev_dbg(hdev->dev, + dev_err(hdev->dev, "EQE %#x in queue is ready but index does not match %d!=%d", cur_eqe, ((eq->prev_eqe_index + 1) & EQ_CTL_INDEX_MASK), diff --git a/drivers/accel/habanalabs/common/memory.c b/drivers/accel/habanalabs/common/memory.c index a7b6a273ce21..4fc72a07d2f5 100644 --- a/drivers/accel/habanalabs/common/memory.c +++ b/drivers/accel/habanalabs/common/memory.c @@ -1034,30 +1034,6 @@ static void unmap_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, } } -static int get_paddr_from_handle(struct hl_ctx *ctx, struct hl_mem_in *args, - u64 *paddr) -{ - struct hl_device *hdev = ctx->hdev; - struct hl_vm *vm = &hdev->vm; - struct hl_vm_phys_pg_pack *phys_pg_pack; - u32 handle; - - handle = lower_32_bits(args->map_device.handle); - spin_lock(&vm->idr_lock); - phys_pg_pack = idr_find(&vm->phys_pg_pack_handles, handle); - if (!phys_pg_pack) { - spin_unlock(&vm->idr_lock); - dev_err(hdev->dev, "no match for handle %u\n", handle); - return -EINVAL; - } - - *paddr = phys_pg_pack->pages[0]; - - spin_unlock(&vm->idr_lock); - - return 0; -} - /** * map_device_va() - map the given memory. * @ctx: pointer to the context structure. @@ -2094,76 +2070,6 @@ err_free_dmabuf_wrapper: return rc; } -static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args) -{ - struct hl_device *hdev = hpriv->hdev; - u64 block_handle, device_addr = 0; - struct hl_ctx *ctx = hpriv->ctx; - u32 handle = 0, block_size; - int rc; - - switch (args->in.op) { - case HL_MEM_OP_ALLOC: - if (args->in.alloc.mem_size == 0) { - dev_err(hdev->dev, "alloc size must be larger than 0\n"); - rc = -EINVAL; - goto out; - } - - /* Force contiguous as there are no real MMU - * translations to overcome physical memory gaps - */ - args->in.flags |= HL_MEM_CONTIGUOUS; - rc = alloc_device_memory(ctx, &args->in, &handle); - - memset(args, 0, sizeof(*args)); - args->out.handle = (__u64) handle; - break; - - case HL_MEM_OP_FREE: - rc = free_device_memory(ctx, &args->in); - break; - - case HL_MEM_OP_MAP: - if (args->in.flags & HL_MEM_USERPTR) { - dev_err(hdev->dev, "Failed to map host memory when MMU is disabled\n"); - rc = -EPERM; - } else { - rc = get_paddr_from_handle(ctx, &args->in, &device_addr); - memset(args, 0, sizeof(*args)); - args->out.device_virt_addr = device_addr; - } - - break; - - case HL_MEM_OP_UNMAP: - rc = 0; - break; - - case HL_MEM_OP_MAP_BLOCK: - rc = map_block(hdev, args->in.map_block.block_addr, &block_handle, &block_size); - args->out.block_handle = block_handle; - args->out.block_size = block_size; - break; - - case HL_MEM_OP_EXPORT_DMABUF_FD: - dev_err(hdev->dev, "Failed to export dma-buf object when MMU is disabled\n"); - rc = -EPERM; - break; - - case HL_MEM_OP_TS_ALLOC: - rc = allocate_timestamps_buffers(hpriv, &args->in, &args->out.handle); - break; - default: - dev_err(hdev->dev, "Unknown opcode for memory IOCTL\n"); - rc = -EINVAL; - break; - } - -out: - return rc; -} - static void ts_buff_release(struct hl_mmap_mem_buf *buf) { struct hl_ts_buff *ts_buff = buf->private; @@ -2282,9 +2188,6 @@ int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data) return -EBUSY; } - if (!hdev->mmu_enable) - return mem_ioctl_no_mmu(hpriv, args); - switch (args->in.op) { case HL_MEM_OP_ALLOC: if (args->in.alloc.mem_size == 0) { @@ -2779,13 +2682,10 @@ int hl_vm_ctx_init(struct hl_ctx *ctx) atomic64_set(&ctx->dram_phys_mem, 0); /* - * - If MMU is enabled, init the ranges as usual. - * - If MMU is disabled, in case of host mapping, the returned address - * is the given one. * In case of DRAM mapping, the returned address is the physical * address of the memory related to the given handle. */ - if (!ctx->hdev->mmu_enable) + if (ctx->hdev->mmu_disable) return 0; dram_range_start = prop->dmmu.start_addr; @@ -2835,7 +2735,7 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx) struct hl_mem_in args; int i; - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return; hl_debugfs_remove_ctx_mem_hash(hdev, ctx); diff --git a/drivers/accel/habanalabs/common/mmu/mmu.c b/drivers/accel/habanalabs/common/mmu/mmu.c index f379e5b461a6..b2145716c605 100644 --- a/drivers/accel/habanalabs/common/mmu/mmu.c +++ b/drivers/accel/habanalabs/common/mmu/mmu.c @@ -44,7 +44,7 @@ int hl_mmu_init(struct hl_device *hdev) { int rc = -EOPNOTSUPP; - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return 0; mutex_init(&hdev->mmu_lock); @@ -82,7 +82,7 @@ fini_dr_mmu: */ void hl_mmu_fini(struct hl_device *hdev) { - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return; if (hdev->mmu_func[MMU_DR_PGT].fini != NULL) @@ -107,7 +107,7 @@ int hl_mmu_ctx_init(struct hl_ctx *ctx) struct hl_device *hdev = ctx->hdev; int rc = -EOPNOTSUPP; - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return 0; if (hdev->mmu_func[MMU_DR_PGT].ctx_init != NULL) { @@ -145,7 +145,7 @@ void hl_mmu_ctx_fini(struct hl_ctx *ctx) { struct hl_device *hdev = ctx->hdev; - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return; if (hdev->mmu_func[MMU_DR_PGT].ctx_fini != NULL) @@ -233,7 +233,7 @@ int hl_mmu_unmap_page(struct hl_ctx *ctx, u64 virt_addr, u32 page_size, bool flu u64 real_virt_addr; bool is_dram_addr; - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return 0; is_dram_addr = hl_is_dram_va(hdev, virt_addr); @@ -301,7 +301,7 @@ int hl_mmu_map_page(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr, u32 page_s bool is_dram_addr; - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return 0; is_dram_addr = hl_is_dram_va(hdev, virt_addr); @@ -472,46 +472,6 @@ int hl_mmu_unmap_contiguous(struct hl_ctx *ctx, u64 virt_addr, u32 size) return rc; } -/* - * hl_mmu_swap_out - marks all mapping of the given ctx as swapped out - * - * @ctx: pointer to the context structure - * - */ -void hl_mmu_swap_out(struct hl_ctx *ctx) -{ - struct hl_device *hdev = ctx->hdev; - - if (!hdev->mmu_enable) - return; - - if (hdev->mmu_func[MMU_DR_PGT].swap_out != NULL) - hdev->mmu_func[MMU_DR_PGT].swap_out(ctx); - - if (hdev->mmu_func[MMU_HR_PGT].swap_out != NULL) - hdev->mmu_func[MMU_HR_PGT].swap_out(ctx); -} - -/* - * hl_mmu_swap_in - marks all mapping of the given ctx as swapped in - * - * @ctx: pointer to the context structure - * - */ -void hl_mmu_swap_in(struct hl_ctx *ctx) -{ - struct hl_device *hdev = ctx->hdev; - - if (!hdev->mmu_enable) - return; - - if (hdev->mmu_func[MMU_DR_PGT].swap_in != NULL) - hdev->mmu_func[MMU_DR_PGT].swap_in(ctx); - - if (hdev->mmu_func[MMU_HR_PGT].swap_in != NULL) - hdev->mmu_func[MMU_HR_PGT].swap_in(ctx); -} - static void hl_mmu_pa_page_with_offset(struct hl_ctx *ctx, u64 virt_addr, struct hl_mmu_hop_info *hops, u64 *phys_addr) @@ -594,7 +554,7 @@ int hl_mmu_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr, int pgt_residency, rc; bool is_dram_addr; - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return -EOPNOTSUPP; prop = &hdev->asic_prop; @@ -625,7 +585,7 @@ int hl_mmu_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr, int hl_mmu_if_set_funcs(struct hl_device *hdev) { - if (!hdev->mmu_enable) + if (hdev->mmu_disable) return 0; switch (hdev->asic_type) { diff --git a/drivers/accel/habanalabs/common/security.c b/drivers/accel/habanalabs/common/security.c index 297e6e44fd0c..fe913965dbad 100644 --- a/drivers/accel/habanalabs/common/security.c +++ b/drivers/accel/habanalabs/common/security.c @@ -284,14 +284,14 @@ void hl_secure_block(struct hl_device *hdev, * @instance_offset: offset between instances * @pb_blocks: blocks array * @blocks_array_size: blocks array size - * @regs_array: register array - * @regs_array_size: register array size + * @user_regs_array: unsecured register array + * @user_regs_array_size: unsecured register array size * @mask: enabled instances mask: 1- enabled, 0- disabled */ int hl_init_pb_with_mask(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, u32 num_instances, u32 instance_offset, const u32 pb_blocks[], u32 blocks_array_size, - const u32 *regs_array, u32 regs_array_size, u64 mask) + const u32 *user_regs_array, u32 user_regs_array_size, u64 mask) { int i, j; struct hl_block_glbl_sec *glbl_sec; @@ -303,8 +303,8 @@ int hl_init_pb_with_mask(struct hl_device *hdev, u32 num_dcores, return -ENOMEM; hl_secure_block(hdev, glbl_sec, blocks_array_size); - hl_unsecure_registers(hdev, regs_array, regs_array_size, 0, pb_blocks, - glbl_sec, blocks_array_size); + hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, 0, + pb_blocks, glbl_sec, blocks_array_size); /* Fill all blocks with the same configuration */ for (i = 0 ; i < num_dcores ; i++) { @@ -336,19 +336,19 @@ int hl_init_pb_with_mask(struct hl_device *hdev, u32 num_dcores, * @instance_offset: offset between instances * @pb_blocks: blocks array * @blocks_array_size: blocks array size - * @regs_array: register array - * @regs_array_size: register array size + * @user_regs_array: unsecured register array + * @user_regs_array_size: unsecured register array size * */ int hl_init_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, u32 num_instances, u32 instance_offset, const u32 pb_blocks[], u32 blocks_array_size, - const u32 *regs_array, u32 regs_array_size) + const u32 *user_regs_array, u32 user_regs_array_size) { return hl_init_pb_with_mask(hdev, num_dcores, dcore_offset, num_instances, instance_offset, pb_blocks, - blocks_array_size, regs_array, regs_array_size, - ULLONG_MAX); + blocks_array_size, user_regs_array, + user_regs_array_size, ULLONG_MAX); } /** @@ -364,15 +364,15 @@ int hl_init_pb(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, * @instance_offset: offset between instances * @pb_blocks: blocks array * @blocks_array_size: blocks array size - * @regs_range_array: register range array - * @regs_range_array_size: register range array size + * @user_regs_range_array: unsecured register range array + * @user_regs_range_array_size: unsecured register range array size * @mask: enabled instances mask: 1- enabled, 0- disabled */ int hl_init_pb_ranges_with_mask(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, u32 num_instances, u32 instance_offset, const u32 pb_blocks[], u32 blocks_array_size, - const struct range *regs_range_array, u32 regs_range_array_size, - u64 mask) + const struct range *user_regs_range_array, + u32 user_regs_range_array_size, u64 mask) { int i, j, rc = 0; struct hl_block_glbl_sec *glbl_sec; @@ -384,8 +384,8 @@ int hl_init_pb_ranges_with_mask(struct hl_device *hdev, u32 num_dcores, return -ENOMEM; hl_secure_block(hdev, glbl_sec, blocks_array_size); - rc = hl_unsecure_registers_range(hdev, regs_range_array, - regs_range_array_size, 0, pb_blocks, glbl_sec, + rc = hl_unsecure_registers_range(hdev, user_regs_range_array, + user_regs_range_array_size, 0, pb_blocks, glbl_sec, blocks_array_size); if (rc) goto free_glbl_sec; @@ -422,19 +422,20 @@ free_glbl_sec: * @instance_offset: offset between instances * @pb_blocks: blocks array * @blocks_array_size: blocks array size - * @regs_range_array: register range array - * @regs_range_array_size: register range array size + * @user_regs_range_array: unsecured register range array + * @user_regs_range_array_size: unsecured register range array size * */ int hl_init_pb_ranges(struct hl_device *hdev, u32 num_dcores, u32 dcore_offset, u32 num_instances, u32 instance_offset, const u32 pb_blocks[], u32 blocks_array_size, - const struct range *regs_range_array, u32 regs_range_array_size) + const struct range *user_regs_range_array, + u32 user_regs_range_array_size) { return hl_init_pb_ranges_with_mask(hdev, num_dcores, dcore_offset, num_instances, instance_offset, pb_blocks, - blocks_array_size, regs_range_array, - regs_range_array_size, ULLONG_MAX); + blocks_array_size, user_regs_range_array, + user_regs_range_array_size, ULLONG_MAX); } /** @@ -447,14 +448,14 @@ int hl_init_pb_ranges(struct hl_device *hdev, u32 num_dcores, * @instance_offset: offset between instances * @pb_blocks: blocks array * @blocks_array_size: blocks array size - * @regs_array: register array - * @regs_array_size: register array size + * @user_regs_array: unsecured register array + * @user_regs_array_size: unsecured register array size * */ int hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, u32 num_instances, u32 instance_offset, const u32 pb_blocks[], u32 blocks_array_size, - const u32 *regs_array, u32 regs_array_size) + const u32 *user_regs_array, u32 user_regs_array_size) { int i, rc = 0; struct hl_block_glbl_sec *glbl_sec; @@ -466,8 +467,8 @@ int hl_init_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset, return -ENOMEM; hl_secure_block(hdev, glbl_sec, blocks_array_size); - rc = hl_unsecure_registers(hdev, regs_array, regs_array_size, 0, - pb_blocks, glbl_sec, blocks_array_size); + rc = hl_unsecure_registers(hdev, user_regs_array, user_regs_array_size, + 0, pb_blocks, glbl_sec, blocks_array_size); if (rc) goto free_glbl_sec; @@ -495,8 +496,8 @@ free_glbl_sec: * @instance_offset: offset between instances * @pb_blocks: blocks array * @blocks_array_size: blocks array size - * @regs_range_array: register range array - * @regs_range_array_size: register range array size + * @user_regs_range_array: unsecured register range array + * @user_regs_range_array_size: unsecured register range array size * */ int hl_init_pb_ranges_single_dcore(struct hl_device *hdev, u32 dcore_offset, diff --git a/drivers/accel/habanalabs/gaudi/gaudi.c b/drivers/accel/habanalabs/gaudi/gaudi.c index a29aa8f7b6f3..056e2ef44afb 100644 --- a/drivers/accel/habanalabs/gaudi/gaudi.c +++ b/drivers/accel/habanalabs/gaudi/gaudi.c @@ -114,13 +114,6 @@ static u32 gaudi_stream_master[GAUDI_STREAM_MASTER_ARR_SIZE] = { GAUDI_QUEUE_ID_DMA_1_3 }; -static const char gaudi_irq_name[GAUDI_MSI_ENTRIES][GAUDI_MAX_STRING_LEN] = { - "gaudi cq 0_0", "gaudi cq 0_1", "gaudi cq 0_2", "gaudi cq 0_3", - "gaudi cq 1_0", "gaudi cq 1_1", "gaudi cq 1_2", "gaudi cq 1_3", - "gaudi cq 5_0", "gaudi cq 5_1", "gaudi cq 5_2", "gaudi cq 5_3", - "gaudi cpu eq" -}; - static const u8 gaudi_dma_assignment[GAUDI_DMA_MAX] = { [GAUDI_PCI_DMA_1] = GAUDI_ENGINE_ID_DMA_0, [GAUDI_PCI_DMA_2] = GAUDI_ENGINE_ID_DMA_1, @@ -1476,8 +1469,7 @@ static int gaudi_collective_wait_create_job(struct hl_device *hdev, } /* Allocate internal mapped CB for non patched CBs */ - cb = hl_cb_kernel_create(hdev, cb_size, - hdev->mmu_enable && !patched_cb); + cb = hl_cb_kernel_create(hdev, cb_size, !patched_cb); if (!cb) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&cntr->out_of_mem_drop_cnt); @@ -3651,9 +3643,6 @@ static int gaudi_mmu_init(struct hl_device *hdev) u64 hop0_addr; int rc, i; - if (!hdev->mmu_enable) - return 0; - if (gaudi->hw_cap_initialized & HW_CAP_MMU) return 0; diff --git a/drivers/accel/habanalabs/gaudi2/gaudi2.c b/drivers/accel/habanalabs/gaudi2/gaudi2.c index b778cf764a68..20c4583f12b0 100644 --- a/drivers/accel/habanalabs/gaudi2/gaudi2.c +++ b/drivers/accel/habanalabs/gaudi2/gaudi2.c @@ -57,13 +57,13 @@ #define GAUDI2_NA_EVENT_CAUSE 0xFF #define GAUDI2_NUM_OF_QM_ERR_CAUSE 18 -#define GAUDI2_NUM_OF_QM_LCP_ERR_CAUSE 25 +#define GAUDI2_NUM_OF_LOWER_QM_ERR_CAUSE 25 #define GAUDI2_NUM_OF_QM_ARB_ERR_CAUSE 3 #define GAUDI2_NUM_OF_ARC_SEI_ERR_CAUSE 14 #define GAUDI2_NUM_OF_CPU_SEI_ERR_CAUSE 3 #define GAUDI2_NUM_OF_QM_SEI_ERR_CAUSE 2 #define GAUDI2_NUM_OF_ROT_ERR_CAUSE 22 -#define GAUDI2_NUM_OF_TPC_INTR_CAUSE 30 +#define GAUDI2_NUM_OF_TPC_INTR_CAUSE 31 #define GAUDI2_NUM_OF_DEC_ERR_CAUSE 25 #define GAUDI2_NUM_OF_MME_ERR_CAUSE 16 #define GAUDI2_NUM_OF_MME_SBTE_ERR_CAUSE 5 @@ -162,6 +162,9 @@ #define PSOC_RAZWI_ENG_STR_SIZE 128 #define PSOC_RAZWI_MAX_ENG_PER_RTR 5 +/* HW scrambles only bits 0-25 */ +#define HW_UNSCRAMBLED_BITS_MASK GENMASK_ULL(63, 26) + struct gaudi2_razwi_info { u32 axuser_xy; u32 rtr_ctrl; @@ -801,7 +804,7 @@ static const char * const gaudi2_qman_error_cause[GAUDI2_NUM_OF_QM_ERR_CAUSE] = "PQC L2H error" }; -static const char * const gaudi2_qman_lower_cp_error_cause[GAUDI2_NUM_OF_QM_LCP_ERR_CAUSE] = { +static const char * const gaudi2_lower_qman_error_cause[GAUDI2_NUM_OF_LOWER_QM_ERR_CAUSE] = { "RSVD0", "CQ AXI HBW error", "CP AXI HBW error", @@ -891,6 +894,7 @@ static const char * const gaudi2_tpc_interrupts_cause[GAUDI2_NUM_OF_TPC_INTR_CAU "invalid_lock_access", "LD_L protection violation", "ST_L protection violation", + "D$ L0CS mismatch", }; static const char * const guadi2_mme_error_cause[GAUDI2_NUM_OF_MME_ERR_CAUSE] = { @@ -3615,6 +3619,12 @@ static int gaudi2_sw_init(struct hl_device *hdev) prop->supports_compute_reset = true; + /* Event queue sanity check added in FW version 1.11 */ + if (hl_is_fw_sw_ver_below(hdev, 1, 11)) + hdev->event_queue.check_eqe_index = false; + else + hdev->event_queue.check_eqe_index = true; + hdev->asic_funcs->set_pci_memory_regions(hdev); rc = gaudi2_special_blocks_iterator_config(hdev); @@ -3630,8 +3640,8 @@ static int gaudi2_sw_init(struct hl_device *hdev) special_blocks_free: gaudi2_special_blocks_iterator_free(hdev); free_scratchpad_mem: - hl_asic_dma_pool_free(hdev, gaudi2->scratchpad_kernel_address, - gaudi2->scratchpad_bus_address); + hl_asic_dma_free_coherent(hdev, PAGE_SIZE, gaudi2->scratchpad_kernel_address, + gaudi2->scratchpad_bus_address); free_virt_msix_db_mem: hl_cpu_accessible_dma_pool_free(hdev, prop->pmmu.page_size, gaudi2->virt_msix_db_cpu_addr); free_cpu_accessible_dma_pool: @@ -4526,7 +4536,7 @@ static int gaudi2_set_tpc_engine_mode(struct hl_device *hdev, u32 engine_id, u32 reg_base = gaudi2_tpc_cfg_blocks_bases[tpc_id]; reg_addr = reg_base + TPC_CFG_STALL_OFFSET; reg_val = FIELD_PREP(DCORE0_TPC0_CFG_TPC_STALL_V_MASK, - !!(engine_command == HL_ENGINE_STALL)); + (engine_command == HL_ENGINE_STALL) ? 1 : 0); WREG32(reg_addr, reg_val); if (engine_command == HL_ENGINE_RESUME) { @@ -4550,7 +4560,7 @@ static int gaudi2_set_mme_engine_mode(struct hl_device *hdev, u32 engine_id, u32 reg_base = gaudi2_mme_ctrl_lo_blocks_bases[mme_id]; reg_addr = reg_base + MME_CTRL_LO_QM_STALL_OFFSET; reg_val = FIELD_PREP(DCORE0_MME_CTRL_LO_QM_STALL_V_MASK, - !!(engine_command == HL_ENGINE_STALL)); + (engine_command == HL_ENGINE_STALL) ? 1 : 0); WREG32(reg_addr, reg_val); return 0; @@ -4571,7 +4581,7 @@ static int gaudi2_set_edma_engine_mode(struct hl_device *hdev, u32 engine_id, u3 reg_base = gaudi2_dma_core_blocks_bases[edma_id]; reg_addr = reg_base + EDMA_CORE_CFG_STALL_OFFSET; reg_val = FIELD_PREP(DCORE0_EDMA0_CORE_CFG_1_HALT_MASK, - !!(engine_command == HL_ENGINE_STALL)); + (engine_command == HL_ENGINE_STALL) ? 1 : 0); WREG32(reg_addr, reg_val); if (engine_command == HL_ENGINE_STALL) { @@ -6148,18 +6158,24 @@ static int gaudi2_execute_soft_reset(struct hl_device *hdev, bool driver_perform u32 poll_timeout_us) { struct cpu_dyn_regs *dyn_regs = &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; + int rc = 0; if (!driver_performs_reset) { - /* set SP to indicate reset request sent to FW */ - if (dyn_regs->cpu_rst_status) - WREG32(le32_to_cpu(dyn_regs->cpu_rst_status), CPU_RST_STATUS_NA); - else - WREG32(mmCPU_RST_STATUS_TO_HOST, CPU_RST_STATUS_NA); - - WREG32(le32_to_cpu(dyn_regs->gic_host_soft_rst_irq), - gaudi2_irq_map_table[GAUDI2_EVENT_CPU_SOFT_RESET].cpu_id); - - return gaudi2_get_soft_rst_done_indication(hdev, poll_timeout_us); + if (hl_is_fw_sw_ver_below(hdev, 1, 10)) { + /* set SP to indicate reset request sent to FW */ + if (dyn_regs->cpu_rst_status) + WREG32(le32_to_cpu(dyn_regs->cpu_rst_status), CPU_RST_STATUS_NA); + else + WREG32(mmCPU_RST_STATUS_TO_HOST, CPU_RST_STATUS_NA); + WREG32(le32_to_cpu(dyn_regs->gic_host_soft_rst_irq), + gaudi2_irq_map_table[GAUDI2_EVENT_CPU_SOFT_RESET].cpu_id); + + /* wait for f/w response */ + rc = gaudi2_get_soft_rst_done_indication(hdev, poll_timeout_us); + } else { + rc = hl_fw_send_soft_reset(hdev); + } + return rc; } /* Block access to engines, QMANs and SM during reset, these @@ -7231,7 +7247,7 @@ static bool gaudi2_get_tpc_idle_status(struct hl_device *hdev, u64 *mask_arr, u8 gaudi2_iterate_tpcs(hdev, &tpc_iter); - return tpc_idle_data.is_idle; + return *tpc_idle_data.is_idle; } static bool gaudi2_get_decoder_idle_status(struct hl_device *hdev, u64 *mask_arr, u8 mask_len, @@ -7737,137 +7753,28 @@ static bool gaudi2_handle_ecc_event(struct hl_device *hdev, u16 event_type, return !!ecc_data->is_critical; } -/* - * gaudi2_queue_idx_dec - decrement queue index (pi/ci) and handle wrap - * - * @idx: the current pi/ci value - * @q_len: the queue length (power of 2) - * - * @return the cyclically decremented index - */ -static inline u32 gaudi2_queue_idx_dec(u32 idx, u32 q_len) -{ - u32 mask = q_len - 1; - - /* - * modular decrement is equivalent to adding (queue_size -1) - * later we take LSBs to make sure the value is in the - * range [0, queue_len - 1] - */ - return (idx + q_len - 1) & mask; -} - -/** - * gaudi2_print_sw_config_stream_data - print SW config stream data - * - * @hdev: pointer to the habanalabs device structure - * @stream: the QMAN's stream - * @qman_base: base address of QMAN registers block - */ -static void gaudi2_print_sw_config_stream_data(struct hl_device *hdev, - u32 stream, u64 qman_base) -{ - u64 cq_ptr_lo, cq_ptr_hi, cq_tsize, cq_ptr; - u32 cq_ptr_lo_off, size; - - cq_ptr_lo_off = mmDCORE0_TPC0_QM_CQ_PTR_LO_1 - mmDCORE0_TPC0_QM_CQ_PTR_LO_0; - - cq_ptr_lo = qman_base + (mmDCORE0_TPC0_QM_CQ_PTR_LO_0 - mmDCORE0_TPC0_QM_BASE) + - stream * cq_ptr_lo_off; - - cq_ptr_hi = cq_ptr_lo + (mmDCORE0_TPC0_QM_CQ_PTR_HI_0 - mmDCORE0_TPC0_QM_CQ_PTR_LO_0); - - cq_tsize = cq_ptr_lo + (mmDCORE0_TPC0_QM_CQ_TSIZE_0 - mmDCORE0_TPC0_QM_CQ_PTR_LO_0); - - cq_ptr = (((u64) RREG32(cq_ptr_hi)) << 32) | RREG32(cq_ptr_lo); - size = RREG32(cq_tsize); - dev_info(hdev->dev, "stop on err: stream: %u, addr: %#llx, size: %x\n", - stream, cq_ptr, size); -} - -/** - * gaudi2_print_last_pqes_on_err - print last PQEs on error - * - * @hdev: pointer to the habanalabs device structure - * @qid_base: first QID of the QMAN (out of 4 streams) - * @stream: the QMAN's stream - * @qman_base: base address of QMAN registers block - * @pr_sw_conf: if true print the SW config stream data (CQ PTR and SIZE) - */ -static void gaudi2_print_last_pqes_on_err(struct hl_device *hdev, u32 qid_base, u32 stream, - u64 qman_base, bool pr_sw_conf) +static void print_lower_qman_data_on_err(struct hl_device *hdev, u64 qman_base) { - u32 ci, qm_ci_stream_off; - struct hl_hw_queue *q; - u64 pq_ci; - int i; - - q = &hdev->kernel_queues[qid_base + stream]; - - qm_ci_stream_off = mmDCORE0_TPC0_QM_PQ_CI_1 - mmDCORE0_TPC0_QM_PQ_CI_0; - pq_ci = qman_base + (mmDCORE0_TPC0_QM_PQ_CI_0 - mmDCORE0_TPC0_QM_BASE) + - stream * qm_ci_stream_off; - - hdev->asic_funcs->hw_queues_lock(hdev); - - if (pr_sw_conf) - gaudi2_print_sw_config_stream_data(hdev, stream, qman_base); - - ci = RREG32(pq_ci); - - /* we should start printing form ci -1 */ - ci = gaudi2_queue_idx_dec(ci, HL_QUEUE_LENGTH); - - for (i = 0; i < PQ_FETCHER_CACHE_SIZE; i++) { - struct hl_bd *bd; - u64 addr; - u32 len; - - bd = q->kernel_address; - bd += ci; - - len = le32_to_cpu(bd->len); - /* len 0 means uninitialized entry- break */ - if (!len) - break; - - addr = le64_to_cpu(bd->ptr); - - dev_info(hdev->dev, "stop on err PQE(stream %u): ci: %u, addr: %#llx, size: %x\n", - stream, ci, addr, len); - - /* get previous ci, wrap if needed */ - ci = gaudi2_queue_idx_dec(ci, HL_QUEUE_LENGTH); - } - - hdev->asic_funcs->hw_queues_unlock(hdev); -} + u32 lo, hi, cq_ptr_size, arc_cq_ptr_size; + u64 cq_ptr, arc_cq_ptr, cp_current_inst; -/** - * print_qman_data_on_err - extract QMAN data on error - * - * @hdev: pointer to the habanalabs device structure - * @qid_base: first QID of the QMAN (out of 4 streams) - * @stream: the QMAN's stream - * @qman_base: base address of QMAN registers block - * - * This function attempt to extract as much data as possible on QMAN error. - * On upper CP print the SW config stream data and last 8 PQEs. - * On lower CP print SW config data and last PQEs of ALL 4 upper CPs - */ -static void print_qman_data_on_err(struct hl_device *hdev, u32 qid_base, u32 stream, u64 qman_base) -{ - u32 i; + lo = RREG32(qman_base + QM_CQ_PTR_LO_4_OFFSET); + hi = RREG32(qman_base + QM_CQ_PTR_HI_4_OFFSET); + cq_ptr = ((u64) hi) << 32 | lo; + cq_ptr_size = RREG32(qman_base + QM_CQ_TSIZE_4_OFFSET); - if (stream != QMAN_STREAMS) { - gaudi2_print_last_pqes_on_err(hdev, qid_base, stream, qman_base, true); - return; - } + lo = RREG32(qman_base + QM_ARC_CQ_PTR_LO_OFFSET); + hi = RREG32(qman_base + QM_ARC_CQ_PTR_HI_OFFSET); + arc_cq_ptr = ((u64) hi) << 32 | lo; + arc_cq_ptr_size = RREG32(qman_base + QM_ARC_CQ_TSIZE_OFFSET); - gaudi2_print_sw_config_stream_data(hdev, stream, qman_base); + lo = RREG32(qman_base + QM_CP_CURRENT_INST_LO_4_OFFSET); + hi = RREG32(qman_base + QM_CP_CURRENT_INST_HI_4_OFFSET); + cp_current_inst = ((u64) hi) << 32 | lo; - for (i = 0 ; i < QMAN_STREAMS ; i++) - gaudi2_print_last_pqes_on_err(hdev, qid_base, i, qman_base, false); + dev_info(hdev->dev, + "LowerQM. CQ: {ptr %#llx, size %u}, ARC_CQ: {ptr %#llx, size %u}, CP: {instruction %#llx}\n", + cq_ptr, cq_ptr_size, arc_cq_ptr, arc_cq_ptr_size, cp_current_inst); } static int gaudi2_handle_qman_err_generic(struct hl_device *hdev, u16 event_type, @@ -7888,8 +7795,8 @@ static int gaudi2_handle_qman_err_generic(struct hl_device *hdev, u16 event_type continue; if (i == QMAN_STREAMS) { - snprintf(reg_desc, ARRAY_SIZE(reg_desc), "LowerCP"); - num_error_causes = GAUDI2_NUM_OF_QM_LCP_ERR_CAUSE; + snprintf(reg_desc, ARRAY_SIZE(reg_desc), "LowerQM"); + num_error_causes = GAUDI2_NUM_OF_LOWER_QM_ERR_CAUSE; } else { snprintf(reg_desc, ARRAY_SIZE(reg_desc), "stream%u", i); num_error_causes = GAUDI2_NUM_OF_QM_ERR_CAUSE; @@ -7900,12 +7807,13 @@ static int gaudi2_handle_qman_err_generic(struct hl_device *hdev, u16 event_type gaudi2_print_event(hdev, event_type, true, "%s. err cause: %s", reg_desc, i == QMAN_STREAMS ? - gaudi2_qman_lower_cp_error_cause[j] : + gaudi2_lower_qman_error_cause[j] : gaudi2_qman_error_cause[j]); error_count++; } - print_qman_data_on_err(hdev, qid_base, i, qman_base); + if (i == QMAN_STREAMS) + print_lower_qman_data_on_err(hdev, qman_base); } arb_err_val = RREG32(arb_err_addr); @@ -8033,7 +7941,7 @@ static void gaudi2_ack_module_razwi_event_handler(struct hl_device *hdev, u8 module_sub_idx, u64 *event_mask) { bool via_sft = false; - u32 hbw_rtr_id, lbw_rtr_id, dcore_id, dcore_rtr_id, eng_id; + u32 hbw_rtr_id, lbw_rtr_id, dcore_id, dcore_rtr_id, eng_id, binned_idx; u64 hbw_rtr_mstr_if_base_addr, lbw_rtr_mstr_if_base_addr; u32 hbw_shrd_aw = 0, hbw_shrd_ar = 0; u32 lbw_shrd_aw = 0, lbw_shrd_ar = 0; @@ -8041,15 +7949,21 @@ static void gaudi2_ack_module_razwi_event_handler(struct hl_device *hdev, switch (module) { case RAZWI_TPC: + sprintf(initiator_name, "TPC_%u", module_idx); + if (hdev->tpc_binning) { + binned_idx = __ffs(hdev->tpc_binning); + if (binned_idx == module_idx) + module_idx = TPC_ID_DCORE0_TPC6; + } + hbw_rtr_id = gaudi2_tpc_initiator_hbw_rtr_id[module_idx]; - if (hl_is_fw_ver_below_1_9(hdev) && + if (hl_is_fw_sw_ver_below(hdev, 1, 9) && !hdev->asic_prop.fw_security_enabled && ((module_idx == 0) || (module_idx == 1))) lbw_rtr_id = DCORE0_RTR0; else lbw_rtr_id = gaudi2_tpc_initiator_lbw_rtr_id[module_idx]; - sprintf(initiator_name, "TPC_%u", module_idx); break; case RAZWI_MME: sprintf(initiator_name, "MME_%u", module_idx); @@ -8108,9 +8022,14 @@ static void gaudi2_ack_module_razwi_event_handler(struct hl_device *hdev, sprintf(initiator_name, "NIC_%u", module_idx); break; case RAZWI_DEC: + sprintf(initiator_name, "DEC_%u", module_idx); + if (hdev->decoder_binning) { + binned_idx = __ffs(hdev->decoder_binning); + if (binned_idx == module_idx) + module_idx = DEC_ID_PCIE_VDEC1; + } hbw_rtr_id = gaudi2_dec_initiator_hbw_rtr_id[module_idx]; lbw_rtr_id = gaudi2_dec_initiator_lbw_rtr_id[module_idx]; - sprintf(initiator_name, "DEC_%u", module_idx); break; case RAZWI_ROT: hbw_rtr_id = gaudi2_rot_initiator_hbw_rtr_id[module_idx]; @@ -8251,6 +8170,7 @@ static bool gaudi2_handle_psoc_razwi_happened(struct hl_device *hdev, u32 razwi_ u16 num_of_eng, eng_id[PSOC_RAZWI_MAX_ENG_PER_RTR]; char eng_name_str[PSOC_RAZWI_ENG_STR_SIZE]; bool razwi_happened = false; + u64 addr; int i; num_of_eng = gaudi2_psoc_razwi_get_engines(common_razwi_info, ARRAY_SIZE(common_razwi_info), @@ -8269,43 +8189,53 @@ static bool gaudi2_handle_psoc_razwi_happened(struct hl_device *hdev, u32 razwi_ if (RREG32(base[i] + DEC_RAZWI_HBW_AW_SET)) { addr_hi = RREG32(base[i] + DEC_RAZWI_HBW_AW_ADDR_HI); addr_lo = RREG32(base[i] + DEC_RAZWI_HBW_AW_ADDR_LO); - dev_err(hdev->dev, + addr = ((u64)addr_hi << 32) + addr_lo; + if (addr) { + dev_err(hdev->dev, "PSOC HBW AW RAZWI: %s, address (aligned to 128 byte): 0x%llX\n", - eng_name_str, ((u64)addr_hi << 32) + addr_lo); - hl_handle_razwi(hdev, ((u64)addr_hi << 32) + addr_lo, &eng_id[0], + eng_name_str, addr); + hl_handle_razwi(hdev, addr, &eng_id[0], num_of_eng, HL_RAZWI_HBW | HL_RAZWI_WRITE, event_mask); - razwi_happened = true; + razwi_happened = true; + } } if (RREG32(base[i] + DEC_RAZWI_HBW_AR_SET)) { addr_hi = RREG32(base[i] + DEC_RAZWI_HBW_AR_ADDR_HI); addr_lo = RREG32(base[i] + DEC_RAZWI_HBW_AR_ADDR_LO); - dev_err(hdev->dev, + addr = ((u64)addr_hi << 32) + addr_lo; + if (addr) { + dev_err(hdev->dev, "PSOC HBW AR RAZWI: %s, address (aligned to 128 byte): 0x%llX\n", - eng_name_str, ((u64)addr_hi << 32) + addr_lo); - hl_handle_razwi(hdev, ((u64)addr_hi << 32) + addr_lo, &eng_id[0], + eng_name_str, addr); + hl_handle_razwi(hdev, addr, &eng_id[0], num_of_eng, HL_RAZWI_HBW | HL_RAZWI_READ, event_mask); - razwi_happened = true; + razwi_happened = true; + } } if (RREG32(base[i] + DEC_RAZWI_LBW_AW_SET)) { addr_lo = RREG32(base[i] + DEC_RAZWI_LBW_AW_ADDR); - dev_err(hdev->dev, + if (addr_lo) { + dev_err(hdev->dev, "PSOC LBW AW RAZWI: %s, address (aligned to 128 byte): 0x%X\n", eng_name_str, addr_lo); - hl_handle_razwi(hdev, addr_lo, &eng_id[0], + hl_handle_razwi(hdev, addr_lo, &eng_id[0], num_of_eng, HL_RAZWI_LBW | HL_RAZWI_WRITE, event_mask); - razwi_happened = true; + razwi_happened = true; + } } if (RREG32(base[i] + DEC_RAZWI_LBW_AR_SET)) { addr_lo = RREG32(base[i] + DEC_RAZWI_LBW_AR_ADDR); - dev_err(hdev->dev, - "PSOC LBW AR RAZWI: %s, address (aligned to 128 byte): 0x%X\n", - eng_name_str, addr_lo); - hl_handle_razwi(hdev, addr_lo, &eng_id[0], + if (addr_lo) { + dev_err(hdev->dev, + "PSOC LBW AR RAZWI: %s, address (aligned to 128 byte): 0x%X\n", + eng_name_str, addr_lo); + hl_handle_razwi(hdev, addr_lo, &eng_id[0], num_of_eng, HL_RAZWI_LBW | HL_RAZWI_READ, event_mask); - razwi_happened = true; + razwi_happened = true; + } } /* In common case the loop will break, when there is only one engine id, or * several engines with the same router. The exceptional case is with psoc razwi @@ -8789,13 +8719,13 @@ static int gaudi2_handle_kdma_core_event(struct hl_device *hdev, u16 event_type, return error_count; } -static int gaudi2_handle_dma_core_event(struct hl_device *hdev, u16 event_type, int sts_addr) +static int gaudi2_handle_dma_core_event(struct hl_device *hdev, u16 event_type, u64 intr_cause) { - u32 error_count = 0, sts_val = RREG32(sts_addr); + u32 error_count = 0; int i; for (i = 0 ; i < GAUDI2_NUM_OF_DMA_CORE_INTR_CAUSE ; i++) - if (sts_val & BIT(i)) { + if (intr_cause & BIT(i)) { gaudi2_print_event(hdev, event_type, true, "err cause: %s", gaudi2_dma_core_interrupts_cause[i]); error_count++; @@ -8806,27 +8736,6 @@ static int gaudi2_handle_dma_core_event(struct hl_device *hdev, u16 event_type, return error_count; } -static int gaudi2_handle_pdma_core_event(struct hl_device *hdev, u16 event_type, int pdma_idx) -{ - u32 sts_addr; - - sts_addr = mmPDMA0_CORE_ERR_CAUSE + pdma_idx * PDMA_OFFSET; - return gaudi2_handle_dma_core_event(hdev, event_type, sts_addr); -} - -static int gaudi2_handle_edma_core_event(struct hl_device *hdev, u16 event_type, int edma_idx) -{ - static const int edma_event_index_map[] = {2, 3, 0, 1, 6, 7, 4, 5}; - u32 sts_addr, index; - - index = edma_event_index_map[edma_idx]; - - sts_addr = mmDCORE0_EDMA0_CORE_ERR_CAUSE + - DCORE_OFFSET * (index / NUM_OF_EDMA_PER_DCORE) + - DCORE_EDMA_OFFSET * (index % NUM_OF_EDMA_PER_DCORE); - return gaudi2_handle_dma_core_event(hdev, event_type, sts_addr); -} - static void gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(struct hl_device *hdev, u64 *event_mask) { u32 mstr_if_base_addr = mmPCIE_MSTR_RR_MSTR_IF_RR_SHRD_HBW_BASE, razwi_happened_addr; @@ -8866,6 +8775,9 @@ static int gaudi2_print_pcie_addr_dec_info(struct hl_device *hdev, u16 event_typ u32 error_count = 0; int i; + gaudi2_print_event(hdev, event_type, true, + "intr_cause_data: %#llx", intr_cause_data); + for (i = 0 ; i < GAUDI2_NUM_OF_PCIE_ADDR_DEC_ERR_CAUSE ; i++) { if (!(intr_cause_data & BIT_ULL(i))) continue; @@ -8874,16 +8786,15 @@ static int gaudi2_print_pcie_addr_dec_info(struct hl_device *hdev, u16 event_typ "err cause: %s", gaudi2_pcie_addr_dec_error_cause[i]); error_count++; - switch (intr_cause_data & BIT_ULL(i)) { - case PCIE_WRAP_PCIE_IC_SEI_INTR_IND_AXI_LBW_ERR_INTR_MASK: - hl_check_for_glbl_errors(hdev); - break; - case PCIE_WRAP_PCIE_IC_SEI_INTR_IND_BAD_ACCESS_INTR_MASK: - gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(hdev, event_mask); - break; - } + /* + * Always check for LBW and HBW additional info as the indication itself is + * sometimes missing + */ } + hl_check_for_glbl_errors(hdev); + gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(hdev, event_mask); + return error_count; } @@ -8937,11 +8848,16 @@ static void gaudi2_handle_page_error(struct hl_device *hdev, u64 mmu_base, bool addr <<= 32; addr |= RREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_PAGE_ERROR_CAPTURE_VA)); - if (!is_pmmu) + if (is_pmmu) { + dev_err_ratelimited(hdev->dev, "PMMU page fault on va 0x%llx\n", addr); + } else { + addr = gaudi2_mmu_descramble_addr(hdev, addr); + addr &= HW_UNSCRAMBLED_BITS_MASK; + dev_err_ratelimited(hdev->dev, "HMMU page fault on va range 0x%llx - 0x%llx\n", + addr, addr + ~HW_UNSCRAMBLED_BITS_MASK); + } - dev_err_ratelimited(hdev->dev, "%s page fault on va 0x%llx\n", - is_pmmu ? "PMMU" : "HMMU", addr); hl_handle_page_fault(hdev, addr, 0, is_pmmu, event_mask); WREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_ACCESS_PAGE_ERROR_VALID), 0); @@ -9709,19 +9625,19 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent case GAUDI2_EVENT_KDMA_CH0_AXI_ERR_RSP: case GAUDI2_EVENT_KDMA0_CORE: error_count = gaudi2_handle_kdma_core_event(hdev, event_type, - le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); + le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_HDMA2_CORE ... GAUDI2_EVENT_HDMA5_CORE: - index = event_type - GAUDI2_EVENT_HDMA2_CORE; - error_count = gaudi2_handle_edma_core_event(hdev, event_type, index); + error_count = gaudi2_handle_dma_core_event(hdev, event_type, + le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_PDMA0_CORE ... GAUDI2_EVENT_PDMA1_CORE: - index = event_type - GAUDI2_EVENT_PDMA0_CORE; - error_count = gaudi2_handle_pdma_core_event(hdev, event_type, index); + error_count = gaudi2_handle_dma_core_event(hdev, event_type, + le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; diff --git a/drivers/accel/habanalabs/gaudi2/gaudi2P.h b/drivers/accel/habanalabs/gaudi2/gaudi2P.h index 1cebe707772e..5f3ce086928e 100644 --- a/drivers/accel/habanalabs/gaudi2/gaudi2P.h +++ b/drivers/accel/habanalabs/gaudi2/gaudi2P.h @@ -98,7 +98,7 @@ #define GAUDI2_DEFAULT_CARD_NAME "HL225" #define QMAN_STREAMS 4 -#define PQ_FETCHER_CACHE_SIZE 8 + #define NUM_OF_MME_SBTE_PORTS 5 #define NUM_OF_MME_WB_PORTS 2 diff --git a/drivers/accel/habanalabs/gaudi2/gaudi2_security.c b/drivers/accel/habanalabs/gaudi2/gaudi2_security.c index 694735f9e6e6..2742b1f801eb 100644 --- a/drivers/accel/habanalabs/gaudi2/gaudi2_security.c +++ b/drivers/accel/habanalabs/gaudi2/gaudi2_security.c @@ -479,6 +479,7 @@ static const u32 gaudi2_pb_dcr0_edma0_unsecured_regs[] = { mmDCORE0_EDMA0_CORE_CTX_TE_NUMROWS, mmDCORE0_EDMA0_CORE_CTX_IDX, mmDCORE0_EDMA0_CORE_CTX_IDX_INC, + mmDCORE0_EDMA0_CORE_RD_LBW_RATE_LIM_CFG, mmDCORE0_EDMA0_QM_CQ_CFG0_0, mmDCORE0_EDMA0_QM_CQ_CFG0_1, mmDCORE0_EDMA0_QM_CQ_CFG0_2, @@ -1533,6 +1534,10 @@ static const u32 gaudi2_pb_dcr0_tpc0_unsecured_regs[] = { mmDCORE0_TPC0_CFG_QM_KERNEL_CONFIG, mmDCORE0_TPC0_CFG_QM_KERNEL_ID, mmDCORE0_TPC0_CFG_QM_POWER_LOOP, + mmDCORE0_TPC0_CFG_TSB_CFG_MTRR_2_0, + mmDCORE0_TPC0_CFG_TSB_CFG_MTRR_2_1, + mmDCORE0_TPC0_CFG_TSB_CFG_MTRR_2_2, + mmDCORE0_TPC0_CFG_TSB_CFG_MTRR_2_3, mmDCORE0_TPC0_CFG_LUT_FUNC32_BASE2_ADDR_LO, mmDCORE0_TPC0_CFG_LUT_FUNC32_BASE2_ADDR_HI, mmDCORE0_TPC0_CFG_LUT_FUNC64_BASE2_ADDR_LO, @@ -1541,6 +1546,7 @@ static const u32 gaudi2_pb_dcr0_tpc0_unsecured_regs[] = { mmDCORE0_TPC0_CFG_LUT_FUNC128_BASE2_ADDR_HI, mmDCORE0_TPC0_CFG_LUT_FUNC256_BASE2_ADDR_LO, mmDCORE0_TPC0_CFG_LUT_FUNC256_BASE2_ADDR_HI, + mmDCORE0_TPC0_CFG_FP8_143_BIAS, mmDCORE0_TPC0_CFG_ROUND_CSR, mmDCORE0_TPC0_CFG_CONV_ROUND_CSR, mmDCORE0_TPC0_CFG_SEMAPHORE, @@ -3442,15 +3448,6 @@ static int gaudi2_init_protection_bits(struct hl_device *hdev) ARRAY_SIZE(gaudi2_pb_thermal_sensor0), NULL, HL_PB_NA); } - /* HBM */ - /* Temporarily skip until SW-63348 is solved - * instance_offset = mmHBM1_MC0_BASE - mmHBM0_MC0_BASE; - * rc |= hl_init_pb_with_mask(hdev, HL_PB_SHARED, HL_PB_NA, GAUDI2_HBM_NUM, - * instance_offset, gaudi2_pb_hbm, - * ARRAY_SIZE(gaudi2_pb_hbm), NULL, HL_PB_NA, - * prop->dram_enabled_mask); - */ - /* Scheduler ARCs */ instance_offset = mmARC_FARM_ARC1_AUX_BASE - mmARC_FARM_ARC0_AUX_BASE; rc |= hl_init_pb_ranges(hdev, HL_PB_SHARED, HL_PB_NA, diff --git a/drivers/accel/habanalabs/goya/goya.c b/drivers/accel/habanalabs/goya/goya.c index fb0ac9df841a..7c685e6075f6 100644 --- a/drivers/accel/habanalabs/goya/goya.c +++ b/drivers/accel/habanalabs/goya/goya.c @@ -2671,9 +2671,6 @@ int goya_mmu_init(struct hl_device *hdev) u64 hop0_addr; int rc, i; - if (!hdev->mmu_enable) - return 0; - if (goya->hw_cap_initialized & HW_CAP_MMU) return 0; diff --git a/drivers/accel/habanalabs/goya/goya_coresight.c b/drivers/accel/habanalabs/goya/goya_coresight.c index e7ac3046cfaa..a6d6cc38bcd8 100644 --- a/drivers/accel/habanalabs/goya/goya_coresight.c +++ b/drivers/accel/habanalabs/goya/goya_coresight.c @@ -371,13 +371,8 @@ static int goya_etr_validate_address(struct hl_device *hdev, u64 addr, return false; } - if (hdev->mmu_enable) { - range_start = prop->dmmu.start_addr; - range_end = prop->dmmu.end_addr; - } else { - range_start = prop->dram_user_base_address; - range_end = prop->dram_end_address; - } + range_start = prop->dmmu.start_addr; + range_end = prop->dmmu.end_addr; return hl_mem_area_inside_range(addr, size, range_start, range_end); } diff --git a/drivers/accel/habanalabs/include/common/cpucp_if.h b/drivers/accel/habanalabs/include/common/cpucp_if.h index 8bbe685458c4..33807b839c37 100644 --- a/drivers/accel/habanalabs/include/common/cpucp_if.h +++ b/drivers/accel/habanalabs/include/common/cpucp_if.h @@ -359,7 +359,7 @@ struct hl_eq_entry { union { __le64 data_placeholder; struct hl_eq_ecc_data ecc_data; - struct hl_eq_hbm_ecc_data hbm_ecc_data; /* Gaudi1 HBM */ + struct hl_eq_hbm_ecc_data hbm_ecc_data; /* Obsolete */ struct hl_eq_sm_sei_data sm_sei_data; struct cpucp_pkt_sync_err pkt_sync_err; struct hl_eq_fw_alive fw_alive; @@ -653,7 +653,7 @@ enum pq_init_status { * which address is passed via the CpuCp packet. In addition, the host's driver * passes the max size it allows the CpuCP to write to the structure, to prevent * data corruption in case of mismatched driver/FW versions. - * Relevant only to Gaudi. + * Obsolete. * * CPUCP_PACKET_GENERIC_PASSTHROUGH - * Generic opcode for all firmware info that is only passed to host @@ -665,6 +665,9 @@ enum pq_init_status { * * CPUCP_PACKET_REGISTER_INTERRUPTS - * Packet to register interrupts indicating LKD is ready to receive events from FW. + * + * CPUCP_PACKET_SOFT_RESET - + * Packet to perform soft-reset. */ enum cpucp_packet_id { @@ -731,6 +734,7 @@ enum cpucp_packet_id { CPUCP_PACKET_RESERVED11, /* not used */ CPUCP_PACKET_RESERVED12, /* internal */ CPUCP_PACKET_REGISTER_INTERRUPTS, /* internal */ + CPUCP_PACKET_SOFT_RESET, /* internal */ CPUCP_PACKET_ID_MAX /* must be last */ }; @@ -864,19 +868,19 @@ struct cpucp_array_data_packet { enum cpucp_led_index { CPUCP_LED0_INDEX = 0, CPUCP_LED1_INDEX, - CPUCP_LED2_INDEX + CPUCP_LED2_INDEX, + CPUCP_LED_MAX_INDEX = CPUCP_LED2_INDEX }; /* * enum cpucp_packet_rc - Error return code * @cpucp_packet_success -> in case of success. - * @cpucp_packet_invalid -> this is to support Goya and Gaudi platform. + * @cpucp_packet_invalid -> this is to support first generation platforms. * @cpucp_packet_fault -> in case of processing error like failing to * get device binding or semaphore etc. - * @cpucp_packet_invalid_pkt -> when cpucp packet is un-supported. This is - * supported Greco onwards. + * @cpucp_packet_invalid_pkt -> when cpucp packet is un-supported. * @cpucp_packet_invalid_params -> when checking parameter like length of buffer - * or attribute value etc. Supported Greco onwards. + * or attribute value etc. * @cpucp_packet_rc_max -> It indicates size of enum so should be at last. */ enum cpucp_packet_rc { @@ -1361,7 +1365,7 @@ struct cpucp_dev_info_signed { #define DCORE_MON_REGS_SZ 512 /* * struct dcore_monitor_regs_data - DCORE monitor regs data. - * the structure follows sync manager block layout. relevant only to Gaudi. + * the structure follows sync manager block layout. Obsolete. * @mon_pay_addrl: array of payload address low bits. * @mon_pay_addrh: array of payload address high bits. * @mon_pay_data: array of payload data. @@ -1376,7 +1380,7 @@ struct dcore_monitor_regs_data { __le32 mon_status[DCORE_MON_REGS_SZ]; }; -/* contains SM data for each SYNC_MNGR (relevant only to Gaudi) */ +/* contains SM data for each SYNC_MNGR (Obsolete) */ struct cpucp_monitor_dump { struct dcore_monitor_regs_data sync_mngr_w_s; struct dcore_monitor_regs_data sync_mngr_e_s; diff --git a/drivers/accel/habanalabs/include/common/hl_boot_if.h b/drivers/accel/habanalabs/include/common/hl_boot_if.h index c58d76a2705c..cff79f7f9f75 100644 --- a/drivers/accel/habanalabs/include/common/hl_boot_if.h +++ b/drivers/accel/habanalabs/include/common/hl_boot_if.h @@ -35,6 +35,7 @@ enum cpu_boot_err { CPU_BOOT_ERR_TPM_FAIL = 20, CPU_BOOT_ERR_TMP_THRESH_INIT_FAIL = 21, CPU_BOOT_ERR_EEPROM_FAIL = 22, + CPU_BOOT_ERR_ENG_ARC_MEM_SCRUB_FAIL = 23, CPU_BOOT_ERR_ENABLED = 31, CPU_BOOT_ERR_SCND_EN = 63, CPU_BOOT_ERR_LAST = 64 /* we have 2 registers of 32 bits */ @@ -51,6 +52,7 @@ enum cpu_boot_err { (1 << CPU_BOOT_ERR_DEVICE_UNUSABLE_FAIL) | \ (1 << CPU_BOOT_ERR_BINNING_FAIL) | \ (1 << CPU_BOOT_ERR_DRAM_SKIPPED) | \ + (1 << CPU_BOOT_ERR_ENG_ARC_MEM_SCRUB_FAIL) | \ (1 << CPU_BOOT_ERR_EEPROM_FAIL)) /* @@ -132,6 +134,9 @@ enum cpu_boot_err { * CPU_BOOT_ERR_EEPROM_FAIL Failed reading EEPROM data. Defaults * are used. * + * CPU_BOOT_ERR_ENG_ARC_MEM_SCRUB_FAIL Failed scrubbing the Engines/ARCFarm + * memories. Boot disabled until reset. + * * CPU_BOOT_ERR0_ENABLED Error registers enabled. * This is a main indication that the * running FW populates the error @@ -157,6 +162,7 @@ enum cpu_boot_err { #define CPU_BOOT_ERR0_TPM_FAIL (1 << CPU_BOOT_ERR_TPM_FAIL) #define CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL (1 << CPU_BOOT_ERR_TMP_THRESH_INIT_FAIL) #define CPU_BOOT_ERR0_EEPROM_FAIL (1 << CPU_BOOT_ERR_EEPROM_FAIL) +#define CPU_BOOT_ERR0_ENG_ARC_MEM_SCRUB_FAIL (1 << CPU_BOOT_ERR_ENG_ARC_MEM_SCRUB_FAIL) #define CPU_BOOT_ERR0_ENABLED (1 << CPU_BOOT_ERR_ENABLED) #define CPU_BOOT_ERR1_ENABLED (1 << CPU_BOOT_ERR_ENABLED) @@ -744,36 +750,6 @@ struct comms_status { }; }; -/** - * HL_MODULES_MAX_NUM is determined by the size of modules_mask in struct - * hl_component_versions - */ -enum hl_modules { - HL_MODULES_BOOT_INFO = 0, - HL_MODULES_EEPROM, - HL_MODULES_FDT, - HL_MODULES_I2C, - HL_MODULES_LZ4, - HL_MODULES_MBEDTLS, - HL_MODULES_MAX_NUM = 16 -}; - -/** - * HL_COMPONENTS_MAX_NUM is determined by the size of components_mask in - * struct cpucp_versions - */ -enum hl_components { - HL_COMPONENTS_PID = 0, - HL_COMPONENTS_MGMT, - HL_COMPONENTS_PREBOOT, - HL_COMPONENTS_PPBOOT, - HL_COMPONENTS_ARMCP, - HL_COMPONENTS_CPLD, - HL_COMPONENTS_UBOOT, - HL_COMPONENTS_FUSE, - HL_COMPONENTS_MAX_NUM = 16 -}; - #define NAME_MAX_LEN 32 /* bytes */ struct hl_module_data { __u8 name[NAME_MAX_LEN]; @@ -787,8 +763,6 @@ struct hl_module_data { * @component: version of the component itself. * @fw_os: Firmware OS Version. * @comp_name: Name of the component. - * @modules_mask: i'th bit (from LSB) is a flag - on if module i in enum - * hl_modules is used. * @modules_counter: number of set bits in modules_mask. * @reserved: reserved for future use. * @modules: versions of the component's modules. Elborated explanation in @@ -800,9 +774,8 @@ struct hl_component_versions { __u8 component[VERSION_MAX_LEN]; __u8 fw_os[VERSION_MAX_LEN]; __u8 comp_name[NAME_MAX_LEN]; - __le16 modules_mask; __u8 modules_counter; - __u8 reserved[1]; + __u8 reserved[3]; struct hl_module_data modules[]; }; diff --git a/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h index 6c58af614236..a08378d0802b 100644 --- a/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h +++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h @@ -242,6 +242,17 @@ #define QM_FENCE2_OFFSET (mmPDMA0_QM_CP_FENCE2_RDATA_0 - mmPDMA0_QM_BASE) #define QM_SEI_STATUS_OFFSET (mmPDMA0_QM_SEI_STATUS - mmPDMA0_QM_BASE) +#define QM_CQ_PTR_LO_4_OFFSET (mmPDMA0_QM_CQ_PTR_LO_4 - mmPDMA0_QM_BASE) +#define QM_CQ_PTR_HI_4_OFFSET (mmPDMA0_QM_CQ_PTR_HI_4 - mmPDMA0_QM_BASE) +#define QM_CQ_TSIZE_4_OFFSET (mmPDMA0_QM_CQ_TSIZE_4 - mmPDMA0_QM_BASE) + +#define QM_ARC_CQ_PTR_LO_OFFSET (mmPDMA0_QM_ARC_CQ_PTR_LO - mmPDMA0_QM_BASE) +#define QM_ARC_CQ_PTR_HI_OFFSET (mmPDMA0_QM_ARC_CQ_PTR_HI - mmPDMA0_QM_BASE) +#define QM_ARC_CQ_TSIZE_OFFSET (mmPDMA0_QM_ARC_CQ_TSIZE - mmPDMA0_QM_BASE) + +#define QM_CP_CURRENT_INST_LO_4_OFFSET (mmPDMA0_QM_CP_CURRENT_INST_LO_4 - mmPDMA0_QM_BASE) +#define QM_CP_CURRENT_INST_HI_4_OFFSET (mmPDMA0_QM_CP_CURRENT_INST_HI_4 - mmPDMA0_QM_BASE) + #define SFT_OFFSET (mmSFT1_HBW_RTR_IF0_RTR_H3_BASE - mmSFT0_HBW_RTR_IF0_RTR_H3_BASE) #define SFT_IF_RTR_OFFSET (mmSFT0_HBW_RTR_IF1_RTR_H3_BASE - mmSFT0_HBW_RTR_IF0_RTR_H3_BASE) diff --git a/drivers/accel/habanalabs/include/gaudi2/gaudi2_fw_if.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_fw_if.h index 8522f24deac0..18ca147b1c86 100644 --- a/drivers/accel/habanalabs/include/gaudi2/gaudi2_fw_if.h +++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_fw_if.h @@ -62,7 +62,7 @@ struct gaudi2_cold_rst_data { u32 fake_security_enable : 1; u32 fake_sig_validation_en : 1; u32 bist_skip_enable : 1; - u32 bist_need_iatu_config : 1; + u32 reserved1 : 1; u32 fake_bis_compliant : 1; u32 wd_rst_cause_arm : 1; u32 wd_rst_cause_arcpid : 1; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ba3fb04bb691..afb3b2f5f425 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 @@ -295,9 +289,7 @@ source "drivers/gpu/drm/armada/Kconfig" source "drivers/gpu/drm/atmel-hlcdc/Kconfig" -source "drivers/gpu/drm/rcar-du/Kconfig" - -source "drivers/gpu/drm/shmobile/Kconfig" +source "drivers/gpu/drm/renesas/Kconfig" source "drivers/gpu/drm/sun4i/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a33257d2bc7f..982d9e06168a 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -156,8 +156,7 @@ obj-$(CONFIG_DRM_UDL) += udl/ obj-$(CONFIG_DRM_AST) += ast/ obj-$(CONFIG_DRM_ARMADA) += armada/ obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ -obj-y += rcar-du/ -obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ +obj-y += renesas/ obj-y += omapdrm/ obj-$(CONFIG_DRM_SUN4I) += sun4i/ obj-y += tilcdc/ 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 <linux/errno.h> +#include <linux/fb.h> #include <linux/kernel.h> #include <linux/module.h> @@ -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/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig index 608f47f41bcd..9fae28db6aa7 100644 --- a/drivers/gpu/drm/bridge/imx/Kconfig +++ b/drivers/gpu/drm/bridge/imx/Kconfig @@ -1,9 +1,13 @@ if ARCH_MXC || COMPILE_TEST +config DRM_IMX_LDB_HELPER + tristate + config DRM_IMX8QM_LDB tristate "Freescale i.MX8QM LVDS display bridge" depends on OF depends on COMMON_CLK + select DRM_IMX_LDB_HELPER select DRM_KMS_HELPER help Choose this to enable the internal LVDS Display Bridge(LDB) found in @@ -13,6 +17,7 @@ config DRM_IMX8QXP_LDB tristate "Freescale i.MX8QXP LVDS display bridge" depends on OF depends on COMMON_CLK + select DRM_IMX_LDB_HELPER select DRM_KMS_HELPER help Choose this to enable the internal LVDS Display Bridge(LDB) found in diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile index aa90ec8d5433..8e2ebf3399a1 100644 --- a/drivers/gpu/drm/bridge/imx/Makefile +++ b/drivers/gpu/drm/bridge/imx/Makefile @@ -1,9 +1,6 @@ -imx8qm-ldb-objs := imx-ldb-helper.o imx8qm-ldb-drv.o +obj-$(CONFIG_DRM_IMX_LDB_HELPER) += imx-ldb-helper.o obj-$(CONFIG_DRM_IMX8QM_LDB) += imx8qm-ldb.o - -imx8qxp-ldb-objs := imx-ldb-helper.o imx8qxp-ldb-drv.o obj-$(CONFIG_DRM_IMX8QXP_LDB) += imx8qxp-ldb.o - obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o diff --git a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c index 7338b84bc83d..6967325cd8ee 100644 --- a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c +++ b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c @@ -4,8 +4,10 @@ * Copyright 2019,2020,2022 NXP */ +#include <linux/export.h> #include <linux/media-bus-format.h> #include <linux/mfd/syscon.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/regmap.h> @@ -19,12 +21,14 @@ bool ldb_channel_is_single_link(struct ldb_channel *ldb_ch) { return ldb_ch->link_type == LDB_CH_SINGLE_LINK; } +EXPORT_SYMBOL_GPL(ldb_channel_is_single_link); bool ldb_channel_is_split_link(struct ldb_channel *ldb_ch) { return ldb_ch->link_type == LDB_CH_DUAL_LINK_EVEN_ODD_PIXELS || ldb_ch->link_type == LDB_CH_DUAL_LINK_ODD_EVEN_PIXELS; } +EXPORT_SYMBOL_GPL(ldb_channel_is_split_link); int ldb_bridge_atomic_check_helper(struct drm_bridge *bridge, struct drm_bridge_state *bridge_state, @@ -38,6 +42,7 @@ int ldb_bridge_atomic_check_helper(struct drm_bridge *bridge, return 0; } +EXPORT_SYMBOL_GPL(ldb_bridge_atomic_check_helper); void ldb_bridge_mode_set_helper(struct drm_bridge *bridge, const struct drm_display_mode *mode, @@ -69,6 +74,7 @@ void ldb_bridge_mode_set_helper(struct drm_bridge *bridge, break; } } +EXPORT_SYMBOL_GPL(ldb_bridge_mode_set_helper); void ldb_bridge_enable_helper(struct drm_bridge *bridge) { @@ -81,6 +87,7 @@ void ldb_bridge_enable_helper(struct drm_bridge *bridge) */ regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl); } +EXPORT_SYMBOL_GPL(ldb_bridge_enable_helper); void ldb_bridge_disable_helper(struct drm_bridge *bridge) { @@ -95,6 +102,7 @@ void ldb_bridge_disable_helper(struct drm_bridge *bridge) regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl); } +EXPORT_SYMBOL_GPL(ldb_bridge_disable_helper); int ldb_bridge_attach_helper(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) @@ -117,6 +125,7 @@ int ldb_bridge_attach_helper(struct drm_bridge *bridge, ldb_ch->next_bridge, bridge, DRM_BRIDGE_ATTACH_NO_CONNECTOR); } +EXPORT_SYMBOL_GPL(ldb_bridge_attach_helper); int ldb_init_helper(struct ldb *ldb) { @@ -157,6 +166,7 @@ int ldb_init_helper(struct ldb *ldb) return 0; } +EXPORT_SYMBOL_GPL(ldb_init_helper); int ldb_find_next_bridge_helper(struct ldb *ldb) { @@ -184,6 +194,7 @@ int ldb_find_next_bridge_helper(struct ldb *ldb) return 0; } +EXPORT_SYMBOL_GPL(ldb_find_next_bridge_helper); void ldb_add_bridge_helper(struct ldb *ldb, const struct drm_bridge_funcs *bridge_funcs) @@ -204,6 +215,7 @@ void ldb_add_bridge_helper(struct ldb *ldb, drm_bridge_add(&ldb_ch->bridge); } } +EXPORT_SYMBOL_GPL(ldb_add_bridge_helper); void ldb_remove_bridge_helper(struct ldb *ldb) { @@ -219,3 +231,8 @@ void ldb_remove_bridge_helper(struct ldb *ldb) drm_bridge_remove(&ldb_ch->bridge); } } +EXPORT_SYMBOL_GPL(ldb_remove_bridge_helper); + +MODULE_DESCRIPTION("i.MX8 LVDS Display Bridge(LDB)/Pixel Mapper bridge helper"); +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/imx/imx8qm-ldb-drv.c b/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c index 386032a02599..386032a02599 100644 --- a/drivers/gpu/drm/bridge/imx/imx8qm-ldb-drv.c +++ b/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-ldb-drv.c b/drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c index c806576b1e22..c806576b1e22 100644 --- a/drivers/gpu/drm/bridge/imx/imx8qxp-ldb-drv.c +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c 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/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c index 77f7f7f54757..5641395fd310 100644 --- a/drivers/gpu/drm/bridge/tc358762.c +++ b/drivers/gpu/drm/bridge/tc358762.c @@ -11,6 +11,7 @@ */ #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of_graph.h> @@ -63,6 +64,7 @@ struct tc358762 { struct drm_bridge bridge; struct regulator *regulator; struct drm_bridge *panel_bridge; + struct gpio_desc *reset_gpio; bool pre_enabled; int error; }; @@ -138,6 +140,9 @@ static void tc358762_post_disable(struct drm_bridge *bridge) ctx->pre_enabled = false; + if (ctx->reset_gpio) + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + ret = regulator_disable(ctx->regulator); if (ret < 0) dev_err(ctx->dev, "error disabling regulators (%d)\n", ret); @@ -152,6 +157,11 @@ static void tc358762_pre_enable(struct drm_bridge *bridge) if (ret < 0) dev_err(ctx->dev, "error enabling regulators (%d)\n", ret); + if (ctx->reset_gpio) { + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 10000); + } + ret = tc358762_init(ctx); if (ret < 0) dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); @@ -185,6 +195,11 @@ static int tc358762_parse_dt(struct tc358762 *ctx) ctx->panel_bridge = panel_bridge; + /* Reset GPIO is optional */ + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) + return PTR_ERR(ctx->reset_gpio); + return 0; } 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 @@ -715,220 +737,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 * @suspend: whether to suspend or resume 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 <linux/fb.h> + #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> @@ -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 <drm/drm_client.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> +#include <drm/drm_gem.h> #include <drm/drm_print.h> #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 <sw0312.kim@samsung.com> */ +#include <linux/fb.h> + #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> @@ -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 <linux/fb.h> #include <linux/pfn_t.h> #include <drm/drm_crtc_helper.h> @@ -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 2c3f7befed17..3b5690acd720 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -28,6 +28,7 @@ #include <linux/console.h> #include <linux/delay.h> #include <linux/errno.h> +#include <linux/fb.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/mm.h> @@ -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); @@ -135,15 +140,12 @@ __diag_ignore_all("-Woverride-init", "Allow overriding the default ops"); 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/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig index 823909da87db..615fdd0ce41b 100644 --- a/drivers/gpu/drm/meson/Kconfig +++ b/drivers/gpu/drm/meson/Kconfig @@ -17,3 +17,10 @@ config DRM_MESON_DW_HDMI default y if DRM_MESON select DRM_DW_HDMI imply DRM_DW_HDMI_I2S_AUDIO + +config DRM_MESON_DW_MIPI_DSI + tristate "MIPI DSI Synopsys Controller support for Amlogic Meson Display" + depends on DRM_MESON + default y if DRM_MESON + select DRM_DW_MIPI_DSI + select GENERIC_PHY_MIPI_DPHY diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile index 3afa31bdc950..43071bdbd4b9 100644 --- a/drivers/gpu/drm/meson/Makefile +++ b/drivers/gpu/drm/meson/Makefile @@ -2,7 +2,8 @@ meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_encoder_cvbs.o meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o meson-drm-y += meson_rdma.o meson_osd_afbcd.o -meson-drm-y += meson_encoder_hdmi.o +meson-drm-y += meson_encoder_hdmi.o meson_encoder_dsi.o obj-$(CONFIG_DRM_MESON) += meson-drm.o obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o +obj-$(CONFIG_DRM_MESON_DW_MIPI_DSI) += meson_dw_mipi_dsi.o diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index ca6d1e59e5d9..747b639ea0c4 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -34,6 +34,7 @@ #include "meson_registers.h" #include "meson_encoder_cvbs.h" #include "meson_encoder_hdmi.h" +#include "meson_encoder_dsi.h" #include "meson_viu.h" #include "meson_vpp.h" #include "meson_rdma.h" @@ -316,32 +317,40 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) goto exit_afbcd; if (has_components) { - ret = component_bind_all(drm->dev, drm); + ret = component_bind_all(dev, drm); if (ret) { dev_err(drm->dev, "Couldn't bind all components\n"); + /* Do not try to unbind */ + has_components = false; goto exit_afbcd; } } ret = meson_encoder_hdmi_init(priv); if (ret) - goto unbind_all; + goto exit_afbcd; + + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + ret = meson_encoder_dsi_init(priv); + if (ret) + goto exit_afbcd; + } ret = meson_plane_create(priv); if (ret) - goto unbind_all; + goto exit_afbcd; ret = meson_overlay_create(priv); if (ret) - goto unbind_all; + goto exit_afbcd; ret = meson_crtc_create(priv); if (ret) - goto unbind_all; + goto exit_afbcd; ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); if (ret) - goto unbind_all; + goto exit_afbcd; drm_mode_config_reset(drm); @@ -359,15 +368,19 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) uninstall_irq: free_irq(priv->vsync_irq, drm); -unbind_all: - if (has_components) - component_unbind_all(drm->dev, drm); exit_afbcd: if (priv->afbcd.ops) priv->afbcd.ops->exit(priv); free_drm: drm_dev_put(drm); + meson_encoder_dsi_remove(priv); + meson_encoder_hdmi_remove(priv); + meson_encoder_cvbs_remove(priv); + + if (has_components) + component_unbind_all(dev, drm); + return ret; } @@ -394,6 +407,7 @@ static void meson_drv_unbind(struct device *dev) free_irq(priv->vsync_irq, drm); drm_dev_put(drm); + meson_encoder_dsi_remove(priv); meson_encoder_hdmi_remove(priv); meson_encoder_cvbs_remove(priv); @@ -446,10 +460,17 @@ static void meson_drv_shutdown(struct platform_device *pdev) drm_atomic_helper_shutdown(priv->drm); } -/* Possible connectors nodes to ignore */ -static const struct of_device_id connectors_match[] = { - { .compatible = "composite-video-connector" }, - { .compatible = "svideo-connector" }, +/* + * Only devices to use as components + * TOFIX: get rid of components when we can finally + * get meson_dx_hdmi to stop using the meson_drm + * private structure for HHI registers. + */ +static const struct of_device_id components_dev_match[] = { + { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, + { .compatible = "amlogic,meson-gxl-dw-hdmi" }, + { .compatible = "amlogic,meson-gxm-dw-hdmi" }, + { .compatible = "amlogic,meson-g12a-dw-hdmi" }, {} }; @@ -467,17 +488,12 @@ static int meson_drv_probe(struct platform_device *pdev) continue; } - /* If an analog connector is detected, count it as an output */ - if (of_match_node(connectors_match, remote)) { - ++count; - of_node_put(remote); - continue; - } + if (of_match_node(components_dev_match, remote)) { + component_match_add(&pdev->dev, &match, component_compare_of, remote); - dev_dbg(&pdev->dev, "parent %pOF remote match add %pOF parent %s\n", - np, remote, dev_name(&pdev->dev)); - - component_match_add(&pdev->dev, &match, component_compare_of, remote); + dev_dbg(&pdev->dev, "parent %pOF remote match add %pOF parent %s\n", + np, remote, dev_name(&pdev->dev)); + } of_node_put(remote); diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index c62ee358456f..b23009a3380f 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -28,6 +28,7 @@ enum vpu_compatible { enum { MESON_ENC_CVBS = 0, MESON_ENC_HDMI, + MESON_ENC_DSI, MESON_ENC_LAST, }; diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c new file mode 100644 index 000000000000..57447abf1a29 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/reset.h> +#include <linux/phy/phy.h> +#include <linux/bitfield.h> + +#include <video/mipi_display.h> + +#include <drm/bridge/dw_mipi_dsi.h> +#include <drm/drm_mipi_dsi.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_device.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_print.h> + +#include "meson_drv.h" +#include "meson_dw_mipi_dsi.h" +#include "meson_registers.h" +#include "meson_venc.h" + +#define DRIVER_NAME "meson-dw-mipi-dsi" +#define DRIVER_DESC "Amlogic Meson MIPI-DSI DRM driver" + +struct meson_dw_mipi_dsi { + struct meson_drm *priv; + struct device *dev; + void __iomem *base; + struct phy *phy; + union phy_configure_opts phy_opts; + struct dw_mipi_dsi *dmd; + struct dw_mipi_dsi_plat_data pdata; + struct mipi_dsi_device *dsi_device; + const struct drm_display_mode *mode; + struct clk *bit_clk; + struct clk *px_clk; + struct reset_control *top_rst; +}; + +#define encoder_to_meson_dw_mipi_dsi(x) \ + container_of(x, struct meson_dw_mipi_dsi, encoder) + +static void meson_dw_mipi_dsi_hw_init(struct meson_dw_mipi_dsi *mipi_dsi) +{ + /* Software reset */ + writel_bits_relaxed(MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR | + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING, + MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR | + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING, + mipi_dsi->base + MIPI_DSI_TOP_SW_RESET); + writel_bits_relaxed(MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR | + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING, + 0, mipi_dsi->base + MIPI_DSI_TOP_SW_RESET); + + /* Enable clocks */ + writel_bits_relaxed(MIPI_DSI_TOP_CLK_SYSCLK_EN | MIPI_DSI_TOP_CLK_PIXCLK_EN, + MIPI_DSI_TOP_CLK_SYSCLK_EN | MIPI_DSI_TOP_CLK_PIXCLK_EN, + mipi_dsi->base + MIPI_DSI_TOP_CLK_CNTL); + + /* Take memory out of power down */ + writel_relaxed(0, mipi_dsi->base + MIPI_DSI_TOP_MEM_PD); +} + +static int dw_mipi_dsi_phy_init(void *priv_data) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + unsigned int dpi_data_format, venc_data_width; + int ret; + + /* Set the bit clock rate to hs_clk_rate */ + ret = clk_set_rate(mipi_dsi->bit_clk, + mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate); + if (ret) { + dev_err(mipi_dsi->dev, "Failed to set DSI Bit clock rate %lu (ret %d)\n", + mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate, ret); + return ret; + } + + /* Make sure the rate of the bit clock is not modified by someone else */ + ret = clk_rate_exclusive_get(mipi_dsi->bit_clk); + if (ret) { + dev_err(mipi_dsi->dev, + "Failed to set the exclusivity on the bit clock rate (ret %d)\n", ret); + return ret; + } + + ret = clk_set_rate(mipi_dsi->px_clk, mipi_dsi->mode->clock * 1000); + + if (ret) { + dev_err(mipi_dsi->dev, "Failed to set DSI Pixel clock rate %u (%d)\n", + mipi_dsi->mode->clock * 1000, ret); + return ret; + } + + switch (mipi_dsi->dsi_device->format) { + case MIPI_DSI_FMT_RGB888: + dpi_data_format = DPI_COLOR_24BIT; + venc_data_width = VENC_IN_COLOR_24B; + break; + case MIPI_DSI_FMT_RGB666: + dpi_data_format = DPI_COLOR_18BIT_CFG_2; + venc_data_width = VENC_IN_COLOR_18B; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + case MIPI_DSI_FMT_RGB565: + return -EINVAL; + } + + /* Configure color format for DPI register */ + writel_relaxed(FIELD_PREP(MIPI_DSI_TOP_DPI_COLOR_MODE, dpi_data_format) | + FIELD_PREP(MIPI_DSI_TOP_IN_COLOR_MODE, venc_data_width) | + FIELD_PREP(MIPI_DSI_TOP_COMP2_SEL, 2) | + FIELD_PREP(MIPI_DSI_TOP_COMP1_SEL, 1) | + FIELD_PREP(MIPI_DSI_TOP_COMP0_SEL, 0), + mipi_dsi->base + MIPI_DSI_TOP_CNTL); + + return phy_configure(mipi_dsi->phy, &mipi_dsi->phy_opts); +} + +static void dw_mipi_dsi_phy_power_on(void *priv_data) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + + if (phy_power_on(mipi_dsi->phy)) + dev_warn(mipi_dsi->dev, "Failed to power on PHY\n"); +} + +static void dw_mipi_dsi_phy_power_off(void *priv_data) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + + if (phy_power_off(mipi_dsi->phy)) + dev_warn(mipi_dsi->dev, "Failed to power off PHY\n"); + + /* Remove the exclusivity on the bit clock rate */ + clk_rate_exclusive_put(mipi_dsi->bit_clk); +} + +static int +dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, + unsigned long mode_flags, u32 lanes, u32 format, + unsigned int *lane_mbps) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + int bpp; + + mipi_dsi->mode = mode; + + bpp = mipi_dsi_pixel_format_to_bpp(mipi_dsi->dsi_device->format); + + phy_mipi_dphy_get_default_config(mode->clock * 1000, + bpp, mipi_dsi->dsi_device->lanes, + &mipi_dsi->phy_opts.mipi_dphy); + + *lane_mbps = DIV_ROUND_UP(mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate, USEC_PER_SEC); + + return 0; +} + +static int +dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, + struct dw_mipi_dsi_dphy_timing *timing) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + + switch (mipi_dsi->mode->hdisplay) { + case 240: + case 768: + case 1920: + case 2560: + timing->clk_lp2hs = 23; + timing->clk_hs2lp = 38; + timing->data_lp2hs = 15; + timing->data_hs2lp = 9; + break; + + default: + timing->clk_lp2hs = 37; + timing->clk_hs2lp = 135; + timing->data_lp2hs = 50; + timing->data_hs2lp = 3; + } + + return 0; +} + +static int +dw_mipi_dsi_get_esc_clk_rate(void *priv_data, unsigned int *esc_clk_rate) +{ + *esc_clk_rate = 4; /* Mhz */ + + return 0; +} + +static const struct dw_mipi_dsi_phy_ops meson_dw_mipi_dsi_phy_ops = { + .init = dw_mipi_dsi_phy_init, + .power_on = dw_mipi_dsi_phy_power_on, + .power_off = dw_mipi_dsi_phy_power_off, + .get_lane_mbps = dw_mipi_dsi_get_lane_mbps, + .get_timing = dw_mipi_dsi_phy_get_timing, + .get_esc_clk_rate = dw_mipi_dsi_get_esc_clk_rate, +}; + +static int meson_dw_mipi_dsi_host_attach(void *priv_data, + struct mipi_dsi_device *device) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + int ret; + + mipi_dsi->dsi_device = device; + + switch (device->format) { + case MIPI_DSI_FMT_RGB888: + break; + case MIPI_DSI_FMT_RGB666: + break; + case MIPI_DSI_FMT_RGB666_PACKED: + case MIPI_DSI_FMT_RGB565: + dev_err(mipi_dsi->dev, "invalid pixel format %d\n", device->format); + return -EINVAL; + } + + ret = phy_init(mipi_dsi->phy); + if (ret) + return ret; + + meson_dw_mipi_dsi_hw_init(mipi_dsi); + + return 0; +} + +static int meson_dw_mipi_dsi_host_detach(void *priv_data, + struct mipi_dsi_device *device) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + + if (device == mipi_dsi->dsi_device) + mipi_dsi->dsi_device = NULL; + else + return -EINVAL; + + return phy_exit(mipi_dsi->phy); +} + +static const struct dw_mipi_dsi_host_ops meson_dw_mipi_dsi_host_ops = { + .attach = meson_dw_mipi_dsi_host_attach, + .detach = meson_dw_mipi_dsi_host_detach, +}; + +static int meson_dw_mipi_dsi_probe(struct platform_device *pdev) +{ + struct meson_dw_mipi_dsi *mipi_dsi; + struct device *dev = &pdev->dev; + + mipi_dsi = devm_kzalloc(dev, sizeof(*mipi_dsi), GFP_KERNEL); + if (!mipi_dsi) + return -ENOMEM; + + mipi_dsi->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mipi_dsi->base)) + return PTR_ERR(mipi_dsi->base); + + mipi_dsi->phy = devm_phy_get(dev, "dphy"); + if (IS_ERR(mipi_dsi->phy)) + return dev_err_probe(dev, PTR_ERR(mipi_dsi->phy), + "failed to get mipi dphy\n"); + + mipi_dsi->bit_clk = devm_clk_get_enabled(dev, "bit"); + if (IS_ERR(mipi_dsi->bit_clk)) { + int ret = PTR_ERR(mipi_dsi->bit_clk); + + /* TOFIX GP0 on some platforms fails to lock in early boot, defer probe */ + if (ret == -EIO) + ret = -EPROBE_DEFER; + + return dev_err_probe(dev, ret, "Unable to get enabled bit_clk\n"); + } + + mipi_dsi->px_clk = devm_clk_get_enabled(dev, "px"); + if (IS_ERR(mipi_dsi->px_clk)) + return dev_err_probe(dev, PTR_ERR(mipi_dsi->px_clk), + "Unable to get enabled px_clk\n"); + + /* + * We use a TOP reset signal because the APB reset signal + * is handled by the TOP control registers. + */ + mipi_dsi->top_rst = devm_reset_control_get_exclusive(dev, "top"); + if (IS_ERR(mipi_dsi->top_rst)) + return dev_err_probe(dev, PTR_ERR(mipi_dsi->top_rst), + "Unable to get reset control\n"); + + reset_control_assert(mipi_dsi->top_rst); + usleep_range(10, 20); + reset_control_deassert(mipi_dsi->top_rst); + + /* MIPI DSI Controller */ + + mipi_dsi->dev = dev; + mipi_dsi->pdata.base = mipi_dsi->base; + mipi_dsi->pdata.max_data_lanes = 4; + mipi_dsi->pdata.phy_ops = &meson_dw_mipi_dsi_phy_ops; + mipi_dsi->pdata.host_ops = &meson_dw_mipi_dsi_host_ops; + mipi_dsi->pdata.priv_data = mipi_dsi; + platform_set_drvdata(pdev, mipi_dsi); + + mipi_dsi->dmd = dw_mipi_dsi_probe(pdev, &mipi_dsi->pdata); + if (IS_ERR(mipi_dsi->dmd)) + return dev_err_probe(dev, PTR_ERR(mipi_dsi->dmd), + "Failed to probe dw_mipi_dsi\n"); + + return 0; +} + +static int meson_dw_mipi_dsi_remove(struct platform_device *pdev) +{ + struct meson_dw_mipi_dsi *mipi_dsi = platform_get_drvdata(pdev); + + dw_mipi_dsi_remove(mipi_dsi->dmd); + + return 0; +} + +static const struct of_device_id meson_dw_mipi_dsi_of_table[] = { + { .compatible = "amlogic,meson-g12a-dw-mipi-dsi", }, + { } +}; +MODULE_DEVICE_TABLE(of, meson_dw_mipi_dsi_of_table); + +static struct platform_driver meson_dw_mipi_dsi_platform_driver = { + .probe = meson_dw_mipi_dsi_probe, + .remove = meson_dw_mipi_dsi_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = meson_dw_mipi_dsi_of_table, + }, +}; +module_platform_driver(meson_dw_mipi_dsi_platform_driver); + +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.h b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.h new file mode 100644 index 000000000000..e1bd6b85d6a3 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * Copyright (C) 2018 Amlogic, Inc. All rights reserved. + */ + +#ifndef __MESON_DW_MIPI_DSI_H +#define __MESON_DW_MIPI_DSI_H + +/* Top-level registers */ +/* [31: 4] Reserved. Default 0. + * [3] RW timing_rst_n: Default 1. + * 1=Assert SW reset of timing feature. 0=Release reset. + * [2] RW dpi_rst_n: Default 1. + * 1=Assert SW reset on mipi_dsi_host_dpi block. 0=Release reset. + * [1] RW intr_rst_n: Default 1. + * 1=Assert SW reset on mipi_dsi_host_intr block. 0=Release reset. + * [0] RW dwc_rst_n: Default 1. + * 1=Assert SW reset on IP core. 0=Release reset. + */ +#define MIPI_DSI_TOP_SW_RESET 0x3c0 + +#define MIPI_DSI_TOP_SW_RESET_DWC BIT(0) +#define MIPI_DSI_TOP_SW_RESET_INTR BIT(1) +#define MIPI_DSI_TOP_SW_RESET_DPI BIT(2) +#define MIPI_DSI_TOP_SW_RESET_TIMING BIT(3) + +/* [31: 5] Reserved. Default 0. + * [4] RW manual_edpihalt: Default 0. + * 1=Manual suspend VencL; 0=do not suspend VencL. + * [3] RW auto_edpihalt_en: Default 0. + * 1=Enable IP's edpihalt signal to suspend VencL; + * 0=IP's edpihalt signal does not affect VencL. + * [2] RW clock_freerun: Apply to auto-clock gate only. Default 0. + * 0=Default, use auto-clock gating to save power; + * 1=use free-run clock, disable auto-clock gating, for debug mode. + * [1] RW enable_pixclk: A manual clock gate option, due to DWC IP does not + * have auto-clock gating. 1=Enable pixclk. Default 0. + * [0] RW enable_sysclk: A manual clock gate option, due to DWC IP does not + * have auto-clock gating. 1=Enable sysclk. Default 0. + */ +#define MIPI_DSI_TOP_CLK_CNTL 0x3c4 + +#define MIPI_DSI_TOP_CLK_SYSCLK_EN BIT(0) +#define MIPI_DSI_TOP_CLK_PIXCLK_EN BIT(1) + +/* [31:24] Reserved. Default 0. + * [23:20] RW dpi_color_mode: Define DPI pixel format. Default 0. + * 0=16-bit RGB565 config 1; + * 1=16-bit RGB565 config 2; + * 2=16-bit RGB565 config 3; + * 3=18-bit RGB666 config 1; + * 4=18-bit RGB666 config 2; + * 5=24-bit RGB888; + * 6=20-bit YCbCr 4:2:2; + * 7=24-bit YCbCr 4:2:2; + * 8=16-bit YCbCr 4:2:2; + * 9=30-bit RGB; + * 10=36-bit RGB; + * 11=12-bit YCbCr 4:2:0. + * [19] Reserved. Default 0. + * [18:16] RW in_color_mode: Define VENC data width. Default 0. + * 0=30-bit pixel; + * 1=24-bit pixel; + * 2=18-bit pixel, RGB666; + * 3=16-bit pixel, RGB565. + * [15:14] RW chroma_subsample: Define method of chroma subsampling. Default 0. + * Applicable to YUV422 or YUV420 only. + * 0=Use even pixel's chroma; + * 1=Use odd pixel's chroma; + * 2=Use averaged value between even and odd pair. + * [13:12] RW comp2_sel: Select which component to be Cr or B: Default 2. + * 0=comp0; 1=comp1; 2=comp2. + * [11:10] RW comp1_sel: Select which component to be Cb or G: Default 1. + * 0=comp0; 1=comp1; 2=comp2. + * [9: 8] RW comp0_sel: Select which component to be Y or R: Default 0. + * 0=comp0; 1=comp1; 2=comp2. + * [7] Reserved. Default 0. + * [6] RW de_pol: Default 0. + * If DE input is active low, set to 1 to invert to active high. + * [5] RW hsync_pol: Default 0. + * If HS input is active low, set to 1 to invert to active high. + * [4] RW vsync_pol: Default 0. + * If VS input is active low, set to 1 to invert to active high. + * [3] RW dpicolorm: Signal to IP. Default 0. + * [2] RW dpishutdn: Signal to IP. Default 0. + * [1] Reserved. Default 0. + * [0] Reserved. Default 0. + */ +#define MIPI_DSI_TOP_CNTL 0x3c8 + +/* VENC data width */ +#define VENC_IN_COLOR_30B 0x0 +#define VENC_IN_COLOR_24B 0x1 +#define VENC_IN_COLOR_18B 0x2 +#define VENC_IN_COLOR_16B 0x3 + +/* DPI pixel format */ +#define DPI_COLOR_16BIT_CFG_1 0 +#define DPI_COLOR_16BIT_CFG_2 1 +#define DPI_COLOR_16BIT_CFG_3 2 +#define DPI_COLOR_18BIT_CFG_1 3 +#define DPI_COLOR_18BIT_CFG_2 4 +#define DPI_COLOR_24BIT 5 +#define DPI_COLOR_20BIT_YCBCR_422 6 +#define DPI_COLOR_24BIT_YCBCR_422 7 +#define DPI_COLOR_16BIT_YCBCR_422 8 +#define DPI_COLOR_30BIT 9 +#define DPI_COLOR_36BIT 10 +#define DPI_COLOR_12BIT_YCBCR_420 11 + +#define MIPI_DSI_TOP_DPI_COLOR_MODE GENMASK(23, 20) +#define MIPI_DSI_TOP_IN_COLOR_MODE GENMASK(18, 16) +#define MIPI_DSI_TOP_CHROMA_SUBSAMPLE GENMASK(15, 14) +#define MIPI_DSI_TOP_COMP2_SEL GENMASK(13, 12) +#define MIPI_DSI_TOP_COMP1_SEL GENMASK(11, 10) +#define MIPI_DSI_TOP_COMP0_SEL GENMASK(9, 8) +#define MIPI_DSI_TOP_DE_INVERT BIT(6) +#define MIPI_DSI_TOP_HSYNC_INVERT BIT(5) +#define MIPI_DSI_TOP_VSYNC_INVERT BIT(4) +#define MIPI_DSI_TOP_DPICOLORM BIT(3) +#define MIPI_DSI_TOP_DPISHUTDN BIT(2) + +#define MIPI_DSI_TOP_SUSPEND_CNTL 0x3cc +#define MIPI_DSI_TOP_SUSPEND_LINE 0x3d0 +#define MIPI_DSI_TOP_SUSPEND_PIX 0x3d4 +#define MIPI_DSI_TOP_MEAS_CNTL 0x3d8 +/* [0] R stat_edpihalt: edpihalt signal from IP. Default 0. */ +#define MIPI_DSI_TOP_STAT 0x3dc +#define MIPI_DSI_TOP_MEAS_STAT_TE0 0x3e0 +#define MIPI_DSI_TOP_MEAS_STAT_TE1 0x3e4 +#define MIPI_DSI_TOP_MEAS_STAT_VS0 0x3e8 +#define MIPI_DSI_TOP_MEAS_STAT_VS1 0x3ec +/* [31:16] RW intr_stat/clr. Default 0. + * For each bit, read as this interrupt level status, + * write 1 to clear. + * [31:22] Reserved + * [ 21] stat/clr of eof interrupt + * [ 21] vde_fall interrupt + * [ 19] stat/clr of de_rise interrupt + * [ 18] stat/clr of vs_fall interrupt + * [ 17] stat/clr of vs_rise interrupt + * [ 16] stat/clr of dwc_edpite interrupt + * [15: 0] RW intr_enable. Default 0. + * For each bit, 1=enable this interrupt, 0=disable. + * [15: 6] Reserved + * [ 5] eof interrupt + * [ 4] de_fall interrupt + * [ 3] de_rise interrupt + * [ 2] vs_fall interrupt + * [ 1] vs_rise interrupt + * [ 0] dwc_edpite interrupt + */ +#define MIPI_DSI_TOP_INTR_CNTL_STAT 0x3f0 +// 31: 2 Reserved. Default 0. +// 1: 0 RW mem_pd. Default 3. +#define MIPI_DSI_TOP_MEM_PD 0x3f4 + +#endif /* __MESON_DW_MIPI_DSI_H */ diff --git a/drivers/gpu/drm/meson/meson_encoder_dsi.c b/drivers/gpu/drm/meson/meson_encoder_dsi.c new file mode 100644 index 000000000000..812e172dec63 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_encoder_dsi.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_bridge_connector.h> +#include <drm/drm_device.h> +#include <drm/drm_probe_helper.h> + +#include "meson_drv.h" +#include "meson_encoder_dsi.h" +#include "meson_registers.h" +#include "meson_venc.h" +#include "meson_vclk.h" + +struct meson_encoder_dsi { + struct drm_encoder encoder; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct meson_drm *priv; +}; + +#define bridge_to_meson_encoder_dsi(x) \ + container_of(x, struct meson_encoder_dsi, bridge) + +static int meson_encoder_dsi_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct meson_encoder_dsi *encoder_dsi = bridge_to_meson_encoder_dsi(bridge); + + return drm_bridge_attach(bridge->encoder, encoder_dsi->next_bridge, + &encoder_dsi->bridge, flags); +} + +static void meson_encoder_dsi_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct meson_encoder_dsi *encoder_dsi = bridge_to_meson_encoder_dsi(bridge); + struct drm_atomic_state *state = bridge_state->base.state; + struct meson_drm *priv = encoder_dsi->priv; + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + struct drm_connector *connector; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + if (WARN_ON(!connector)) + return; + + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + + /* ENCL clock setup is handled by CCF */ + + meson_venc_mipi_dsi_mode_set(priv, &crtc_state->adjusted_mode); + meson_encl_load_gamma(priv); + + writel_relaxed(0, priv->io_base + _REG(ENCL_VIDEO_EN)); + + writel_bits_relaxed(ENCL_VIDEO_MODE_ADV_VFIFO_EN, ENCL_VIDEO_MODE_ADV_VFIFO_EN, + priv->io_base + _REG(ENCL_VIDEO_MODE_ADV)); + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_EN)); + + writel_bits_relaxed(BIT(0), 0, priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); + + writel_relaxed(1, priv->io_base + _REG(ENCL_VIDEO_EN)); +} + +static void meson_encoder_dsi_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct meson_encoder_dsi *meson_encoder_dsi = + bridge_to_meson_encoder_dsi(bridge); + struct meson_drm *priv = meson_encoder_dsi->priv; + + writel_relaxed(0, priv->io_base + _REG(ENCL_VIDEO_EN)); + + writel_bits_relaxed(BIT(0), BIT(0), priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); +} + +static const struct drm_bridge_funcs meson_encoder_dsi_bridge_funcs = { + .attach = meson_encoder_dsi_attach, + .atomic_enable = meson_encoder_dsi_atomic_enable, + .atomic_disable = meson_encoder_dsi_atomic_disable, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, +}; + +int meson_encoder_dsi_init(struct meson_drm *priv) +{ + struct meson_encoder_dsi *meson_encoder_dsi; + struct device_node *remote; + int ret; + + meson_encoder_dsi = devm_kzalloc(priv->dev, sizeof(*meson_encoder_dsi), GFP_KERNEL); + if (!meson_encoder_dsi) + return -ENOMEM; + + /* DSI Transceiver Bridge */ + remote = of_graph_get_remote_node(priv->dev->of_node, 2, 0); + if (!remote) { + dev_err(priv->dev, "DSI transceiver device is disabled"); + return 0; + } + + meson_encoder_dsi->next_bridge = of_drm_find_bridge(remote); + if (!meson_encoder_dsi->next_bridge) { + dev_dbg(priv->dev, "Failed to find DSI transceiver bridge\n"); + return -EPROBE_DEFER; + } + + /* DSI Encoder Bridge */ + meson_encoder_dsi->bridge.funcs = &meson_encoder_dsi_bridge_funcs; + meson_encoder_dsi->bridge.of_node = priv->dev->of_node; + meson_encoder_dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; + + drm_bridge_add(&meson_encoder_dsi->bridge); + + meson_encoder_dsi->priv = priv; + + /* Encoder */ + ret = drm_simple_encoder_init(priv->drm, &meson_encoder_dsi->encoder, + DRM_MODE_ENCODER_DSI); + if (ret) { + dev_err(priv->dev, "Failed to init DSI encoder: %d\n", ret); + return ret; + } + + meson_encoder_dsi->encoder.possible_crtcs = BIT(0); + + /* Attach DSI Encoder Bridge to Encoder */ + ret = drm_bridge_attach(&meson_encoder_dsi->encoder, &meson_encoder_dsi->bridge, NULL, 0); + if (ret) { + dev_err(priv->dev, "Failed to attach bridge: %d\n", ret); + return ret; + } + + /* + * We should have now in place: + * encoder->[dsi encoder bridge]->[dw-mipi-dsi bridge]->[panel bridge]->[panel] + */ + + priv->encoders[MESON_ENC_DSI] = meson_encoder_dsi; + + dev_dbg(priv->dev, "DSI encoder initialized\n"); + + return 0; +} + +void meson_encoder_dsi_remove(struct meson_drm *priv) +{ + struct meson_encoder_dsi *meson_encoder_dsi; + + if (priv->encoders[MESON_ENC_DSI]) { + meson_encoder_dsi = priv->encoders[MESON_ENC_DSI]; + drm_bridge_remove(&meson_encoder_dsi->bridge); + drm_bridge_remove(meson_encoder_dsi->next_bridge); + } +} diff --git a/drivers/gpu/drm/meson/meson_encoder_dsi.h b/drivers/gpu/drm/meson/meson_encoder_dsi.h new file mode 100644 index 000000000000..9277d7015193 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_encoder_dsi.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + */ + +#ifndef __MESON_ENCODER_DSI_H +#define __MESON_ENCODER_DSI_H + +int meson_encoder_dsi_init(struct meson_drm *priv); +void meson_encoder_dsi_remove(struct meson_drm *priv); + +#endif /* __MESON_ENCODER_DSI_H */ diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h index 0f3cafab8860..3d73d00a1f4c 100644 --- a/drivers/gpu/drm/meson/meson_registers.h +++ b/drivers/gpu/drm/meson/meson_registers.h @@ -812,6 +812,7 @@ #define VENC_STATA 0x1b6d #define VENC_INTCTRL 0x1b6e #define VENC_INTCTRL_ENCI_LNRST_INT_EN BIT(1) +#define VENC_INTCTRL_ENCP_LNRST_INT_EN BIT(9) #define VENC_INTFLAG 0x1b6f #define VENC_VIDEO_TST_EN 0x1b70 #define VENC_VIDEO_TST_MDSEL 0x1b71 @@ -1192,7 +1193,11 @@ #define ENCL_VIDEO_PB_OFFST 0x1ca5 #define ENCL_VIDEO_PR_OFFST 0x1ca6 #define ENCL_VIDEO_MODE 0x1ca7 +#define ENCL_PX_LN_CNT_SHADOW_EN BIT(15) #define ENCL_VIDEO_MODE_ADV 0x1ca8 +#define ENCL_VIDEO_MODE_ADV_VFIFO_EN BIT(3) +#define ENCL_VIDEO_MODE_ADV_GAIN_HDTV BIT(4) +#define ENCL_SEL_GAMMA_RGB_IN BIT(10) #define ENCL_DBG_PX_RST 0x1ca9 #define ENCL_DBG_LN_RST 0x1caa #define ENCL_DBG_PX_INT 0x1cab @@ -1219,11 +1224,14 @@ #define ENCL_VIDEO_VOFFST 0x1cc0 #define ENCL_VIDEO_RGB_CTRL 0x1cc1 #define ENCL_VIDEO_FILT_CTRL 0x1cc2 +#define ENCL_VIDEO_FILT_CTRL_BYPASS_FILTER BIT(12) #define ENCL_VIDEO_OFLD_VPEQ_OFST 0x1cc3 #define ENCL_VIDEO_OFLD_VOAV_OFST 0x1cc4 #define ENCL_VIDEO_MATRIX_CB 0x1cc5 #define ENCL_VIDEO_MATRIX_CR 0x1cc6 #define ENCL_VIDEO_RGBIN_CTRL 0x1cc7 +#define ENCL_VIDEO_RGBIN_RGB BIT(0) +#define ENCL_VIDEO_RGBIN_ZBLK BIT(1) #define ENCL_MAX_LINE_SWITCH_POINT 0x1cc8 #define ENCL_DACSEL_0 0x1cc9 #define ENCL_DACSEL_1 0x1cca @@ -1300,13 +1308,28 @@ #define RDMA_STATUS2 0x1116 #define RDMA_STATUS3 0x1117 #define L_GAMMA_CNTL_PORT 0x1400 +#define L_GAMMA_CNTL_PORT_VCOM_POL BIT(7) /* RW */ +#define L_GAMMA_CNTL_PORT_RVS_OUT BIT(6) /* RW */ +#define L_GAMMA_CNTL_PORT_ADR_RDY BIT(5) /* Read Only */ +#define L_GAMMA_CNTL_PORT_WR_RDY BIT(4) /* Read Only */ +#define L_GAMMA_CNTL_PORT_RD_RDY BIT(3) /* Read Only */ +#define L_GAMMA_CNTL_PORT_TR BIT(2) /* RW */ +#define L_GAMMA_CNTL_PORT_SET BIT(1) /* RW */ +#define L_GAMMA_CNTL_PORT_EN BIT(0) /* RW */ #define L_GAMMA_DATA_PORT 0x1401 #define L_GAMMA_ADDR_PORT 0x1402 +#define L_GAMMA_ADDR_PORT_RD BIT(12) +#define L_GAMMA_ADDR_PORT_AUTO_INC BIT(11) +#define L_GAMMA_ADDR_PORT_SEL_R BIT(10) +#define L_GAMMA_ADDR_PORT_SEL_G BIT(9) +#define L_GAMMA_ADDR_PORT_SEL_B BIT(8) +#define L_GAMMA_ADDR_PORT_ADDR GENMASK(7, 0) #define L_GAMMA_VCOM_HSWITCH_ADDR 0x1403 #define L_RGB_BASE_ADDR 0x1405 #define L_RGB_COEFF_ADDR 0x1406 #define L_POL_CNTL_ADDR 0x1407 #define L_DITH_CNTL_ADDR 0x1408 +#define L_DITH_CNTL_DITH10_EN BIT(10) #define L_GAMMA_PROBE_CTRL 0x1409 #define L_GAMMA_PROBE_COLOR_L 0x140a #define L_GAMMA_PROBE_COLOR_H 0x140b @@ -1363,6 +1386,8 @@ #define L_LCD_PWM1_HI_ADDR 0x143f #define L_INV_CNT_ADDR 0x1440 #define L_TCON_MISC_SEL_ADDR 0x1441 +#define L_TCON_MISC_SEL_STV1 BIT(4) +#define L_TCON_MISC_SEL_STV2 BIT(5) #define L_DUAL_PORT_CNTL_ADDR 0x1442 #define MLVDS_CLK_CTL1_HI 0x1443 #define MLVDS_CLK_CTL1_LO 0x1444 diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 27ef9f88e4ff..3bf0d6e4fc30 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -5,7 +5,9 @@ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. */ +#include <linux/bitfield.h> #include <linux/export.h> +#include <linux/iopoll.h> #include <drm/drm_modes.h> @@ -1557,6 +1559,205 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, } EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set); +static unsigned short meson_encl_gamma_table[256] = { + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, + 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, + 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, + 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, + 256, 260, 264, 268, 272, 276, 280, 284, 288, 292, 296, 300, 304, 308, 312, 316, + 320, 324, 328, 332, 336, 340, 344, 348, 352, 356, 360, 364, 368, 372, 376, 380, + 384, 388, 392, 396, 400, 404, 408, 412, 416, 420, 424, 428, 432, 436, 440, 444, + 448, 452, 456, 460, 464, 468, 472, 476, 480, 484, 488, 492, 496, 500, 504, 508, + 512, 516, 520, 524, 528, 532, 536, 540, 544, 548, 552, 556, 560, 564, 568, 572, + 576, 580, 584, 588, 592, 596, 600, 604, 608, 612, 616, 620, 624, 628, 632, 636, + 640, 644, 648, 652, 656, 660, 664, 668, 672, 676, 680, 684, 688, 692, 696, 700, + 704, 708, 712, 716, 720, 724, 728, 732, 736, 740, 744, 748, 752, 756, 760, 764, + 768, 772, 776, 780, 784, 788, 792, 796, 800, 804, 808, 812, 816, 820, 824, 828, + 832, 836, 840, 844, 848, 852, 856, 860, 864, 868, 872, 876, 880, 884, 888, 892, + 896, 900, 904, 908, 912, 916, 920, 924, 928, 932, 936, 940, 944, 948, 952, 956, + 960, 964, 968, 972, 976, 980, 984, 988, 992, 996, 1000, 1004, 1008, 1012, 1016, 1020, +}; + +static void meson_encl_set_gamma_table(struct meson_drm *priv, u16 *data, + u32 rgb_mask) +{ + int i, ret; + u32 reg; + + writel_bits_relaxed(L_GAMMA_CNTL_PORT_EN, 0, + priv->io_base + _REG(L_GAMMA_CNTL_PORT)); + + ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT), + reg, reg & L_GAMMA_CNTL_PORT_ADR_RDY, 10, 10000); + if (ret) + pr_warn("%s: GAMMA ADR_RDY timeout\n", __func__); + + writel_relaxed(L_GAMMA_ADDR_PORT_AUTO_INC | rgb_mask | + FIELD_PREP(L_GAMMA_ADDR_PORT_ADDR, 0), + priv->io_base + _REG(L_GAMMA_ADDR_PORT)); + + for (i = 0; i < 256; i++) { + ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT), + reg, reg & L_GAMMA_CNTL_PORT_WR_RDY, + 10, 10000); + if (ret) + pr_warn_once("%s: GAMMA WR_RDY timeout\n", __func__); + + writel_relaxed(data[i], priv->io_base + _REG(L_GAMMA_DATA_PORT)); + } + + ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT), + reg, reg & L_GAMMA_CNTL_PORT_ADR_RDY, 10, 10000); + if (ret) + pr_warn("%s: GAMMA ADR_RDY timeout\n", __func__); + + writel_relaxed(L_GAMMA_ADDR_PORT_AUTO_INC | rgb_mask | + FIELD_PREP(L_GAMMA_ADDR_PORT_ADDR, 0x23), + priv->io_base + _REG(L_GAMMA_ADDR_PORT)); +} + +void meson_encl_load_gamma(struct meson_drm *priv) +{ + meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_R); + meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_G); + meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_B); + + writel_bits_relaxed(L_GAMMA_CNTL_PORT_EN, L_GAMMA_CNTL_PORT_EN, + priv->io_base + _REG(L_GAMMA_CNTL_PORT)); +} + +void meson_venc_mipi_dsi_mode_set(struct meson_drm *priv, + const struct drm_display_mode *mode) +{ + unsigned int max_pxcnt; + unsigned int max_lncnt; + unsigned int havon_begin; + unsigned int havon_end; + unsigned int vavon_bline; + unsigned int vavon_eline; + unsigned int hso_begin; + unsigned int hso_end; + unsigned int vso_begin; + unsigned int vso_end; + unsigned int vso_bline; + unsigned int vso_eline; + + max_pxcnt = mode->htotal - 1; + max_lncnt = mode->vtotal - 1; + havon_begin = mode->htotal - mode->hsync_start; + havon_end = havon_begin + mode->hdisplay - 1; + vavon_bline = mode->vtotal - mode->vsync_start; + vavon_eline = vavon_bline + mode->vdisplay - 1; + hso_begin = 0; + hso_end = mode->hsync_end - mode->hsync_start; + vso_begin = 0; + vso_end = 0; + vso_bline = 0; + vso_eline = mode->vsync_end - mode->vsync_start; + + meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCL); + + writel_relaxed(0, priv->io_base + _REG(ENCL_VIDEO_EN)); + + writel_relaxed(ENCL_PX_LN_CNT_SHADOW_EN, priv->io_base + _REG(ENCL_VIDEO_MODE)); + writel_relaxed(ENCL_VIDEO_MODE_ADV_VFIFO_EN | + ENCL_VIDEO_MODE_ADV_GAIN_HDTV | + ENCL_SEL_GAMMA_RGB_IN, priv->io_base + _REG(ENCL_VIDEO_MODE_ADV)); + + writel_relaxed(ENCL_VIDEO_FILT_CTRL_BYPASS_FILTER, + priv->io_base + _REG(ENCL_VIDEO_FILT_CTRL)); + writel_relaxed(max_pxcnt, priv->io_base + _REG(ENCL_VIDEO_MAX_PXCNT)); + writel_relaxed(max_lncnt, priv->io_base + _REG(ENCL_VIDEO_MAX_LNCNT)); + writel_relaxed(havon_begin, priv->io_base + _REG(ENCL_VIDEO_HAVON_BEGIN)); + writel_relaxed(havon_end, priv->io_base + _REG(ENCL_VIDEO_HAVON_END)); + writel_relaxed(vavon_bline, priv->io_base + _REG(ENCL_VIDEO_VAVON_BLINE)); + writel_relaxed(vavon_eline, priv->io_base + _REG(ENCL_VIDEO_VAVON_ELINE)); + + writel_relaxed(hso_begin, priv->io_base + _REG(ENCL_VIDEO_HSO_BEGIN)); + writel_relaxed(hso_end, priv->io_base + _REG(ENCL_VIDEO_HSO_END)); + writel_relaxed(vso_begin, priv->io_base + _REG(ENCL_VIDEO_VSO_BEGIN)); + writel_relaxed(vso_end, priv->io_base + _REG(ENCL_VIDEO_VSO_END)); + writel_relaxed(vso_bline, priv->io_base + _REG(ENCL_VIDEO_VSO_BLINE)); + writel_relaxed(vso_eline, priv->io_base + _REG(ENCL_VIDEO_VSO_ELINE)); + writel_relaxed(ENCL_VIDEO_RGBIN_RGB | ENCL_VIDEO_RGBIN_ZBLK, + priv->io_base + _REG(ENCL_VIDEO_RGBIN_CTRL)); + + /* default black pattern */ + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_MDSEL)); + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_Y)); + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_CB)); + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_CR)); + writel_relaxed(1, priv->io_base + _REG(ENCL_TST_EN)); + writel_bits_relaxed(ENCL_VIDEO_MODE_ADV_VFIFO_EN, 0, + priv->io_base + _REG(ENCL_VIDEO_MODE_ADV)); + + writel_relaxed(1, priv->io_base + _REG(ENCL_VIDEO_EN)); + + writel_relaxed(0, priv->io_base + _REG(L_RGB_BASE_ADDR)); + writel_relaxed(0x400, priv->io_base + _REG(L_RGB_COEFF_ADDR)); /* Magic value */ + + writel_relaxed(L_DITH_CNTL_DITH10_EN, priv->io_base + _REG(L_DITH_CNTL_ADDR)); + + /* DE signal for TTL */ + writel_relaxed(havon_begin, priv->io_base + _REG(L_OEH_HS_ADDR)); + writel_relaxed(havon_end + 1, priv->io_base + _REG(L_OEH_HE_ADDR)); + writel_relaxed(vavon_bline, priv->io_base + _REG(L_OEH_VS_ADDR)); + writel_relaxed(vavon_eline, priv->io_base + _REG(L_OEH_VE_ADDR)); + + /* DE signal for TTL */ + writel_relaxed(havon_begin, priv->io_base + _REG(L_OEV1_HS_ADDR)); + writel_relaxed(havon_end + 1, priv->io_base + _REG(L_OEV1_HE_ADDR)); + writel_relaxed(vavon_bline, priv->io_base + _REG(L_OEV1_VS_ADDR)); + writel_relaxed(vavon_eline, priv->io_base + _REG(L_OEV1_VE_ADDR)); + + /* Hsync signal for TTL */ + if (mode->flags & DRM_MODE_FLAG_PHSYNC) { + writel_relaxed(hso_begin, priv->io_base + _REG(L_STH1_HS_ADDR)); + writel_relaxed(hso_end, priv->io_base + _REG(L_STH1_HE_ADDR)); + } else { + writel_relaxed(hso_end, priv->io_base + _REG(L_STH1_HS_ADDR)); + writel_relaxed(hso_begin, priv->io_base + _REG(L_STH1_HE_ADDR)); + } + writel_relaxed(0, priv->io_base + _REG(L_STH1_VS_ADDR)); + writel_relaxed(max_lncnt, priv->io_base + _REG(L_STH1_VE_ADDR)); + + /* Vsync signal for TTL */ + writel_relaxed(vso_begin, priv->io_base + _REG(L_STV1_HS_ADDR)); + writel_relaxed(vso_end, priv->io_base + _REG(L_STV1_HE_ADDR)); + if (mode->flags & DRM_MODE_FLAG_PVSYNC) { + writel_relaxed(vso_bline, priv->io_base + _REG(L_STV1_VS_ADDR)); + writel_relaxed(vso_eline, priv->io_base + _REG(L_STV1_VE_ADDR)); + } else { + writel_relaxed(vso_eline, priv->io_base + _REG(L_STV1_VS_ADDR)); + writel_relaxed(vso_bline, priv->io_base + _REG(L_STV1_VE_ADDR)); + } + + /* DE signal */ + writel_relaxed(havon_begin, priv->io_base + _REG(L_DE_HS_ADDR)); + writel_relaxed(havon_end + 1, priv->io_base + _REG(L_DE_HE_ADDR)); + writel_relaxed(vavon_bline, priv->io_base + _REG(L_DE_VS_ADDR)); + writel_relaxed(vavon_eline, priv->io_base + _REG(L_DE_VE_ADDR)); + + /* Hsync signal */ + writel_relaxed(hso_begin, priv->io_base + _REG(L_HSYNC_HS_ADDR)); + writel_relaxed(hso_end, priv->io_base + _REG(L_HSYNC_HE_ADDR)); + writel_relaxed(0, priv->io_base + _REG(L_HSYNC_VS_ADDR)); + writel_relaxed(max_lncnt, priv->io_base + _REG(L_HSYNC_VE_ADDR)); + + /* Vsync signal */ + writel_relaxed(vso_begin, priv->io_base + _REG(L_VSYNC_HS_ADDR)); + writel_relaxed(vso_end, priv->io_base + _REG(L_VSYNC_HE_ADDR)); + writel_relaxed(vso_bline, priv->io_base + _REG(L_VSYNC_VS_ADDR)); + writel_relaxed(vso_eline, priv->io_base + _REG(L_VSYNC_VE_ADDR)); + + writel_relaxed(0, priv->io_base + _REG(L_INV_CNT_ADDR)); + writel_relaxed(L_TCON_MISC_SEL_STV1 | L_TCON_MISC_SEL_STV2, + priv->io_base + _REG(L_TCON_MISC_SEL_ADDR)); + + priv->venc.current_mode = MESON_VENC_MODE_MIPI_DSI; +} +EXPORT_SYMBOL_GPL(meson_venc_mipi_dsi_mode_set); + void meson_venci_cvbs_mode_set(struct meson_drm *priv, struct meson_cvbs_enci_mode *mode) { @@ -1747,8 +1948,15 @@ unsigned int meson_venci_get_field(struct meson_drm *priv) void meson_venc_enable_vsync(struct meson_drm *priv) { - writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN, - priv->io_base + _REG(VENC_INTCTRL)); + switch (priv->venc.current_mode) { + case MESON_VENC_MODE_MIPI_DSI: + writel_relaxed(VENC_INTCTRL_ENCP_LNRST_INT_EN, + priv->io_base + _REG(VENC_INTCTRL)); + break; + default: + writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN, + priv->io_base + _REG(VENC_INTCTRL)); + } regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25)); } diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h index 9138255ffc9e..0f59adb1c6db 100644 --- a/drivers/gpu/drm/meson/meson_venc.h +++ b/drivers/gpu/drm/meson/meson_venc.h @@ -21,6 +21,7 @@ enum { MESON_VENC_MODE_CVBS_PAL, MESON_VENC_MODE_CVBS_NTSC, MESON_VENC_MODE_HDMI, + MESON_VENC_MODE_MIPI_DSI, }; struct meson_cvbs_enci_mode { @@ -47,6 +48,9 @@ struct meson_cvbs_enci_mode { unsigned int analog_sync_adj; }; +/* LCD Encoder gamma setup */ +void meson_encl_load_gamma(struct meson_drm *priv); + /* HDMI Clock parameters */ enum drm_mode_status meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); @@ -63,6 +67,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int ycrcb_map, bool yuv420_mode, const struct drm_display_mode *mode); +void meson_venc_mipi_dsi_mode_set(struct meson_drm *priv, + const struct drm_display_mode *mode); unsigned int meson_venci_get_field(struct meson_drm *priv); void meson_venc_enable_vsync(struct meson_drm *priv); diff --git a/drivers/gpu/drm/meson/meson_vpp.h b/drivers/gpu/drm/meson/meson_vpp.h index afc9553ed8d3..b790042a1650 100644 --- a/drivers/gpu/drm/meson/meson_vpp.h +++ b/drivers/gpu/drm/meson/meson_vpp.h @@ -12,6 +12,8 @@ struct drm_rect; struct meson_drm; +/* Mux VIU/VPP to ENCL */ +#define MESON_VIU_VPP_MUX_ENCL 0x0 /* Mux VIU/VPP to ENCI */ #define MESON_VIU_VPP_MUX_ENCI 0x5 /* Mux VIU/VPP to ENCP */ 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 <robdclark@gmail.com> */ +#include <linux/fb.h> + #include <drm/drm_drv.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> @@ -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 <linux/dma-mapping.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_drv.h> +#include <drm/drm_encoder.h> #include <drm/drm_fbdev_dma.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -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); - - ret = drm_bridge_attach(&lcdif->encoder, bridge, NULL, 0); - if (ret) - return dev_err_probe(drm->dev, ret, "Failed to attach bridge\n"); - - lcdif->bridge = bridge; + for_each_endpoint_of_node(dev->of_node, ep) { + struct device_node *remote; + struct of_endpoint of_ep; + struct drm_encoder *encoder; + + remote = of_graph_get_remote_port_parent(ep); + if (!of_device_is_available(remote)) { + of_node_put(remote); + continue; + } + of_node_put(remote); + + 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 <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> -#include <drm/drm_encoder.h> #include <drm/drm_plane.h> 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 <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_color_mgmt.h> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include <drm/drm_encoder.h> #include <drm/drm_fb_dma_helper.h> @@ -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,25 +649,17 @@ 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 <rob@ti.com> */ +#include <linux/fb.h> + #include <drm/drm_drv.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> @@ -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-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index f5a6046f1d19..3cc9fb0d4f5d 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -1301,6 +1301,416 @@ static const struct panel_init_cmd starry_qfh032011_53g_init_cmd[] = { {}, }; +static const struct panel_init_cmd starry_himax83102_j02_init_cmd[] = { + _INIT_DCS_CMD(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00), + _INIT_DCS_CMD(0xB1, 0x2C, 0xB5, 0xB5, 0x31, 0xF1, 0x31, 0xD7, 0x2F, 0x36, 0x36, 0x36, 0x36, 0x1A, 0x8B, 0x11, + 0x65, 0x00, 0x88, 0xFA, 0xFF, 0xFF, 0x8F, 0xFF, 0x08, 0x74, 0x33), + _INIT_DCS_CMD(0xB2, 0x00, 0x47, 0xB0, 0x80, 0x00, 0x12, 0x72, 0x3C, 0xA3, 0x03, 0x03, 0x00, 0x00, 0x88, 0xF5), + _INIT_DCS_CMD(0xB4, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x63, 0x5C, 0x63, 0x5C, 0x01, 0x9E), + _INIT_DCS_CMD(0xE9, 0xCD), + _INIT_DCS_CMD(0xBA, 0x84), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xBC, 0x1B, 0x04), + _INIT_DCS_CMD(0xBE, 0x20), + _INIT_DCS_CMD(0xBF, 0xFC, 0xC4), + _INIT_DCS_CMD(0xC0, 0x36, 0x36, 0x22, 0x11, 0x22, 0xA0, 0x61, 0x08, 0xF5, 0x03), + _INIT_DCS_CMD(0xE9, 0xCC), + _INIT_DCS_CMD(0xC7, 0x80), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xE9, 0xC6), + _INIT_DCS_CMD(0xC8, 0x97), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xC9, 0x00, 0x1E, 0x13, 0x88, 0x01), + _INIT_DCS_CMD(0xCB, 0x08, 0x13, 0x07, 0x00, 0x0F, 0x33), + _INIT_DCS_CMD(0xCC, 0x02), + _INIT_DCS_CMD(0xE9, 0xC4), + _INIT_DCS_CMD(0xD0, 0x03), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xD1, 0x37, 0x06, 0x00, 0x02, 0x04, 0x0C, 0xFF), + _INIT_DCS_CMD(0xD2, 0x1F, 0x11, 0x1F), + _INIT_DCS_CMD(0xD3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x37, 0x47, 0x34, 0x3B, 0x12, 0x12, 0x03, + 0x03, 0x32, 0x10, 0x10, 0x00, 0x10, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32, 0x17, 0x94, 0x07, 0x94, 0x00, 0x00), + _INIT_DCS_CMD(0xD5, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x40, 0x40, 0x1A, 0x1A, + 0x1B, 0x1B, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x28, 0x29, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18), + _INIT_DCS_CMD(0xD6, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x40, 0x40, 0x19, 0x19, 0x1A, 0x1A, + 0x1B, 0x1B, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x29, 0x28, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18), + _INIT_DCS_CMD(0xD8, 0xAA, 0xBA, 0xEA, 0xAA, 0xAA, 0xA0, 0xAA, 0xBA, 0xEA, 0xAA, 0xAA, 0xA0, 0xAA, 0xBA, 0xEA, 0xAA, + 0xAA, 0xA0, 0xAA, 0xBA, 0xEA, 0xAA, 0xAA, 0xA0, 0xAA, 0xBA, 0xEA, 0xAA, 0xAA, 0xA0, 0xAA, 0xBA, 0xEA, 0xAA, 0xAA, 0xA0), + _INIT_DCS_CMD(0xE0, 0x00, 0x09, 0x14, 0x1E, 0x26, 0x48, 0x61, 0x67, 0x6C, 0x67, 0x7D, 0x7F, 0x80, 0x8B, 0x87, 0x8F, 0x98, 0xAB, + 0xAB, 0x55, 0x5C, 0x68, 0x73, 0x00, 0x09, 0x14, 0x1E, 0x26, 0x48, 0x61, 0x67, 0x6C, 0x67, 0x7D, 0x7F, 0x80, 0x8B, 0x87, 0x8F, 0x98, 0xAB, 0xAB, 0x55, 0x5C, 0x68, 0x73), + _INIT_DCS_CMD(0xE7, 0x0E, 0x10, 0x10, 0x21, 0x2B, 0x9A, 0x02, 0x54, 0x9A, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x12, 0x05, 0x02, 0x02, 0x10), + _INIT_DCS_CMD(0xBD, 0x01), + _INIT_DCS_CMD(0xB1, 0x01, 0xBF, 0x11), + _INIT_DCS_CMD(0xCB, 0x86), + _INIT_DCS_CMD(0xD2, 0x3C, 0xFA), + _INIT_DCS_CMD(0xE9, 0xC5), + _INIT_DCS_CMD(0xD3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0C, 0x01), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xE7, 0x02, 0x00, 0x28, 0x01, 0x7E, 0x0F, 0x7E, 0x10, 0xA0, 0x00, 0x00, 0x20, 0x40, 0x50, 0x40), + _INIT_DCS_CMD(0xBD, 0x02), + _INIT_DCS_CMD(0xD8, 0xFF, 0xFF, 0xBF, 0xFE, 0xAA, 0xA0, 0xFF, 0xFF, 0xBF, 0xFE, 0xAA, 0xA0), + _INIT_DCS_CMD(0xE7, 0xFE, 0x04, 0xFE, 0x04, 0xFE, 0x04, 0x03, 0x03, 0x03, 0x26, 0x00, 0x26, 0x81, 0x02, 0x40, 0x00, 0x20, 0x9E, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00), + _INIT_DCS_CMD(0xBD, 0x03), + _INIT_DCS_CMD(0xE9, 0xC6), + _INIT_DCS_CMD(0xB4, 0x03, 0xFF, 0xF8), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xD8, 0x00, 0x2A, 0xAA, 0xA8, 0x00, 0x00, 0x00, 0x2A, 0xAA, 0xA8, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x2A, 0xAA, 0xA8, + 0x00, 0x00, 0x00, 0x2A, 0xAA, 0xA8, 0x00, 0x00), + _INIT_DCS_CMD(0xBD, 0x00), + _INIT_DCS_CMD(0xE9, 0xC4), + _INIT_DCS_CMD(0xBA, 0x96), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xBD, 0x01), + _INIT_DCS_CMD(0xE9, 0xC5), + _INIT_DCS_CMD(0xBA, 0x4F), + _INIT_DCS_CMD(0xE9, 0x3F), + _INIT_DCS_CMD(0xBD, 0x00), + _INIT_DCS_CMD(0x11), + _INIT_DELAY_CMD(120), + _INIT_DCS_CMD(0x29), + {}, +}; + +static const struct panel_init_cmd starry_ili9882t_init_cmd[] = { + _INIT_DELAY_CMD(5), + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x01), + _INIT_DCS_CMD(0x00, 0x42), + _INIT_DCS_CMD(0x01, 0x11), + _INIT_DCS_CMD(0x02, 0x00), + _INIT_DCS_CMD(0x03, 0x00), + + _INIT_DCS_CMD(0x04, 0x01), + _INIT_DCS_CMD(0x05, 0x11), + _INIT_DCS_CMD(0x06, 0x00), + _INIT_DCS_CMD(0x07, 0x00), + + _INIT_DCS_CMD(0x08, 0x80), + _INIT_DCS_CMD(0x09, 0x81), + _INIT_DCS_CMD(0x0A, 0x71), + _INIT_DCS_CMD(0x0B, 0x00), + + _INIT_DCS_CMD(0x0C, 0x00), + _INIT_DCS_CMD(0x0E, 0x1A), + + _INIT_DCS_CMD(0x24, 0x00), + _INIT_DCS_CMD(0x25, 0x00), + _INIT_DCS_CMD(0x26, 0x00), + _INIT_DCS_CMD(0x27, 0x00), + + _INIT_DCS_CMD(0x2C, 0xD4), + _INIT_DCS_CMD(0xB9, 0x40), + + _INIT_DCS_CMD(0xB0, 0x11), + + _INIT_DCS_CMD(0xE6, 0x32), + _INIT_DCS_CMD(0xD1, 0x30), + + _INIT_DCS_CMD(0xD6, 0x55), + + _INIT_DCS_CMD(0xD0, 0x01), + _INIT_DCS_CMD(0xE3, 0x93), + _INIT_DCS_CMD(0xE4, 0x00), + _INIT_DCS_CMD(0xE5, 0x80), + + _INIT_DCS_CMD(0x31, 0x07), + _INIT_DCS_CMD(0x32, 0x07), + _INIT_DCS_CMD(0x33, 0x07), + _INIT_DCS_CMD(0x34, 0x07), + _INIT_DCS_CMD(0x35, 0x07), + _INIT_DCS_CMD(0x36, 0x01), + _INIT_DCS_CMD(0x37, 0x00), + _INIT_DCS_CMD(0x38, 0x28), + _INIT_DCS_CMD(0x39, 0x29), + _INIT_DCS_CMD(0x3A, 0x11), + _INIT_DCS_CMD(0x3B, 0x13), + _INIT_DCS_CMD(0x3C, 0x15), + _INIT_DCS_CMD(0x3D, 0x17), + _INIT_DCS_CMD(0x3E, 0x09), + _INIT_DCS_CMD(0x3F, 0x0D), + _INIT_DCS_CMD(0x40, 0x02), + _INIT_DCS_CMD(0x41, 0x02), + _INIT_DCS_CMD(0x42, 0x02), + _INIT_DCS_CMD(0x43, 0x02), + _INIT_DCS_CMD(0x44, 0x02), + _INIT_DCS_CMD(0x45, 0x02), + _INIT_DCS_CMD(0x46, 0x02), + + _INIT_DCS_CMD(0x47, 0x07), + _INIT_DCS_CMD(0x48, 0x07), + _INIT_DCS_CMD(0x49, 0x07), + _INIT_DCS_CMD(0x4A, 0x07), + _INIT_DCS_CMD(0x4B, 0x07), + _INIT_DCS_CMD(0x4C, 0x01), + _INIT_DCS_CMD(0x4D, 0x00), + _INIT_DCS_CMD(0x4E, 0x28), + _INIT_DCS_CMD(0x4F, 0x29), + _INIT_DCS_CMD(0x50, 0x10), + _INIT_DCS_CMD(0x51, 0x12), + _INIT_DCS_CMD(0x52, 0x14), + _INIT_DCS_CMD(0x53, 0x16), + _INIT_DCS_CMD(0x54, 0x08), + _INIT_DCS_CMD(0x55, 0x0C), + _INIT_DCS_CMD(0x56, 0x02), + _INIT_DCS_CMD(0x57, 0x02), + _INIT_DCS_CMD(0x58, 0x02), + _INIT_DCS_CMD(0x59, 0x02), + _INIT_DCS_CMD(0x5A, 0x02), + _INIT_DCS_CMD(0x5B, 0x02), + _INIT_DCS_CMD(0x5C, 0x02), + + _INIT_DCS_CMD(0x61, 0x07), + _INIT_DCS_CMD(0x62, 0x07), + _INIT_DCS_CMD(0x63, 0x07), + _INIT_DCS_CMD(0x64, 0x07), + _INIT_DCS_CMD(0x65, 0x07), + _INIT_DCS_CMD(0x66, 0x01), + _INIT_DCS_CMD(0x67, 0x00), + _INIT_DCS_CMD(0x68, 0x28), + _INIT_DCS_CMD(0x69, 0x29), + _INIT_DCS_CMD(0x6A, 0x16), + _INIT_DCS_CMD(0x6B, 0x14), + _INIT_DCS_CMD(0x6C, 0x12), + _INIT_DCS_CMD(0x6D, 0x10), + _INIT_DCS_CMD(0x6E, 0x0C), + _INIT_DCS_CMD(0x6F, 0x08), + _INIT_DCS_CMD(0x70, 0x02), + _INIT_DCS_CMD(0x71, 0x02), + _INIT_DCS_CMD(0x72, 0x02), + _INIT_DCS_CMD(0x73, 0x02), + _INIT_DCS_CMD(0x74, 0x02), + _INIT_DCS_CMD(0x75, 0x02), + _INIT_DCS_CMD(0x76, 0x02), + + _INIT_DCS_CMD(0x77, 0x07), + _INIT_DCS_CMD(0x78, 0x07), + _INIT_DCS_CMD(0x79, 0x07), + _INIT_DCS_CMD(0x7A, 0x07), + _INIT_DCS_CMD(0x7B, 0x07), + _INIT_DCS_CMD(0x7C, 0x01), + _INIT_DCS_CMD(0x7D, 0x00), + _INIT_DCS_CMD(0x7E, 0x28), + _INIT_DCS_CMD(0x7F, 0x29), + _INIT_DCS_CMD(0x80, 0x17), + _INIT_DCS_CMD(0x81, 0x15), + _INIT_DCS_CMD(0x82, 0x13), + _INIT_DCS_CMD(0x83, 0x11), + _INIT_DCS_CMD(0x84, 0x0D), + _INIT_DCS_CMD(0x85, 0x09), + _INIT_DCS_CMD(0x86, 0x02), + _INIT_DCS_CMD(0x87, 0x07), + _INIT_DCS_CMD(0x88, 0x07), + _INIT_DCS_CMD(0x89, 0x07), + _INIT_DCS_CMD(0x8A, 0x07), + _INIT_DCS_CMD(0x8B, 0x07), + _INIT_DCS_CMD(0x8C, 0x07), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x02), + _INIT_DCS_CMD(0x29, 0x3A), + _INIT_DCS_CMD(0x2A, 0x3B), + + _INIT_DCS_CMD(0x06, 0x01), + _INIT_DCS_CMD(0x07, 0x01), + _INIT_DCS_CMD(0x08, 0x0C), + _INIT_DCS_CMD(0x09, 0x44), + + _INIT_DCS_CMD(0x3C, 0x0A), + _INIT_DCS_CMD(0x39, 0x11), + _INIT_DCS_CMD(0x3D, 0x00), + _INIT_DCS_CMD(0x3A, 0x0C), + _INIT_DCS_CMD(0x3B, 0x44), + + _INIT_DCS_CMD(0x53, 0x1F), + _INIT_DCS_CMD(0x5E, 0x40), + _INIT_DCS_CMD(0x84, 0x00), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x03), + _INIT_DCS_CMD(0x20, 0x01), + _INIT_DCS_CMD(0x21, 0x3C), + _INIT_DCS_CMD(0x22, 0xFA), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x0A), + _INIT_DCS_CMD(0xE0, 0x01), + _INIT_DCS_CMD(0xE2, 0x01), + _INIT_DCS_CMD(0xE5, 0x91), + _INIT_DCS_CMD(0xE6, 0x3C), + _INIT_DCS_CMD(0xE7, 0x00), + _INIT_DCS_CMD(0xE8, 0xFA), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x12), + _INIT_DCS_CMD(0x87, 0x2C), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x05), + _INIT_DCS_CMD(0x73, 0xE5), + _INIT_DCS_CMD(0x7F, 0x6B), + _INIT_DCS_CMD(0x6D, 0xA4), + _INIT_DCS_CMD(0x79, 0x54), + _INIT_DCS_CMD(0x69, 0x97), + _INIT_DCS_CMD(0x6A, 0x97), + _INIT_DCS_CMD(0xA5, 0x3F), + _INIT_DCS_CMD(0x61, 0xDA), + _INIT_DCS_CMD(0xA7, 0xF1), + _INIT_DCS_CMD(0x5F, 0x01), + _INIT_DCS_CMD(0x62, 0x3F), + _INIT_DCS_CMD(0x1D, 0x90), + _INIT_DCS_CMD(0x86, 0x87), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x06), + _INIT_DCS_CMD(0xC0, 0x80), + _INIT_DCS_CMD(0xC1, 0x07), + _INIT_DCS_CMD(0xCA, 0x58), + _INIT_DCS_CMD(0xCB, 0x02), + _INIT_DCS_CMD(0xCE, 0x58), + _INIT_DCS_CMD(0xCF, 0x02), + _INIT_DCS_CMD(0x67, 0x60), + _INIT_DCS_CMD(0x10, 0x00), + _INIT_DCS_CMD(0x92, 0x22), + _INIT_DCS_CMD(0xD3, 0x08), + _INIT_DCS_CMD(0xD6, 0x55), + _INIT_DCS_CMD(0xDC, 0x38), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x08), + _INIT_DCS_CMD(0xE0, 0x00, 0x10, 0x2A, 0x4D, 0x61, 0x56, 0x6A, 0x6E, 0x79, 0x76, 0x8F, 0x95, 0x98, 0xAE, 0xAA, 0xB2, 0xBB, 0xCE, 0xC6, 0xBD, 0xD5, 0xE2, 0xE8), + _INIT_DCS_CMD(0xE1, 0x00, 0x10, 0x2A, 0x4D, 0x61, 0x56, 0x6A, 0x6E, 0x79, 0x76, 0x8F, 0x95, 0x98, 0xAE, 0xAA, 0xB2, 0xBB, 0xCE, 0xC6, 0xBD, 0xD5, 0xE2, 0xE8), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x04), + _INIT_DCS_CMD(0xBA, 0x81), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x0C), + _INIT_DCS_CMD(0x00, 0x02), + _INIT_DCS_CMD(0x01, 0x00), + _INIT_DCS_CMD(0x02, 0x03), + _INIT_DCS_CMD(0x03, 0x01), + _INIT_DCS_CMD(0x04, 0x03), + _INIT_DCS_CMD(0x05, 0x02), + _INIT_DCS_CMD(0x06, 0x04), + _INIT_DCS_CMD(0x07, 0x03), + _INIT_DCS_CMD(0x08, 0x03), + _INIT_DCS_CMD(0x09, 0x04), + _INIT_DCS_CMD(0x0A, 0x04), + _INIT_DCS_CMD(0x0B, 0x05), + _INIT_DCS_CMD(0x0C, 0x04), + _INIT_DCS_CMD(0x0D, 0x06), + _INIT_DCS_CMD(0x0E, 0x05), + _INIT_DCS_CMD(0x0F, 0x07), + _INIT_DCS_CMD(0x10, 0x04), + _INIT_DCS_CMD(0x11, 0x08), + _INIT_DCS_CMD(0x12, 0x05), + _INIT_DCS_CMD(0x13, 0x09), + _INIT_DCS_CMD(0x14, 0x05), + _INIT_DCS_CMD(0x15, 0x0A), + _INIT_DCS_CMD(0x16, 0x06), + _INIT_DCS_CMD(0x17, 0x0B), + _INIT_DCS_CMD(0x18, 0x05), + _INIT_DCS_CMD(0x19, 0x0C), + _INIT_DCS_CMD(0x1A, 0x06), + _INIT_DCS_CMD(0x1B, 0x0D), + _INIT_DCS_CMD(0x1C, 0x06), + _INIT_DCS_CMD(0x1D, 0x0E), + _INIT_DCS_CMD(0x1E, 0x07), + _INIT_DCS_CMD(0x1F, 0x0F), + _INIT_DCS_CMD(0x20, 0x06), + _INIT_DCS_CMD(0x21, 0x10), + _INIT_DCS_CMD(0x22, 0x07), + _INIT_DCS_CMD(0x23, 0x11), + _INIT_DCS_CMD(0x24, 0x07), + _INIT_DCS_CMD(0x25, 0x12), + _INIT_DCS_CMD(0x26, 0x08), + _INIT_DCS_CMD(0x27, 0x13), + _INIT_DCS_CMD(0x28, 0x07), + _INIT_DCS_CMD(0x29, 0x14), + _INIT_DCS_CMD(0x2A, 0x08), + _INIT_DCS_CMD(0x2B, 0x15), + _INIT_DCS_CMD(0x2C, 0x08), + _INIT_DCS_CMD(0x2D, 0x16), + _INIT_DCS_CMD(0x2E, 0x09), + _INIT_DCS_CMD(0x2F, 0x17), + _INIT_DCS_CMD(0x30, 0x08), + _INIT_DCS_CMD(0x31, 0x18), + _INIT_DCS_CMD(0x32, 0x09), + _INIT_DCS_CMD(0x33, 0x19), + _INIT_DCS_CMD(0x34, 0x09), + _INIT_DCS_CMD(0x35, 0x1A), + _INIT_DCS_CMD(0x36, 0x0A), + _INIT_DCS_CMD(0x37, 0x1B), + _INIT_DCS_CMD(0x38, 0x0A), + _INIT_DCS_CMD(0x39, 0x1C), + _INIT_DCS_CMD(0x3A, 0x0A), + _INIT_DCS_CMD(0x3B, 0x1D), + _INIT_DCS_CMD(0x3C, 0x0A), + _INIT_DCS_CMD(0x3D, 0x1E), + _INIT_DCS_CMD(0x3E, 0x0A), + _INIT_DCS_CMD(0x3F, 0x1F), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x04), + _INIT_DCS_CMD(0xBA, 0x01), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x0E), + _INIT_DCS_CMD(0x02, 0x0C), + _INIT_DCS_CMD(0x20, 0x10), + _INIT_DCS_CMD(0x25, 0x16), + _INIT_DCS_CMD(0x26, 0xE0), + _INIT_DCS_CMD(0x27, 0x00), + _INIT_DCS_CMD(0x29, 0x71), + _INIT_DCS_CMD(0x2A, 0x46), + _INIT_DCS_CMD(0x2B, 0x1F), + _INIT_DCS_CMD(0x2D, 0xC7), + _INIT_DCS_CMD(0x31, 0x02), + _INIT_DCS_CMD(0x32, 0xDF), + _INIT_DCS_CMD(0x33, 0x5A), + _INIT_DCS_CMD(0x34, 0xC0), + _INIT_DCS_CMD(0x35, 0x5A), + _INIT_DCS_CMD(0x36, 0xC0), + _INIT_DCS_CMD(0x38, 0x65), + _INIT_DCS_CMD(0x80, 0x3E), + _INIT_DCS_CMD(0x81, 0xA0), + _INIT_DCS_CMD(0xB0, 0x01), + _INIT_DCS_CMD(0xB1, 0xCC), + _INIT_DCS_CMD(0xC0, 0x12), + _INIT_DCS_CMD(0xC2, 0xCC), + _INIT_DCS_CMD(0xC3, 0xCC), + _INIT_DCS_CMD(0xC4, 0xCC), + _INIT_DCS_CMD(0xC5, 0xCC), + _INIT_DCS_CMD(0xC6, 0xCC), + _INIT_DCS_CMD(0xC7, 0xCC), + _INIT_DCS_CMD(0xC8, 0xCC), + _INIT_DCS_CMD(0xC9, 0xCC), + _INIT_DCS_CMD(0x30, 0x00), + _INIT_DCS_CMD(0x00, 0x81), + _INIT_DCS_CMD(0x08, 0x02), + _INIT_DCS_CMD(0x09, 0x00), + _INIT_DCS_CMD(0x07, 0x21), + _INIT_DCS_CMD(0x04, 0x10), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x1E), + _INIT_DCS_CMD(0x60, 0x00), + _INIT_DCS_CMD(0x64, 0x00), + _INIT_DCS_CMD(0x6D, 0x00), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x0B), + _INIT_DCS_CMD(0xA6, 0x44), + _INIT_DCS_CMD(0xA7, 0xB6), + _INIT_DCS_CMD(0xA8, 0x03), + _INIT_DCS_CMD(0xA9, 0x03), + _INIT_DCS_CMD(0xAA, 0x51), + _INIT_DCS_CMD(0xAB, 0x51), + _INIT_DCS_CMD(0xAC, 0x04), + _INIT_DCS_CMD(0xBD, 0x92), + _INIT_DCS_CMD(0xBE, 0xA1), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x05), + _INIT_DCS_CMD(0x86, 0x87), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x06), + _INIT_DCS_CMD(0x92, 0x22), + + _INIT_DCS_CMD(0xFF, 0x98, 0x82, 0x00), + _INIT_DCS_CMD(0x11), + _INIT_DELAY_CMD(120), + _INIT_DCS_CMD(0x29), + _INIT_DELAY_CMD(20), + {}, +}; + static inline struct boe_panel *to_boe_panel(struct drm_panel *panel) { return container_of(panel, struct boe_panel, base); @@ -1698,6 +2108,62 @@ static const struct panel_desc starry_qfh032011_53g_desc = { .init_cmds = starry_qfh032011_53g_init_cmd, }; +static const struct drm_display_mode starry_himax83102_j02_default_mode = { + .clock = 161600, + .hdisplay = 1200, + .hsync_start = 1200 + 40, + .hsync_end = 1200 + 40 + 20, + .htotal = 1200 + 40 + 20 + 40, + .vdisplay = 1920, + .vsync_start = 1920 + 116, + .vsync_end = 1920 + 116 + 8, + .vtotal = 1920 + 116 + 8 + 12, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const struct panel_desc starry_himax83102_j02_desc = { + .modes = &starry_himax83102_j02_default_mode, + .bpc = 8, + .size = { + .width_mm = 141, + .height_mm = 226, + }, + .lanes = 4, + .format = MIPI_DSI_FMT_RGB888, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM, + .init_cmds = starry_himax83102_j02_init_cmd, + .lp11_before_reset = true, +}; + +static const struct drm_display_mode starry_ili9882t_default_mode = { + .clock = 165280, + .hdisplay = 1200, + .hsync_start = 1200 + 32, + .hsync_end = 1200 + 32 + 30, + .htotal = 1200 + 32 + 30 + 32, + .vdisplay = 1920, + .vsync_start = 1920 + 68, + .vsync_end = 1920 + 68 + 2, + .vtotal = 1920 + 68 + 2 + 10, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const struct panel_desc starry_ili9882t_desc = { + .modes = &starry_ili9882t_default_mode, + .bpc = 8, + .size = { + .width_mm = 141, + .height_mm = 226, + }, + .lanes = 4, + .format = MIPI_DSI_FMT_RGB888, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM, + .init_cmds = starry_ili9882t_init_cmd, + .lp11_before_reset = true, +}; + static int boe_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector) { @@ -1871,6 +2337,12 @@ static const struct of_device_id boe_of_match[] = { { .compatible = "starry,2081101qfh032011-53g", .data = &starry_qfh032011_53g_desc }, + { .compatible = "starry,himax83102-j02", + .data = &starry_himax83102_j02_desc + }, + { .compatible = "starry,ili9882t", + .data = &starry_ili9882t_desc + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, boe_of_match); 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-khadas-ts050.c b/drivers/gpu/drm/panel/panel-khadas-ts050.c index 1ab1ebe30882..b942a0162274 100644 --- a/drivers/gpu/drm/panel/panel-khadas-ts050.c +++ b/drivers/gpu/drm/panel/panel-khadas-ts050.c @@ -568,7 +568,7 @@ static const struct khadas_ts050_panel_cmd init_code[] = { {0xfb, 0x01}, /* Select CMD1 */ {0xff, 0x00}, - {0xd3, 0x05}, /* RGBMIPICTRL: VSYNC back porch = 5 */ + {0xd3, 0x22}, /* RGBMIPICTRL: VSYNC back porch = 34 */ {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */ }; @@ -717,15 +717,15 @@ static int khadas_ts050_panel_disable(struct drm_panel *panel) } static const struct drm_display_mode default_mode = { - .clock = 120000, - .hdisplay = 1088, - .hsync_start = 1088 + 104, - .hsync_end = 1088 + 104 + 4, - .htotal = 1088 + 104 + 4 + 127, + .clock = 160000, + .hdisplay = 1080, + .hsync_start = 1080 + 117, + .hsync_end = 1080 + 117 + 5, + .htotal = 1080 + 117 + 5 + 160, .vdisplay = 1920, .vsync_start = 1920 + 4, - .vsync_end = 1920 + 4 + 2, - .vtotal = 1920 + 4 + 2 + 3, + .vsync_end = 1920 + 4 + 3, + .vtotal = 1920 + 4 + 3 + 31, .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, }; 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..a247a0e7c799 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, @@ -3251,6 +3281,32 @@ static const struct panel_desc qishenglong_gopher2b_lcd = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct display_timing rocktech_rk043fn48h_timing = { + .pixelclock = { 6000000, 9000000, 12000000 }, + .hactive = { 480, 480, 480 }, + .hback_porch = { 8, 43, 43 }, + .hfront_porch = { 2, 8, 8 }, + .hsync_len = { 1, 1, 1 }, + .vactive = { 272, 272, 272 }, + .vback_porch = { 2, 12, 12 }, + .vfront_porch = { 1, 4, 4 }, + .vsync_len = { 1, 10, 10 }, + .flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW | + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE, +}; + +static const struct panel_desc rocktech_rk043fn48h = { + .timings = &rocktech_rk043fn48h_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 95, + .height = 54, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; + static const struct display_timing rocktech_rk070er9427_timing = { .pixelclock = { 26400000, 33300000, 46800000 }, .hactive = { 800, 800, 800 }, @@ -3994,6 +4050,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, }, { @@ -4288,6 +4347,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "qishenglong,gopher2b-lcd", .data = &qishenglong_gopher2b_lcd, }, { + .compatible = "rocktech,rk043fn48h", + .data = &rocktech_rk043fn48h, + }, { .compatible = "rocktech,rk070er9427", .data = &rocktech_rk070er9427, }, { 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 <linux/fb.h> #include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/vga_switcheroo.h> @@ -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/renesas/Kconfig b/drivers/gpu/drm/renesas/Kconfig new file mode 100644 index 000000000000..3777dad17f81 --- /dev/null +++ b/drivers/gpu/drm/renesas/Kconfig @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +source "drivers/gpu/drm/renesas/rcar-du/Kconfig" +source "drivers/gpu/drm/renesas/shmobile/Kconfig" diff --git a/drivers/gpu/drm/renesas/Makefile b/drivers/gpu/drm/renesas/Makefile new file mode 100644 index 000000000000..ec0e89e7a592 --- /dev/null +++ b/drivers/gpu/drm/renesas/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += rcar-du/ +obj-$(CONFIG_DRM_SHMOBILE) += shmobile/ diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/renesas/rcar-du/Kconfig index 53c356aed5d5..53c356aed5d5 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/renesas/rcar-du/Kconfig diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/renesas/rcar-du/Makefile index b8f2c82651d9..b8f2c82651d9 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/renesas/rcar-du/Makefile diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.c index e2a67dda4658..e2a67dda4658 100644 --- a/drivers/gpu/drm/rcar-du/rcar_cmm.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.c diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.h index 628072acc98b..628072acc98b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_cmm.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.h diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c index d6d29be6b4f4..7e175dbfd892 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c @@ -223,20 +223,6 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) * DU channels that have a display PLL can't use the internal * system clock, and have no internal clock divider. */ - - /* - * The H3 ES1.x exhibits dot clock duty cycle stability issues. - * We can work around them by configuring the DPLL to twice the - * desired frequency, coupled with a /2 post-divider. Restrict - * the workaround to H3 ES1.x as ES2.0 and all other SoCs have - * no post-divider when a display PLL is present (as shown by - * the workaround breaking HDMI output on M3-W during testing). - */ - if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY) { - target *= 2; - div = 1; - } - extclk = clk_get_rate(rcrtc->extclock); rcar_du_dpll_divider(rcrtc, &dpll, extclk, target); @@ -245,30 +231,13 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m) | DPLLCR_STBY; - if (rcrtc->index == 1) { + if (rcrtc->index == 1) dpllcr |= DPLLCR_PLCS1 | DPLLCR_INCS_DOTCLKIN1; - } else { - dpllcr |= DPLLCR_PLCS0_PLL + else + dpllcr |= DPLLCR_PLCS0 | DPLLCR_INCS_DOTCLKIN0; - /* - * On ES2.x we have a single mux controlled via bit 21, - * which selects between DCLKIN source (bit 21 = 0) and - * a PLL source (bit 21 = 1), where the PLL is always - * PLL1. - * - * On ES1.x we have an additional mux, controlled - * via bit 20, for choosing between PLL0 (bit 20 = 0) - * and PLL1 (bit 20 = 1). We always want to use PLL1, - * so on ES1.x, in addition to setting bit 21, we need - * to set the bit 20. - */ - - if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PLL) - dpllcr |= DPLLCR_PLCS0_H3ES1X_PLL1; - } - rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr); escr = ESCR_DCLKSEL_DCLKIN | div; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.h index d0f38a8b3561..d0f38a8b3561 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.h diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.c index b9a94c5260e9..1ffde19cb87f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.c @@ -16,7 +16,6 @@ #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/slab.h> -#include <linux/sys_soc.h> #include <linux/wait.h> #include <drm/drm_atomic_helper.h> @@ -387,43 +386,6 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = { .dpll_mask = BIT(2) | BIT(1), }; -static const struct rcar_du_device_info rcar_du_r8a7795_es1_info = { - .gen = 3, - .features = RCAR_DU_FEATURE_CRTC_IRQ - | RCAR_DU_FEATURE_CRTC_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, - .quirks = RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY - | RCAR_DU_QUIRK_H3_ES1_PLL, - .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0), - .routes = { - /* - * R8A7795 has one RGB output, two HDMI outputs and one - * LVDS output. - */ - [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(3), - .port = 0, - }, - [RCAR_DU_OUTPUT_HDMI0] = { - .possible_crtcs = BIT(1), - .port = 1, - }, - [RCAR_DU_OUTPUT_HDMI1] = { - .possible_crtcs = BIT(2), - .port = 2, - }, - [RCAR_DU_OUTPUT_LVDS0] = { - .possible_crtcs = BIT(0), - .port = 3, - }, - }, - .num_lvds = 1, - .num_rpf = 5, - .dpll_mask = BIT(2) | BIT(1), -}; - static const struct rcar_du_device_info rcar_du_r8a7796_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ @@ -614,11 +576,6 @@ static const struct of_device_id rcar_du_of_table[] = { MODULE_DEVICE_TABLE(of, rcar_du_of_table); -static const struct soc_device_attribute rcar_du_soc_table[] = { - { .soc_id = "r8a7795", .revision = "ES1.*", .data = &rcar_du_r8a7795_es1_info }, - { /* sentinel */ } -}; - const char *rcar_du_output_name(enum rcar_du_output output) { static const char * const names[] = { @@ -707,7 +664,6 @@ static void rcar_du_shutdown(struct platform_device *pdev) static int rcar_du_probe(struct platform_device *pdev) { - const struct soc_device_attribute *soc_attr; struct rcar_du_device *rcdu; unsigned int mask; int ret; @@ -725,10 +681,6 @@ static int rcar_du_probe(struct platform_device *pdev) rcdu->info = of_device_get_match_data(rcdu->dev); - soc_attr = soc_device_match(rcar_du_soc_table); - if (soc_attr) - rcdu->info = soc_attr->data; - platform_set_drvdata(pdev, rcdu); /* I/O resources */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.h index acc3673fefe1..5cfa2bb7ad93 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.h @@ -34,8 +34,6 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_NO_BLENDING BIT(5) /* PnMR.SPIM does not have ALP nor EOR bits */ #define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */ -#define RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY BIT(1) /* H3 ES1 has pclk stability issue */ -#define RCAR_DU_QUIRK_H3_ES1_PLL BIT(2) /* H3 ES1 PLL setup differs from non-ES1 */ enum rcar_du_output { RCAR_DU_OUTPUT_DPAD0, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c index 7ecec7b04a8d..7ecec7b04a8d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.h index e5ec8fbb3979..e5ec8fbb3979 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.h diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_group.c index 2ccd2581f544..2ccd2581f544 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_group.c diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_group.h index 55649ad86a10..55649ad86a10 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_group.h diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c index adfb36b0e815..adfb36b0e815 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.h index f31afeeee05a..f31afeeee05a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.h diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.c index d759e0192181..d759e0192181 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.c diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.h index f9893d7d6dfc..f9893d7d6dfc 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.h diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_regs.h index 6c750fab6ebb..391de6661d8b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_regs.h @@ -283,8 +283,7 @@ #define DPLLCR 0x20044 #define DPLLCR_CODE (0x95 << 24) #define DPLLCR_PLCS1 (1 << 23) -#define DPLLCR_PLCS0_PLL (1 << 21) -#define DPLLCR_PLCS0_H3ES1X_PLL1 (1 << 20) +#define DPLLCR_PLCS0 (1 << 21) #define DPLLCR_CLKE (1 << 18) #define DPLLCR_FDPLL(n) ((n) << 12) #define DPLLCR_N(n) ((n) << 5) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.c index 45c05d0ffc70..45c05d0ffc70 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.c diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.h index 67630f0b6599..67630f0b6599 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.h diff --git a/drivers/gpu/drm/rcar-du/rcar_du_writeback.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_writeback.c index 8cd37d7b8ae2..8cd37d7b8ae2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_writeback.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_writeback.c diff --git a/drivers/gpu/drm/rcar-du/rcar_du_writeback.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_writeback.h index a71c9c08cafa..a71c9c08cafa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_writeback.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_writeback.h diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c index 18ed14911b98..18ed14911b98 100644 --- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c index ca215b588fd7..ca215b588fd7 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.h b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.h index 887c63500000..887c63500000 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.h diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds_regs.h index ab0406a27d33..ab0406a27d33 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds_regs.h diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c index e10e4d4b89a2..e10e4d4b89a2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.h b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.h index 528a196e6edd..528a196e6edd 100644 --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.h diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi_regs.h index f8114d11f2d1..f8114d11f2d1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi_regs.h diff --git a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rzg2l_mipi_dsi.c index aa95b85a2964..aa95b85a2964 100644 --- a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rcar-du/rzg2l_mipi_dsi.c diff --git a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h b/drivers/gpu/drm/renesas/rcar-du/rzg2l_mipi_dsi_regs.h index 1dbc16ec64a4..1dbc16ec64a4 100644 --- a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h +++ b/drivers/gpu/drm/renesas/rcar-du/rzg2l_mipi_dsi_regs.h diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/renesas/shmobile/Kconfig index ad14112999ad..ad14112999ad 100644 --- a/drivers/gpu/drm/shmobile/Kconfig +++ b/drivers/gpu/drm/renesas/shmobile/Kconfig diff --git a/drivers/gpu/drm/shmobile/Makefile b/drivers/gpu/drm/renesas/shmobile/Makefile index 861edafed856..861edafed856 100644 --- a/drivers/gpu/drm/shmobile/Makefile +++ b/drivers/gpu/drm/renesas/shmobile/Makefile diff --git a/drivers/gpu/drm/shmobile/shmob_drm_backlight.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c index 794573badfe8..794573badfe8 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_backlight.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c diff --git a/drivers/gpu/drm/shmobile/shmob_drm_backlight.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h index d9abb7a60be5..d9abb7a60be5 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_backlight.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 11dd2bc803e7..11dd2bc803e7 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h index 21718843f46d..21718843f46d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 30493ce87419..30493ce87419 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h index 4964ddd5ab74..4964ddd5ab74 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c index 99381cc0abf3..99381cc0abf3 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h index 0347b1fd2338..0347b1fd2338 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 850986cee848..850986cee848 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.h index e72b21a4288f..e72b21a4288f 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.h diff --git a/drivers/gpu/drm/shmobile/shmob_drm_regs.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_regs.h index 058533685c4c..058533685c4c 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_regs.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_regs.h 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 <linux/console.h> +#include <linux/fb.h> #include <linux/vmalloc.h> #include <drm/drm_drv.h> @@ -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/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile index b99fa4a73b68..d2e1788a8227 100644 --- a/drivers/gpu/drm/virtio/Makefile +++ b/drivers/gpu/drm/virtio/Makefile @@ -6,6 +6,6 @@ virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o virtgpu_vram.o \ virtgpu_display.o virtgpu_vq.o \ virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ - virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o + virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o virtgpu_submit.o obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index af6ffb696086..4126c384286b 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -486,4 +486,8 @@ void virtio_gpu_vram_unmap_dma_buf(struct device *dev, struct sg_table *sgt, enum dma_data_direction dir); +/* virtgpu_submit.c */ +int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); + #endif diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index da45215a933d..b24b11f25197 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -38,36 +38,6 @@ VIRTGPU_BLOB_FLAG_USE_SHAREABLE | \ VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) -static int virtio_gpu_fence_event_create(struct drm_device *dev, - struct drm_file *file, - struct virtio_gpu_fence *fence, - uint32_t ring_idx) -{ - struct virtio_gpu_fpriv *vfpriv = file->driver_priv; - struct virtio_gpu_fence_event *e = NULL; - int ret; - - if (!(vfpriv->ring_idx_mask & BIT_ULL(ring_idx))) - return 0; - - e = kzalloc(sizeof(*e), GFP_KERNEL); - if (!e) - return -ENOMEM; - - e->event.type = VIRTGPU_EVENT_FENCE_SIGNALED; - e->event.length = sizeof(e->event); - - ret = drm_event_reserve_init(dev, file, &e->base, &e->event); - if (ret) - goto free; - - fence->e = e; - return 0; -free: - kfree(e); - return ret; -} - /* Must be called with &virtio_gpu_fpriv.struct_mutex held. */ static void virtio_gpu_create_context_locked(struct virtio_gpu_device *vgdev, struct virtio_gpu_fpriv *vfpriv) @@ -108,158 +78,6 @@ static int virtio_gpu_map_ioctl(struct drm_device *dev, void *data, &virtio_gpu_map->offset); } -/* - * Usage of execbuffer: - * Relocations need to take into account the full VIRTIO_GPUDrawable size. - * However, the command as passed from user space must *not* contain the initial - * VIRTIO_GPUReleaseInfo struct (first XXX bytes) - */ -static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_virtgpu_execbuffer *exbuf = data; - struct virtio_gpu_device *vgdev = dev->dev_private; - struct virtio_gpu_fpriv *vfpriv = file->driver_priv; - struct virtio_gpu_fence *out_fence; - int ret; - uint32_t *bo_handles = NULL; - void __user *user_bo_handles = NULL; - struct virtio_gpu_object_array *buflist = NULL; - struct sync_file *sync_file; - int out_fence_fd = -1; - void *buf; - uint64_t fence_ctx; - uint32_t ring_idx; - - fence_ctx = vgdev->fence_drv.context; - ring_idx = 0; - - if (vgdev->has_virgl_3d == false) - return -ENOSYS; - - if ((exbuf->flags & ~VIRTGPU_EXECBUF_FLAGS)) - return -EINVAL; - - if ((exbuf->flags & VIRTGPU_EXECBUF_RING_IDX)) { - if (exbuf->ring_idx >= vfpriv->num_rings) - return -EINVAL; - - if (!vfpriv->base_fence_ctx) - return -EINVAL; - - fence_ctx = vfpriv->base_fence_ctx; - ring_idx = exbuf->ring_idx; - } - - virtio_gpu_create_context(dev, file); - if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) { - struct dma_fence *in_fence; - - in_fence = sync_file_get_fence(exbuf->fence_fd); - - if (!in_fence) - return -EINVAL; - - /* - * Wait if the fence is from a foreign context, or if the fence - * array contains any fence from a foreign context. - */ - ret = 0; - if (!dma_fence_match_context(in_fence, fence_ctx + ring_idx)) - ret = dma_fence_wait(in_fence, true); - - dma_fence_put(in_fence); - if (ret) - return ret; - } - - if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) { - out_fence_fd = get_unused_fd_flags(O_CLOEXEC); - if (out_fence_fd < 0) - return out_fence_fd; - } - - if (exbuf->num_bo_handles) { - bo_handles = kvmalloc_array(exbuf->num_bo_handles, - sizeof(uint32_t), GFP_KERNEL); - if (!bo_handles) { - ret = -ENOMEM; - goto out_unused_fd; - } - - user_bo_handles = u64_to_user_ptr(exbuf->bo_handles); - if (copy_from_user(bo_handles, user_bo_handles, - exbuf->num_bo_handles * sizeof(uint32_t))) { - ret = -EFAULT; - goto out_unused_fd; - } - - buflist = virtio_gpu_array_from_handles(file, bo_handles, - exbuf->num_bo_handles); - if (!buflist) { - ret = -ENOENT; - goto out_unused_fd; - } - kvfree(bo_handles); - bo_handles = NULL; - } - - buf = vmemdup_user(u64_to_user_ptr(exbuf->command), exbuf->size); - if (IS_ERR(buf)) { - ret = PTR_ERR(buf); - goto out_unused_fd; - } - - if (buflist) { - ret = virtio_gpu_array_lock_resv(buflist); - if (ret) - goto out_memdup; - } - - out_fence = virtio_gpu_fence_alloc(vgdev, fence_ctx, ring_idx); - if(!out_fence) { - ret = -ENOMEM; - goto out_unresv; - } - - ret = virtio_gpu_fence_event_create(dev, file, out_fence, ring_idx); - if (ret) - goto out_unresv; - - if (out_fence_fd >= 0) { - sync_file = sync_file_create(&out_fence->f); - if (!sync_file) { - dma_fence_put(&out_fence->f); - ret = -ENOMEM; - goto out_unresv; - } - - exbuf->fence_fd = out_fence_fd; - fd_install(out_fence_fd, sync_file->file); - } - - virtio_gpu_cmd_submit(vgdev, buf, exbuf->size, - vfpriv->ctx_id, buflist, out_fence); - dma_fence_put(&out_fence->f); - virtio_gpu_notify(vgdev); - return 0; - -out_unresv: - if (buflist) - virtio_gpu_array_unlock_resv(buflist); -out_memdup: - kvfree(buf); -out_unused_fd: - kvfree(bo_handles); - if (buflist) - virtio_gpu_array_put_free(buflist); - - if (out_fence_fd >= 0) - put_unused_fd(out_fence_fd); - - return ret; -} - static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c new file mode 100644 index 000000000000..cf3c04b16a7a --- /dev/null +++ b/drivers/gpu/drm/virtio/virtgpu_submit.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2015 Red Hat, Inc. + * All Rights Reserved. + * + * Authors: + * Dave Airlie + * Alon Levy + */ + +#include <linux/dma-fence-unwrap.h> +#include <linux/file.h> +#include <linux/sync_file.h> +#include <linux/uaccess.h> + +#include <drm/drm_file.h> +#include <drm/virtgpu_drm.h> + +#include "virtgpu_drv.h" + +struct virtio_gpu_submit { + struct virtio_gpu_object_array *buflist; + struct drm_virtgpu_execbuffer *exbuf; + struct virtio_gpu_fence *out_fence; + struct virtio_gpu_fpriv *vfpriv; + struct virtio_gpu_device *vgdev; + struct sync_file *sync_file; + struct drm_file *file; + int out_fence_fd; + u64 fence_ctx; + u32 ring_idx; + void *buf; +}; + +static int virtio_gpu_do_fence_wait(struct virtio_gpu_submit *submit, + struct dma_fence *in_fence) +{ + u32 context = submit->fence_ctx + submit->ring_idx; + + if (dma_fence_match_context(in_fence, context)) + return 0; + + return dma_fence_wait(in_fence, true); +} + +static int virtio_gpu_dma_fence_wait(struct virtio_gpu_submit *submit, + struct dma_fence *fence) +{ + struct dma_fence_unwrap itr; + struct dma_fence *f; + int err; + + dma_fence_unwrap_for_each(f, &itr, fence) { + err = virtio_gpu_do_fence_wait(submit, f); + if (err) + return err; + } + + return 0; +} + +static int virtio_gpu_fence_event_create(struct drm_device *dev, + struct drm_file *file, + struct virtio_gpu_fence *fence, + u32 ring_idx) +{ + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct virtio_gpu_fence_event *e = NULL; + int ret; + + if (!(vfpriv->ring_idx_mask & BIT_ULL(ring_idx))) + return 0; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) + return -ENOMEM; + + e->event.type = VIRTGPU_EVENT_FENCE_SIGNALED; + e->event.length = sizeof(e->event); + + ret = drm_event_reserve_init(dev, file, &e->base, &e->event); + if (ret) { + kfree(e); + return ret; + } + + fence->e = e; + + return 0; +} + +static int virtio_gpu_init_submit_buflist(struct virtio_gpu_submit *submit) +{ + struct drm_virtgpu_execbuffer *exbuf = submit->exbuf; + u32 *bo_handles; + + if (!exbuf->num_bo_handles) + return 0; + + bo_handles = kvmalloc_array(exbuf->num_bo_handles, sizeof(*bo_handles), + GFP_KERNEL); + if (!bo_handles) + return -ENOMEM; + + if (copy_from_user(bo_handles, u64_to_user_ptr(exbuf->bo_handles), + exbuf->num_bo_handles * sizeof(*bo_handles))) { + kvfree(bo_handles); + return -EFAULT; + } + + submit->buflist = virtio_gpu_array_from_handles(submit->file, bo_handles, + exbuf->num_bo_handles); + if (!submit->buflist) { + kvfree(bo_handles); + return -ENOENT; + } + + kvfree(bo_handles); + + return 0; +} + +static void virtio_gpu_cleanup_submit(struct virtio_gpu_submit *submit) +{ + if (!IS_ERR(submit->buf)) + kvfree(submit->buf); + + if (submit->buflist) + virtio_gpu_array_put_free(submit->buflist); + + if (submit->out_fence_fd >= 0) + put_unused_fd(submit->out_fence_fd); + + if (submit->out_fence) + dma_fence_put(&submit->out_fence->f); + + if (submit->sync_file) + fput(submit->sync_file->file); +} + +static void virtio_gpu_submit(struct virtio_gpu_submit *submit) +{ + virtio_gpu_cmd_submit(submit->vgdev, submit->buf, submit->exbuf->size, + submit->vfpriv->ctx_id, submit->buflist, + submit->out_fence); + virtio_gpu_notify(submit->vgdev); +} + +static void virtio_gpu_complete_submit(struct virtio_gpu_submit *submit) +{ + submit->buf = NULL; + submit->buflist = NULL; + submit->sync_file = NULL; + submit->out_fence = NULL; + submit->out_fence_fd = -1; +} + +static int virtio_gpu_init_submit(struct virtio_gpu_submit *submit, + struct drm_virtgpu_execbuffer *exbuf, + struct drm_device *dev, + struct drm_file *file, + u64 fence_ctx, u32 ring_idx) +{ + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fence *out_fence; + int err; + + memset(submit, 0, sizeof(*submit)); + + out_fence = virtio_gpu_fence_alloc(vgdev, fence_ctx, ring_idx); + if (!out_fence) + return -ENOMEM; + + err = virtio_gpu_fence_event_create(dev, file, out_fence, ring_idx); + if (err) { + dma_fence_put(&out_fence->f); + return err; + } + + submit->out_fence = out_fence; + submit->fence_ctx = fence_ctx; + submit->ring_idx = ring_idx; + submit->out_fence_fd = -1; + submit->vfpriv = vfpriv; + submit->vgdev = vgdev; + submit->exbuf = exbuf; + submit->file = file; + + err = virtio_gpu_init_submit_buflist(submit); + if (err) + return err; + + submit->buf = vmemdup_user(u64_to_user_ptr(exbuf->command), exbuf->size); + if (IS_ERR(submit->buf)) + return PTR_ERR(submit->buf); + + if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) { + err = get_unused_fd_flags(O_CLOEXEC); + if (err < 0) + return err; + + submit->out_fence_fd = err; + + submit->sync_file = sync_file_create(&out_fence->f); + if (!submit->sync_file) + return -ENOMEM; + } + + return 0; +} + +static int virtio_gpu_wait_in_fence(struct virtio_gpu_submit *submit) +{ + int ret = 0; + + if (submit->exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) { + struct dma_fence *in_fence = + sync_file_get_fence(submit->exbuf->fence_fd); + if (!in_fence) + return -EINVAL; + + /* + * Wait if the fence is from a foreign context, or if the + * fence array contains any fence from a foreign context. + */ + ret = virtio_gpu_dma_fence_wait(submit, in_fence); + + dma_fence_put(in_fence); + } + + return ret; +} + +static void virtio_gpu_install_out_fence_fd(struct virtio_gpu_submit *submit) +{ + if (submit->sync_file) { + submit->exbuf->fence_fd = submit->out_fence_fd; + fd_install(submit->out_fence_fd, submit->sync_file->file); + } +} + +static int virtio_gpu_lock_buflist(struct virtio_gpu_submit *submit) +{ + if (submit->buflist) + return virtio_gpu_array_lock_resv(submit->buflist); + + return 0; +} + +int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + u64 fence_ctx = vgdev->fence_drv.context; + struct drm_virtgpu_execbuffer *exbuf = data; + struct virtio_gpu_submit submit; + u32 ring_idx = 0; + int ret = -EINVAL; + + if (!vgdev->has_virgl_3d) + return -ENOSYS; + + if (exbuf->flags & ~VIRTGPU_EXECBUF_FLAGS) + return ret; + + if (exbuf->flags & VIRTGPU_EXECBUF_RING_IDX) { + if (exbuf->ring_idx >= vfpriv->num_rings) + return ret; + + if (!vfpriv->base_fence_ctx) + return ret; + + fence_ctx = vfpriv->base_fence_ctx; + ring_idx = exbuf->ring_idx; + } + + virtio_gpu_create_context(dev, file); + + ret = virtio_gpu_init_submit(&submit, exbuf, dev, file, + fence_ctx, ring_idx); + if (ret) + goto cleanup; + + /* + * Await in-fences in the end of the job submission path to + * optimize the path by proceeding directly to the submission + * to virtio after the waits. + */ + ret = virtio_gpu_wait_in_fence(&submit); + if (ret) + goto cleanup; + + ret = virtio_gpu_lock_buflist(&submit); + if (ret) + goto cleanup; + + virtio_gpu_submit(&submit); + + /* + * Set up usr-out data after submitting the job to optimize + * the job submission path. + */ + virtio_gpu_install_out_fence_fd(&submit); + virtio_gpu_complete_submit(&submit); +cleanup: + virtio_gpu_cleanup_submit(&submit); + + return ret; +} 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,31 +253,10 @@ 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_deferred_io(struct fb_info *info, struct list_head *pagereflist); +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); -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_deferred_io(struct fb_info *info, struct list_head *pagereflist); 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, @@ -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 @@ -43,6 +43,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 */ struct drm_gem_object_funcs { @@ -175,6 +194,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: * * Virtual memory operations used with mmap. 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 @@ -539,8 +539,30 @@ 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 diff --git a/include/uapi/drm/habanalabs_accel.h b/include/uapi/drm/habanalabs_accel.h index d9ef1b151d04..e6436f3e8ea6 100644 --- a/include/uapi/drm/habanalabs_accel.h +++ b/include/uapi/drm/habanalabs_accel.h @@ -787,18 +787,28 @@ enum hl_server_type { * The address which accessing it caused the razwi. * Razwi initiator. * Razwi cause, was it a page fault or MMU access error. + * May return 0 even though no new data is available, in that case + * timestamp will be 0. * HL_INFO_DEV_MEM_ALLOC_PAGE_SIZES - Retrieve valid page sizes for device memory allocation * HL_INFO_SECURED_ATTESTATION - Retrieve attestation report of the boot. * HL_INFO_REGISTER_EVENTFD - Register eventfd for event notifications. * HL_INFO_UNREGISTER_EVENTFD - Unregister eventfd * HL_INFO_GET_EVENTS - Retrieve the last occurred events * HL_INFO_UNDEFINED_OPCODE_EVENT - Retrieve last undefined opcode error information. + * May return 0 even though no new data is available, in that case + * timestamp will be 0. * HL_INFO_ENGINE_STATUS - Retrieve the status of all the h/w engines in the asic. * HL_INFO_PAGE_FAULT_EVENT - Retrieve parameters of captured page fault. + * May return 0 even though no new data is available, in that case + * timestamp will be 0. * HL_INFO_USER_MAPPINGS - Retrieve user mappings, captured after page fault event. * HL_INFO_FW_GENERIC_REQ - Send generic request to FW. * HL_INFO_HW_ERR_EVENT - Retrieve information on the reported HW error. + * May return 0 even though no new data is available, in that case + * timestamp will be 0. * HL_INFO_FW_ERR_EVENT - Retrieve information on the reported FW error. + * May return 0 even though no new data is available, in that case + * timestamp will be 0. */ #define HL_INFO_HW_IP_INFO 0 #define HL_INFO_HW_EVENTS 1 |