Merge tag 'drm-msm-next-2022-07-10' of https://gitlab.freedesktop.org/drm/msm into drm-next
Next for v5.20 GPU: - a619 support - Fix for unclocked GMU register access - Devcore dump enhancements Core: - client utilization via fdinfo support - fix fence rollover issue - gem: Lockdep false-positive warning fix - gem: Switch to pfn mappings DPU: - constification of HW catalog - support for using encoder as CRC source - WB support on sc7180 - WB resolution fixes DP: - dropped custom bulk clock implementation - made dp_bridge_mode_valid() return MODE_CLOCK_HIGH where applicable - fix link retraining on resolution change MDP5: - MSM8953 perf data HDMI: - YAML'ification of schema - dropped obsolete GPIO support - misc cleanups Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rob Clark <robdclark@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/CAF6AEGtuqswBGPw-kCYzJvckK2RR1XTeUEgaXwVG_mvpbv3gPA@mail.gmail.com
This commit is contained in:
commit
d9e019bb39
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: MSM Display Port Controller
|
||||
|
||||
maintainers:
|
||||
- Kuogee Hsieh <khsieh@codeaurora.org>
|
||||
- Kuogee Hsieh <quic_khsieh@quicinc.com>
|
||||
|
||||
description: |
|
||||
Device tree bindings for DisplayPort host controller for MSM targets
|
||||
@ -76,6 +76,9 @@ properties:
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
vdda-0p9-supply: true
|
||||
vdda-1p2-supply: true
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
properties:
|
||||
@ -137,6 +140,9 @@ examples:
|
||||
|
||||
power-domains = <&rpmhpd SC7180_CX>;
|
||||
|
||||
vdda-0p9-supply = <&vdda_usb_ss_dp_core>;
|
||||
vdda-1p2-supply = <&vdda_usb_ss_dp_1p2>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -1,99 +0,0 @@
|
||||
Qualcomm adreno/snapdragon hdmi output
|
||||
|
||||
Required properties:
|
||||
- compatible: one of the following
|
||||
* "qcom,hdmi-tx-8996"
|
||||
* "qcom,hdmi-tx-8994"
|
||||
* "qcom,hdmi-tx-8084"
|
||||
* "qcom,hdmi-tx-8974"
|
||||
* "qcom,hdmi-tx-8660"
|
||||
* "qcom,hdmi-tx-8960"
|
||||
- reg: Physical base address and length of the controller's registers
|
||||
- reg-names: "core_physical"
|
||||
- interrupts: The interrupt signal from the hdmi block.
|
||||
- power-domains: Should be <&mmcc MDSS_GDSC>.
|
||||
- clocks: device clocks
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- core-vdda-supply: phandle to supply regulator
|
||||
- hdmi-mux-supply: phandle to mux regulator
|
||||
- phys: the phandle for the HDMI PHY device
|
||||
- phy-names: the name of the corresponding PHY device
|
||||
|
||||
Optional properties:
|
||||
- hpd-gpios: hpd pin
|
||||
- qcom,hdmi-tx-mux-en-gpios: hdmi mux enable pin
|
||||
- qcom,hdmi-tx-mux-sel-gpios: hdmi mux select pin
|
||||
- qcom,hdmi-tx-mux-lpm-gpios: hdmi mux lpm pin
|
||||
- power-domains: reference to the power domain(s), if available.
|
||||
- pinctrl-names: the pin control state names; should contain "default"
|
||||
- pinctrl-0: the default pinctrl state (active)
|
||||
- pinctrl-1: the "sleep" pinctrl state
|
||||
|
||||
HDMI PHY:
|
||||
Required properties:
|
||||
- compatible: Could be the following
|
||||
* "qcom,hdmi-phy-8660"
|
||||
* "qcom,hdmi-phy-8960"
|
||||
* "qcom,hdmi-phy-8974"
|
||||
* "qcom,hdmi-phy-8084"
|
||||
* "qcom,hdmi-phy-8996"
|
||||
- #phy-cells: Number of cells in a PHY specifier; Should be 0.
|
||||
- reg: Physical base address and length of the registers of the PHY sub blocks.
|
||||
- reg-names: The names of register regions. The following regions are required:
|
||||
* "hdmi_phy"
|
||||
* "hdmi_pll"
|
||||
For HDMI PHY on msm8996, these additional register regions are required:
|
||||
* "hdmi_tx_l0"
|
||||
* "hdmi_tx_l1"
|
||||
* "hdmi_tx_l3"
|
||||
* "hdmi_tx_l4"
|
||||
- power-domains: Should be <&mmcc MDSS_GDSC>.
|
||||
- clocks: device clocks
|
||||
See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
|
||||
- core-vdda-supply: phandle to vdda regulator device node
|
||||
|
||||
Example:
|
||||
|
||||
/ {
|
||||
...
|
||||
|
||||
hdmi: hdmi@4a00000 {
|
||||
compatible = "qcom,hdmi-tx-8960";
|
||||
reg-names = "core_physical";
|
||||
reg = <0x04a00000 0x2f0>;
|
||||
interrupts = <GIC_SPI 79 0>;
|
||||
power-domains = <&mmcc MDSS_GDSC>;
|
||||
clock-names =
|
||||
"core",
|
||||
"master_iface",
|
||||
"slave_iface";
|
||||
clocks =
|
||||
<&mmcc HDMI_APP_CLK>,
|
||||
<&mmcc HDMI_M_AHB_CLK>,
|
||||
<&mmcc HDMI_S_AHB_CLK>;
|
||||
qcom,hdmi-tx-ddc-clk = <&msmgpio 70 GPIO_ACTIVE_HIGH>;
|
||||
qcom,hdmi-tx-ddc-data = <&msmgpio 71 GPIO_ACTIVE_HIGH>;
|
||||
qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>;
|
||||
core-vdda-supply = <&pm8921_hdmi_mvs>;
|
||||
hdmi-mux-supply = <&ext_3p3v>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&hpd_active &ddc_active &cec_active>;
|
||||
pinctrl-1 = <&hpd_suspend &ddc_suspend &cec_suspend>;
|
||||
|
||||
phys = <&hdmi_phy>;
|
||||
phy-names = "hdmi_phy";
|
||||
};
|
||||
|
||||
hdmi_phy: phy@4a00400 {
|
||||
compatible = "qcom,hdmi-phy-8960";
|
||||
reg-names = "hdmi_phy",
|
||||
"hdmi_pll";
|
||||
reg = <0x4a00400 0x60>,
|
||||
<0x4a00500 0x100>;
|
||||
#phy-cells = <0>;
|
||||
power-domains = <&mmcc MDSS_GDSC>;
|
||||
clock-names = "slave_iface";
|
||||
clocks = <&mmcc HDMI_S_AHB_CLK>;
|
||||
core-vdda-supply = <&pm8921_hdmi_mvs>;
|
||||
};
|
||||
};
|
232
Documentation/devicetree/bindings/display/msm/hdmi.yaml
Normal file
232
Documentation/devicetree/bindings/display/msm/hdmi.yaml
Normal file
@ -0,0 +1,232 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
|
||||
$id: http://devicetree.org/schemas/display/msm/hdmi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Adreno/Snapdragon HDMI output
|
||||
|
||||
maintainers:
|
||||
- Rob Clark <robdclark@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,hdmi-tx-8084
|
||||
- qcom,hdmi-tx-8660
|
||||
- qcom,hdmi-tx-8960
|
||||
- qcom,hdmi-tx-8974
|
||||
- qcom,hdmi-tx-8994
|
||||
- qcom,hdmi-tx-8996
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
reg-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: core_physical
|
||||
- const: qfprom_physical
|
||||
- const: hdcp_physical
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
enum:
|
||||
- hdmi_phy
|
||||
- hdmi-phy
|
||||
deprecated: true
|
||||
|
||||
core-vdda-supply:
|
||||
description: phandle to VDDA supply regulator
|
||||
|
||||
hdmi-mux-supply:
|
||||
description: phandle to mux regulator
|
||||
deprecated: true
|
||||
|
||||
core-vcc-supply:
|
||||
description: phandle to VCC supply regulator
|
||||
|
||||
hpd-gpios:
|
||||
maxItems: 1
|
||||
description: hpd pin
|
||||
|
||||
qcom,hdmi-tx-mux-en-gpios:
|
||||
maxItems: 1
|
||||
deprecated: true
|
||||
description: HDMI mux enable pin
|
||||
|
||||
qcom,hdmi-tx-mux-sel-gpios:
|
||||
maxItems: 1
|
||||
deprecated: true
|
||||
description: HDMI mux select pin
|
||||
|
||||
qcom,hdmi-tx-mux-lpm-gpios:
|
||||
maxItems: 1
|
||||
deprecated: true
|
||||
description: HDMI mux lpm pin
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 1
|
||||
|
||||
ports:
|
||||
type: object
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
description: |
|
||||
Output endpoints of the controller.
|
||||
|
||||
required:
|
||||
- port@0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- phys
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,hdmi-tx-8960
|
||||
- qcom,hdmi-tx-8660
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: master_iface
|
||||
- const: slave_iface
|
||||
core-vcc-supplies: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,hdmi-tx-8974
|
||||
- qcom,hdmi-tx-8084
|
||||
- qcom,hdmi-tx-8994
|
||||
- qcom,hdmi-tx-8996
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 5
|
||||
clock-names:
|
||||
items:
|
||||
- const: mdp_core
|
||||
- const: iface
|
||||
- const: core
|
||||
- const: alt_iface
|
||||
- const: extp
|
||||
hdmi-mux-supplies: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
hdmi: hdmi@4a00000 {
|
||||
compatible = "qcom,hdmi-tx-8960";
|
||||
reg-names = "core_physical";
|
||||
reg = <0x04a00000 0x2f0>;
|
||||
interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-names = "core",
|
||||
"master_iface",
|
||||
"slave_iface";
|
||||
clocks = <&clk 61>,
|
||||
<&clk 72>,
|
||||
<&clk 98>;
|
||||
hpd-gpios = <&msmgpio 72 GPIO_ACTIVE_HIGH>;
|
||||
core-vdda-supply = <&pm8921_hdmi_mvs>;
|
||||
hdmi-mux-supply = <&ext_3p3v>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&hpd_active &ddc_active &cec_active>;
|
||||
pinctrl-1 = <&hpd_suspend &ddc_suspend &cec_suspend>;
|
||||
|
||||
phys = <&hdmi_phy>;
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-msm8996.h>
|
||||
#include <dt-bindings/clock/qcom,mmcc-msm8996.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
hdmi@9a0000 {
|
||||
compatible = "qcom,hdmi-tx-8996";
|
||||
reg = <0x009a0000 0x50c>,
|
||||
<0x00070000 0x6158>,
|
||||
<0x009e0000 0xfff>;
|
||||
reg-names = "core_physical",
|
||||
"qfprom_physical",
|
||||
"hdcp_physical";
|
||||
|
||||
interrupt-parent = <&mdss>;
|
||||
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
clocks = <&mmcc MDSS_MDP_CLK>,
|
||||
<&mmcc MDSS_AHB_CLK>,
|
||||
<&mmcc MDSS_HDMI_CLK>,
|
||||
<&mmcc MDSS_HDMI_AHB_CLK>,
|
||||
<&mmcc MDSS_EXTPCLK_CLK>;
|
||||
clock-names = "mdp_core",
|
||||
"iface",
|
||||
"core",
|
||||
"alt_iface",
|
||||
"extp";
|
||||
|
||||
phys = <&hdmi_phy>;
|
||||
#sound-dai-cells = <1>;
|
||||
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&hdmi_hpd_active &hdmi_ddc_active>;
|
||||
pinctrl-1 = <&hdmi_hpd_suspend &hdmi_ddc_suspend>;
|
||||
|
||||
core-vdda-supply = <&vreg_l12a_1p8>;
|
||||
core-vcc-supply = <&vreg_s4a_1p8>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
endpoint {
|
||||
remote-endpoint = <&mdp5_intf3_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
104
Documentation/devicetree/bindings/phy/qcom,hdmi-phy-other.yaml
Normal file
104
Documentation/devicetree/bindings/phy/qcom,hdmi-phy-other.yaml
Normal file
@ -0,0 +1,104 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
|
||||
$id: http://devicetree.org/schemas/phy/qcom,hdmi-phy-other.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Adreno/Snapdragon HDMI phy
|
||||
|
||||
maintainers:
|
||||
- Rob Clark <robdclark@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,hdmi-phy-8660
|
||||
- qcom,hdmi-phy-8960
|
||||
- qcom,hdmi-phy-8974
|
||||
- qcom,hdmi-phy-8084
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: hdmi_phy
|
||||
- const: hdmi_pll
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
core-vdda-supply:
|
||||
description: phandle to VDDA supply regulator
|
||||
|
||||
vddio-supply:
|
||||
description: phandle to VDD I/O supply regulator
|
||||
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,hdmi-phy-8660
|
||||
- qcom,hdmi-phy-8960
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
items:
|
||||
- const: slave_iface
|
||||
vddio-supply: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,hdmi-phy-8084
|
||||
- qcom,hdmi-phy-8974
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: iface
|
||||
- const: alt_iface
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- reg
|
||||
- reg-names
|
||||
- '#phy-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
hdmi_phy: phy@4a00400 {
|
||||
compatible = "qcom,hdmi-phy-8960";
|
||||
reg-names = "hdmi_phy",
|
||||
"hdmi_pll";
|
||||
reg = <0x4a00400 0x60>,
|
||||
<0x4a00500 0x100>;
|
||||
#phy-cells = <0>;
|
||||
power-domains = <&mmcc 1>;
|
||||
clock-names = "slave_iface";
|
||||
clocks = <&clk 21>;
|
||||
core-vdda-supply = <&pm8921_hdmi_mvs>;
|
||||
};
|
85
Documentation/devicetree/bindings/phy/qcom,hdmi-phy-qmp.yaml
Normal file
85
Documentation/devicetree/bindings/phy/qcom,hdmi-phy-qmp.yaml
Normal file
@ -0,0 +1,85 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
|
||||
$id: http://devicetree.org/schemas/phy/qcom,hdmi-phy-qmp.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Adreno/Snapdragon QMP HDMI phy
|
||||
|
||||
maintainers:
|
||||
- Rob Clark <robdclark@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,hdmi-phy-8996
|
||||
|
||||
reg:
|
||||
maxItems: 6
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: hdmi_pll
|
||||
- const: hdmi_tx_l0
|
||||
- const: hdmi_tx_l1
|
||||
- const: hdmi_tx_l2
|
||||
- const: hdmi_tx_l3
|
||||
- const: hdmi_phy
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: iface
|
||||
- const: ref
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
vcca-supply:
|
||||
description: phandle to VCCA supply regulator
|
||||
|
||||
vddio-supply:
|
||||
description: phandle to VDD I/O supply regulator
|
||||
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- reg
|
||||
- reg-names
|
||||
- '#phy-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
hdmi-phy@9a0600 {
|
||||
compatible = "qcom,hdmi-phy-8996";
|
||||
reg = <0x009a0600 0x1c4>,
|
||||
<0x009a0a00 0x124>,
|
||||
<0x009a0c00 0x124>,
|
||||
<0x009a0e00 0x124>,
|
||||
<0x009a1000 0x124>,
|
||||
<0x009a1200 0x0c8>;
|
||||
reg-names = "hdmi_pll",
|
||||
"hdmi_tx_l0",
|
||||
"hdmi_tx_l1",
|
||||
"hdmi_tx_l2",
|
||||
"hdmi_tx_l3",
|
||||
"hdmi_phy";
|
||||
|
||||
clocks = <&mmcc 116>,
|
||||
<&gcc 214>;
|
||||
clock-names = "iface",
|
||||
"ref";
|
||||
#phy-cells = <0>;
|
||||
|
||||
vddio-supply = <&vreg_l12a_1p8>;
|
||||
vcca-supply = <&vreg_l28a_0p925>;
|
||||
};
|
@ -105,6 +105,27 @@ 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>
|
||||
|
||||
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
|
||||
engine.
|
||||
|
||||
Values are not required to be constantly monotonic if it makes the driver
|
||||
implementation easier, but are required to catch up with the previously reported
|
||||
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]
|
||||
|
||||
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
|
||||
time active without considering what frequency the engine is operating as a
|
||||
percentage of it's maximum frequency.
|
||||
|
||||
===============================
|
||||
Driver specific implementations
|
||||
===============================
|
||||
|
@ -119,7 +119,6 @@ msm-$(CONFIG_DRM_MSM_GPU_STATE) += adreno/a6xx_gpu_state.o
|
||||
|
||||
msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
|
||||
dp/dp_catalog.o \
|
||||
dp/dp_clk_util.o \
|
||||
dp/dp_ctrl.o \
|
||||
dp/dp_display.o \
|
||||
dp/dp_drm.o \
|
||||
|
@ -1666,18 +1666,10 @@ static u64 a5xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
|
||||
{
|
||||
u64 busy_cycles;
|
||||
|
||||
/* Only read the gpu busy if the hardware is already active */
|
||||
if (pm_runtime_get_if_in_use(&gpu->pdev->dev) == 0) {
|
||||
*out_sample_rate = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO,
|
||||
REG_A5XX_RBBM_PERFCTR_RBBM_0_HI);
|
||||
*out_sample_rate = clk_get_rate(gpu->core_clk);
|
||||
|
||||
pm_runtime_put(&gpu->pdev->dev);
|
||||
|
||||
return busy_cycles;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,8 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
|
||||
A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
|
||||
}
|
||||
|
||||
void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
|
||||
void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp,
|
||||
bool suspended)
|
||||
{
|
||||
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
|
||||
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
|
||||
@ -127,15 +128,16 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
|
||||
|
||||
/*
|
||||
* This can get called from devfreq while the hardware is idle. Don't
|
||||
* bring up the power if it isn't already active
|
||||
* bring up the power if it isn't already active. All we're doing here
|
||||
* is updating the frequency so that when we come back online we're at
|
||||
* the right rate.
|
||||
*/
|
||||
if (pm_runtime_get_if_in_use(gmu->dev) == 0)
|
||||
if (suspended)
|
||||
return;
|
||||
|
||||
if (!gmu->legacy) {
|
||||
a6xx_hfi_set_freq(gmu, perf_index);
|
||||
dev_pm_opp_set_opp(&gpu->pdev->dev, opp);
|
||||
pm_runtime_put(gmu->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -159,7 +161,6 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
|
||||
dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret);
|
||||
|
||||
dev_pm_opp_set_opp(&gpu->pdev->dev, opp);
|
||||
pm_runtime_put(gmu->dev);
|
||||
}
|
||||
|
||||
unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu)
|
||||
@ -504,7 +505,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)
|
||||
|
||||
static inline void pdc_write(void __iomem *ptr, u32 offset, u32 value)
|
||||
{
|
||||
return msm_writel(value, ptr + (offset << 2));
|
||||
msm_writel(value, ptr + (offset << 2));
|
||||
}
|
||||
|
||||
static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev,
|
||||
@ -527,6 +528,8 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
|
||||
pdc_in_aop = true;
|
||||
else if (adreno_is_a618(adreno_gpu) || adreno_is_a640_family(adreno_gpu))
|
||||
pdc_address_offset = 0x30090;
|
||||
else if (adreno_is_a619(adreno_gpu))
|
||||
pdc_address_offset = 0x300a0;
|
||||
else
|
||||
pdc_address_offset = 0x30080;
|
||||
|
||||
@ -601,7 +604,8 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
|
||||
|
||||
pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 4, 0x10108);
|
||||
pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 4, 0x30000);
|
||||
if (adreno_is_a618(adreno_gpu) || adreno_is_a650_family(adreno_gpu))
|
||||
if (adreno_is_a618(adreno_gpu) || adreno_is_a619(adreno_gpu) ||
|
||||
adreno_is_a650_family(adreno_gpu))
|
||||
pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x2);
|
||||
else
|
||||
pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x3);
|
||||
@ -895,7 +899,7 @@ static void a6xx_gmu_set_initial_freq(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
|
||||
return;
|
||||
|
||||
gmu->freq = 0; /* so a6xx_gmu_set_freq() doesn't exit early */
|
||||
a6xx_gmu_set_freq(gpu, gpu_opp);
|
||||
a6xx_gmu_set_freq(gpu, gpu_opp, false);
|
||||
dev_pm_opp_put(gpu_opp);
|
||||
}
|
||||
|
||||
@ -1537,6 +1541,12 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
|
||||
SZ_16M - SZ_16K, 0x04000, "icache");
|
||||
if (ret)
|
||||
goto err_memory;
|
||||
/*
|
||||
* NOTE: when porting legacy ("pre-650-family") GPUs you may be tempted to add a condition
|
||||
* to allocate icache/dcache here, as per downstream code flow, but it may not actually be
|
||||
* necessary. If you omit this step and you don't get random pagefaults, you are likely
|
||||
* good to go without this!
|
||||
*/
|
||||
} else if (adreno_is_a640_family(adreno_gpu)) {
|
||||
ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache,
|
||||
SZ_256K - SZ_16K, 0x04000, "icache");
|
||||
@ -1547,9 +1557,7 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
|
||||
SZ_256K - SZ_16K, 0x44000, "dcache");
|
||||
if (ret)
|
||||
goto err_memory;
|
||||
} else {
|
||||
BUG_ON(adreno_is_a660_family(adreno_gpu));
|
||||
|
||||
} else if (adreno_is_a630(adreno_gpu) || adreno_is_a615_family(adreno_gpu)) {
|
||||
/* HFI v1, has sptprac */
|
||||
gmu->legacy = true;
|
||||
|
||||
|
@ -98,7 +98,7 @@ static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset)
|
||||
|
||||
static inline void gmu_write(struct a6xx_gmu *gmu, u32 offset, u32 value)
|
||||
{
|
||||
return msm_writel(value, gmu->mmio + (offset << 2));
|
||||
msm_writel(value, gmu->mmio + (offset << 2));
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -138,7 +138,7 @@ static inline u32 gmu_read_rscc(struct a6xx_gmu *gmu, u32 offset)
|
||||
|
||||
static inline void gmu_write_rscc(struct a6xx_gmu *gmu, u32 offset, u32 value)
|
||||
{
|
||||
return msm_writel(value, gmu->rscc + (offset << 2));
|
||||
msm_writel(value, gmu->rscc + (offset << 2));
|
||||
}
|
||||
|
||||
#define gmu_poll_timeout_rscc(gmu, addr, val, cond, interval, timeout) \
|
||||
|
@ -252,6 +252,74 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
|
||||
a6xx_flush(gpu, ring);
|
||||
}
|
||||
|
||||
/* For a615 family (a615, a616, a618 and a619) */
|
||||
const struct adreno_reglist a615_hwcg[] = {
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_SP0, 0x02222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL2_SP0, 0x02222220},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_SP0, 0x00000080},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_SP0, 0x0000F3CF},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_TP0, 0x02222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_TP1, 0x02222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL2_TP1, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL3_TP0, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL3_TP1, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL4_TP0, 0x00022222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL4_TP1, 0x00022222},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_TP0, 0x77777777},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_TP1, 0x77777777},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST2_TP0, 0x77777777},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST2_TP1, 0x77777777},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST3_TP0, 0x77777777},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST3_TP1, 0x77777777},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST4_TP0, 0x00077777},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST4_TP1, 0x00077777},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_TP0, 0x11111111},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_TP1, 0x11111111},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY2_TP0, 0x11111111},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY2_TP1, 0x11111111},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY3_TP0, 0x11111111},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY3_TP1, 0x11111111},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY4_TP0, 0x00011111},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY4_TP1, 0x00011111},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_UCHE, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL2_UCHE, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL3_UCHE, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL4_UCHE, 0x00222222},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_UCHE, 0x00000004},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_UCHE, 0x00000002},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_RB0, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL2_RB0, 0x00002222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_CCU0, 0x00002020},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_CCU1, 0x00002220},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_CCU2, 0x00002220},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_CCU3, 0x00002220},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_RB_CCU0, 0x00040F00},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_RB_CCU1, 0x00040F00},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_RB_CCU2, 0x00040F00},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_RB_CCU3, 0x00040F00},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_RAC, 0x05022022},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL2_RAC, 0x00005555},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_RAC, 0x00000011},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_RAC, 0x00445044},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM, 0x04222222},
|
||||
{REG_A6XX_RBBM_CLOCK_MODE_GPC, 0x00222222},
|
||||
{REG_A6XX_RBBM_CLOCK_MODE_VFD, 0x00002222},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00000000},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_GPC, 0x04104004},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_VFD, 0x00000000},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_HLSQ, 0x00000000},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00004000},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_GPC, 0x00000200},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_VFD, 0x00002222},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_HLSQ_2, 0x00000002},
|
||||
{REG_A6XX_RBBM_CLOCK_MODE_HLSQ, 0x00002222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_GMU_GX, 0x00000222},
|
||||
{REG_A6XX_RBBM_CLOCK_DELAY_GMU_GX, 0x00000111},
|
||||
{REG_A6XX_RBBM_CLOCK_HYST_GMU_GX, 0x00000555},
|
||||
{},
|
||||
};
|
||||
|
||||
const struct adreno_reglist a630_hwcg[] = {
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_SP0, 0x22222222},
|
||||
{REG_A6XX_RBBM_CLOCK_CNTL_SP1, 0x22222222},
|
||||
@ -555,7 +623,7 @@ static void a6xx_set_hwcg(struct msm_gpu *gpu, bool state)
|
||||
gpu_write(gpu, REG_A6XX_RBBM_CLOCK_CNTL, state ? clock_cntl_on : 0);
|
||||
}
|
||||
|
||||
/* For a615, a616, a618, A619, a630, a640 and a680 */
|
||||
/* For a615, a616, a618, a619, a630, a640 and a680 */
|
||||
static const u32 a6xx_protect[] = {
|
||||
A6XX_PROTECT_RDONLY(0x00000, 0x04ff),
|
||||
A6XX_PROTECT_RDONLY(0x00501, 0x0005),
|
||||
@ -1446,7 +1514,7 @@ static void a6xx_llc_rmw(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 mask, u32 or)
|
||||
|
||||
static void a6xx_llc_write(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 value)
|
||||
{
|
||||
return msm_writel(value, a6xx_gpu->llc_mmio + (reg << 2));
|
||||
msm_writel(value, a6xx_gpu->llc_mmio + (reg << 2));
|
||||
}
|
||||
|
||||
static void a6xx_llc_deactivate(struct a6xx_gpu *a6xx_gpu)
|
||||
@ -1658,27 +1726,21 @@ static u64 a6xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
|
||||
/* 19.2MHz */
|
||||
*out_sample_rate = 19200000;
|
||||
|
||||
/* Only read the gpu busy if the hardware is already active */
|
||||
if (pm_runtime_get_if_in_use(a6xx_gpu->gmu.dev) == 0)
|
||||
return 0;
|
||||
|
||||
busy_cycles = gmu_read64(&a6xx_gpu->gmu,
|
||||
REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
|
||||
REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H);
|
||||
|
||||
|
||||
pm_runtime_put(a6xx_gpu->gmu.dev);
|
||||
|
||||
return busy_cycles;
|
||||
}
|
||||
|
||||
static void a6xx_gpu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
|
||||
static void a6xx_gpu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp,
|
||||
bool suspended)
|
||||
{
|
||||
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
|
||||
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
|
||||
|
||||
mutex_lock(&a6xx_gpu->gmu.lock);
|
||||
a6xx_gmu_set_freq(gpu, opp);
|
||||
a6xx_gmu_set_freq(gpu, opp, suspended);
|
||||
mutex_unlock(&a6xx_gpu->gmu.lock);
|
||||
}
|
||||
|
||||
@ -1737,7 +1799,8 @@ a6xx_create_private_address_space(struct msm_gpu *gpu)
|
||||
return ERR_CAST(mmu);
|
||||
|
||||
return msm_gem_address_space_create(mmu,
|
||||
"gpu", 0x100000000ULL, SZ_4G);
|
||||
"gpu", 0x100000000ULL,
|
||||
adreno_private_address_space_size(gpu));
|
||||
}
|
||||
|
||||
static uint32_t a6xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
|
||||
@ -1763,6 +1826,22 @@ static u32 a618_get_speed_bin(u32 fuse)
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
static u32 a619_get_speed_bin(u32 fuse)
|
||||
{
|
||||
if (fuse == 0)
|
||||
return 0;
|
||||
else if (fuse == 120)
|
||||
return 4;
|
||||
else if (fuse == 138)
|
||||
return 3;
|
||||
else if (fuse == 169)
|
||||
return 2;
|
||||
else if (fuse == 180)
|
||||
return 1;
|
||||
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
static u32 adreno_7c3_get_speed_bin(u32 fuse)
|
||||
{
|
||||
if (fuse == 0)
|
||||
@ -1782,6 +1861,9 @@ static u32 fuse_to_supp_hw(struct device *dev, struct adreno_rev rev, u32 fuse)
|
||||
if (adreno_cmp_rev(ADRENO_REV(6, 1, 8, ANY_ID), rev))
|
||||
val = a618_get_speed_bin(fuse);
|
||||
|
||||
if (adreno_cmp_rev(ADRENO_REV(6, 1, 9, ANY_ID), rev))
|
||||
val = a619_get_speed_bin(fuse);
|
||||
|
||||
if (adreno_cmp_rev(ADRENO_REV(6, 3, 5, ANY_ID), rev))
|
||||
val = adreno_7c3_get_speed_bin(fuse);
|
||||
|
||||
|
@ -77,7 +77,8 @@ void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state);
|
||||
int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node);
|
||||
void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu);
|
||||
|
||||
void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp);
|
||||
void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp,
|
||||
bool suspended);
|
||||
unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu);
|
||||
|
||||
void a6xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
|
||||
|
@ -205,8 +205,8 @@ static int a6xx_hfi_get_fw_version(struct a6xx_gmu *gmu, u32 *version)
|
||||
{
|
||||
struct a6xx_hfi_msg_fw_version msg = { 0 };
|
||||
|
||||
/* Currently supporting version 1.1 */
|
||||
msg.supported_version = (1 << 28) | (1 << 16);
|
||||
/* Currently supporting version 1.10 */
|
||||
msg.supported_version = (1 << 28) | (1 << 19) | (1 << 17);
|
||||
|
||||
return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_FW_VERSION, &msg, sizeof(msg),
|
||||
version, sizeof(*version));
|
||||
@ -285,6 +285,65 @@ static void a618_build_bw_table(struct a6xx_hfi_msg_bw_table *msg)
|
||||
msg->cnoc_cmds_data[1][0] = 0x60000001;
|
||||
}
|
||||
|
||||
static void a619_build_bw_table(struct a6xx_hfi_msg_bw_table *msg)
|
||||
{
|
||||
msg->bw_level_num = 13;
|
||||
|
||||
msg->ddr_cmds_num = 3;
|
||||
msg->ddr_wait_bitmask = 0x0;
|
||||
|
||||
msg->ddr_cmds_addrs[0] = 0x50000;
|
||||
msg->ddr_cmds_addrs[1] = 0x50004;
|
||||
msg->ddr_cmds_addrs[2] = 0x50080;
|
||||
|
||||
msg->ddr_cmds_data[0][0] = 0x40000000;
|
||||
msg->ddr_cmds_data[0][1] = 0x40000000;
|
||||
msg->ddr_cmds_data[0][2] = 0x40000000;
|
||||
msg->ddr_cmds_data[1][0] = 0x6000030c;
|
||||
msg->ddr_cmds_data[1][1] = 0x600000db;
|
||||
msg->ddr_cmds_data[1][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[2][0] = 0x60000618;
|
||||
msg->ddr_cmds_data[2][1] = 0x600001b6;
|
||||
msg->ddr_cmds_data[2][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[3][0] = 0x60000925;
|
||||
msg->ddr_cmds_data[3][1] = 0x60000291;
|
||||
msg->ddr_cmds_data[3][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[4][0] = 0x60000dc1;
|
||||
msg->ddr_cmds_data[4][1] = 0x600003dc;
|
||||
msg->ddr_cmds_data[4][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[5][0] = 0x600010ad;
|
||||
msg->ddr_cmds_data[5][1] = 0x600004ae;
|
||||
msg->ddr_cmds_data[5][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[6][0] = 0x600014c3;
|
||||
msg->ddr_cmds_data[6][1] = 0x600005d4;
|
||||
msg->ddr_cmds_data[6][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[7][0] = 0x6000176a;
|
||||
msg->ddr_cmds_data[7][1] = 0x60000693;
|
||||
msg->ddr_cmds_data[7][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[8][0] = 0x60001f01;
|
||||
msg->ddr_cmds_data[8][1] = 0x600008b5;
|
||||
msg->ddr_cmds_data[8][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[9][0] = 0x60002940;
|
||||
msg->ddr_cmds_data[9][1] = 0x60000b95;
|
||||
msg->ddr_cmds_data[9][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[10][0] = 0x60002f68;
|
||||
msg->ddr_cmds_data[10][1] = 0x60000d50;
|
||||
msg->ddr_cmds_data[10][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[11][0] = 0x60003700;
|
||||
msg->ddr_cmds_data[11][1] = 0x60000f71;
|
||||
msg->ddr_cmds_data[11][2] = 0x60000008;
|
||||
msg->ddr_cmds_data[12][0] = 0x60003fce;
|
||||
msg->ddr_cmds_data[12][1] = 0x600011ea;
|
||||
msg->ddr_cmds_data[12][2] = 0x60000008;
|
||||
|
||||
msg->cnoc_cmds_num = 1;
|
||||
msg->cnoc_wait_bitmask = 0x0;
|
||||
|
||||
msg->cnoc_cmds_addrs[0] = 0x50054;
|
||||
|
||||
msg->cnoc_cmds_data[0][0] = 0x40000000;
|
||||
}
|
||||
|
||||
static void a640_build_bw_table(struct a6xx_hfi_msg_bw_table *msg)
|
||||
{
|
||||
/*
|
||||
@ -462,6 +521,8 @@ static int a6xx_hfi_send_bw_table(struct a6xx_gmu *gmu)
|
||||
|
||||
if (adreno_is_a618(adreno_gpu))
|
||||
a618_build_bw_table(&msg);
|
||||
else if (adreno_is_a619(adreno_gpu))
|
||||
a619_build_bw_table(&msg);
|
||||
else if (adreno_is_a640_family(adreno_gpu))
|
||||
a640_build_bw_table(&msg);
|
||||
else if (adreno_is_a650(adreno_gpu))
|
||||
|
@ -264,6 +264,19 @@ static const struct adreno_info gpulist[] = {
|
||||
.gmem = SZ_512K,
|
||||
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
|
||||
.init = a6xx_gpu_init,
|
||||
}, {
|
||||
.rev = ADRENO_REV(6, 1, 9, ANY_ID),
|
||||
.revn = 619,
|
||||
.name = "A619",
|
||||
.fw = {
|
||||
[ADRENO_FW_SQE] = "a630_sqe.fw",
|
||||
[ADRENO_FW_GMU] = "a619_gmu.bin",
|
||||
},
|
||||
.gmem = SZ_512K,
|
||||
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
|
||||
.init = a6xx_gpu_init,
|
||||
.zapfw = "a615_zap.mdt",
|
||||
.hwcg = a615_hwcg,
|
||||
}, {
|
||||
.rev = ADRENO_REV(6, 3, 0, ANY_ID),
|
||||
.revn = 630,
|
||||
@ -303,6 +316,7 @@ static const struct adreno_info gpulist[] = {
|
||||
.init = a6xx_gpu_init,
|
||||
.zapfw = "a650_zap.mdt",
|
||||
.hwcg = a650_hwcg,
|
||||
.address_space_size = SZ_16G,
|
||||
}, {
|
||||
.rev = ADRENO_REV(6, 6, 0, ANY_ID),
|
||||
.revn = 660,
|
||||
@ -316,6 +330,7 @@ static const struct adreno_info gpulist[] = {
|
||||
.init = a6xx_gpu_init,
|
||||
.zapfw = "a660_zap.mdt",
|
||||
.hwcg = a660_hwcg,
|
||||
.address_space_size = SZ_16G,
|
||||
}, {
|
||||
.rev = ADRENO_REV(6, 3, 5, ANY_ID),
|
||||
.fw = {
|
||||
@ -326,6 +341,7 @@ static const struct adreno_info gpulist[] = {
|
||||
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
|
||||
.init = a6xx_gpu_init,
|
||||
.hwcg = a660_hwcg,
|
||||
.address_space_size = SZ_16G,
|
||||
}, {
|
||||
.rev = ADRENO_REV(6, 8, 0, ANY_ID),
|
||||
.revn = 680,
|
||||
@ -355,6 +371,7 @@ MODULE_FIRMWARE("qcom/a530_zap.mdt");
|
||||
MODULE_FIRMWARE("qcom/a530_zap.b00");
|
||||
MODULE_FIRMWARE("qcom/a530_zap.b01");
|
||||
MODULE_FIRMWARE("qcom/a530_zap.b02");
|
||||
MODULE_FIRMWARE("qcom/a619_gmu.bin");
|
||||
MODULE_FIRMWARE("qcom/a630_sqe.fw");
|
||||
MODULE_FIRMWARE("qcom/a630_gmu.bin");
|
||||
MODULE_FIRMWARE("qcom/a630_zap.mbn");
|
||||
@ -415,6 +432,12 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Now that we have firmware loaded, and are ready to begin
|
||||
* booting the gpu, go ahead and enable runpm:
|
||||
*/
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
/* Make sure pm runtime is active and reset any previous errors */
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
|
||||
|
@ -21,6 +21,10 @@
|
||||
#include "msm_gem.h"
|
||||
#include "msm_mmu.h"
|
||||
|
||||
static u64 address_space_size = 0;
|
||||
MODULE_PARM_DESC(address_space_size, "Override for size of processes private GPU address space");
|
||||
module_param(address_space_size, ullong, 0600);
|
||||
|
||||
static bool zap_available = true;
|
||||
|
||||
static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
|
||||
@ -228,6 +232,19 @@ adreno_iommu_create_address_space(struct msm_gpu *gpu,
|
||||
return aspace;
|
||||
}
|
||||
|
||||
u64 adreno_private_address_space_size(struct msm_gpu *gpu)
|
||||
{
|
||||
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
|
||||
|
||||
if (address_space_size)
|
||||
return address_space_size;
|
||||
|
||||
if (adreno_gpu->info->address_space_size)
|
||||
return adreno_gpu->info->address_space_size;
|
||||
|
||||
return SZ_4G;
|
||||
}
|
||||
|
||||
int adreno_get_param(struct msm_gpu *gpu, struct msm_file_private *ctx,
|
||||
uint32_t param, uint64_t *value, uint32_t *len)
|
||||
{
|
||||
@ -790,11 +807,11 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
|
||||
for (i = 0; i < gpu->nr_rings; i++) {
|
||||
drm_printf(p, " - id: %d\n", i);
|
||||
drm_printf(p, " iova: 0x%016llx\n", state->ring[i].iova);
|
||||
drm_printf(p, " last-fence: %d\n", state->ring[i].seqno);
|
||||
drm_printf(p, " retired-fence: %d\n", state->ring[i].fence);
|
||||
drm_printf(p, " rptr: %d\n", state->ring[i].rptr);
|
||||
drm_printf(p, " wptr: %d\n", state->ring[i].wptr);
|
||||
drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ);
|
||||
drm_printf(p, " last-fence: %u\n", state->ring[i].seqno);
|
||||
drm_printf(p, " retired-fence: %u\n", state->ring[i].fence);
|
||||
drm_printf(p, " rptr: %u\n", state->ring[i].rptr);
|
||||
drm_printf(p, " wptr: %u\n", state->ring[i].wptr);
|
||||
drm_printf(p, " size: %u\n", MSM_GPU_RINGBUFFER_SZ);
|
||||
|
||||
adreno_show_object(p, &state->ring[i].data,
|
||||
state->ring[i].data_size, &state->ring[i].encoded);
|
||||
@ -807,6 +824,7 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
|
||||
drm_printf(p, " - iova: 0x%016llx\n",
|
||||
state->bos[i].iova);
|
||||
drm_printf(p, " size: %zd\n", state->bos[i].size);
|
||||
drm_printf(p, " name: %-32s\n", state->bos[i].name);
|
||||
|
||||
adreno_show_object(p, &state->bos[i].data,
|
||||
state->bos[i].size, &state->bos[i].encoded);
|
||||
@ -1047,7 +1065,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
|
||||
pm_runtime_set_autosuspend_delay(dev,
|
||||
adreno_gpu->info->inactive_period);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
|
||||
gpu_name, &adreno_gpu_config);
|
||||
|
@ -57,7 +57,7 @@ struct adreno_reglist {
|
||||
u32 value;
|
||||
};
|
||||
|
||||
extern const struct adreno_reglist a630_hwcg[], a640_hwcg[], a650_hwcg[], a660_hwcg[];
|
||||
extern const struct adreno_reglist a615_hwcg[], a630_hwcg[], a640_hwcg[], a650_hwcg[], a660_hwcg[];
|
||||
|
||||
struct adreno_info {
|
||||
struct adreno_rev rev;
|
||||
@ -70,6 +70,7 @@ struct adreno_info {
|
||||
const char *zapfw;
|
||||
u32 inactive_period;
|
||||
const struct adreno_reglist *hwcg;
|
||||
u64 address_space_size;
|
||||
};
|
||||
|
||||
const struct adreno_info *adreno_info(struct adreno_rev rev);
|
||||
@ -199,7 +200,7 @@ static inline int adreno_is_a420(struct adreno_gpu *gpu)
|
||||
|
||||
static inline int adreno_is_a430(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 430;
|
||||
return gpu->revn == 430;
|
||||
}
|
||||
|
||||
static inline int adreno_is_a506(struct adreno_gpu *gpu)
|
||||
@ -239,12 +240,17 @@ static inline int adreno_is_a540(struct adreno_gpu *gpu)
|
||||
|
||||
static inline int adreno_is_a618(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 618;
|
||||
return gpu->revn == 618;
|
||||
}
|
||||
|
||||
static inline int adreno_is_a619(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 619;
|
||||
}
|
||||
|
||||
static inline int adreno_is_a630(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 630;
|
||||
return gpu->revn == 630;
|
||||
}
|
||||
|
||||
static inline int adreno_is_a640_family(struct adreno_gpu *gpu)
|
||||
@ -254,32 +260,38 @@ static inline int adreno_is_a640_family(struct adreno_gpu *gpu)
|
||||
|
||||
static inline int adreno_is_a650(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 650;
|
||||
return gpu->revn == 650;
|
||||
}
|
||||
|
||||
static inline int adreno_is_7c3(struct adreno_gpu *gpu)
|
||||
{
|
||||
/* The order of args is important here to handle ANY_ID correctly */
|
||||
return adreno_cmp_rev(ADRENO_REV(6, 3, 5, ANY_ID), gpu->rev);
|
||||
return adreno_cmp_rev(ADRENO_REV(6, 3, 5, ANY_ID), gpu->rev);
|
||||
}
|
||||
|
||||
static inline int adreno_is_a660(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 660;
|
||||
return gpu->revn == 660;
|
||||
}
|
||||
|
||||
/* check for a615, a616, a618, a619 or any derivatives */
|
||||
static inline int adreno_is_a615_family(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 615 || gpu->revn == 616 || gpu->revn == 618 || gpu->revn == 619;
|
||||
}
|
||||
|
||||
static inline int adreno_is_a660_family(struct adreno_gpu *gpu)
|
||||
{
|
||||
return adreno_is_a660(gpu) || adreno_is_7c3(gpu);
|
||||
return adreno_is_a660(gpu) || adreno_is_7c3(gpu);
|
||||
}
|
||||
|
||||
/* check for a650, a660, or any derivatives */
|
||||
static inline int adreno_is_a650_family(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->revn == 650 || gpu->revn == 620 ||
|
||||
adreno_is_a660_family(gpu);
|
||||
return gpu->revn == 650 || gpu->revn == 620 || adreno_is_a660_family(gpu);
|
||||
}
|
||||
|
||||
u64 adreno_private_address_space_size(struct msm_gpu *gpu);
|
||||
int adreno_get_param(struct msm_gpu *gpu, struct msm_file_private *ctx,
|
||||
uint32_t param, uint64_t *value, uint32_t *len);
|
||||
int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx,
|
||||
|
@ -53,7 +53,7 @@ static u64 _dpu_core_perf_calc_bw(struct dpu_kms *kms,
|
||||
crtc_plane_bw += pstate->plane_fetch_bw;
|
||||
}
|
||||
|
||||
bw_factor = kms->catalog->perf.bw_inefficiency_factor;
|
||||
bw_factor = kms->catalog->perf->bw_inefficiency_factor;
|
||||
if (bw_factor) {
|
||||
crtc_plane_bw *= bw_factor;
|
||||
do_div(crtc_plane_bw, 100);
|
||||
@ -90,7 +90,7 @@ static u64 _dpu_core_perf_calc_clk(struct dpu_kms *kms,
|
||||
crtc_clk = max(pstate->plane_clk, crtc_clk);
|
||||
}
|
||||
|
||||
clk_factor = kms->catalog->perf.clk_inefficiency_factor;
|
||||
clk_factor = kms->catalog->perf->clk_inefficiency_factor;
|
||||
if (clk_factor) {
|
||||
crtc_clk *= clk_factor;
|
||||
do_div(crtc_clk, 100);
|
||||
@ -128,7 +128,7 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
|
||||
perf->core_clk_rate = kms->perf.fix_core_clk_rate;
|
||||
} else {
|
||||
perf->bw_ctl = _dpu_core_perf_calc_bw(kms, crtc);
|
||||
perf->max_per_pipe_ib = kms->catalog->perf.min_dram_ib;
|
||||
perf->max_per_pipe_ib = kms->catalog->perf->min_dram_ib;
|
||||
perf->core_clk_rate = _dpu_core_perf_calc_clk(kms, crtc, state);
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
|
||||
bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000);
|
||||
DRM_DEBUG_ATOMIC("calculated bandwidth=%uk\n", bw);
|
||||
|
||||
threshold = kms->catalog->perf.max_bw_high;
|
||||
threshold = kms->catalog->perf->max_bw_high;
|
||||
|
||||
DRM_DEBUG_ATOMIC("final threshold bw limit = %d\n", threshold);
|
||||
|
||||
@ -413,7 +413,7 @@ static ssize_t _dpu_core_perf_mode_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct dpu_core_perf *perf = file->private_data;
|
||||
struct dpu_perf_cfg *cfg = &perf->catalog->perf;
|
||||
const struct dpu_perf_cfg *cfg = perf->catalog->perf;
|
||||
u32 perf_mode = 0;
|
||||
int ret;
|
||||
|
||||
@ -468,7 +468,7 @@ static const struct file_operations dpu_core_perf_mode_fops = {
|
||||
int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent)
|
||||
{
|
||||
struct dpu_core_perf *perf = &dpu_kms->perf;
|
||||
struct dpu_mdss_cfg *catalog = perf->catalog;
|
||||
const struct dpu_mdss_cfg *catalog = perf->catalog;
|
||||
struct dentry *entry;
|
||||
|
||||
entry = debugfs_create_dir("core_perf", parent);
|
||||
@ -480,15 +480,15 @@ int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent)
|
||||
debugfs_create_u32("enable_bw_release", 0600, entry,
|
||||
(u32 *)&perf->enable_bw_release);
|
||||
debugfs_create_u32("threshold_low", 0600, entry,
|
||||
(u32 *)&catalog->perf.max_bw_low);
|
||||
(u32 *)&catalog->perf->max_bw_low);
|
||||
debugfs_create_u32("threshold_high", 0600, entry,
|
||||
(u32 *)&catalog->perf.max_bw_high);
|
||||
(u32 *)&catalog->perf->max_bw_high);
|
||||
debugfs_create_u32("min_core_ib", 0600, entry,
|
||||
(u32 *)&catalog->perf.min_core_ib);
|
||||
(u32 *)&catalog->perf->min_core_ib);
|
||||
debugfs_create_u32("min_llcc_ib", 0600, entry,
|
||||
(u32 *)&catalog->perf.min_llcc_ib);
|
||||
(u32 *)&catalog->perf->min_llcc_ib);
|
||||
debugfs_create_u32("min_dram_ib", 0600, entry,
|
||||
(u32 *)&catalog->perf.min_dram_ib);
|
||||
(u32 *)&catalog->perf->min_dram_ib);
|
||||
debugfs_create_file("perf_mode", 0600, entry,
|
||||
(u32 *)perf, &dpu_core_perf_mode_fops);
|
||||
debugfs_create_u64("fix_core_clk_rate", 0600, entry,
|
||||
@ -517,7 +517,7 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf)
|
||||
|
||||
int dpu_core_perf_init(struct dpu_core_perf *perf,
|
||||
struct drm_device *dev,
|
||||
struct dpu_mdss_cfg *catalog,
|
||||
const struct dpu_mdss_cfg *catalog,
|
||||
struct clk *core_clk)
|
||||
{
|
||||
perf->dev = dev;
|
||||
|
@ -68,7 +68,7 @@ struct dpu_core_perf_tune {
|
||||
struct dpu_core_perf {
|
||||
struct drm_device *dev;
|
||||
struct dentry *debugfs_root;
|
||||
struct dpu_mdss_cfg *catalog;
|
||||
const struct dpu_mdss_cfg *catalog;
|
||||
struct clk *core_clk;
|
||||
u64 core_clk_rate;
|
||||
u64 max_core_clk_rate;
|
||||
@ -119,7 +119,7 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf);
|
||||
*/
|
||||
int dpu_core_perf_init(struct dpu_core_perf *perf,
|
||||
struct drm_device *dev,
|
||||
struct dpu_mdss_cfg *catalog,
|
||||
const struct dpu_mdss_cfg *catalog,
|
||||
struct clk *core_clk);
|
||||
|
||||
struct dpu_kms;
|
||||
|
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
@ -80,6 +81,8 @@ static enum dpu_crtc_crc_source dpu_crtc_parse_crc_source(const char *src_name)
|
||||
if (!strcmp(src_name, "auto") ||
|
||||
!strcmp(src_name, "lm"))
|
||||
return DPU_CRTC_CRC_SOURCE_LAYER_MIXER;
|
||||
if (!strcmp(src_name, "encoder"))
|
||||
return DPU_CRTC_CRC_SOURCE_ENCODER;
|
||||
|
||||
return DPU_CRTC_CRC_SOURCE_INVALID;
|
||||
}
|
||||
@ -95,23 +98,54 @@ static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER)
|
||||
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) {
|
||||
*values_cnt = crtc_state->num_mixers;
|
||||
} else if (source == DPU_CRTC_CRC_SOURCE_ENCODER) {
|
||||
struct drm_encoder *drm_enc;
|
||||
|
||||
*values_cnt = 0;
|
||||
|
||||
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask)
|
||||
*values_cnt += dpu_encoder_get_crc_values_cnt(drm_enc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state)
|
||||
{
|
||||
struct dpu_crtc_mixer *m;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < crtc_state->num_mixers; ++i) {
|
||||
m = &crtc_state->mixers[i];
|
||||
|
||||
if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
|
||||
continue;
|
||||
|
||||
/* Calculate MISR over 1 frame */
|
||||
m->hw_lm->ops.setup_misr(m->hw_lm, true, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void dpu_crtc_setup_encoder_misr(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_encoder *drm_enc;
|
||||
|
||||
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask)
|
||||
dpu_encoder_setup_misr(drm_enc);
|
||||
}
|
||||
|
||||
static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
|
||||
{
|
||||
enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name);
|
||||
enum dpu_crtc_crc_source current_source;
|
||||
struct dpu_crtc_state *crtc_state;
|
||||
struct drm_device *drm_dev = crtc->dev;
|
||||
struct dpu_crtc_mixer *m;
|
||||
|
||||
bool was_enabled;
|
||||
bool enable = false;
|
||||
int i, ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (source < 0) {
|
||||
DRM_DEBUG_DRIVER("Invalid CRC source %s for CRTC%d\n", src_name, crtc->index);
|
||||
@ -148,16 +182,12 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
|
||||
|
||||
crtc_state->crc_frame_skip_count = 0;
|
||||
|
||||
for (i = 0; i < crtc_state->num_mixers; ++i) {
|
||||
m = &crtc_state->mixers[i];
|
||||
|
||||
if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
|
||||
continue;
|
||||
|
||||
/* Calculate MISR over 1 frame */
|
||||
m->hw_lm->ops.setup_misr(m->hw_lm, true, 1);
|
||||
}
|
||||
|
||||
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER)
|
||||
dpu_crtc_setup_lm_misr(crtc_state);
|
||||
else if (source == DPU_CRTC_CRC_SOURCE_ENCODER)
|
||||
dpu_crtc_setup_encoder_misr(crtc);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
cleanup:
|
||||
drm_modeset_unlock(&crtc->mutex);
|
||||
@ -176,26 +206,17 @@ static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc)
|
||||
return dpu_encoder_get_vsync_count(encoder);
|
||||
}
|
||||
|
||||
|
||||
static int dpu_crtc_get_crc(struct drm_crtc *crtc)
|
||||
static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc,
|
||||
struct dpu_crtc_state *crtc_state)
|
||||
{
|
||||
struct dpu_crtc_state *crtc_state;
|
||||
struct dpu_crtc_mixer *m;
|
||||
u32 crcs[CRTC_DUAL_MIXERS];
|
||||
|
||||
int i = 0;
|
||||
int rc = 0;
|
||||
|
||||
crtc_state = to_dpu_crtc_state(crtc->state);
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(crcs) != ARRAY_SIZE(crtc_state->mixers));
|
||||
|
||||
/* Skip first 2 frames in case of "uncooked" CRCs */
|
||||
if (crtc_state->crc_frame_skip_count < 2) {
|
||||
crtc_state->crc_frame_skip_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < crtc_state->num_mixers; ++i) {
|
||||
|
||||
m = &crtc_state->mixers[i];
|
||||
@ -216,6 +237,46 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc)
|
||||
drm_crtc_accurate_vblank_count(crtc), crcs);
|
||||
}
|
||||
|
||||
static int dpu_crtc_get_encoder_crc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_encoder *drm_enc;
|
||||
int rc, pos = 0;
|
||||
u32 crcs[INTF_MAX];
|
||||
|
||||
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) {
|
||||
rc = dpu_encoder_get_crc(drm_enc, crcs, pos);
|
||||
if (rc < 0) {
|
||||
if (rc != -ENODATA)
|
||||
DRM_DEBUG_DRIVER("MISR read failed\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
pos += rc;
|
||||
}
|
||||
|
||||
return drm_crtc_add_crc_entry(crtc, true,
|
||||
drm_crtc_accurate_vblank_count(crtc), crcs);
|
||||
}
|
||||
|
||||
static int dpu_crtc_get_crc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state);
|
||||
|
||||
/* Skip first 2 frames in case of "uncooked" CRCs */
|
||||
if (crtc_state->crc_frame_skip_count < 2) {
|
||||
crtc_state->crc_frame_skip_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER)
|
||||
return dpu_crtc_get_lm_crc(crtc, crtc_state);
|
||||
else if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_ENCODER)
|
||||
return dpu_crtc_get_encoder_crc(crtc);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq,
|
||||
int *vpos, int *hpos,
|
||||
@ -363,6 +424,9 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
|
||||
if (!state)
|
||||
continue;
|
||||
|
||||
if (!state->visible)
|
||||
continue;
|
||||
|
||||
pstate = to_dpu_plane_state(state);
|
||||
fb = state->fb;
|
||||
|
||||
@ -1136,6 +1200,9 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
if (cnt >= DPU_STAGE_MAX * 4)
|
||||
continue;
|
||||
|
||||
if (!pstate->visible)
|
||||
continue;
|
||||
|
||||
pstates[cnt].dpu_pstate = dpu_pstate;
|
||||
pstates[cnt].drm_pstate = pstate;
|
||||
pstates[cnt].stage = pstate->normalized_zpos;
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
@ -12,7 +13,6 @@
|
||||
#include <drm/drm_crtc.h>
|
||||
#include "dpu_kms.h"
|
||||
#include "dpu_core_perf.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
#define DPU_CRTC_NAME_SIZE 12
|
||||
|
||||
@ -73,11 +73,13 @@ struct dpu_crtc_smmu_state_data {
|
||||
* enum dpu_crtc_crc_source: CRC source
|
||||
* @DPU_CRTC_CRC_SOURCE_NONE: no source set
|
||||
* @DPU_CRTC_CRC_SOURCE_LAYER_MIXER: CRC in layer mixer
|
||||
* @DPU_CRTC_CRC_SOURCE_ENCODER: CRC in encoder
|
||||
* @DPU_CRTC_CRC_SOURCE_INVALID: Invalid source
|
||||
*/
|
||||
enum dpu_crtc_crc_source {
|
||||
DPU_CRTC_CRC_SOURCE_NONE = 0,
|
||||
DPU_CRTC_CRC_SOURCE_LAYER_MIXER,
|
||||
DPU_CRTC_CRC_SOURCE_ENCODER,
|
||||
DPU_CRTC_CRC_SOURCE_MAX,
|
||||
DPU_CRTC_CRC_SOURCE_INVALID = -1
|
||||
};
|
||||
@ -201,6 +203,8 @@ struct dpu_crtc {
|
||||
* @mixers : List of active mixers
|
||||
* @num_ctls : Number of ctl paths in use
|
||||
* @hw_ctls : List of active ctl paths
|
||||
* @crc_source : CRC source
|
||||
* @crc_frame_skip_count: Number of frames skipped before getting CRC
|
||||
*/
|
||||
struct dpu_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
|
@ -225,6 +225,70 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
|
||||
return dpu_enc->wide_bus_en;
|
||||
}
|
||||
|
||||
int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct dpu_encoder_virt *dpu_enc;
|
||||
int i, num_intf = 0;
|
||||
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
|
||||
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
|
||||
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
|
||||
|
||||
if (phys->hw_intf && phys->hw_intf->ops.setup_misr
|
||||
&& phys->hw_intf->ops.collect_misr)
|
||||
num_intf++;
|
||||
}
|
||||
|
||||
return num_intf;
|
||||
}
|
||||
|
||||
void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct dpu_encoder_virt *dpu_enc;
|
||||
|
||||
int i;
|
||||
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
|
||||
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
|
||||
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
|
||||
|
||||
if (!phys->hw_intf || !phys->hw_intf->ops.setup_misr)
|
||||
continue;
|
||||
|
||||
phys->hw_intf->ops.setup_misr(phys->hw_intf, true, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos)
|
||||
{
|
||||
struct dpu_encoder_virt *dpu_enc;
|
||||
|
||||
int i, rc = 0, entries_added = 0;
|
||||
|
||||
if (!drm_enc->crtc) {
|
||||
DRM_ERROR("no crtc found for encoder %d\n", drm_enc->index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
|
||||
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
|
||||
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
|
||||
|
||||
if (!phys->hw_intf || !phys->hw_intf->ops.collect_misr)
|
||||
continue;
|
||||
|
||||
rc = phys->hw_intf->ops.collect_misr(phys->hw_intf, &crcs[pos + entries_added]);
|
||||
if (rc)
|
||||
return rc;
|
||||
entries_added++;
|
||||
}
|
||||
|
||||
return entries_added;
|
||||
}
|
||||
|
||||
static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned bpc)
|
||||
{
|
||||
struct dpu_hw_dither_cfg dither_cfg = { 0 };
|
||||
@ -634,7 +698,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
|
||||
}
|
||||
|
||||
if (hw_mdptop->ops.setup_vsync_source &&
|
||||
disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
|
||||
disp_info->is_cmd_mode) {
|
||||
for (i = 0; i < dpu_enc->num_phys_encs; i++)
|
||||
vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx;
|
||||
|
||||
@ -718,8 +782,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
|
||||
}
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
priv = drm_enc->dev->dev_private;
|
||||
is_vid_mode = dpu_enc->disp_info.capabilities &
|
||||
MSM_DISPLAY_CAP_VID_MODE;
|
||||
is_vid_mode = !dpu_enc->disp_info.is_cmd_mode;
|
||||
|
||||
/*
|
||||
* when idle_pc is not supported, process only KICKOFF, STOP and MODESET
|
||||
@ -1048,24 +1111,6 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
|
||||
phys->hw_pp = dpu_enc->hw_pp[i];
|
||||
phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
|
||||
|
||||
if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
|
||||
phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
|
||||
|
||||
if (phys->wb_idx >= WB_0 && phys->wb_idx < WB_MAX)
|
||||
phys->hw_wb = dpu_rm_get_wb(&dpu_kms->rm, phys->wb_idx);
|
||||
|
||||
if (!phys->hw_intf && !phys->hw_wb) {
|
||||
DPU_ERROR_ENC(dpu_enc,
|
||||
"no intf or wb block assigned at idx: %d\n", i);
|
||||
return;
|
||||
}
|
||||
|
||||
if (phys->hw_intf && phys->hw_wb) {
|
||||
DPU_ERROR_ENC(dpu_enc,
|
||||
"invalid phys both intf and wb block at idx: %d\n", i);
|
||||
return;
|
||||
}
|
||||
|
||||
phys->cached_mode = crtc_state->adjusted_mode;
|
||||
if (phys->ops.atomic_mode_set)
|
||||
phys->ops.atomic_mode_set(phys, crtc_state, conn_state);
|
||||
@ -1205,37 +1250,37 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
|
||||
mutex_unlock(&dpu_enc->enc_lock);
|
||||
}
|
||||
|
||||
static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
|
||||
static enum dpu_intf dpu_encoder_get_intf(const struct dpu_mdss_cfg *catalog,
|
||||
enum dpu_intf_type type, u32 controller_id)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (type != INTF_WB) {
|
||||
for (i = 0; i < catalog->intf_count; i++) {
|
||||
if (catalog->intf[i].type == type
|
||||
&& catalog->intf[i].controller_id == controller_id) {
|
||||
return catalog->intf[i].id;
|
||||
}
|
||||
if (type == INTF_WB)
|
||||
return INTF_MAX;
|
||||
|
||||
for (i = 0; i < catalog->intf_count; i++) {
|
||||
if (catalog->intf[i].type == type
|
||||
&& catalog->intf[i].controller_id == controller_id) {
|
||||
return catalog->intf[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
return INTF_MAX;
|
||||
}
|
||||
|
||||
static enum dpu_wb dpu_encoder_get_wb(struct dpu_mdss_cfg *catalog,
|
||||
static enum dpu_wb dpu_encoder_get_wb(const struct dpu_mdss_cfg *catalog,
|
||||
enum dpu_intf_type type, u32 controller_id)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (type != INTF_WB)
|
||||
goto end;
|
||||
return WB_MAX;
|
||||
|
||||
for (i = 0; i < catalog->wb_count; i++) {
|
||||
if (catalog->wb[i].id == controller_id)
|
||||
return catalog->wb[i].id;
|
||||
}
|
||||
|
||||
end:
|
||||
return WB_MAX;
|
||||
}
|
||||
|
||||
@ -1603,7 +1648,7 @@ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc)
|
||||
|
||||
/* update only for command mode primary ctl */
|
||||
if ((phys == dpu_enc->cur_master) &&
|
||||
(disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
|
||||
disp_info->is_cmd_mode
|
||||
&& ctl->ops.trigger_pending)
|
||||
ctl->ops.trigger_pending(ctl);
|
||||
}
|
||||
@ -2139,39 +2184,36 @@ static int dpu_encoder_virt_add_phys_encs(
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
|
||||
enc = dpu_encoder_phys_vid_init(params);
|
||||
|
||||
if (IS_ERR_OR_NULL(enc)) {
|
||||
DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n",
|
||||
PTR_ERR(enc));
|
||||
return enc == NULL ? -EINVAL : PTR_ERR(enc);
|
||||
}
|
||||
|
||||
dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
|
||||
++dpu_enc->num_phys_encs;
|
||||
}
|
||||
|
||||
if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
|
||||
enc = dpu_encoder_phys_cmd_init(params);
|
||||
|
||||
if (IS_ERR_OR_NULL(enc)) {
|
||||
DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n",
|
||||
PTR_ERR(enc));
|
||||
return enc == NULL ? -EINVAL : PTR_ERR(enc);
|
||||
}
|
||||
|
||||
dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
|
||||
++dpu_enc->num_phys_encs;
|
||||
}
|
||||
|
||||
if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
|
||||
enc = dpu_encoder_phys_wb_init(params);
|
||||
|
||||
if (IS_ERR_OR_NULL(enc)) {
|
||||
if (IS_ERR(enc)) {
|
||||
DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
|
||||
PTR_ERR(enc));
|
||||
return enc == NULL ? -EINVAL : PTR_ERR(enc);
|
||||
PTR_ERR(enc));
|
||||
return PTR_ERR(enc);
|
||||
}
|
||||
|
||||
dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
|
||||
++dpu_enc->num_phys_encs;
|
||||
} else if (disp_info->is_cmd_mode) {
|
||||
enc = dpu_encoder_phys_cmd_init(params);
|
||||
|
||||
if (IS_ERR(enc)) {
|
||||
DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n",
|
||||
PTR_ERR(enc));
|
||||
return PTR_ERR(enc);
|
||||
}
|
||||
|
||||
dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
|
||||
++dpu_enc->num_phys_encs;
|
||||
} else {
|
||||
enc = dpu_encoder_phys_vid_init(params);
|
||||
|
||||
if (IS_ERR(enc)) {
|
||||
DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n",
|
||||
PTR_ERR(enc));
|
||||
return PTR_ERR(enc);
|
||||
}
|
||||
|
||||
dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
|
||||
@ -2230,8 +2272,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
|
||||
|
||||
DPU_DEBUG("dsi_info->num_of_h_tiles %d\n", disp_info->num_of_h_tiles);
|
||||
|
||||
if ((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) ||
|
||||
(disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE))
|
||||
if (disp_info->intf_type != DRM_MODE_ENCODER_VIRTUAL)
|
||||
dpu_enc->idle_pc_supported =
|
||||
dpu_kms->catalog->caps->has_idle_pc;
|
||||
|
||||
@ -2294,7 +2335,25 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
|
||||
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
|
||||
atomic_set(&phys->vsync_cnt, 0);
|
||||
atomic_set(&phys->underrun_cnt, 0);
|
||||
|
||||
if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
|
||||
phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
|
||||
|
||||
if (phys->wb_idx >= WB_0 && phys->wb_idx < WB_MAX)
|
||||
phys->hw_wb = dpu_rm_get_wb(&dpu_kms->rm, phys->wb_idx);
|
||||
|
||||
if (!phys->hw_intf && !phys->hw_wb) {
|
||||
DPU_ERROR_ENC(dpu_enc, "no intf or wb block assigned at idx: %d\n", i);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (phys->hw_intf && phys->hw_wb) {
|
||||
DPU_ERROR_ENC(dpu_enc,
|
||||
"invalid phys both intf and wb block at idx: %d\n", i);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dpu_enc->enc_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
@ -21,19 +22,19 @@
|
||||
/**
|
||||
* struct msm_display_info - defines display properties
|
||||
* @intf_type: DRM_MODE_ENCODER_ type
|
||||
* @capabilities: Bitmask of display flags
|
||||
* @num_of_h_tiles: Number of horizontal tiles in case of split interface
|
||||
* @h_tile_instance: Controller instance used per tile. Number of elements is
|
||||
* based on num_of_h_tiles
|
||||
* @is_cmd_mode Boolean to indicate if the CMD mode is requested
|
||||
* @is_te_using_watchdog_timer: Boolean to indicate watchdog TE is
|
||||
* used instead of panel TE in cmd mode panels
|
||||
* @dsc: DSC configuration data for DSC-enabled displays
|
||||
*/
|
||||
struct msm_display_info {
|
||||
int intf_type;
|
||||
uint32_t capabilities;
|
||||
uint32_t num_of_h_tiles;
|
||||
uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY];
|
||||
bool is_cmd_mode;
|
||||
bool is_te_using_watchdog_timer;
|
||||
struct msm_display_dsc_config *dsc;
|
||||
};
|
||||
@ -174,6 +175,27 @@ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
|
||||
|
||||
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_get_crc_values_cnt - get number of physical encoders contained
|
||||
* in virtual encoder that can collect CRC values
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
* Returns: Number of physical encoders for given drm encoder
|
||||
*/
|
||||
int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_setup_misr - enable misr calculations
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
*/
|
||||
void dpu_encoder_setup_misr(const struct drm_encoder *drm_encoder);
|
||||
|
||||
/**
|
||||
* dpu_encoder_get_crc - get the crc value from interface blocks
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
* Returns: 0 on success, error otherwise
|
||||
*/
|
||||
int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos);
|
||||
|
||||
/**
|
||||
* dpu_encoder_use_dsc_merge - returns true if the encoder uses DSC merge topology.
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "dpu_hw_top.h"
|
||||
#include "dpu_hw_wb.h"
|
||||
#include "dpu_hw_lm.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
#include "dpu_hw_merge3d.h"
|
||||
#include "dpu_hw_interrupts.h"
|
||||
#include "dpu_core_irq.h"
|
||||
@ -22,8 +21,6 @@
|
||||
#include "dpu_crtc.h"
|
||||
#include "disp/msm_disp_snapshot.h"
|
||||
|
||||
#define DEFAULT_MAX_WRITEBACK_WIDTH 2048
|
||||
|
||||
#define to_dpu_encoder_phys_wb(x) \
|
||||
container_of(x, struct dpu_encoder_phys_wb, base)
|
||||
|
||||
@ -105,8 +102,8 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
struct dpu_hw_wb *hw_wb;
|
||||
struct dpu_hw_wb_qos_cfg qos_cfg;
|
||||
struct dpu_mdss_cfg *catalog;
|
||||
struct dpu_qos_lut_tbl *qos_lut_tb;
|
||||
const struct dpu_mdss_cfg *catalog;
|
||||
const struct dpu_qos_lut_tbl *qos_lut_tb;
|
||||
|
||||
if (!phys_enc || !phys_enc->dpu_kms || !phys_enc->dpu_kms->catalog) {
|
||||
DPU_ERROR("invalid parameter(s)\n");
|
||||
@ -120,11 +117,11 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
|
||||
memset(&qos_cfg, 0, sizeof(struct dpu_hw_wb_qos_cfg));
|
||||
qos_cfg.danger_safe_en = true;
|
||||
qos_cfg.danger_lut =
|
||||
catalog->perf.danger_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
|
||||
catalog->perf->danger_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
|
||||
|
||||
qos_cfg.safe_lut = catalog->perf.safe_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
|
||||
qos_cfg.safe_lut = catalog->perf->safe_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
|
||||
|
||||
qos_lut_tb = &catalog->perf.qos_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
|
||||
qos_lut_tb = &catalog->perf->qos_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
|
||||
qos_cfg.creq_lut = _dpu_hw_get_qos_lut(qos_lut_tb, 0);
|
||||
|
||||
if (hw_wb->ops.setup_qos_lut)
|
||||
@ -168,7 +165,7 @@ static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc,
|
||||
if (hw_wb->ops.setup_cdp) {
|
||||
memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
|
||||
|
||||
cdp_cfg.enable = phys_enc->dpu_kms->catalog->perf.cdp_cfg
|
||||
cdp_cfg.enable = phys_enc->dpu_kms->catalog->perf->cdp_cfg
|
||||
[DPU_PERF_CDP_USAGE_NRT].wr_enable;
|
||||
cdp_cfg.ubwc_meta_enable =
|
||||
DPU_FORMAT_IS_UBWC(wb_cfg->dest.format);
|
||||
@ -280,9 +277,9 @@ static int dpu_encoder_phys_wb_atomic_check(
|
||||
DPU_ERROR("invalid fb h=%d, mode h=%d\n", fb->height,
|
||||
mode->vdisplay);
|
||||
return -EINVAL;
|
||||
} else if (fb->width > DEFAULT_MAX_WRITEBACK_WIDTH) {
|
||||
} else if (fb->width > phys_enc->hw_wb->caps->maxlinewidth) {
|
||||
DPU_ERROR("invalid fb w=%d, maxlinewidth=%u\n",
|
||||
fb->width, DEFAULT_MAX_WRITEBACK_WIDTH);
|
||||
fb->width, phys_enc->hw_wb->caps->maxlinewidth);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DPU_HW_BLK_H
|
||||
#define _DPU_HW_BLK_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
struct dpu_hw_blk;
|
||||
|
||||
|
||||
/**
|
||||
* struct dpu_hw_blk - definition of hardware block object
|
||||
* @list: list of hardware blocks
|
||||
* @type: hardware block type
|
||||
* @id: instance id
|
||||
* @refcount: reference/usage count
|
||||
*/
|
||||
struct dpu_hw_blk {
|
||||
/* opaque */
|
||||
};
|
||||
|
||||
#endif /*_DPU_HW_BLK_H */
|
@ -50,11 +50,14 @@
|
||||
#define DMA_CURSOR_MSM8998_MASK \
|
||||
(DMA_MSM8998_MASK | BIT(DPU_SSPP_CURSOR))
|
||||
|
||||
#define MIXER_SDM845_MASK \
|
||||
#define MIXER_MSM8998_MASK \
|
||||
(BIT(DPU_MIXER_SOURCESPLIT) | BIT(DPU_DIM_LAYER))
|
||||
|
||||
#define MIXER_SDM845_MASK \
|
||||
(BIT(DPU_MIXER_SOURCESPLIT) | BIT(DPU_DIM_LAYER) | BIT(DPU_MIXER_COMBINED_ALPHA))
|
||||
|
||||
#define MIXER_SC7180_MASK \
|
||||
(BIT(DPU_DIM_LAYER))
|
||||
(BIT(DPU_DIM_LAYER) | BIT(DPU_MIXER_COMBINED_ALPHA))
|
||||
|
||||
#define PINGPONG_SDM845_MASK BIT(DPU_PINGPONG_DITHER)
|
||||
|
||||
@ -936,17 +939,17 @@ static const struct dpu_lm_sub_blks msm8998_lm_sblk = {
|
||||
};
|
||||
|
||||
static const struct dpu_lm_cfg msm8998_lm[] = {
|
||||
LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK,
|
||||
LM_BLK("lm_0", LM_0, 0x44000, MIXER_MSM8998_MASK,
|
||||
&msm8998_lm_sblk, PINGPONG_0, LM_2, DSPP_0),
|
||||
LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK,
|
||||
LM_BLK("lm_1", LM_1, 0x45000, MIXER_MSM8998_MASK,
|
||||
&msm8998_lm_sblk, PINGPONG_1, LM_5, DSPP_1),
|
||||
LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK,
|
||||
LM_BLK("lm_2", LM_2, 0x46000, MIXER_MSM8998_MASK,
|
||||
&msm8998_lm_sblk, PINGPONG_2, LM_0, 0),
|
||||
LM_BLK("lm_3", LM_3, 0x47000, MIXER_SDM845_MASK,
|
||||
LM_BLK("lm_3", LM_3, 0x47000, MIXER_MSM8998_MASK,
|
||||
&msm8998_lm_sblk, PINGPONG_MAX, 0, 0),
|
||||
LM_BLK("lm_4", LM_4, 0x48000, MIXER_SDM845_MASK,
|
||||
LM_BLK("lm_4", LM_4, 0x48000, MIXER_MSM8998_MASK,
|
||||
&msm8998_lm_sblk, PINGPONG_MAX, 0, 0),
|
||||
LM_BLK("lm_5", LM_5, 0x49000, MIXER_SDM845_MASK,
|
||||
LM_BLK("lm_5", LM_5, 0x49000, MIXER_MSM8998_MASK,
|
||||
&msm8998_lm_sblk, PINGPONG_3, LM_1, 0),
|
||||
};
|
||||
|
||||
@ -1012,7 +1015,7 @@ static const struct dpu_lm_cfg sm8150_lm[] = {
|
||||
|
||||
static const struct dpu_lm_cfg sc7280_lm[] = {
|
||||
LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK,
|
||||
&sc7180_lm_sblk, PINGPONG_0, 0, 0),
|
||||
&sc7180_lm_sblk, PINGPONG_0, 0, DSPP_0),
|
||||
LM_BLK("lm_2", LM_2, 0x46000, MIXER_SC7180_MASK,
|
||||
&sc7180_lm_sblk, PINGPONG_2, LM_3, 0),
|
||||
LM_BLK("lm_3", LM_3, 0x47000, MIXER_SC7180_MASK,
|
||||
@ -1285,7 +1288,7 @@ static const struct dpu_intf_cfg qcm2290_intf[] = {
|
||||
* Writeback blocks config
|
||||
*************************************************************/
|
||||
#define WB_BLK(_name, _id, _base, _features, _clk_ctrl, \
|
||||
__xin_id, vbif_id, _reg, _wb_done_bit) \
|
||||
__xin_id, vbif_id, _reg, _max_linewidth, _wb_done_bit) \
|
||||
{ \
|
||||
.name = _name, .id = _id, \
|
||||
.base = _base, .len = 0x2c8, \
|
||||
@ -1295,13 +1298,13 @@ static const struct dpu_intf_cfg qcm2290_intf[] = {
|
||||
.clk_ctrl = _clk_ctrl, \
|
||||
.xin_id = __xin_id, \
|
||||
.vbif_idx = vbif_id, \
|
||||
.maxlinewidth = DEFAULT_DPU_LINE_WIDTH, \
|
||||
.maxlinewidth = _max_linewidth, \
|
||||
.intr_wb_done = DPU_IRQ_IDX(_reg, _wb_done_bit) \
|
||||
}
|
||||
|
||||
static const struct dpu_wb_cfg sm8250_wb[] = {
|
||||
WB_BLK("wb_2", WB_2, 0x65000, WB_SM8250_MASK, DPU_CLK_CTRL_WB2, 6,
|
||||
VBIF_RT, MDP_SSPP_TOP0_INTR, 4),
|
||||
VBIF_RT, MDP_SSPP_TOP0_INTR, 4096, 4),
|
||||
};
|
||||
|
||||
/*************************************************************
|
||||
@ -1336,6 +1339,7 @@ static const struct dpu_vbif_cfg msm8998_vbif[] = {
|
||||
.default_ot_wr_limit = 32,
|
||||
.features = BIT(DPU_VBIF_QOS_REMAP) | BIT(DPU_VBIF_QOS_OTLIM),
|
||||
.xin_halt_timeout = 0x4000,
|
||||
.qos_rp_remap_size = 0x20,
|
||||
.dynamic_ot_rd_tbl = {
|
||||
.count = ARRAY_SIZE(msm8998_ot_rdwr_cfg),
|
||||
.cfg = msm8998_ot_rdwr_cfg,
|
||||
@ -1363,6 +1367,7 @@ static const struct dpu_vbif_cfg sdm845_vbif[] = {
|
||||
.base = 0, .len = 0x1040,
|
||||
.features = BIT(DPU_VBIF_QOS_REMAP),
|
||||
.xin_halt_timeout = 0x4000,
|
||||
.qos_rp_remap_size = 0x40,
|
||||
.qos_rt_tbl = {
|
||||
.npriority_lvl = ARRAY_SIZE(sdm845_rt_pri_lvl),
|
||||
.priority_lvl = sdm845_rt_pri_lvl,
|
||||
@ -1717,275 +1722,221 @@ static const struct dpu_perf_cfg qcm2290_perf_data = {
|
||||
.bw_inefficiency_factor = 120,
|
||||
};
|
||||
/*************************************************************
|
||||
* Hardware catalog init
|
||||
* Hardware catalog
|
||||
*************************************************************/
|
||||
|
||||
/*
|
||||
* msm8998_cfg_init(): populate sdm845 dpu sub-blocks reg offsets
|
||||
* and instance counts.
|
||||
*/
|
||||
static void msm8998_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &msm8998_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(msm8998_mdp),
|
||||
.mdp = msm8998_mdp,
|
||||
.ctl_count = ARRAY_SIZE(msm8998_ctl),
|
||||
.ctl = msm8998_ctl,
|
||||
.sspp_count = ARRAY_SIZE(msm8998_sspp),
|
||||
.sspp = msm8998_sspp,
|
||||
.mixer_count = ARRAY_SIZE(msm8998_lm),
|
||||
.mixer = msm8998_lm,
|
||||
.dspp_count = ARRAY_SIZE(msm8998_dspp),
|
||||
.dspp = msm8998_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sdm845_pp),
|
||||
.pingpong = sdm845_pp,
|
||||
.intf_count = ARRAY_SIZE(msm8998_intf),
|
||||
.intf = msm8998_intf,
|
||||
.vbif_count = ARRAY_SIZE(msm8998_vbif),
|
||||
.vbif = msm8998_vbif,
|
||||
.reg_dma_count = 0,
|
||||
.perf = msm8998_perf_data,
|
||||
.mdss_irqs = IRQ_SM8250_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* sdm845_cfg_init(): populate sdm845 dpu sub-blocks reg offsets
|
||||
* and instance counts.
|
||||
*/
|
||||
static void sdm845_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &sdm845_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sdm845_mdp),
|
||||
.mdp = sdm845_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sdm845_ctl),
|
||||
.ctl = sdm845_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sdm845_sspp),
|
||||
.sspp = sdm845_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sdm845_lm),
|
||||
.mixer = sdm845_lm,
|
||||
.pingpong_count = ARRAY_SIZE(sdm845_pp),
|
||||
.pingpong = sdm845_pp,
|
||||
.dsc_count = ARRAY_SIZE(sdm845_dsc),
|
||||
.dsc = sdm845_dsc,
|
||||
.intf_count = ARRAY_SIZE(sdm845_intf),
|
||||
.intf = sdm845_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = sdm845_regdma,
|
||||
.perf = sdm845_perf_data,
|
||||
.mdss_irqs = IRQ_SDM845_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* sc7180_cfg_init(): populate sc7180 dpu sub-blocks reg offsets
|
||||
* and instance counts.
|
||||
*/
|
||||
static void sc7180_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &sc7180_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sc7180_mdp),
|
||||
.mdp = sc7180_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sc7180_ctl),
|
||||
.ctl = sc7180_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sc7180_sspp),
|
||||
.sspp = sc7180_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sc7180_lm),
|
||||
.mixer = sc7180_lm,
|
||||
.dspp_count = ARRAY_SIZE(sc7180_dspp),
|
||||
.dspp = sc7180_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sc7180_pp),
|
||||
.pingpong = sc7180_pp,
|
||||
.intf_count = ARRAY_SIZE(sc7180_intf),
|
||||
.intf = sc7180_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = sdm845_regdma,
|
||||
.perf = sc7180_perf_data,
|
||||
.mdss_irqs = IRQ_SC7180_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* sm8150_cfg_init(): populate sm8150 dpu sub-blocks reg offsets
|
||||
* and instance counts.
|
||||
*/
|
||||
static void sm8150_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &sm8150_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sdm845_mdp),
|
||||
.mdp = sdm845_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sm8150_ctl),
|
||||
.ctl = sm8150_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sdm845_sspp),
|
||||
.sspp = sdm845_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sm8150_lm),
|
||||
.mixer = sm8150_lm,
|
||||
.dspp_count = ARRAY_SIZE(sm8150_dspp),
|
||||
.dspp = sm8150_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sm8150_pp),
|
||||
.pingpong = sm8150_pp,
|
||||
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
|
||||
.merge_3d = sm8150_merge_3d,
|
||||
.intf_count = ARRAY_SIZE(sm8150_intf),
|
||||
.intf = sm8150_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = sm8150_regdma,
|
||||
.perf = sm8150_perf_data,
|
||||
.mdss_irqs = IRQ_SDM845_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* sc8180x_cfg_init(): populate sc8180 dpu sub-blocks reg offsets
|
||||
* and instance counts.
|
||||
*/
|
||||
static void sc8180x_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &sc8180x_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sc8180x_mdp),
|
||||
.mdp = sc8180x_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sm8150_ctl),
|
||||
.ctl = sm8150_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sdm845_sspp),
|
||||
.sspp = sdm845_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sm8150_lm),
|
||||
.mixer = sm8150_lm,
|
||||
.pingpong_count = ARRAY_SIZE(sm8150_pp),
|
||||
.pingpong = sm8150_pp,
|
||||
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
|
||||
.merge_3d = sm8150_merge_3d,
|
||||
.intf_count = ARRAY_SIZE(sc8180x_intf),
|
||||
.intf = sc8180x_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = sm8150_regdma,
|
||||
.perf = sc8180x_perf_data,
|
||||
.mdss_irqs = IRQ_SC8180X_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* sm8250_cfg_init(): populate sm8250 dpu sub-blocks reg offsets
|
||||
* and instance counts.
|
||||
*/
|
||||
static void sm8250_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &sm8250_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sm8250_mdp),
|
||||
.mdp = sm8250_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sm8150_ctl),
|
||||
.ctl = sm8150_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sm8250_sspp),
|
||||
.sspp = sm8250_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sm8150_lm),
|
||||
.mixer = sm8150_lm,
|
||||
.dspp_count = ARRAY_SIZE(sm8150_dspp),
|
||||
.dspp = sm8150_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sm8150_pp),
|
||||
.pingpong = sm8150_pp,
|
||||
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
|
||||
.merge_3d = sm8150_merge_3d,
|
||||
.intf_count = ARRAY_SIZE(sm8150_intf),
|
||||
.intf = sm8150_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.wb_count = ARRAY_SIZE(sm8250_wb),
|
||||
.wb = sm8250_wb,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = sm8250_regdma,
|
||||
.perf = sm8250_perf_data,
|
||||
.mdss_irqs = IRQ_SM8250_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
static void sc7280_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &sc7280_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sc7280_mdp),
|
||||
.mdp = sc7280_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sc7280_ctl),
|
||||
.ctl = sc7280_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sc7280_sspp),
|
||||
.sspp = sc7280_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sc7280_lm),
|
||||
.mixer = sc7280_lm,
|
||||
.pingpong_count = ARRAY_SIZE(sc7280_pp),
|
||||
.pingpong = sc7280_pp,
|
||||
.intf_count = ARRAY_SIZE(sc7280_intf),
|
||||
.intf = sc7280_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.perf = sc7280_perf_data,
|
||||
.mdss_irqs = IRQ_SC7280_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* qcm2290_cfg_init(): populate qcm2290 dpu sub-blocks reg offsets
|
||||
* and instance counts.
|
||||
*/
|
||||
static void qcm2290_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
*dpu_cfg = (struct dpu_mdss_cfg){
|
||||
.caps = &qcm2290_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(qcm2290_mdp),
|
||||
.mdp = qcm2290_mdp,
|
||||
.ctl_count = ARRAY_SIZE(qcm2290_ctl),
|
||||
.ctl = qcm2290_ctl,
|
||||
.sspp_count = ARRAY_SIZE(qcm2290_sspp),
|
||||
.sspp = qcm2290_sspp,
|
||||
.mixer_count = ARRAY_SIZE(qcm2290_lm),
|
||||
.mixer = qcm2290_lm,
|
||||
.dspp_count = ARRAY_SIZE(qcm2290_dspp),
|
||||
.dspp = qcm2290_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(qcm2290_pp),
|
||||
.pingpong = qcm2290_pp,
|
||||
.intf_count = ARRAY_SIZE(qcm2290_intf),
|
||||
.intf = qcm2290_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = sdm845_regdma,
|
||||
.perf = qcm2290_perf_data,
|
||||
.mdss_irqs = IRQ_SC7180_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
static const struct dpu_mdss_hw_cfg_handler cfg_handler[] = {
|
||||
{ .hw_rev = DPU_HW_VER_300, .cfg_init = msm8998_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_301, .cfg_init = msm8998_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_400, .cfg_init = sdm845_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_401, .cfg_init = sdm845_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_500, .cfg_init = sm8150_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_501, .cfg_init = sm8150_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_510, .cfg_init = sc8180x_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_600, .cfg_init = sm8250_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_620, .cfg_init = sc7180_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_650, .cfg_init = qcm2290_cfg_init},
|
||||
{ .hw_rev = DPU_HW_VER_720, .cfg_init = sc7280_cfg_init},
|
||||
static const struct dpu_mdss_cfg msm8998_dpu_cfg = {
|
||||
.caps = &msm8998_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(msm8998_mdp),
|
||||
.mdp = msm8998_mdp,
|
||||
.ctl_count = ARRAY_SIZE(msm8998_ctl),
|
||||
.ctl = msm8998_ctl,
|
||||
.sspp_count = ARRAY_SIZE(msm8998_sspp),
|
||||
.sspp = msm8998_sspp,
|
||||
.mixer_count = ARRAY_SIZE(msm8998_lm),
|
||||
.mixer = msm8998_lm,
|
||||
.dspp_count = ARRAY_SIZE(msm8998_dspp),
|
||||
.dspp = msm8998_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sdm845_pp),
|
||||
.pingpong = sdm845_pp,
|
||||
.intf_count = ARRAY_SIZE(msm8998_intf),
|
||||
.intf = msm8998_intf,
|
||||
.vbif_count = ARRAY_SIZE(msm8998_vbif),
|
||||
.vbif = msm8998_vbif,
|
||||
.reg_dma_count = 0,
|
||||
.perf = &msm8998_perf_data,
|
||||
.mdss_irqs = IRQ_SM8250_MASK,
|
||||
};
|
||||
|
||||
void dpu_hw_catalog_deinit(struct dpu_mdss_cfg *dpu_cfg)
|
||||
{
|
||||
kfree(dpu_cfg);
|
||||
}
|
||||
static const struct dpu_mdss_cfg sdm845_dpu_cfg = {
|
||||
.caps = &sdm845_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sdm845_mdp),
|
||||
.mdp = sdm845_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sdm845_ctl),
|
||||
.ctl = sdm845_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sdm845_sspp),
|
||||
.sspp = sdm845_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sdm845_lm),
|
||||
.mixer = sdm845_lm,
|
||||
.pingpong_count = ARRAY_SIZE(sdm845_pp),
|
||||
.pingpong = sdm845_pp,
|
||||
.dsc_count = ARRAY_SIZE(sdm845_dsc),
|
||||
.dsc = sdm845_dsc,
|
||||
.intf_count = ARRAY_SIZE(sdm845_intf),
|
||||
.intf = sdm845_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = &sdm845_regdma,
|
||||
.perf = &sdm845_perf_data,
|
||||
.mdss_irqs = IRQ_SDM845_MASK,
|
||||
};
|
||||
|
||||
struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev)
|
||||
static const struct dpu_mdss_cfg sc7180_dpu_cfg = {
|
||||
.caps = &sc7180_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sc7180_mdp),
|
||||
.mdp = sc7180_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sc7180_ctl),
|
||||
.ctl = sc7180_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sc7180_sspp),
|
||||
.sspp = sc7180_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sc7180_lm),
|
||||
.mixer = sc7180_lm,
|
||||
.dspp_count = ARRAY_SIZE(sc7180_dspp),
|
||||
.dspp = sc7180_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sc7180_pp),
|
||||
.pingpong = sc7180_pp,
|
||||
.intf_count = ARRAY_SIZE(sc7180_intf),
|
||||
.intf = sc7180_intf,
|
||||
.wb_count = ARRAY_SIZE(sm8250_wb),
|
||||
.wb = sm8250_wb,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = &sdm845_regdma,
|
||||
.perf = &sc7180_perf_data,
|
||||
.mdss_irqs = IRQ_SC7180_MASK,
|
||||
};
|
||||
|
||||
static const struct dpu_mdss_cfg sm8150_dpu_cfg = {
|
||||
.caps = &sm8150_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sdm845_mdp),
|
||||
.mdp = sdm845_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sm8150_ctl),
|
||||
.ctl = sm8150_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sdm845_sspp),
|
||||
.sspp = sdm845_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sm8150_lm),
|
||||
.mixer = sm8150_lm,
|
||||
.dspp_count = ARRAY_SIZE(sm8150_dspp),
|
||||
.dspp = sm8150_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sm8150_pp),
|
||||
.pingpong = sm8150_pp,
|
||||
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
|
||||
.merge_3d = sm8150_merge_3d,
|
||||
.intf_count = ARRAY_SIZE(sm8150_intf),
|
||||
.intf = sm8150_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = &sm8150_regdma,
|
||||
.perf = &sm8150_perf_data,
|
||||
.mdss_irqs = IRQ_SDM845_MASK,
|
||||
};
|
||||
|
||||
static const struct dpu_mdss_cfg sc8180x_dpu_cfg = {
|
||||
.caps = &sc8180x_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sc8180x_mdp),
|
||||
.mdp = sc8180x_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sm8150_ctl),
|
||||
.ctl = sm8150_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sdm845_sspp),
|
||||
.sspp = sdm845_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sm8150_lm),
|
||||
.mixer = sm8150_lm,
|
||||
.pingpong_count = ARRAY_SIZE(sm8150_pp),
|
||||
.pingpong = sm8150_pp,
|
||||
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
|
||||
.merge_3d = sm8150_merge_3d,
|
||||
.intf_count = ARRAY_SIZE(sc8180x_intf),
|
||||
.intf = sc8180x_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = &sm8150_regdma,
|
||||
.perf = &sc8180x_perf_data,
|
||||
.mdss_irqs = IRQ_SC8180X_MASK,
|
||||
};
|
||||
|
||||
static const struct dpu_mdss_cfg sm8250_dpu_cfg = {
|
||||
.caps = &sm8250_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sm8250_mdp),
|
||||
.mdp = sm8250_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sm8150_ctl),
|
||||
.ctl = sm8150_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sm8250_sspp),
|
||||
.sspp = sm8250_sspp,
|
||||
.mixer_count = ARRAY_SIZE(sm8150_lm),
|
||||
.mixer = sm8150_lm,
|
||||
.dspp_count = ARRAY_SIZE(sm8150_dspp),
|
||||
.dspp = sm8150_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(sm8150_pp),
|
||||
.pingpong = sm8150_pp,
|
||||
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
|
||||
.merge_3d = sm8150_merge_3d,
|
||||
.intf_count = ARRAY_SIZE(sm8150_intf),
|
||||
.intf = sm8150_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.wb_count = ARRAY_SIZE(sm8250_wb),
|
||||
.wb = sm8250_wb,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = &sm8250_regdma,
|
||||
.perf = &sm8250_perf_data,
|
||||
.mdss_irqs = IRQ_SM8250_MASK,
|
||||
};
|
||||
|
||||
static const struct dpu_mdss_cfg sc7280_dpu_cfg = {
|
||||
.caps = &sc7280_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(sc7280_mdp),
|
||||
.mdp = sc7280_mdp,
|
||||
.ctl_count = ARRAY_SIZE(sc7280_ctl),
|
||||
.ctl = sc7280_ctl,
|
||||
.sspp_count = ARRAY_SIZE(sc7280_sspp),
|
||||
.sspp = sc7280_sspp,
|
||||
.dspp_count = ARRAY_SIZE(sc7180_dspp),
|
||||
.dspp = sc7180_dspp,
|
||||
.mixer_count = ARRAY_SIZE(sc7280_lm),
|
||||
.mixer = sc7280_lm,
|
||||
.pingpong_count = ARRAY_SIZE(sc7280_pp),
|
||||
.pingpong = sc7280_pp,
|
||||
.intf_count = ARRAY_SIZE(sc7280_intf),
|
||||
.intf = sc7280_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.perf = &sc7280_perf_data,
|
||||
.mdss_irqs = IRQ_SC7280_MASK,
|
||||
};
|
||||
|
||||
static const struct dpu_mdss_cfg qcm2290_dpu_cfg = {
|
||||
.caps = &qcm2290_dpu_caps,
|
||||
.mdp_count = ARRAY_SIZE(qcm2290_mdp),
|
||||
.mdp = qcm2290_mdp,
|
||||
.ctl_count = ARRAY_SIZE(qcm2290_ctl),
|
||||
.ctl = qcm2290_ctl,
|
||||
.sspp_count = ARRAY_SIZE(qcm2290_sspp),
|
||||
.sspp = qcm2290_sspp,
|
||||
.mixer_count = ARRAY_SIZE(qcm2290_lm),
|
||||
.mixer = qcm2290_lm,
|
||||
.dspp_count = ARRAY_SIZE(qcm2290_dspp),
|
||||
.dspp = qcm2290_dspp,
|
||||
.pingpong_count = ARRAY_SIZE(qcm2290_pp),
|
||||
.pingpong = qcm2290_pp,
|
||||
.intf_count = ARRAY_SIZE(qcm2290_intf),
|
||||
.intf = qcm2290_intf,
|
||||
.vbif_count = ARRAY_SIZE(sdm845_vbif),
|
||||
.vbif = sdm845_vbif,
|
||||
.reg_dma_count = 1,
|
||||
.dma_cfg = &sdm845_regdma,
|
||||
.perf = &qcm2290_perf_data,
|
||||
.mdss_irqs = IRQ_SC7180_MASK,
|
||||
};
|
||||
|
||||
static const struct dpu_mdss_hw_cfg_handler cfg_handler[] = {
|
||||
{ .hw_rev = DPU_HW_VER_300, .dpu_cfg = &msm8998_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_301, .dpu_cfg = &msm8998_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_400, .dpu_cfg = &sdm845_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_401, .dpu_cfg = &sdm845_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_500, .dpu_cfg = &sm8150_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_501, .dpu_cfg = &sm8150_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_510, .dpu_cfg = &sc8180x_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_600, .dpu_cfg = &sm8250_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_620, .dpu_cfg = &sc7180_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_650, .dpu_cfg = &qcm2290_dpu_cfg},
|
||||
{ .hw_rev = DPU_HW_VER_720, .dpu_cfg = &sc7280_dpu_cfg},
|
||||
};
|
||||
|
||||
const struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev)
|
||||
{
|
||||
int i;
|
||||
struct dpu_mdss_cfg *dpu_cfg;
|
||||
@ -1995,15 +1946,12 @@ struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cfg_handler); i++) {
|
||||
if (cfg_handler[i].hw_rev == hw_rev) {
|
||||
cfg_handler[i].cfg_init(dpu_cfg);
|
||||
dpu_cfg->hwversion = hw_rev;
|
||||
return dpu_cfg;
|
||||
}
|
||||
if (cfg_handler[i].hw_rev == hw_rev)
|
||||
return cfg_handler[i].dpu_cfg;
|
||||
}
|
||||
|
||||
DPU_ERROR("unsupported chipset id:%X\n", hw_rev);
|
||||
dpu_hw_catalog_deinit(dpu_cfg);
|
||||
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,7 @@ enum {
|
||||
* @DPU_MIXER_SOURCESPLIT Layer mixer supports source-split configuration
|
||||
* @DPU_MIXER_GC Gamma correction block
|
||||
* @DPU_DIM_LAYER Layer mixer supports dim layer
|
||||
* @DPU_MIXER_COMBINED_ALPHA Layer mixer has combined alpha register
|
||||
* @DPU_MIXER_MAX maximum value
|
||||
*/
|
||||
enum {
|
||||
@ -152,6 +153,7 @@ enum {
|
||||
DPU_MIXER_SOURCESPLIT,
|
||||
DPU_MIXER_GC,
|
||||
DPU_DIM_LAYER,
|
||||
DPU_MIXER_COMBINED_ALPHA,
|
||||
DPU_MIXER_MAX
|
||||
};
|
||||
|
||||
@ -707,6 +709,7 @@ struct dpu_vbif_qos_tbl {
|
||||
* @ot_rd_limit default OT read limit
|
||||
* @ot_wr_limit default OT write limit
|
||||
* @xin_halt_timeout maximum time (in usec) for xin to halt
|
||||
* @qos_rp_remap_size size of VBIF_XINL_QOS_RP_REMAP register space
|
||||
* @dynamic_ot_rd_tbl dynamic OT read configuration table
|
||||
* @dynamic_ot_wr_tbl dynamic OT write configuration table
|
||||
* @qos_rt_tbl real-time QoS priority table
|
||||
@ -719,6 +722,7 @@ struct dpu_vbif_cfg {
|
||||
u32 default_ot_rd_limit;
|
||||
u32 default_ot_wr_limit;
|
||||
u32 xin_halt_timeout;
|
||||
u32 qos_rp_remap_size;
|
||||
struct dpu_vbif_dynamic_ot_tbl dynamic_ot_rd_tbl;
|
||||
struct dpu_vbif_dynamic_ot_tbl dynamic_ot_wr_tbl;
|
||||
struct dpu_vbif_qos_tbl qos_rt_tbl;
|
||||
@ -822,8 +826,6 @@ struct dpu_perf_cfg {
|
||||
* @mdss_irqs: Bitmap with the irqs supported by the target
|
||||
*/
|
||||
struct dpu_mdss_cfg {
|
||||
u32 hwversion;
|
||||
|
||||
const struct dpu_caps *caps;
|
||||
|
||||
u32 mdp_count;
|
||||
@ -857,7 +859,7 @@ struct dpu_mdss_cfg {
|
||||
const struct dpu_wb_cfg *wb;
|
||||
|
||||
u32 reg_dma_count;
|
||||
struct dpu_reg_dma_cfg dma_cfg;
|
||||
const struct dpu_reg_dma_cfg *dma_cfg;
|
||||
|
||||
u32 ad_count;
|
||||
|
||||
@ -866,7 +868,7 @@ struct dpu_mdss_cfg {
|
||||
|
||||
/* Add additional block data structures here */
|
||||
|
||||
struct dpu_perf_cfg perf;
|
||||
const struct dpu_perf_cfg *perf;
|
||||
const struct dpu_format_extended *dma_formats;
|
||||
const struct dpu_format_extended *cursor_formats;
|
||||
const struct dpu_format_extended *vig_formats;
|
||||
@ -876,7 +878,7 @@ struct dpu_mdss_cfg {
|
||||
|
||||
struct dpu_mdss_hw_cfg_handler {
|
||||
u32 hw_rev;
|
||||
void (*cfg_init)(struct dpu_mdss_cfg *dpu_cfg);
|
||||
const struct dpu_mdss_cfg *dpu_cfg;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -886,12 +888,6 @@ struct dpu_mdss_hw_cfg_handler {
|
||||
*
|
||||
* Return: dpu config structure
|
||||
*/
|
||||
struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev);
|
||||
|
||||
/**
|
||||
* dpu_hw_catalog_deinit - dpu hardware catalog cleanup
|
||||
* @dpu_cfg: pointer returned from init function
|
||||
*/
|
||||
void dpu_hw_catalog_deinit(struct dpu_mdss_cfg *dpu_cfg);
|
||||
const struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev);
|
||||
|
||||
#endif /* _DPU_HW_CATALOG_H */
|
||||
|
@ -58,10 +58,7 @@ static const struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl,
|
||||
|
||||
for (i = 0; i < m->ctl_count; i++) {
|
||||
if (ctl == m->ctl[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->ctl[i].base;
|
||||
b->length = m->ctl[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->ctl[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_CTL;
|
||||
return &m->ctl[i];
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_catalog.h"
|
||||
#include "dpu_hw_sspp.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
/**
|
||||
* dpu_ctl_mode_sel: Interface mode selection
|
||||
|
@ -158,7 +158,7 @@ static void dpu_hw_dsc_config_thresh(struct dpu_hw_dsc *hw_dsc,
|
||||
}
|
||||
|
||||
static struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc,
|
||||
struct dpu_mdss_cfg *m,
|
||||
const struct dpu_mdss_cfg *m,
|
||||
void __iomem *addr,
|
||||
struct dpu_hw_blk_reg_map *b)
|
||||
{
|
||||
@ -166,10 +166,7 @@ static struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc,
|
||||
|
||||
for (i = 0; i < m->dsc_count; i++) {
|
||||
if (dsc == m->dsc[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->dsc[i].base;
|
||||
b->length = m->dsc[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->dsc[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_DSC;
|
||||
return &m->dsc[i];
|
||||
}
|
||||
@ -187,7 +184,7 @@ static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops,
|
||||
};
|
||||
|
||||
struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
|
||||
struct dpu_mdss_cfg *m)
|
||||
const struct dpu_mdss_cfg *m)
|
||||
{
|
||||
struct dpu_hw_dsc *c;
|
||||
struct dpu_dsc_cfg *cfg;
|
||||
|
@ -64,7 +64,7 @@ struct dpu_hw_dsc {
|
||||
* Returns: Error code or allocated dpu_hw_dsc context
|
||||
*/
|
||||
struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
|
||||
struct dpu_mdss_cfg *m);
|
||||
const struct dpu_mdss_cfg *m);
|
||||
|
||||
/**
|
||||
* dpu_hw_dsc_destroy - destroys dsc driver context
|
||||
|
@ -80,10 +80,7 @@ static const struct dpu_dspp_cfg *_dspp_offset(enum dpu_dspp dspp,
|
||||
|
||||
for (i = 0; i < m->dspp_count; i++) {
|
||||
if (dspp == m->dspp[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->dspp[i].base;
|
||||
b->length = m->dspp[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->dspp[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_DSPP;
|
||||
return &m->dspp[i];
|
||||
}
|
||||
|
@ -5,8 +5,6 @@
|
||||
#ifndef _DPU_HW_DSPP_H
|
||||
#define _DPU_HW_DSPP_H
|
||||
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
struct dpu_hw_dspp;
|
||||
|
||||
/**
|
||||
|
@ -398,16 +398,14 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx)
|
||||
return intr_status;
|
||||
}
|
||||
|
||||
static void __intr_offset(struct dpu_mdss_cfg *m,
|
||||
static void __intr_offset(const struct dpu_mdss_cfg *m,
|
||||
void __iomem *addr, struct dpu_hw_blk_reg_map *hw)
|
||||
{
|
||||
hw->base_off = addr;
|
||||
hw->blk_off = m->mdp[0].base;
|
||||
hw->hwversion = m->hwversion;
|
||||
hw->blk_addr = addr + m->mdp[0].base;
|
||||
}
|
||||
|
||||
struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr,
|
||||
struct dpu_mdss_cfg *m)
|
||||
const struct dpu_mdss_cfg *m)
|
||||
{
|
||||
struct dpu_hw_intr *intr;
|
||||
int nirq = MDP_INTR_MAX * 32;
|
||||
|
@ -67,7 +67,7 @@ struct dpu_hw_intr {
|
||||
* @m : pointer to mdss catalog data
|
||||
*/
|
||||
struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr,
|
||||
struct dpu_mdss_cfg *m);
|
||||
const struct dpu_mdss_cfg *m);
|
||||
|
||||
/**
|
||||
* dpu_hw_intr_destroy(): Cleanup interrutps hw object
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "dpu_hwio.h"
|
||||
@ -67,6 +69,9 @@
|
||||
#define INTF_CFG2_DATABUS_WIDEN BIT(0)
|
||||
#define INTF_CFG2_DATA_HCTL_EN BIT(4)
|
||||
|
||||
#define INTF_MISR_CTRL 0x180
|
||||
#define INTF_MISR_SIGNATURE 0x184
|
||||
|
||||
static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
|
||||
const struct dpu_mdss_cfg *m,
|
||||
void __iomem *addr,
|
||||
@ -77,10 +82,7 @@ static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
|
||||
for (i = 0; i < m->intf_count; i++) {
|
||||
if ((intf == m->intf[i].id) &&
|
||||
(m->intf[i].type != INTF_NONE)) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->intf[i].base;
|
||||
b->length = m->intf[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->intf[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_INTF;
|
||||
return &m->intf[i];
|
||||
}
|
||||
@ -319,6 +321,16 @@ static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf)
|
||||
return DPU_REG_READ(c, INTF_LINE_COUNT);
|
||||
}
|
||||
|
||||
static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf, bool enable, u32 frame_count)
|
||||
{
|
||||
dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, enable, frame_count);
|
||||
}
|
||||
|
||||
static int dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf, u32 *misr_value)
|
||||
{
|
||||
return dpu_hw_collect_misr(&intf->hw, INTF_MISR_CTRL, INTF_MISR_SIGNATURE, misr_value);
|
||||
}
|
||||
|
||||
static void _setup_intf_ops(struct dpu_hw_intf_ops *ops,
|
||||
unsigned long cap)
|
||||
{
|
||||
@ -329,6 +341,8 @@ static void _setup_intf_ops(struct dpu_hw_intf_ops *ops,
|
||||
ops->get_line_count = dpu_hw_intf_get_line_count;
|
||||
if (cap & BIT(DPU_INTF_INPUT_CTRL))
|
||||
ops->bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk;
|
||||
ops->setup_misr = dpu_hw_intf_setup_misr;
|
||||
ops->collect_misr = dpu_hw_intf_collect_misr;
|
||||
}
|
||||
|
||||
struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DPU_HW_INTF_H
|
||||
@ -8,7 +10,6 @@
|
||||
#include "dpu_hw_catalog.h"
|
||||
#include "dpu_hw_mdss.h"
|
||||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
struct dpu_hw_intf;
|
||||
|
||||
@ -57,6 +58,8 @@ struct intf_status {
|
||||
* @ get_line_count: reads current vertical line counter
|
||||
* @bind_pingpong_blk: enable/disable the connection with pingpong which will
|
||||
* feed pixels to this interface
|
||||
* @setup_misr: enable/disable MISR
|
||||
* @collect_misr: read MISR signature
|
||||
*/
|
||||
struct dpu_hw_intf_ops {
|
||||
void (*setup_timing_gen)(struct dpu_hw_intf *intf,
|
||||
@ -77,6 +80,8 @@ struct dpu_hw_intf_ops {
|
||||
void (*bind_pingpong_blk)(struct dpu_hw_intf *intf,
|
||||
bool enable,
|
||||
const enum dpu_pingpong pp);
|
||||
void (*setup_misr)(struct dpu_hw_intf *intf, bool enable, u32 frame_count);
|
||||
int (*collect_misr)(struct dpu_hw_intf *intf, u32 *misr_value);
|
||||
};
|
||||
|
||||
struct dpu_hw_intf {
|
||||
|
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -27,11 +28,6 @@
|
||||
|
||||
#define LM_MISR_CTRL 0x310
|
||||
#define LM_MISR_SIGNATURE 0x314
|
||||
#define LM_MISR_FRAME_COUNT_MASK 0xFF
|
||||
#define LM_MISR_CTRL_ENABLE BIT(8)
|
||||
#define LM_MISR_CTRL_STATUS BIT(9)
|
||||
#define LM_MISR_CTRL_STATUS_CLEAR BIT(10)
|
||||
#define LM_MISR_CTRL_FREE_RUN_MASK BIT(31)
|
||||
|
||||
|
||||
static const struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer,
|
||||
@ -43,10 +39,7 @@ static const struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer,
|
||||
|
||||
for (i = 0; i < m->mixer_count; i++) {
|
||||
if (mixer == m->mixer[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->mixer[i].base;
|
||||
b->length = m->mixer[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->mixer[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_LM;
|
||||
return &m->mixer[i];
|
||||
}
|
||||
@ -108,47 +101,15 @@ static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx,
|
||||
|
||||
static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count)
|
||||
{
|
||||
struct dpu_hw_blk_reg_map *c = &ctx->hw;
|
||||
u32 config = 0;
|
||||
|
||||
DPU_REG_WRITE(c, LM_MISR_CTRL, LM_MISR_CTRL_STATUS_CLEAR);
|
||||
|
||||
/* Clear old MISR value (in case it's read before a new value is calculated)*/
|
||||
wmb();
|
||||
|
||||
if (enable) {
|
||||
config = (frame_count & LM_MISR_FRAME_COUNT_MASK) |
|
||||
LM_MISR_CTRL_ENABLE | LM_MISR_CTRL_FREE_RUN_MASK;
|
||||
|
||||
DPU_REG_WRITE(c, LM_MISR_CTRL, config);
|
||||
} else {
|
||||
DPU_REG_WRITE(c, LM_MISR_CTRL, 0);
|
||||
}
|
||||
|
||||
dpu_hw_setup_misr(&ctx->hw, LM_MISR_CTRL, enable, frame_count);
|
||||
}
|
||||
|
||||
static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value)
|
||||
{
|
||||
struct dpu_hw_blk_reg_map *c = &ctx->hw;
|
||||
u32 ctrl = 0;
|
||||
|
||||
if (!misr_value)
|
||||
return -EINVAL;
|
||||
|
||||
ctrl = DPU_REG_READ(c, LM_MISR_CTRL);
|
||||
|
||||
if (!(ctrl & LM_MISR_CTRL_ENABLE))
|
||||
return -ENODATA;
|
||||
|
||||
if (!(ctrl & LM_MISR_CTRL_STATUS))
|
||||
return -EINVAL;
|
||||
|
||||
*misr_value = DPU_REG_READ(c, LM_MISR_SIGNATURE);
|
||||
|
||||
return 0;
|
||||
return dpu_hw_collect_misr(&ctx->hw, LM_MISR_CTRL, LM_MISR_SIGNATURE, misr_value);
|
||||
}
|
||||
|
||||
static void dpu_hw_lm_setup_blend_config_sdm845(struct dpu_hw_mixer *ctx,
|
||||
static void dpu_hw_lm_setup_blend_config_combined_alpha(struct dpu_hw_mixer *ctx,
|
||||
u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
|
||||
{
|
||||
struct dpu_hw_blk_reg_map *c = &ctx->hw;
|
||||
@ -204,8 +165,8 @@ static void _setup_mixer_ops(const struct dpu_mdss_cfg *m,
|
||||
unsigned long features)
|
||||
{
|
||||
ops->setup_mixer_out = dpu_hw_lm_setup_out;
|
||||
if (m->hwversion >= DPU_HW_VER_400)
|
||||
ops->setup_blend_config = dpu_hw_lm_setup_blend_config_sdm845;
|
||||
if (test_bit(DPU_MIXER_COMBINED_ALPHA, &features))
|
||||
ops->setup_blend_config = dpu_hw_lm_setup_blend_config_combined_alpha;
|
||||
else
|
||||
ops->setup_blend_config = dpu_hw_lm_setup_blend_config;
|
||||
ops->setup_alpha_out = dpu_hw_lm_setup_color3;
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "dpu_hw_mdss.h"
|
||||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
struct dpu_hw_mixer;
|
||||
|
||||
|
@ -23,10 +23,7 @@ static const struct dpu_merge_3d_cfg *_merge_3d_offset(enum dpu_merge_3d idx,
|
||||
|
||||
for (i = 0; i < m->merge_3d_count; i++) {
|
||||
if (idx == m->merge_3d[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->merge_3d[i].base;
|
||||
b->length = m->merge_3d[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->merge_3d[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_PINGPONG;
|
||||
return &m->merge_3d[i];
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "dpu_hw_catalog.h"
|
||||
#include "dpu_hw_mdss.h"
|
||||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
struct dpu_hw_merge_3d;
|
||||
|
||||
|
@ -51,10 +51,7 @@ static const struct dpu_pingpong_cfg *_pingpong_offset(enum dpu_pingpong pp,
|
||||
|
||||
for (i = 0; i < m->pingpong_count; i++) {
|
||||
if (pp == m->pingpong[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->pingpong[i].base;
|
||||
b->length = m->pingpong[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->pingpong[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_PINGPONG;
|
||||
return &m->pingpong[i];
|
||||
}
|
||||
@ -158,7 +155,7 @@ static int dpu_hw_pp_poll_timeout_wr_ptr(struct dpu_hw_pingpong *pp,
|
||||
return -EINVAL;
|
||||
|
||||
c = &pp->hw;
|
||||
rc = readl_poll_timeout(c->base_off + c->blk_off + PP_LINE_COUNT,
|
||||
rc = readl_poll_timeout(c->blk_addr + PP_LINE_COUNT,
|
||||
val, (val & 0xffff) >= 1, 10, timeout_us);
|
||||
|
||||
return rc;
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "dpu_hw_catalog.h"
|
||||
#include "dpu_hw_mdss.h"
|
||||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
#define DITHER_MATRIX_SZ 16
|
||||
|
||||
|
@ -761,7 +761,7 @@ int _dpu_hw_sspp_init_debugfs(struct dpu_hw_pipe *hw_pipe, struct dpu_kms *kms,
|
||||
|
||||
static const struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp,
|
||||
void __iomem *addr,
|
||||
struct dpu_mdss_cfg *catalog,
|
||||
const struct dpu_mdss_cfg *catalog,
|
||||
struct dpu_hw_blk_reg_map *b)
|
||||
{
|
||||
int i;
|
||||
@ -769,10 +769,7 @@ static const struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp,
|
||||
if ((sspp < SSPP_MAX) && catalog && addr && b) {
|
||||
for (i = 0; i < catalog->sspp_count; i++) {
|
||||
if (sspp == catalog->sspp[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = catalog->sspp[i].base;
|
||||
b->length = catalog->sspp[i].len;
|
||||
b->hwversion = catalog->hwversion;
|
||||
b->blk_addr = addr + catalog->sspp[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_SSPP;
|
||||
return &catalog->sspp[i];
|
||||
}
|
||||
@ -783,7 +780,7 @@ static const struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp,
|
||||
}
|
||||
|
||||
struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx,
|
||||
void __iomem *addr, struct dpu_mdss_cfg *catalog,
|
||||
void __iomem *addr, const struct dpu_mdss_cfg *catalog,
|
||||
bool is_virtual_pipe)
|
||||
{
|
||||
struct dpu_hw_pipe *hw_pipe;
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "dpu_hw_catalog.h"
|
||||
#include "dpu_hw_mdss.h"
|
||||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
#include "dpu_formats.h"
|
||||
|
||||
struct dpu_hw_pipe;
|
||||
@ -360,7 +359,7 @@ struct dpu_hw_sspp_ops {
|
||||
struct dpu_hw_pipe {
|
||||
struct dpu_hw_blk base;
|
||||
struct dpu_hw_blk_reg_map hw;
|
||||
struct dpu_mdss_cfg *catalog;
|
||||
const struct dpu_mdss_cfg *catalog;
|
||||
const struct dpu_mdp_cfg *mdp;
|
||||
|
||||
/* Pipe */
|
||||
@ -381,7 +380,7 @@ struct dpu_kms;
|
||||
* @is_virtual_pipe: is this pipe virtual pipe
|
||||
*/
|
||||
struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx,
|
||||
void __iomem *addr, struct dpu_mdss_cfg *catalog,
|
||||
void __iomem *addr, const struct dpu_mdss_cfg *catalog,
|
||||
bool is_virtual_pipe);
|
||||
|
||||
/**
|
||||
|
@ -285,10 +285,7 @@ static const struct dpu_mdp_cfg *_top_offset(enum dpu_mdp mdp,
|
||||
|
||||
for (i = 0; i < m->mdp_count; i++) {
|
||||
if (mdp == m->mdp[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->mdp[i].base;
|
||||
b->length = m->mdp[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->mdp[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_TOP;
|
||||
return &m->mdp[i];
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "dpu_hw_catalog.h"
|
||||
#include "dpu_hw_mdss.h"
|
||||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_blk.h"
|
||||
|
||||
struct dpu_hw_mdp;
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
@ -80,13 +82,13 @@ void dpu_reg_write(struct dpu_hw_blk_reg_map *c,
|
||||
/* don't need to mutex protect this */
|
||||
if (c->log_mask & dpu_hw_util_log_mask)
|
||||
DPU_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n",
|
||||
name, c->blk_off + reg_off, val);
|
||||
writel_relaxed(val, c->base_off + c->blk_off + reg_off);
|
||||
name, reg_off, val);
|
||||
writel_relaxed(val, c->blk_addr + reg_off);
|
||||
}
|
||||
|
||||
int dpu_reg_read(struct dpu_hw_blk_reg_map *c, u32 reg_off)
|
||||
{
|
||||
return readl_relaxed(c->base_off + c->blk_off + reg_off);
|
||||
return readl_relaxed(c->blk_addr + reg_off);
|
||||
}
|
||||
|
||||
u32 *dpu_hw_util_get_log_mask_ptr(void)
|
||||
@ -447,3 +449,48 @@ u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c,
|
||||
u32 misr_ctrl_offset,
|
||||
bool enable, u32 frame_count)
|
||||
{
|
||||
u32 config = 0;
|
||||
|
||||
DPU_REG_WRITE(c, misr_ctrl_offset, MISR_CTRL_STATUS_CLEAR);
|
||||
|
||||
/* Clear old MISR value (in case it's read before a new value is calculated)*/
|
||||
wmb();
|
||||
|
||||
if (enable) {
|
||||
config = (frame_count & MISR_FRAME_COUNT_MASK) |
|
||||
MISR_CTRL_ENABLE | MISR_CTRL_FREE_RUN_MASK;
|
||||
|
||||
DPU_REG_WRITE(c, misr_ctrl_offset, config);
|
||||
} else {
|
||||
DPU_REG_WRITE(c, misr_ctrl_offset, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c,
|
||||
u32 misr_ctrl_offset,
|
||||
u32 misr_signature_offset,
|
||||
u32 *misr_value)
|
||||
{
|
||||
u32 ctrl = 0;
|
||||
|
||||
if (!misr_value)
|
||||
return -EINVAL;
|
||||
|
||||
ctrl = DPU_REG_READ(c, misr_ctrl_offset);
|
||||
|
||||
if (!(ctrl & MISR_CTRL_ENABLE))
|
||||
return -ENODATA;
|
||||
|
||||
if (!(ctrl & MISR_CTRL_STATUS))
|
||||
return -EINVAL;
|
||||
|
||||
*misr_value = DPU_REG_READ(c, misr_signature_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -12,26 +13,31 @@
|
||||
#include "dpu_hw_catalog.h"
|
||||
|
||||
#define REG_MASK(n) ((BIT(n)) - 1)
|
||||
#define MISR_FRAME_COUNT_MASK 0xFF
|
||||
#define MISR_CTRL_ENABLE BIT(8)
|
||||
#define MISR_CTRL_STATUS BIT(9)
|
||||
#define MISR_CTRL_STATUS_CLEAR BIT(10)
|
||||
#define MISR_CTRL_FREE_RUN_MASK BIT(31)
|
||||
|
||||
/*
|
||||
* This is the common struct maintained by each sub block
|
||||
* for mapping the register offsets in this block to the
|
||||
* absoulute IO address
|
||||
* @base_off: mdp register mapped offset
|
||||
* @blk_off: pipe offset relative to mdss offset
|
||||
* @length length of register block offset
|
||||
* @xin_id xin id
|
||||
* @hwversion mdss hw version number
|
||||
* @blk_addr: hw block register mapped address
|
||||
* @log_mask: log mask for this block
|
||||
*/
|
||||
struct dpu_hw_blk_reg_map {
|
||||
void __iomem *base_off;
|
||||
u32 blk_off;
|
||||
u32 length;
|
||||
u32 xin_id;
|
||||
u32 hwversion;
|
||||
void __iomem *blk_addr;
|
||||
u32 log_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_hw_blk - opaque hardware block object
|
||||
*/
|
||||
struct dpu_hw_blk {
|
||||
/* opaque */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_hw_scaler3_de_cfg : QSEEDv3 detail enhancer configuration
|
||||
* @enable: detail enhancer enable/disable
|
||||
@ -343,4 +349,14 @@ void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c,
|
||||
u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
|
||||
u32 total_fl);
|
||||
|
||||
void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c,
|
||||
u32 misr_ctrl_offset,
|
||||
bool enable,
|
||||
u32 frame_count);
|
||||
|
||||
int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c,
|
||||
u32 misr_ctrl_offset,
|
||||
u32 misr_signature_offset,
|
||||
u32 *misr_value);
|
||||
|
||||
#endif /* _DPU_HW_UTIL_H */
|
||||
|
@ -30,7 +30,7 @@
|
||||
#define VBIF_XIN_HALT_CTRL0 0x0200
|
||||
#define VBIF_XIN_HALT_CTRL1 0x0204
|
||||
#define VBIF_XINL_QOS_RP_REMAP_000 0x0550
|
||||
#define VBIF_XINL_QOS_LVL_REMAP_000(v) (v < DPU_HW_VER_400 ? 0x570 : 0x0590)
|
||||
#define VBIF_XINL_QOS_LVL_REMAP_000(vbif) (VBIF_XINL_QOS_RP_REMAP_000 + (vbif)->cap->qos_rp_remap_size)
|
||||
|
||||
static void dpu_hw_clear_errors(struct dpu_hw_vbif *vbif,
|
||||
u32 *pnd_errors, u32 *src_errors)
|
||||
@ -163,7 +163,7 @@ static void dpu_hw_set_qos_remap(struct dpu_hw_vbif *vbif,
|
||||
|
||||
c = &vbif->hw;
|
||||
|
||||
reg_lvl = VBIF_XINL_QOS_LVL_REMAP_000(c->hwversion);
|
||||
reg_lvl = VBIF_XINL_QOS_LVL_REMAP_000(vbif);
|
||||
reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8);
|
||||
reg_shift = (xin_id & 0x7) * 4;
|
||||
|
||||
@ -220,10 +220,7 @@ static const struct dpu_vbif_cfg *_top_offset(enum dpu_vbif vbif,
|
||||
|
||||
for (i = 0; i < m->vbif_count; i++) {
|
||||
if (vbif == m->vbif[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->vbif[i].base;
|
||||
b->length = m->vbif[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->vbif[i].base;
|
||||
b->log_mask = DPU_DBG_MASK_VBIF;
|
||||
return &m->vbif[i];
|
||||
}
|
||||
|
@ -60,10 +60,7 @@ static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb,
|
||||
|
||||
for (i = 0; i < m->wb_count; i++) {
|
||||
if (wb == m->wb[i].id) {
|
||||
b->base_off = addr;
|
||||
b->blk_off = m->wb[i].base;
|
||||
b->length = m->wb[i].len;
|
||||
b->hwversion = m->hwversion;
|
||||
b->blk_addr = addr + m->wb[i].base;
|
||||
return &m->wb[i];
|
||||
}
|
||||
}
|
||||
|
@ -583,9 +583,7 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev,
|
||||
}
|
||||
|
||||
info.h_tile_instance[info.num_of_h_tiles++] = i;
|
||||
info.capabilities = msm_dsi_is_cmd_mode(priv->dsi[i]) ?
|
||||
MSM_DISPLAY_CAP_CMD_MODE :
|
||||
MSM_DISPLAY_CAP_VID_MODE;
|
||||
info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]);
|
||||
|
||||
info.dsc = msm_dsi_get_dsc_config(priv->dsi[i]);
|
||||
|
||||
@ -638,7 +636,6 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
|
||||
|
||||
info.num_of_h_tiles = 1;
|
||||
info.h_tile_instance[0] = i;
|
||||
info.capabilities = MSM_DISPLAY_CAP_VID_MODE;
|
||||
info.intf_type = encoder->encoder_type;
|
||||
rc = dpu_encoder_setup(dev, encoder, &info);
|
||||
if (rc) {
|
||||
@ -746,7 +743,7 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
|
||||
unsigned int num_encoders;
|
||||
|
||||
struct msm_drm_private *priv;
|
||||
struct dpu_mdss_cfg *catalog;
|
||||
const struct dpu_mdss_cfg *catalog;
|
||||
|
||||
int primary_planes_idx = 0, cursor_planes_idx = 0, i, ret;
|
||||
int max_crtc_count;
|
||||
@ -843,8 +840,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms)
|
||||
dpu_rm_destroy(&dpu_kms->rm);
|
||||
dpu_kms->rm_init = false;
|
||||
|
||||
if (dpu_kms->catalog)
|
||||
dpu_hw_catalog_deinit(dpu_kms->catalog);
|
||||
dpu_kms->catalog = NULL;
|
||||
|
||||
if (dpu_kms->vbif[VBIF_NRT])
|
||||
@ -906,7 +901,7 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
|
||||
{
|
||||
int i;
|
||||
struct dpu_kms *dpu_kms;
|
||||
struct dpu_mdss_cfg *cat;
|
||||
const struct dpu_mdss_cfg *cat;
|
||||
struct dpu_hw_mdp *top;
|
||||
|
||||
dpu_kms = to_dpu_kms(kms);
|
||||
@ -951,8 +946,8 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
|
||||
msm_disp_snapshot_add_block(disp_state, cat->wb[i].len,
|
||||
dpu_kms->mmio + cat->wb[i].base, "wb_%d", i);
|
||||
|
||||
msm_disp_snapshot_add_block(disp_state, top->hw.length,
|
||||
dpu_kms->mmio + top->hw.blk_off, "top");
|
||||
msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len,
|
||||
dpu_kms->mmio + cat->mdp[0].base, "top");
|
||||
|
||||
pm_runtime_put_sync(&dpu_kms->pdev->dev);
|
||||
}
|
||||
@ -998,32 +993,14 @@ static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms)
|
||||
|
||||
static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms)
|
||||
{
|
||||
struct iommu_domain *domain;
|
||||
struct msm_gem_address_space *aspace;
|
||||
struct msm_mmu *mmu;
|
||||
struct device *dpu_dev = dpu_kms->dev->dev;
|
||||
struct device *mdss_dev = dpu_dev->parent;
|
||||
|
||||
domain = iommu_domain_alloc(&platform_bus_type);
|
||||
if (!domain)
|
||||
return 0;
|
||||
|
||||
/* IOMMUs are a part of MDSS device tree binding, not the
|
||||
* MDP/DPU device. */
|
||||
mmu = msm_iommu_new(mdss_dev, domain);
|
||||
if (IS_ERR(mmu)) {
|
||||
iommu_domain_free(domain);
|
||||
return PTR_ERR(mmu);
|
||||
}
|
||||
aspace = msm_gem_address_space_create(mmu, "dpu1",
|
||||
0x1000, 0x100000000 - 0x1000);
|
||||
|
||||
if (IS_ERR(aspace)) {
|
||||
mmu->funcs->destroy(mmu);
|
||||
aspace = msm_kms_init_aspace(dpu_kms->dev);
|
||||
if (IS_ERR(aspace))
|
||||
return PTR_ERR(aspace);
|
||||
}
|
||||
|
||||
dpu_kms->base.aspace = aspace;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ struct dpu_kms {
|
||||
struct msm_kms base;
|
||||
struct drm_device *dev;
|
||||
int core_rev;
|
||||
struct dpu_mdss_cfg *catalog;
|
||||
const struct dpu_mdss_cfg *catalog;
|
||||
|
||||
/* io/register spaces: */
|
||||
void __iomem *mmio, *vbif[VBIF_MAX], *reg_dma;
|
||||
|
@ -108,7 +108,7 @@ struct dpu_plane {
|
||||
bool is_rt_pipe;
|
||||
bool is_virtual;
|
||||
struct list_head mplane_list;
|
||||
struct dpu_mdss_cfg *catalog;
|
||||
const struct dpu_mdss_cfg *catalog;
|
||||
};
|
||||
|
||||
static const uint64_t supported_format_modifiers[] = {
|
||||
@ -162,7 +162,7 @@ static void _dpu_plane_calc_bw(struct drm_plane *plane,
|
||||
vbp = mode->vtotal - mode->vsync_end;
|
||||
vpw = mode->vsync_end - mode->vsync_start;
|
||||
vfp = mode->vsync_start - mode->vdisplay;
|
||||
hw_latency_lines = dpu_kms->catalog->perf.min_prefill_lines;
|
||||
hw_latency_lines = dpu_kms->catalog->perf->min_prefill_lines;
|
||||
scale_factor = src_height > dst_height ?
|
||||
mult_frac(src_height, 1, dst_height) : 1;
|
||||
|
||||
@ -311,7 +311,7 @@ static void _dpu_plane_set_qos_lut(struct drm_plane *plane,
|
||||
}
|
||||
|
||||
qos_lut = _dpu_hw_get_qos_lut(
|
||||
&pdpu->catalog->perf.qos_lut_tbl[lut_usage], total_fl);
|
||||
&pdpu->catalog->perf->qos_lut_tbl[lut_usage], total_fl);
|
||||
|
||||
trace_dpu_perf_set_qos_luts(pdpu->pipe - SSPP_VIG0,
|
||||
(fmt) ? fmt->base.pixel_format : 0,
|
||||
@ -338,9 +338,9 @@ static void _dpu_plane_set_danger_lut(struct drm_plane *plane,
|
||||
u32 danger_lut, safe_lut;
|
||||
|
||||
if (!pdpu->is_rt_pipe) {
|
||||
danger_lut = pdpu->catalog->perf.danger_lut_tbl
|
||||
danger_lut = pdpu->catalog->perf->danger_lut_tbl
|
||||
[DPU_QOS_LUT_USAGE_NRT];
|
||||
safe_lut = pdpu->catalog->perf.safe_lut_tbl
|
||||
safe_lut = pdpu->catalog->perf->safe_lut_tbl
|
||||
[DPU_QOS_LUT_USAGE_NRT];
|
||||
} else {
|
||||
fmt = dpu_get_dpu_format_ext(
|
||||
@ -348,14 +348,14 @@ static void _dpu_plane_set_danger_lut(struct drm_plane *plane,
|
||||
fb->modifier);
|
||||
|
||||
if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) {
|
||||
danger_lut = pdpu->catalog->perf.danger_lut_tbl
|
||||
danger_lut = pdpu->catalog->perf->danger_lut_tbl
|
||||
[DPU_QOS_LUT_USAGE_LINEAR];
|
||||
safe_lut = pdpu->catalog->perf.safe_lut_tbl
|
||||
safe_lut = pdpu->catalog->perf->safe_lut_tbl
|
||||
[DPU_QOS_LUT_USAGE_LINEAR];
|
||||
} else {
|
||||
danger_lut = pdpu->catalog->perf.danger_lut_tbl
|
||||
danger_lut = pdpu->catalog->perf->danger_lut_tbl
|
||||
[DPU_QOS_LUT_USAGE_MACROTILE];
|
||||
safe_lut = pdpu->catalog->perf.safe_lut_tbl
|
||||
safe_lut = pdpu->catalog->perf->safe_lut_tbl
|
||||
[DPU_QOS_LUT_USAGE_MACROTILE];
|
||||
}
|
||||
}
|
||||
@ -1227,7 +1227,7 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
|
||||
|
||||
memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
|
||||
|
||||
cdp_cfg.enable = pdpu->catalog->perf.cdp_cfg
|
||||
cdp_cfg.enable = pdpu->catalog->perf->cdp_cfg
|
||||
[DPU_PERF_CDP_USAGE_RT].rd_enable;
|
||||
cdp_cfg.ubwc_meta_enable =
|
||||
DPU_FORMAT_IS_UBWC(fmt);
|
||||
|
@ -95,7 +95,7 @@ int dpu_rm_destroy(struct dpu_rm *rm)
|
||||
}
|
||||
|
||||
int dpu_rm_init(struct dpu_rm *rm,
|
||||
struct dpu_mdss_cfg *cat,
|
||||
const struct dpu_mdss_cfg *cat,
|
||||
void __iomem *mmio)
|
||||
{
|
||||
int rc, i;
|
||||
|
@ -42,7 +42,7 @@ struct dpu_rm {
|
||||
* @Return: 0 on Success otherwise -ERROR
|
||||
*/
|
||||
int dpu_rm_init(struct dpu_rm *rm,
|
||||
struct dpu_mdss_cfg *cat,
|
||||
const struct dpu_mdss_cfg *cat,
|
||||
void __iomem *mmio);
|
||||
|
||||
/**
|
||||
|
@ -13,8 +13,6 @@
|
||||
#include "msm_mmu.h"
|
||||
#include "mdp4_kms.h"
|
||||
|
||||
static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev);
|
||||
|
||||
static int mdp4_hw_init(struct msm_kms *kms)
|
||||
{
|
||||
struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
|
||||
@ -386,13 +384,17 @@ static void read_mdp_hw_revision(struct mdp4_kms *mdp4_kms,
|
||||
static int mdp4_kms_init(struct drm_device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev->dev);
|
||||
struct mdp4_platform_config *config = mdp4_get_config(pdev);
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct mdp4_kms *mdp4_kms;
|
||||
struct msm_kms *kms = NULL;
|
||||
struct iommu_domain *iommu;
|
||||
struct msm_gem_address_space *aspace;
|
||||
int irq, ret;
|
||||
u32 major, minor;
|
||||
unsigned long max_clk;
|
||||
|
||||
/* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
|
||||
max_clk = 266667000;
|
||||
|
||||
mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL);
|
||||
if (!mdp4_kms) {
|
||||
@ -460,7 +462,7 @@ static int mdp4_kms_init(struct drm_device *dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
clk_set_rate(mdp4_kms->clk, config->max_clk);
|
||||
clk_set_rate(mdp4_kms->clk, max_clk);
|
||||
|
||||
read_mdp_hw_revision(mdp4_kms, &major, &minor);
|
||||
|
||||
@ -480,7 +482,7 @@ static int mdp4_kms_init(struct drm_device *dev)
|
||||
ret = PTR_ERR(mdp4_kms->lut_clk);
|
||||
goto fail;
|
||||
}
|
||||
clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
|
||||
clk_set_rate(mdp4_kms->lut_clk, max_clk);
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev->dev);
|
||||
@ -497,9 +499,9 @@ static int mdp4_kms_init(struct drm_device *dev)
|
||||
mdp4_disable(mdp4_kms);
|
||||
mdelay(16);
|
||||
|
||||
if (config->iommu) {
|
||||
struct msm_mmu *mmu = msm_iommu_new(&pdev->dev,
|
||||
config->iommu);
|
||||
iommu = iommu_domain_alloc(pdev->dev.bus);
|
||||
if (iommu) {
|
||||
struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, iommu);
|
||||
|
||||
aspace = msm_gem_address_space_create(mmu,
|
||||
"mdp4", 0x1000, 0x100000000 - 0x1000);
|
||||
@ -553,17 +555,6 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev)
|
||||
{
|
||||
static struct mdp4_platform_config config = {};
|
||||
|
||||
/* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
|
||||
config.max_clk = 266667000;
|
||||
config.iommu = iommu_domain_alloc(&platform_bus_type);
|
||||
|
||||
return &config;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops mdp4_pm_ops = {
|
||||
.prepare = msm_pm_prepare,
|
||||
.complete = msm_pm_complete,
|
||||
|
@ -42,12 +42,6 @@ struct mdp4_kms {
|
||||
};
|
||||
#define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base)
|
||||
|
||||
/* platform config data (ie. from DT, or pdata) */
|
||||
struct mdp4_platform_config {
|
||||
struct iommu_domain *iommu;
|
||||
uint32_t max_clk;
|
||||
};
|
||||
|
||||
static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data)
|
||||
{
|
||||
msm_writel(data, mdp4_kms->mmio + reg);
|
||||
|
@ -837,6 +837,11 @@ static const struct mdp5_cfg_hw msm8x53_config = {
|
||||
[2] = INTF_DSI,
|
||||
},
|
||||
},
|
||||
.perf = {
|
||||
.ab_inefficiency = 100,
|
||||
.ib_inefficiency = 200,
|
||||
.clk_inefficiency = 105
|
||||
},
|
||||
.max_clk = 400000000,
|
||||
};
|
||||
|
||||
@ -1248,8 +1253,6 @@ static const struct mdp5_cfg_handler cfg_handlers_v3[] = {
|
||||
{ .revision = 3, .config = { .hw = &sdm630_config } },
|
||||
};
|
||||
|
||||
static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
|
||||
|
||||
const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
|
||||
{
|
||||
return cfg_handler->config.hw;
|
||||
@ -1274,10 +1277,8 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
|
||||
uint32_t major, uint32_t minor)
|
||||
{
|
||||
struct drm_device *dev = mdp5_kms->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev->dev);
|
||||
struct mdp5_cfg_handler *cfg_handler;
|
||||
const struct mdp5_cfg_handler *cfg_handlers;
|
||||
struct mdp5_cfg_platform *pconfig;
|
||||
int i, ret = 0, num_handlers;
|
||||
|
||||
cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL);
|
||||
@ -1320,9 +1321,6 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
|
||||
cfg_handler->revision = minor;
|
||||
cfg_handler->config.hw = mdp5_cfg;
|
||||
|
||||
pconfig = mdp5_get_config(pdev);
|
||||
memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig));
|
||||
|
||||
DBG("MDP5: %s hw config selected", mdp5_cfg->name);
|
||||
|
||||
return cfg_handler;
|
||||
@ -1333,12 +1331,3 @@ fail:
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
|
||||
{
|
||||
static struct mdp5_cfg_platform config = {};
|
||||
|
||||
config.iommu = iommu_domain_alloc(&platform_bus_type);
|
||||
|
||||
return &config;
|
||||
}
|
||||
|
@ -104,14 +104,8 @@ struct mdp5_cfg_hw {
|
||||
uint32_t max_clk;
|
||||
};
|
||||
|
||||
/* platform config data (ie. from DT, or pdata) */
|
||||
struct mdp5_cfg_platform {
|
||||
struct iommu_domain *iommu;
|
||||
};
|
||||
|
||||
struct mdp5_cfg {
|
||||
const struct mdp5_cfg_hw *hw;
|
||||
struct mdp5_cfg_platform platform;
|
||||
};
|
||||
|
||||
struct mdp5_kms;
|
||||
|
@ -557,7 +557,6 @@ static int mdp5_kms_init(struct drm_device *dev)
|
||||
struct msm_kms *kms;
|
||||
struct msm_gem_address_space *aspace;
|
||||
int irq, i, ret;
|
||||
struct device *iommu_dev;
|
||||
|
||||
ret = mdp5_init(to_platform_device(dev->dev), dev);
|
||||
|
||||
@ -601,32 +600,14 @@ static int mdp5_kms_init(struct drm_device *dev)
|
||||
}
|
||||
mdelay(16);
|
||||
|
||||
if (config->platform.iommu) {
|
||||
struct msm_mmu *mmu;
|
||||
|
||||
iommu_dev = &pdev->dev;
|
||||
if (!dev_iommu_fwspec_get(iommu_dev))
|
||||
iommu_dev = iommu_dev->parent;
|
||||
|
||||
mmu = msm_iommu_new(iommu_dev, config->platform.iommu);
|
||||
|
||||
aspace = msm_gem_address_space_create(mmu, "mdp5",
|
||||
0x1000, 0x100000000 - 0x1000);
|
||||
|
||||
if (IS_ERR(aspace)) {
|
||||
if (!IS_ERR(mmu))
|
||||
mmu->funcs->destroy(mmu);
|
||||
ret = PTR_ERR(aspace);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
kms->aspace = aspace;
|
||||
} else {
|
||||
DRM_DEV_INFO(&pdev->dev,
|
||||
"no iommu, fallback to phys contig buffers for scanout\n");
|
||||
aspace = NULL;
|
||||
aspace = msm_kms_init_aspace(mdp5_kms->dev);
|
||||
if (IS_ERR(aspace)) {
|
||||
ret = PTR_ERR(aspace);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
kms->aspace = aspace;
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
ret = modeset_init(mdp5_kms);
|
||||
|
@ -123,12 +123,13 @@ int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
|
||||
{
|
||||
struct msm_drm_private *priv = s->dev->dev_private;
|
||||
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
|
||||
struct mdp5_global_state *state = mdp5_get_global_state(s);
|
||||
struct mdp5_global_state *state;
|
||||
struct mdp5_hw_pipe_state *new_state;
|
||||
|
||||
if (!hwpipe)
|
||||
return 0;
|
||||
|
||||
state = mdp5_get_global_state(s);
|
||||
if (IS_ERR(state))
|
||||
return PTR_ERR(state);
|
||||
|
||||
|
@ -1,120 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/clk-conf.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "dp_clk_util.h"
|
||||
|
||||
void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = num_clk - 1; i >= 0; i--) {
|
||||
if (clk_arry[i].clk)
|
||||
clk_put(clk_arry[i].clk);
|
||||
clk_arry[i].clk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; i < num_clk; i++) {
|
||||
clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
|
||||
rc = PTR_ERR_OR_ZERO(clk_arry[i].clk);
|
||||
if (rc) {
|
||||
DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
|
||||
__builtin_return_address(0), __func__,
|
||||
clk_arry[i].clk_name, rc);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
error:
|
||||
for (i--; i >= 0; i--) {
|
||||
if (clk_arry[i].clk)
|
||||
clk_put(clk_arry[i].clk);
|
||||
clk_arry[i].clk = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; i < num_clk; i++) {
|
||||
if (clk_arry[i].clk) {
|
||||
if (clk_arry[i].type != DSS_CLK_AHB) {
|
||||
DEV_DBG("%pS->%s: '%s' rate %ld\n",
|
||||
__builtin_return_address(0), __func__,
|
||||
clk_arry[i].clk_name,
|
||||
clk_arry[i].rate);
|
||||
rc = clk_set_rate(clk_arry[i].clk,
|
||||
clk_arry[i].rate);
|
||||
if (rc) {
|
||||
DEV_ERR("%pS->%s: %s failed. rc=%d\n",
|
||||
__builtin_return_address(0),
|
||||
__func__,
|
||||
clk_arry[i].clk_name, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEV_ERR("%pS->%s: '%s' is not available\n",
|
||||
__builtin_return_address(0), __func__,
|
||||
clk_arry[i].clk_name);
|
||||
rc = -EPERM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
if (enable) {
|
||||
for (i = 0; i < num_clk; i++) {
|
||||
DEV_DBG("%pS->%s: enable '%s'\n",
|
||||
__builtin_return_address(0), __func__,
|
||||
clk_arry[i].clk_name);
|
||||
rc = clk_prepare_enable(clk_arry[i].clk);
|
||||
if (rc)
|
||||
DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
|
||||
__builtin_return_address(0),
|
||||
__func__,
|
||||
clk_arry[i].clk_name, rc);
|
||||
|
||||
if (rc && i) {
|
||||
msm_dss_enable_clk(&clk_arry[i - 1],
|
||||
i - 1, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = num_clk - 1; i >= 0; i--) {
|
||||
DEV_DBG("%pS->%s: disable '%s'\n",
|
||||
__builtin_return_address(0), __func__,
|
||||
clk_arry[i].clk_name);
|
||||
|
||||
clk_disable_unprepare(clk_arry[i].clk);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __DP_CLK_UTIL_H__
|
||||
#define __DP_CLK_UTIL_H__
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define DEV_DBG(fmt, args...) pr_debug(fmt, ##args)
|
||||
#define DEV_INFO(fmt, args...) pr_info(fmt, ##args)
|
||||
#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args)
|
||||
#define DEV_ERR(fmt, args...) pr_err(fmt, ##args)
|
||||
|
||||
enum dss_clk_type {
|
||||
DSS_CLK_AHB, /* no set rate. rate controlled through rpm */
|
||||
DSS_CLK_PCLK,
|
||||
};
|
||||
|
||||
struct dss_clk {
|
||||
struct clk *clk; /* clk handle */
|
||||
char clk_name[32];
|
||||
enum dss_clk_type type;
|
||||
unsigned long rate;
|
||||
unsigned long max_rate;
|
||||
};
|
||||
|
||||
struct dss_module_power {
|
||||
unsigned int num_clk;
|
||||
struct dss_clk *clk_config;
|
||||
};
|
||||
|
||||
int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
|
||||
void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
|
||||
int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
|
||||
int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
|
||||
#endif /* __DP_CLK_UTIL_H__ */
|
@ -1321,9 +1321,9 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
|
||||
enum dp_pm_type module, char *name, unsigned long rate)
|
||||
{
|
||||
u32 num = ctrl->parser->mp[module].num_clk;
|
||||
struct dss_clk *cfg = ctrl->parser->mp[module].clk_config;
|
||||
struct clk_bulk_data *cfg = ctrl->parser->mp[module].clocks;
|
||||
|
||||
while (num && strcmp(cfg->clk_name, name)) {
|
||||
while (num && strcmp(cfg->id, name)) {
|
||||
num--;
|
||||
cfg++;
|
||||
}
|
||||
@ -1332,7 +1332,7 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
|
||||
rate, name);
|
||||
|
||||
if (num)
|
||||
cfg->rate = rate;
|
||||
clk_set_rate(cfg->clk, rate);
|
||||
else
|
||||
DRM_ERROR("%s clock doesn't exit to set rate %lu\n",
|
||||
name, rate);
|
||||
@ -1349,12 +1349,11 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
|
||||
opts_dp->lanes = ctrl->link->link_params.num_lanes;
|
||||
opts_dp->link_rate = ctrl->link->link_params.rate / 100;
|
||||
opts_dp->ssc = drm_dp_max_downspread(dpcd);
|
||||
dp_ctrl_set_clock_rate(ctrl, DP_CTRL_PM, "ctrl_link",
|
||||
ctrl->link->link_params.rate * 1000);
|
||||
|
||||
phy_configure(phy, &dp_io->phy_opts);
|
||||
phy_power_on(phy);
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, ctrl->link->link_params.rate * 1000);
|
||||
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, true);
|
||||
if (ret)
|
||||
DRM_ERROR("Unable to start link clocks. ret=%d\n", ret);
|
||||
@ -1462,6 +1461,7 @@ static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)
|
||||
* link clock might have been adjusted as part of the
|
||||
* link maintenance.
|
||||
*/
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to disable clocks. ret=%d\n", ret);
|
||||
@ -1493,6 +1493,7 @@ static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
|
||||
|
||||
dp_catalog_ctrl_reset(ctrl->catalog);
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
|
||||
@ -1929,6 +1930,7 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
|
||||
}
|
||||
}
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
|
||||
@ -1997,6 +1999,7 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to disable pixel clocks. ret=%d\n", ret);
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
|
||||
|
@ -131,35 +131,43 @@ struct msm_dp_config {
|
||||
size_t num_descs;
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sc7180_dp_descs[] = {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
};
|
||||
|
||||
static const struct msm_dp_config sc7180_dp_cfg = {
|
||||
.descs = (const struct msm_dp_desc[]) {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
},
|
||||
.num_descs = 1,
|
||||
.descs = sc7180_dp_descs,
|
||||
.num_descs = ARRAY_SIZE(sc7180_dp_descs),
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sc7280_dp_descs[] = {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
[MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
|
||||
};
|
||||
|
||||
static const struct msm_dp_config sc7280_dp_cfg = {
|
||||
.descs = (const struct msm_dp_desc[]) {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
[MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
|
||||
},
|
||||
.num_descs = 2,
|
||||
.descs = sc7280_dp_descs,
|
||||
.num_descs = ARRAY_SIZE(sc7280_dp_descs),
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sc8180x_dp_descs[] = {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
[MSM_DP_CONTROLLER_1] = { .io_start = 0x0ae98000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
[MSM_DP_CONTROLLER_2] = { .io_start = 0x0ae9a000, .connector_type = DRM_MODE_CONNECTOR_eDP },
|
||||
};
|
||||
|
||||
static const struct msm_dp_config sc8180x_dp_cfg = {
|
||||
.descs = (const struct msm_dp_desc[]) {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
[MSM_DP_CONTROLLER_1] = { .io_start = 0x0ae98000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
[MSM_DP_CONTROLLER_2] = { .io_start = 0x0ae9a000, .connector_type = DRM_MODE_CONNECTOR_eDP },
|
||||
},
|
||||
.num_descs = 3,
|
||||
.descs = sc8180x_dp_descs,
|
||||
.num_descs = ARRAY_SIZE(sc8180x_dp_descs),
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sm8350_dp_descs[] = {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
};
|
||||
|
||||
static const struct msm_dp_config sm8350_dp_cfg = {
|
||||
.descs = (const struct msm_dp_desc[]) {
|
||||
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
|
||||
},
|
||||
.num_descs = 1,
|
||||
.descs = sm8350_dp_descs,
|
||||
.num_descs = ARRAY_SIZE(sm8350_dp_descs),
|
||||
};
|
||||
|
||||
static const struct of_device_id dp_dt_match[] = {
|
||||
@ -610,9 +618,6 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int dp_display_enable(struct dp_display_private *dp, u32 data);
|
||||
static int dp_display_disable(struct dp_display_private *dp, u32 data);
|
||||
|
||||
static void dp_display_handle_plugged_change(struct msm_dp *dp_display,
|
||||
bool plugged)
|
||||
{
|
||||
@ -859,12 +864,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_display_prepare(struct msm_dp *dp_display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_display_enable(struct dp_display_private *dp, u32 data)
|
||||
static int dp_display_enable(struct dp_display_private *dp, bool force_link_train)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_dp *dp_display = &dp->dp_display;
|
||||
@ -875,7 +875,7 @@ static int dp_display_enable(struct dp_display_private *dp, u32 data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = dp_ctrl_on_stream(dp->ctrl, data);
|
||||
rc = dp_ctrl_on_stream(dp->ctrl, force_link_train);
|
||||
if (!rc)
|
||||
dp_display->power_on = true;
|
||||
|
||||
@ -901,7 +901,7 @@ static int dp_display_post_enable(struct msm_dp *dp_display)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_display_disable(struct dp_display_private *dp, u32 data)
|
||||
static int dp_display_disable(struct dp_display_private *dp)
|
||||
{
|
||||
struct msm_dp *dp_display = &dp->dp_display;
|
||||
|
||||
@ -940,11 +940,6 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_display_unprepare(struct msm_dp *dp_display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_display_set_plugged_cb(struct msm_dp *dp_display,
|
||||
hdmi_codec_plugged_cb fn, struct device *codec_dev)
|
||||
{
|
||||
@ -992,7 +987,7 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
return MODE_OK;
|
||||
|
||||
if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
|
||||
return MODE_BAD;
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
dp_display = container_of(dp, struct dp_display_private, dp_display);
|
||||
link_info = &dp_display->panel->link_info;
|
||||
@ -1460,21 +1455,9 @@ static int dp_pm_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_pm_prepare(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_pm_complete(struct device *dev)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dp_pm_ops = {
|
||||
.suspend = dp_pm_suspend,
|
||||
.resume = dp_pm_resume,
|
||||
.prepare = dp_pm_prepare,
|
||||
.complete = dp_pm_complete,
|
||||
};
|
||||
|
||||
static struct platform_driver dp_display_driver = {
|
||||
@ -1624,8 +1607,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
dp_display->encoder = encoder;
|
||||
|
||||
ret = dp_display_get_next_bridge(dp_display);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1641,7 +1622,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
|
||||
priv->bridges[priv->num_bridges++] = dp_display->bridge;
|
||||
|
||||
dp_display->connector = dp_drm_connector_init(dp_display);
|
||||
dp_display->connector = dp_drm_connector_init(dp_display, encoder);
|
||||
if (IS_ERR(dp_display->connector)) {
|
||||
ret = PTR_ERR(dp_display->connector);
|
||||
DRM_DEV_ERROR(dev->dev,
|
||||
@ -1688,13 +1669,6 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
rc = dp_display_prepare(dp);
|
||||
if (rc) {
|
||||
DRM_ERROR("DP display prepare failed, rc=%d\n", rc);
|
||||
mutex_unlock(&dp_display->event_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
state = dp_display->hpd_state;
|
||||
|
||||
if (state == ST_DISPLAY_OFF) {
|
||||
@ -1707,8 +1681,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
|
||||
rc = dp_display_post_enable(dp);
|
||||
if (rc) {
|
||||
DRM_ERROR("DP display post enable failed, rc=%d\n", rc);
|
||||
dp_display_disable(dp_display, 0);
|
||||
dp_display_unprepare(dp);
|
||||
dp_display_disable(dp_display);
|
||||
}
|
||||
|
||||
/* completed connection */
|
||||
@ -1733,7 +1706,6 @@ void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
|
||||
{
|
||||
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = dp_bridge->dp_display;
|
||||
int rc = 0;
|
||||
u32 state;
|
||||
struct dp_display_private *dp_display;
|
||||
|
||||
@ -1750,11 +1722,7 @@ void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
dp_display_disable(dp_display, 0);
|
||||
|
||||
rc = dp_display_unprepare(dp);
|
||||
if (rc)
|
||||
DRM_ERROR("DP display unprepare failed, rc=%d\n", rc);
|
||||
dp_display_disable(dp_display);
|
||||
|
||||
state = dp_display->hpd_state;
|
||||
if (state == ST_DISCONNECT_PENDING) {
|
||||
|
@ -15,7 +15,6 @@ struct msm_dp {
|
||||
struct device *codec_dev;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_bridge *next_bridge;
|
||||
bool is_connected;
|
||||
bool audio_enabled;
|
||||
|
@ -116,7 +116,7 @@ struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *
|
||||
}
|
||||
|
||||
if (dp_display->next_bridge) {
|
||||
rc = drm_bridge_attach(dp_display->encoder,
|
||||
rc = drm_bridge_attach(encoder,
|
||||
dp_display->next_bridge, bridge,
|
||||
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (rc < 0) {
|
||||
@ -130,15 +130,15 @@ struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *
|
||||
}
|
||||
|
||||
/* connector initialization */
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_connector *connector = NULL;
|
||||
|
||||
connector = drm_bridge_connector_init(dp_display->drm_dev, dp_display->encoder);
|
||||
connector = drm_bridge_connector_init(dp_display->drm_dev, encoder);
|
||||
if (IS_ERR(connector))
|
||||
return connector;
|
||||
|
||||
drm_connector_attach_encoder(connector, dp_display->encoder);
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
return connector;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ struct msm_dp_bridge {
|
||||
|
||||
#define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
|
||||
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display);
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder);
|
||||
struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
|
@ -160,11 +160,11 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
|
||||
}
|
||||
|
||||
core_power->num_clk = core_clk_count;
|
||||
core_power->clk_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_clk) * core_power->num_clk,
|
||||
core_power->clocks = devm_kcalloc(dev,
|
||||
core_power->num_clk, sizeof(struct clk_bulk_data),
|
||||
GFP_KERNEL);
|
||||
if (!core_power->clk_config)
|
||||
return -EINVAL;
|
||||
if (!core_power->clocks)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize the CTRL power module */
|
||||
if (ctrl_clk_count == 0) {
|
||||
@ -173,12 +173,12 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
|
||||
}
|
||||
|
||||
ctrl_power->num_clk = ctrl_clk_count;
|
||||
ctrl_power->clk_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_clk) * ctrl_power->num_clk,
|
||||
ctrl_power->clocks = devm_kcalloc(dev,
|
||||
ctrl_power->num_clk, sizeof(struct clk_bulk_data),
|
||||
GFP_KERNEL);
|
||||
if (!ctrl_power->clk_config) {
|
||||
if (!ctrl_power->clocks) {
|
||||
ctrl_power->num_clk = 0;
|
||||
return -EINVAL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Initialize the STREAM power module */
|
||||
@ -188,12 +188,12 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
|
||||
}
|
||||
|
||||
stream_power->num_clk = stream_clk_count;
|
||||
stream_power->clk_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_clk) * stream_power->num_clk,
|
||||
stream_power->clocks = devm_kcalloc(dev,
|
||||
stream_power->num_clk, sizeof(struct clk_bulk_data),
|
||||
GFP_KERNEL);
|
||||
if (!stream_power->clk_config) {
|
||||
if (!stream_power->clocks) {
|
||||
stream_power->num_clk = 0;
|
||||
return -EINVAL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -232,29 +232,16 @@ static int dp_parser_clock(struct dp_parser *parser)
|
||||
}
|
||||
if (dp_parser_check_prefix("core", clk_name) &&
|
||||
core_clk_index < core_clk_count) {
|
||||
struct dss_clk *clk =
|
||||
&core_power->clk_config[core_clk_index];
|
||||
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
|
||||
clk->type = DSS_CLK_AHB;
|
||||
core_power->clocks[core_clk_index].id = devm_kstrdup(dev, clk_name, GFP_KERNEL);
|
||||
core_clk_index++;
|
||||
} else if (dp_parser_check_prefix("stream", clk_name) &&
|
||||
stream_clk_index < stream_clk_count) {
|
||||
struct dss_clk *clk =
|
||||
&stream_power->clk_config[stream_clk_index];
|
||||
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
|
||||
clk->type = DSS_CLK_PCLK;
|
||||
stream_power->clocks[stream_clk_index].id = devm_kstrdup(dev, clk_name, GFP_KERNEL);
|
||||
stream_clk_index++;
|
||||
} else if (dp_parser_check_prefix("ctrl", clk_name) &&
|
||||
ctrl_clk_index < ctrl_clk_count) {
|
||||
struct dss_clk *clk =
|
||||
&ctrl_power->clk_config[ctrl_clk_index];
|
||||
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
|
||||
ctrl_power->clocks[ctrl_clk_index].id = devm_kstrdup(dev, clk_name, GFP_KERNEL);
|
||||
ctrl_clk_index++;
|
||||
if (dp_parser_check_prefix("ctrl_link", clk_name) ||
|
||||
dp_parser_check_prefix("stream_pixel", clk_name))
|
||||
clk->type = DSS_CLK_PCLK;
|
||||
else
|
||||
clk->type = DSS_CLK_AHB;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/phy/phy-dp.h>
|
||||
|
||||
#include "dp_clk_util.h"
|
||||
#include "msm_drv.h"
|
||||
|
||||
#define DP_LABEL "MDSS DP DISPLAY"
|
||||
@ -106,6 +105,11 @@ struct dp_regulator_cfg {
|
||||
struct dp_reg_entry regs[DP_DEV_REGULATOR_MAX];
|
||||
};
|
||||
|
||||
struct dss_module_power {
|
||||
unsigned int num_clk;
|
||||
struct clk_bulk_data *clocks;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_parser - DP parser's data exposed to clients
|
||||
*
|
||||
|
@ -106,107 +106,30 @@ static int dp_power_clk_init(struct dp_power_private *power)
|
||||
ctrl = &power->parser->mp[DP_CTRL_PM];
|
||||
stream = &power->parser->mp[DP_STREAM_PM];
|
||||
|
||||
rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk);
|
||||
rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to get %s clk. err=%d\n",
|
||||
dp_parser_pm_name(DP_CORE_PM), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk);
|
||||
rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to get %s clk. err=%d\n",
|
||||
dp_parser_pm_name(DP_CTRL_PM), rc);
|
||||
msm_dss_put_clk(core->clk_config, core->num_clk);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = msm_dss_get_clk(dev, stream->clk_config, stream->num_clk);
|
||||
rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to get %s clk. err=%d\n",
|
||||
dp_parser_pm_name(DP_CTRL_PM), rc);
|
||||
msm_dss_put_clk(core->clk_config, core->num_clk);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_power_clk_deinit(struct dp_power_private *power)
|
||||
{
|
||||
struct dss_module_power *core, *ctrl, *stream;
|
||||
|
||||
core = &power->parser->mp[DP_CORE_PM];
|
||||
ctrl = &power->parser->mp[DP_CTRL_PM];
|
||||
stream = &power->parser->mp[DP_STREAM_PM];
|
||||
|
||||
if (!core || !ctrl || !stream) {
|
||||
DRM_ERROR("invalid power_data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
|
||||
msm_dss_put_clk(core->clk_config, core->num_clk);
|
||||
msm_dss_put_clk(stream->clk_config, stream->num_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_power_clk_set_link_rate(struct dp_power_private *power,
|
||||
struct dss_clk *clk_arry, int num_clk, int enable)
|
||||
{
|
||||
u32 rate;
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; i < num_clk; i++) {
|
||||
if (clk_arry[i].clk) {
|
||||
if (clk_arry[i].type == DSS_CLK_PCLK) {
|
||||
if (enable)
|
||||
rate = clk_arry[i].rate;
|
||||
else
|
||||
rate = 0;
|
||||
|
||||
rc = dev_pm_opp_set_rate(power->dev, rate);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
enum dp_pm_type module, bool enable)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp = &power->parser->mp[module];
|
||||
|
||||
if (module == DP_CTRL_PM) {
|
||||
rc = dp_power_clk_set_link_rate(power, mp->clk_config, mp->num_clk, enable);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to set link clks rate\n");
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (enable) {
|
||||
rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to set clks rate\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to %d clks, err: %d\n", enable, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
@ -234,6 +157,7 @@ int dp_power_clk_enable(struct dp_power *dp_power,
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_power_private *power;
|
||||
struct dss_module_power *mp;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
@ -266,8 +190,9 @@ int dp_power_clk_enable(struct dp_power *dp_power,
|
||||
if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
|
||||
drm_dbg_dp(power->drm_dev,
|
||||
"Enable core clks before link clks\n");
|
||||
mp = &power->parser->mp[DP_CORE_PM];
|
||||
|
||||
rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable);
|
||||
rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
|
||||
if (rc) {
|
||||
DRM_ERROR("fail to enable clks: %s. err=%d\n",
|
||||
dp_parser_pm_name(DP_CORE_PM), rc);
|
||||
@ -277,12 +202,15 @@ int dp_power_clk_enable(struct dp_power *dp_power,
|
||||
}
|
||||
}
|
||||
|
||||
rc = dp_power_clk_set_rate(power, pm_type, enable);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to '%s' clks for: %s. err=%d\n",
|
||||
enable ? "enable" : "disable",
|
||||
dp_parser_pm_name(pm_type), rc);
|
||||
return rc;
|
||||
mp = &power->parser->mp[pm_type];
|
||||
if (enable) {
|
||||
rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to enable clks, err: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
|
||||
}
|
||||
|
||||
if (pm_type == DP_CORE_PM)
|
||||
@ -347,9 +275,7 @@ void dp_power_client_deinit(struct dp_power *dp_power)
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
dp_power_clk_deinit(power);
|
||||
pm_runtime_disable(&power->pdev->dev);
|
||||
|
||||
}
|
||||
|
||||
int dp_power_init(struct dp_power *dp_power, bool flip)
|
||||
|
@ -1082,12 +1082,32 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
|
||||
|
||||
static void dsi_sw_reset(struct msm_dsi_host *msm_host)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = dsi_read(msm_host, REG_DSI_CTRL);
|
||||
|
||||
if (ctrl & DSI_CTRL_ENABLE) {
|
||||
dsi_write(msm_host, REG_DSI_CTRL, ctrl & ~DSI_CTRL_ENABLE);
|
||||
/*
|
||||
* dsi controller need to be disabled before
|
||||
* clocks turned on
|
||||
*/
|
||||
wmb();
|
||||
}
|
||||
|
||||
dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
|
||||
wmb(); /* clocks need to be enabled before reset */
|
||||
|
||||
/* dsi controller can only be reset while clocks are running */
|
||||
dsi_write(msm_host, REG_DSI_RESET, 1);
|
||||
msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */
|
||||
dsi_write(msm_host, REG_DSI_RESET, 0);
|
||||
wmb(); /* controller out of reset */
|
||||
|
||||
if (ctrl & DSI_CTRL_ENABLE) {
|
||||
dsi_write(msm_host, REG_DSI_CTRL, ctrl);
|
||||
wmb(); /* make sure dsi controller enabled again */
|
||||
}
|
||||
}
|
||||
|
||||
static void dsi_op_mode_config(struct msm_dsi_host *msm_host,
|
||||
@ -1480,32 +1500,6 @@ static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host,
|
||||
return len;
|
||||
}
|
||||
|
||||
static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host)
|
||||
{
|
||||
u32 data0, data1;
|
||||
|
||||
data0 = dsi_read(msm_host, REG_DSI_CTRL);
|
||||
data1 = data0;
|
||||
data1 &= ~DSI_CTRL_ENABLE;
|
||||
dsi_write(msm_host, REG_DSI_CTRL, data1);
|
||||
/*
|
||||
* dsi controller need to be disabled before
|
||||
* clocks turned on
|
||||
*/
|
||||
wmb();
|
||||
|
||||
dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
|
||||
wmb(); /* make sure clocks enabled */
|
||||
|
||||
/* dsi controller can only be reset while clocks are running */
|
||||
dsi_write(msm_host, REG_DSI_RESET, 1);
|
||||
msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */
|
||||
dsi_write(msm_host, REG_DSI_RESET, 0);
|
||||
wmb(); /* controller out of reset */
|
||||
dsi_write(msm_host, REG_DSI_CTRL, data0);
|
||||
wmb(); /* make sure dsi controller enabled again */
|
||||
}
|
||||
|
||||
static void dsi_hpd_worker(struct work_struct *work)
|
||||
{
|
||||
struct msm_dsi_host *msm_host =
|
||||
@ -1522,7 +1516,7 @@ static void dsi_err_worker(struct work_struct *work)
|
||||
|
||||
pr_err_ratelimited("%s: status=%x\n", __func__, status);
|
||||
if (status & DSI_ERR_STATE_MDP_FIFO_UNDERFLOW)
|
||||
dsi_sw_reset_restore(msm_host);
|
||||
dsi_sw_reset(msm_host);
|
||||
|
||||
/* It is safe to clear here because error irq is disabled. */
|
||||
msm_host->err_work_state = 0;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_of.h>
|
||||
|
||||
#include <sound/hdmi-codec.h>
|
||||
#include "hdmi.h"
|
||||
@ -133,6 +134,10 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
|
||||
hdmi->config = config;
|
||||
spin_lock_init(&hdmi->reg_lock);
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge);
|
||||
if (ret && ret != -ENODEV)
|
||||
goto fail;
|
||||
|
||||
hdmi->mmio = msm_ioremap(pdev, config->mmio_name);
|
||||
if (IS_ERR(hdmi->mmio)) {
|
||||
ret = PTR_ERR(hdmi->mmio);
|
||||
@ -180,6 +185,9 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < config->pwr_reg_cnt; i++)
|
||||
hdmi->pwr_regs[i].supply = config->pwr_reg_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %d\n", ret);
|
||||
@ -230,6 +238,20 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
|
||||
hdmi->pwr_clks[i] = clk;
|
||||
}
|
||||
|
||||
hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
|
||||
/* This will catch e.g. -EPROBE_DEFER */
|
||||
if (IS_ERR(hdmi->hpd_gpiod)) {
|
||||
ret = PTR_ERR(hdmi->hpd_gpiod);
|
||||
DRM_DEV_ERROR(&pdev->dev, "failed to get hpd gpio: (%d)\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!hdmi->hpd_gpiod)
|
||||
DBG("failed to get HPD gpio");
|
||||
|
||||
if (hdmi->hpd_gpiod)
|
||||
gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD");
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
|
||||
@ -291,6 +313,15 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hdmi->next_bridge) {
|
||||
ret = drm_bridge_attach(hdmi->encoder, hdmi->next_bridge, hdmi->bridge,
|
||||
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to attach next HDMI bridge: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
hdmi->connector = drm_bridge_connector_init(hdmi->dev, encoder);
|
||||
if (IS_ERR(hdmi->connector)) {
|
||||
ret = PTR_ERR(hdmi->connector);
|
||||
@ -353,12 +384,7 @@ fail:
|
||||
.item ## _names = item ##_names_ ## entry, \
|
||||
.item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry)
|
||||
|
||||
static const char *pwr_reg_names_none[] = {};
|
||||
static const char *hpd_reg_names_none[] = {};
|
||||
|
||||
static struct hdmi_platform_config hdmi_tx_8660_config;
|
||||
|
||||
static const char *hpd_reg_names_8960[] = {"core-vdda", "hdmi-mux"};
|
||||
static const char *hpd_reg_names_8960[] = {"core-vdda"};
|
||||
static const char *hpd_clk_names_8960[] = {"core", "master_iface", "slave_iface"};
|
||||
|
||||
static struct hdmi_platform_config hdmi_tx_8960_config = {
|
||||
@ -367,59 +393,17 @@ static struct hdmi_platform_config hdmi_tx_8960_config = {
|
||||
};
|
||||
|
||||
static const char *pwr_reg_names_8x74[] = {"core-vdda", "core-vcc"};
|
||||
static const char *hpd_reg_names_8x74[] = {"hpd-gdsc", "hpd-5v"};
|
||||
static const char *pwr_clk_names_8x74[] = {"extp", "alt_iface"};
|
||||
static const char *hpd_clk_names_8x74[] = {"iface", "core", "mdp_core"};
|
||||
static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0};
|
||||
|
||||
static struct hdmi_platform_config hdmi_tx_8974_config = {
|
||||
HDMI_CFG(pwr_reg, 8x74),
|
||||
HDMI_CFG(hpd_reg, 8x74),
|
||||
HDMI_CFG(pwr_clk, 8x74),
|
||||
HDMI_CFG(hpd_clk, 8x74),
|
||||
.hpd_freq = hpd_clk_freq_8x74,
|
||||
};
|
||||
|
||||
static const char *hpd_reg_names_8084[] = {"hpd-gdsc", "hpd-5v", "hpd-5v-en"};
|
||||
|
||||
static struct hdmi_platform_config hdmi_tx_8084_config = {
|
||||
HDMI_CFG(pwr_reg, 8x74),
|
||||
HDMI_CFG(hpd_reg, 8084),
|
||||
HDMI_CFG(pwr_clk, 8x74),
|
||||
HDMI_CFG(hpd_clk, 8x74),
|
||||
.hpd_freq = hpd_clk_freq_8x74,
|
||||
};
|
||||
|
||||
static struct hdmi_platform_config hdmi_tx_8994_config = {
|
||||
HDMI_CFG(pwr_reg, 8x74),
|
||||
HDMI_CFG(hpd_reg, none),
|
||||
HDMI_CFG(pwr_clk, 8x74),
|
||||
HDMI_CFG(hpd_clk, 8x74),
|
||||
.hpd_freq = hpd_clk_freq_8x74,
|
||||
};
|
||||
|
||||
static struct hdmi_platform_config hdmi_tx_8996_config = {
|
||||
HDMI_CFG(pwr_reg, none),
|
||||
HDMI_CFG(hpd_reg, none),
|
||||
HDMI_CFG(pwr_clk, 8x74),
|
||||
HDMI_CFG(hpd_clk, 8x74),
|
||||
.hpd_freq = hpd_clk_freq_8x74,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
const bool output;
|
||||
const int value;
|
||||
const char *label;
|
||||
} msm_hdmi_gpio_pdata[] = {
|
||||
{ "qcom,hdmi-tx-ddc-clk", true, 1, "HDMI_DDC_CLK" },
|
||||
{ "qcom,hdmi-tx-ddc-data", true, 1, "HDMI_DDC_DATA" },
|
||||
{ "qcom,hdmi-tx-hpd", false, 1, "HDMI_HPD" },
|
||||
{ "qcom,hdmi-tx-mux-en", true, 1, "HDMI_MUX_EN" },
|
||||
{ "qcom,hdmi-tx-mux-sel", true, 0, "HDMI_MUX_SEL" },
|
||||
{ "qcom,hdmi-tx-mux-lpm", true, 1, "HDMI_MUX_LPM" },
|
||||
};
|
||||
|
||||
/*
|
||||
* HDMI audio codec callbacks
|
||||
*/
|
||||
@ -531,7 +515,7 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
struct hdmi_platform_config *hdmi_cfg;
|
||||
struct hdmi *hdmi;
|
||||
struct device_node *of_node = dev->of_node;
|
||||
int i, err;
|
||||
int err;
|
||||
|
||||
hdmi_cfg = (struct hdmi_platform_config *)
|
||||
of_device_get_match_data(dev);
|
||||
@ -543,42 +527,6 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
hdmi_cfg->mmio_name = "core_physical";
|
||||
hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
|
||||
|
||||
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
|
||||
const char *name = msm_hdmi_gpio_pdata[i].name;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
/*
|
||||
* We are fetching the GPIO lines "as is" since the connector
|
||||
* code is enabling and disabling the lines. Until that point
|
||||
* the power-on default value will be kept.
|
||||
*/
|
||||
gpiod = devm_gpiod_get_optional(dev, name, GPIOD_ASIS);
|
||||
/* This will catch e.g. -PROBE_DEFER */
|
||||
if (IS_ERR(gpiod))
|
||||
return PTR_ERR(gpiod);
|
||||
if (!gpiod) {
|
||||
/* Try a second time, stripping down the name */
|
||||
char name3[32];
|
||||
|
||||
/*
|
||||
* Try again after stripping out the "qcom,hdmi-tx"
|
||||
* prefix. This is mainly to match "hpd-gpios" used
|
||||
* in the upstream bindings.
|
||||
*/
|
||||
if (sscanf(name, "qcom,hdmi-tx-%s", name3))
|
||||
gpiod = devm_gpiod_get_optional(dev, name3, GPIOD_ASIS);
|
||||
if (IS_ERR(gpiod))
|
||||
return PTR_ERR(gpiod);
|
||||
if (!gpiod)
|
||||
DBG("failed to get gpio: %s", name);
|
||||
}
|
||||
hdmi_cfg->gpios[i].gpiod = gpiod;
|
||||
if (gpiod)
|
||||
gpiod_set_consumer_name(gpiod, msm_hdmi_gpio_pdata[i].label);
|
||||
hdmi_cfg->gpios[i].output = msm_hdmi_gpio_pdata[i].output;
|
||||
hdmi_cfg->gpios[i].value = msm_hdmi_gpio_pdata[i].value;
|
||||
}
|
||||
|
||||
dev->platform_data = hdmi_cfg;
|
||||
|
||||
hdmi = msm_hdmi_init(to_platform_device(dev));
|
||||
@ -626,12 +574,12 @@ static int msm_hdmi_dev_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id msm_hdmi_dt_match[] = {
|
||||
{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8974_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8974_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8974_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
|
||||
{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -19,17 +19,9 @@
|
||||
#include "msm_drv.h"
|
||||
#include "hdmi.xml.h"
|
||||
|
||||
#define HDMI_MAX_NUM_GPIO 6
|
||||
|
||||
struct hdmi_phy;
|
||||
struct hdmi_platform_config;
|
||||
|
||||
struct hdmi_gpio_data {
|
||||
struct gpio_desc *gpiod;
|
||||
bool output;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct hdmi_audio {
|
||||
bool enabled;
|
||||
struct hdmi_audio_infoframe infoframe;
|
||||
@ -61,6 +53,8 @@ struct hdmi {
|
||||
struct clk **hpd_clks;
|
||||
struct clk **pwr_clks;
|
||||
|
||||
struct gpio_desc *hpd_gpiod;
|
||||
|
||||
struct hdmi_phy *phy;
|
||||
struct device *phy_dev;
|
||||
|
||||
@ -68,6 +62,8 @@ struct hdmi {
|
||||
struct drm_connector *connector;
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
struct drm_bridge *next_bridge;
|
||||
|
||||
/* the encoder we are hooked to (outside of hdmi block) */
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
@ -109,9 +105,6 @@ struct hdmi_platform_config {
|
||||
/* clks that need to be on for screen pwr (ie pixel clk): */
|
||||
const char **pwr_clk_names;
|
||||
int pwr_clk_cnt;
|
||||
|
||||
/* gpio's: */
|
||||
struct hdmi_gpio_data gpios[HDMI_MAX_NUM_GPIO];
|
||||
};
|
||||
|
||||
struct hdmi_bridge {
|
||||
|
@ -160,14 +160,6 @@ static void msm_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
|
||||
}
|
||||
|
||||
static void msm_hdmi_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
}
|
||||
|
||||
static void msm_hdmi_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
}
|
||||
|
||||
static void msm_hdmi_bridge_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
@ -307,8 +299,6 @@ static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge
|
||||
|
||||
static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
|
||||
.pre_enable = msm_hdmi_bridge_pre_enable,
|
||||
.enable = msm_hdmi_bridge_enable,
|
||||
.disable = msm_hdmi_bridge_disable,
|
||||
.post_disable = msm_hdmi_bridge_post_disable,
|
||||
.mode_set = msm_hdmi_bridge_mode_set,
|
||||
.mode_valid = msm_hdmi_bridge_mode_valid,
|
||||
|
@ -60,48 +60,6 @@ static void msm_hdmi_phy_reset(struct hdmi *hdmi)
|
||||
}
|
||||
}
|
||||
|
||||
static int gpio_config(struct hdmi *hdmi, bool on)
|
||||
{
|
||||
const struct hdmi_platform_config *config = hdmi->config;
|
||||
int i;
|
||||
|
||||
if (on) {
|
||||
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
|
||||
struct hdmi_gpio_data gpio = config->gpios[i];
|
||||
|
||||
if (gpio.gpiod) {
|
||||
if (gpio.output) {
|
||||
gpiod_direction_output(gpio.gpiod,
|
||||
gpio.value);
|
||||
} else {
|
||||
gpiod_direction_input(gpio.gpiod);
|
||||
gpiod_set_value_cansleep(gpio.gpiod,
|
||||
gpio.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBG("gpio on");
|
||||
} else {
|
||||
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
|
||||
struct hdmi_gpio_data gpio = config->gpios[i];
|
||||
|
||||
if (!gpio.gpiod)
|
||||
continue;
|
||||
|
||||
if (gpio.output) {
|
||||
int value = gpio.value ? 0 : 1;
|
||||
|
||||
gpiod_set_value_cansleep(gpio.gpiod, value);
|
||||
}
|
||||
}
|
||||
|
||||
DBG("gpio off");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
|
||||
{
|
||||
const struct hdmi_platform_config *config = hdmi->config;
|
||||
@ -154,11 +112,8 @@ int msm_hdmi_hpd_enable(struct drm_bridge *bridge)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = gpio_config(hdmi, true);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev, "failed to configure GPIOs: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
if (hdmi->hpd_gpiod)
|
||||
gpiod_set_value_cansleep(hdmi->hpd_gpiod, 1);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
enable_hpd_clocks(hdmi, true);
|
||||
@ -207,10 +162,6 @@ void msm_hdmi_hpd_disable(struct hdmi_bridge *hdmi_bridge)
|
||||
enable_hpd_clocks(hdmi, false);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
ret = gpio_config(hdmi, false);
|
||||
if (ret)
|
||||
dev_warn(dev, "failed to unconfigure GPIOs: %d\n", ret);
|
||||
|
||||
ret = pinctrl_pm_select_sleep_state(dev);
|
||||
if (ret)
|
||||
dev_warn(dev, "pinctrl state chg failed: %d\n", ret);
|
||||
@ -269,10 +220,7 @@ static enum drm_connector_status detect_reg(struct hdmi *hdmi)
|
||||
#define HPD_GPIO_INDEX 2
|
||||
static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
|
||||
{
|
||||
const struct hdmi_platform_config *config = hdmi->config;
|
||||
struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
|
||||
|
||||
return gpiod_get_value(hpd_gpio.gpiod) ?
|
||||
return gpiod_get_value(hdmi->hpd_gpiod) ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
}
|
||||
@ -282,8 +230,6 @@ enum drm_connector_status msm_hdmi_bridge_detect(
|
||||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
const struct hdmi_platform_config *config = hdmi->config;
|
||||
struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
|
||||
enum drm_connector_status stat_gpio, stat_reg;
|
||||
int retry = 20;
|
||||
|
||||
@ -291,7 +237,7 @@ enum drm_connector_status msm_hdmi_bridge_detect(
|
||||
* some platforms may not have hpd gpio. Rely only on the status
|
||||
* provided by REG_HDMI_HPD_INT_STATUS in this case.
|
||||
*/
|
||||
if (!hpd_gpio.gpiod)
|
||||
if (!hdmi->hpd_gpiod)
|
||||
return detect_reg(hdmi);
|
||||
|
||||
do {
|
||||
|
@ -122,8 +122,20 @@ static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy)
|
||||
HDMI_8x60_PHY_REG2_PD_DESER);
|
||||
}
|
||||
|
||||
static const char * const hdmi_phy_8x60_reg_names[] = {
|
||||
"core-vdda",
|
||||
};
|
||||
|
||||
static const char * const hdmi_phy_8x60_clk_names[] = {
|
||||
"slave_iface",
|
||||
};
|
||||
|
||||
const struct hdmi_phy_cfg msm_hdmi_phy_8x60_cfg = {
|
||||
.type = MSM_HDMI_PHY_8x60,
|
||||
.powerup = hdmi_phy_8x60_powerup,
|
||||
.powerdown = hdmi_phy_8x60_powerdown,
|
||||
.reg_names = hdmi_phy_8x60_reg_names,
|
||||
.num_regs = ARRAY_SIZE(hdmi_phy_8x60_reg_names),
|
||||
.clk_names = hdmi_phy_8x60_clk_names,
|
||||
.num_clks = ARRAY_SIZE(hdmi_phy_8x60_clk_names),
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "msm_gem.h"
|
||||
#include "msm_gpu.h"
|
||||
#include "msm_kms.h"
|
||||
#include "msm_mmu.h"
|
||||
#include "adreno/adreno_gpu.h"
|
||||
|
||||
/*
|
||||
@ -267,12 +268,56 @@ static int msm_drm_uninit(struct device *dev)
|
||||
|
||||
#include <linux/of_address.h>
|
||||
|
||||
struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev)
|
||||
{
|
||||
struct iommu_domain *domain;
|
||||
struct msm_gem_address_space *aspace;
|
||||
struct msm_mmu *mmu;
|
||||
struct device *mdp_dev = dev->dev;
|
||||
struct device *mdss_dev = mdp_dev->parent;
|
||||
struct device *iommu_dev;
|
||||
|
||||
/*
|
||||
* IOMMUs can be a part of MDSS device tree binding, or the
|
||||
* MDP/DPU device.
|
||||
*/
|
||||
if (device_iommu_mapped(mdp_dev))
|
||||
iommu_dev = mdp_dev;
|
||||
else
|
||||
iommu_dev = mdss_dev;
|
||||
|
||||
domain = iommu_domain_alloc(iommu_dev->bus);
|
||||
if (!domain) {
|
||||
drm_info(dev, "no IOMMU, fallback to phys contig buffers for scanout\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mmu = msm_iommu_new(iommu_dev, domain);
|
||||
if (IS_ERR(mmu)) {
|
||||
iommu_domain_free(domain);
|
||||
return ERR_CAST(mmu);
|
||||
}
|
||||
|
||||
aspace = msm_gem_address_space_create(mmu, "mdp_kms",
|
||||
0x1000, 0x100000000 - 0x1000);
|
||||
if (IS_ERR(aspace))
|
||||
mmu->funcs->destroy(mmu);
|
||||
|
||||
return aspace;
|
||||
}
|
||||
|
||||
bool msm_use_mmu(struct drm_device *dev)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
|
||||
/* a2xx comes with its own MMU */
|
||||
return priv->is_a2xx || iommu_present(&platform_bus_type);
|
||||
/*
|
||||
* a2xx comes with its own MMU
|
||||
* On other platforms IOMMU can be declared specified either for the
|
||||
* MDP/DPU device or for its parent, MDSS device.
|
||||
*/
|
||||
return priv->is_a2xx ||
|
||||
device_iommu_mapped(dev->dev) ||
|
||||
device_iommu_mapped(dev->dev->parent);
|
||||
}
|
||||
|
||||
static int msm_init_vram(struct drm_device *dev)
|
||||
@ -633,12 +678,25 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct drm_msm_gem_new *args = data;
|
||||
uint32_t flags = args->flags;
|
||||
|
||||
if (args->flags & ~MSM_BO_FLAGS) {
|
||||
DRM_ERROR("invalid flags: %08x\n", args->flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Uncached CPU mappings are deprecated, as of:
|
||||
*
|
||||
* 9ef364432db4 ("drm/msm: deprecate MSM_BO_UNCACHED (map as writecombine instead)")
|
||||
*
|
||||
* So promote them to WC.
|
||||
*/
|
||||
if (flags & MSM_BO_UNCACHED) {
|
||||
flags &= ~MSM_BO_CACHED;
|
||||
flags |= MSM_BO_WC;
|
||||
}
|
||||
|
||||
return msm_gem_new_handle(dev, file, args->size,
|
||||
args->flags, &args->handle, NULL);
|
||||
}
|
||||
@ -948,7 +1006,24 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW),
|
||||
};
|
||||
|
||||
DEFINE_DRM_GEM_FOPS(fops);
|
||||
static void msm_fop_show_fdinfo(struct seq_file *m, struct file *f)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static const struct file_operations fops = {
|
||||
.owner = THIS_MODULE,
|
||||
DRM_GEM_FOPS,
|
||||
.show_fdinfo = msm_fop_show_fdinfo,
|
||||
};
|
||||
|
||||
static const struct drm_driver msm_driver = {
|
||||
.driver_features = DRIVER_GEM |
|
||||
|
@ -61,16 +61,6 @@ enum msm_dp_controller {
|
||||
#define MSM_GPU_MAX_RINGS 4
|
||||
#define MAX_H_TILES_PER_DISPLAY 2
|
||||
|
||||
/**
|
||||
* enum msm_display_caps - features/capabilities supported by displays
|
||||
* @MSM_DISPLAY_CAP_VID_MODE: Video or "active" mode supported
|
||||
* @MSM_DISPLAY_CAP_CMD_MODE: Command mode supported
|
||||
*/
|
||||
enum msm_display_caps {
|
||||
MSM_DISPLAY_CAP_VID_MODE = BIT(0),
|
||||
MSM_DISPLAY_CAP_CMD_MODE = BIT(1),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum msm_event_wait - type of HW events to wait for
|
||||
* @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
|
||||
@ -234,6 +224,7 @@ void msm_crtc_disable_vblank(struct drm_crtc *crtc);
|
||||
int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
|
||||
void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu);
|
||||
|
||||
struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev);
|
||||
bool msm_use_mmu(struct drm_device *dev);
|
||||
|
||||
int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
|
@ -28,6 +28,14 @@ msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr,
|
||||
fctx->fenceptr = fenceptr;
|
||||
spin_lock_init(&fctx->spinlock);
|
||||
|
||||
/*
|
||||
* Start out close to the 32b fence rollover point, so we can
|
||||
* catch bugs with fence comparisons.
|
||||
*/
|
||||
fctx->last_fence = 0xffffff00;
|
||||
fctx->completed_fence = fctx->last_fence;
|
||||
*fctx->fenceptr = fctx->last_fence;
|
||||
|
||||
return fctx;
|
||||
}
|
||||
|
||||
@ -52,7 +60,8 @@ void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fctx->spinlock, flags);
|
||||
fctx->completed_fence = max(fence, fctx->completed_fence);
|
||||
if (fence_after(fence, fctx->completed_fence))
|
||||
fctx->completed_fence = fence;
|
||||
spin_unlock_irqrestore(&fctx->spinlock, flags);
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
|
||||
/* For non-cached buffers, ensure the new pages are clean
|
||||
* because display controller, GPU, etc. are not coherent:
|
||||
*/
|
||||
if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
|
||||
if (msm_obj->flags & MSM_BO_WC)
|
||||
sync_for_device(msm_obj);
|
||||
|
||||
update_inactive(msm_obj);
|
||||
@ -160,7 +160,7 @@ static void put_pages(struct drm_gem_object *obj)
|
||||
* pages are clean because display controller,
|
||||
* GPU, etc. are not coherent:
|
||||
*/
|
||||
if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
|
||||
if (msm_obj->flags & MSM_BO_WC)
|
||||
sync_for_cpu(msm_obj);
|
||||
|
||||
sg_free_table(msm_obj->sgt);
|
||||
@ -213,7 +213,7 @@ void msm_gem_put_pages(struct drm_gem_object *obj)
|
||||
|
||||
static pgprot_t msm_gem_pgprot(struct msm_gem_object *msm_obj, pgprot_t prot)
|
||||
{
|
||||
if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
|
||||
if (msm_obj->flags & MSM_BO_WC)
|
||||
return pgprot_writecombine(prot);
|
||||
return prot;
|
||||
}
|
||||
@ -259,7 +259,8 @@ static vm_fault_t msm_gem_fault(struct vm_fault *vmf)
|
||||
VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address,
|
||||
pfn, pfn << PAGE_SHIFT);
|
||||
|
||||
ret = vmf_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV));
|
||||
ret = vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
|
||||
out_unlock:
|
||||
msm_gem_unlock(obj);
|
||||
out:
|
||||
@ -1004,7 +1005,7 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
|
||||
#endif
|
||||
|
||||
/* don't call directly! Use drm_gem_object_put() */
|
||||
void msm_gem_free_object(struct drm_gem_object *obj)
|
||||
static void msm_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||
struct drm_device *dev = obj->dev;
|
||||
@ -1020,8 +1021,6 @@ void msm_gem_free_object(struct drm_gem_object *obj)
|
||||
list_del(&msm_obj->mm_list);
|
||||
mutex_unlock(&priv->mm_lock);
|
||||
|
||||
msm_gem_lock(obj);
|
||||
|
||||
/* object should not be on active list: */
|
||||
GEM_WARN_ON(is_active(msm_obj));
|
||||
|
||||
@ -1037,17 +1036,11 @@ void msm_gem_free_object(struct drm_gem_object *obj)
|
||||
|
||||
put_iova_vmas(obj);
|
||||
|
||||
/* dma_buf_detach() grabs resv lock, so we need to unlock
|
||||
* prior to drm_prime_gem_destroy
|
||||
*/
|
||||
msm_gem_unlock(obj);
|
||||
|
||||
drm_prime_gem_destroy(obj, msm_obj->sgt);
|
||||
} else {
|
||||
msm_gem_vunmap(obj);
|
||||
put_pages(obj);
|
||||
put_iova_vmas(obj);
|
||||
msm_gem_unlock(obj);
|
||||
}
|
||||
|
||||
drm_gem_object_release(obj);
|
||||
@ -1059,7 +1052,7 @@ static int msm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
|
||||
{
|
||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||
|
||||
vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
|
||||
vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
|
||||
vma->vm_page_prot = msm_gem_pgprot(msm_obj, vm_get_page_prot(vma->vm_flags));
|
||||
|
||||
return 0;
|
||||
@ -1114,7 +1107,6 @@ static int msm_gem_new_impl(struct drm_device *dev,
|
||||
struct msm_gem_object *msm_obj;
|
||||
|
||||
switch (flags & MSM_BO_CACHE_MASK) {
|
||||
case MSM_BO_UNCACHED:
|
||||
case MSM_BO_CACHED:
|
||||
case MSM_BO_WC:
|
||||
break;
|
||||
|
@ -175,7 +175,6 @@ void msm_gem_active_get(struct drm_gem_object *obj, struct msm_gpu *gpu);
|
||||
void msm_gem_active_put(struct drm_gem_object *obj);
|
||||
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout);
|
||||
int msm_gem_cpu_fini(struct drm_gem_object *obj);
|
||||
void msm_gem_free_object(struct drm_gem_object *obj);
|
||||
int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
|
||||
uint32_t size, uint32_t flags, uint32_t *handle, char *name);
|
||||
struct drm_gem_object *msm_gem_new(struct drm_device *dev,
|
||||
@ -230,7 +229,19 @@ msm_gem_unlock(struct drm_gem_object *obj)
|
||||
static inline bool
|
||||
msm_gem_is_locked(struct drm_gem_object *obj)
|
||||
{
|
||||
return dma_resv_is_locked(obj->resv);
|
||||
/*
|
||||
* Destroying the object is a special case.. msm_gem_free_object()
|
||||
* calls many things that WARN_ON if the obj lock is not held. But
|
||||
* acquiring the obj lock in msm_gem_free_object() can cause a
|
||||
* locking order inversion between reservation_ww_class_mutex and
|
||||
* fs_reclaim.
|
||||
*
|
||||
* This deadlock is not actually possible, because no one should
|
||||
* be already holding the lock when msm_gem_free_object() is called.
|
||||
* Unfortunately lockdep is not aware of this detail. So when the
|
||||
* refcount drops to zero, we pretend it is already locked.
|
||||
*/
|
||||
return dma_resv_is_locked(obj->resv) || (kref_read(&obj->refcount) == 0);
|
||||
}
|
||||
|
||||
static inline bool is_active(struct msm_gem_object *msm_obj)
|
||||
|
@ -15,7 +15,7 @@
|
||||
/* Default disabled for now until it has some more testing on the different
|
||||
* iommu combinations that can be paired with the driver:
|
||||
*/
|
||||
bool enable_eviction = false;
|
||||
static bool enable_eviction = false;
|
||||
MODULE_PARM_DESC(enable_eviction, "Enable swappable GEM buffers");
|
||||
module_param(enable_eviction, bool, 0600);
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*/
|
||||
|
||||
#include "drm/drm_drv.h"
|
||||
|
||||
#include "msm_gpu.h"
|
||||
#include "msm_gem.h"
|
||||
#include "msm_mmu.h"
|
||||
@ -146,6 +148,16 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int msm_gpu_hw_init(struct msm_gpu *gpu)
|
||||
{
|
||||
int ret;
|
||||
@ -209,7 +221,7 @@ static void msm_gpu_devcoredump_free(void *data)
|
||||
}
|
||||
|
||||
static void msm_gpu_crashstate_get_bo(struct msm_gpu_state *state,
|
||||
struct msm_gem_object *obj, u64 iova, u32 flags)
|
||||
struct msm_gem_object *obj, u64 iova, bool full)
|
||||
{
|
||||
struct msm_gpu_state_bo *state_bo = &state->bos[state->nr_bos];
|
||||
|
||||
@ -217,8 +229,11 @@ static void msm_gpu_crashstate_get_bo(struct msm_gpu_state *state,
|
||||
state_bo->size = obj->base.size;
|
||||
state_bo->iova = iova;
|
||||
|
||||
/* Only store data for non imported buffer objects marked for read */
|
||||
if ((flags & MSM_SUBMIT_BO_READ) && !obj->base.import_attach) {
|
||||
BUILD_BUG_ON(sizeof(state_bo->name) != sizeof(obj->name));
|
||||
|
||||
memcpy(state_bo->name, obj->name, sizeof(state_bo->name));
|
||||
|
||||
if (full) {
|
||||
void *ptr;
|
||||
|
||||
state_bo->data = kvmalloc(obj->base.size, GFP_KERNEL);
|
||||
@ -264,34 +279,15 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu,
|
||||
state->fault_info = gpu->fault_info;
|
||||
|
||||
if (submit) {
|
||||
int i, nr = 0;
|
||||
int i;
|
||||
|
||||
/* count # of buffers to dump: */
|
||||
for (i = 0; i < submit->nr_bos; i++)
|
||||
if (should_dump(submit, i))
|
||||
nr++;
|
||||
/* always dump cmd bo's, but don't double count them: */
|
||||
for (i = 0; i < submit->nr_cmds; i++)
|
||||
if (!should_dump(submit, submit->cmd[i].idx))
|
||||
nr++;
|
||||
|
||||
state->bos = kcalloc(nr,
|
||||
state->bos = kcalloc(submit->nr_bos,
|
||||
sizeof(struct msm_gpu_state_bo), GFP_KERNEL);
|
||||
|
||||
for (i = 0; state->bos && i < submit->nr_bos; i++) {
|
||||
if (should_dump(submit, i)) {
|
||||
msm_gpu_crashstate_get_bo(state, submit->bos[i].obj,
|
||||
submit->bos[i].iova, submit->bos[i].flags);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; state->bos && i < submit->nr_cmds; i++) {
|
||||
int idx = submit->cmd[i].idx;
|
||||
|
||||
if (!should_dump(submit, submit->cmd[i].idx)) {
|
||||
msm_gpu_crashstate_get_bo(state, submit->bos[idx].obj,
|
||||
submit->bos[idx].iova, submit->bos[idx].flags);
|
||||
}
|
||||
msm_gpu_crashstate_get_bo(state, submit->bos[i].obj,
|
||||
submit->bos[i].iova,
|
||||
should_dump(submit, i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -634,7 +630,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_ringbuffer *ring,
|
||||
{
|
||||
int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT;
|
||||
volatile struct msm_gpu_submit_stats *stats;
|
||||
u64 elapsed, clock = 0;
|
||||
u64 elapsed, clock = 0, cycles;
|
||||
unsigned long flags;
|
||||
|
||||
stats = &ring->memptrs->stats[index];
|
||||
@ -642,12 +638,17 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_ringbuffer *ring,
|
||||
elapsed = (stats->alwayson_end - stats->alwayson_start) * 10000;
|
||||
do_div(elapsed, 192);
|
||||
|
||||
cycles = stats->cpcycles_end - stats->cpcycles_start;
|
||||
|
||||
/* Calculate the clock frequency from the number of CP cycles */
|
||||
if (elapsed) {
|
||||
clock = (stats->cpcycles_end - stats->cpcycles_start) * 1000;
|
||||
clock = cycles * 1000;
|
||||
do_div(clock, elapsed);
|
||||
}
|
||||
|
||||
submit->queue->ctx->elapsed_ns += elapsed;
|
||||
submit->queue->ctx->cycles += cycles;
|
||||
|
||||
trace_msm_gpu_submit_retired(submit, elapsed, clock,
|
||||
stats->alwayson_start, stats->alwayson_end);
|
||||
|
||||
@ -917,7 +918,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
|
||||
|
||||
memptrs = msm_gem_kernel_new(drm,
|
||||
sizeof(struct msm_rbmemptrs) * nr_rings,
|
||||
check_apriv(gpu, MSM_BO_UNCACHED), gpu->aspace, &gpu->memptrs_bo,
|
||||
check_apriv(gpu, MSM_BO_WC), gpu->aspace, &gpu->memptrs_bo,
|
||||
&memptrs_iova);
|
||||
|
||||
if (IS_ERR(memptrs)) {
|
||||
|
@ -64,11 +64,14 @@ struct msm_gpu_funcs {
|
||||
/* for generation specific debugfs: */
|
||||
void (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor);
|
||||
#endif
|
||||
/* note: gpu_busy() can assume that we have been pm_resumed */
|
||||
u64 (*gpu_busy)(struct msm_gpu *gpu, unsigned long *out_sample_rate);
|
||||
struct msm_gpu_state *(*gpu_state_get)(struct msm_gpu *gpu);
|
||||
int (*gpu_state_put)(struct msm_gpu_state *state);
|
||||
unsigned long (*gpu_get_freq)(struct msm_gpu *gpu);
|
||||
void (*gpu_set_freq)(struct msm_gpu *gpu, struct dev_pm_opp *opp);
|
||||
/* note: gpu_set_freq() can assume that we have been pm_resumed */
|
||||
void (*gpu_set_freq)(struct msm_gpu *gpu, struct dev_pm_opp *opp,
|
||||
bool suspended);
|
||||
struct msm_gem_address_space *(*create_address_space)
|
||||
(struct msm_gpu *gpu, struct platform_device *pdev);
|
||||
struct msm_gem_address_space *(*create_private_address_space)
|
||||
@ -92,6 +95,9 @@ struct msm_gpu_devfreq {
|
||||
/** devfreq: devfreq instance */
|
||||
struct devfreq *devfreq;
|
||||
|
||||
/** lock: lock for "suspended", "busy_cycles", and "time" */
|
||||
struct mutex lock;
|
||||
|
||||
/**
|
||||
* idle_constraint:
|
||||
*
|
||||
@ -135,6 +141,9 @@ struct msm_gpu_devfreq {
|
||||
* elapsed
|
||||
*/
|
||||
struct msm_hrtimer_work boost_work;
|
||||
|
||||
/** suspended: tracks if we're suspended */
|
||||
bool suspended;
|
||||
};
|
||||
|
||||
struct msm_gpu {
|
||||
@ -361,6 +370,22 @@ struct msm_file_private {
|
||||
/** cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE */
|
||||
char *cmdline;
|
||||
|
||||
/**
|
||||
* elapsed:
|
||||
*
|
||||
* The total (cumulative) elapsed time GPU was busy with rendering
|
||||
* from this context in ns.
|
||||
*/
|
||||
uint64_t elapsed_ns;
|
||||
|
||||
/**
|
||||
* cycles:
|
||||
*
|
||||
* The total (cumulative) GPU cycles elapsed attributed to this
|
||||
* context.
|
||||
*/
|
||||
uint64_t cycles;
|
||||
|
||||
/**
|
||||
* entities:
|
||||
*
|
||||
@ -464,6 +489,7 @@ struct msm_gpu_state_bo {
|
||||
size_t size;
|
||||
void *data;
|
||||
bool encoded;
|
||||
char name[32];
|
||||
};
|
||||
|
||||
struct msm_gpu_state {
|
||||
@ -544,6 +570,9 @@ static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)
|
||||
int msm_gpu_pm_suspend(struct msm_gpu *gpu);
|
||||
int msm_gpu_pm_resume(struct msm_gpu *gpu);
|
||||
|
||||
void msm_gpu_show_fdinfo(struct msm_gpu *gpu, struct msm_file_private *ctx,
|
||||
struct drm_printer *p);
|
||||
|
||||
int msm_submitqueue_init(struct drm_device *drm, struct msm_file_private *ctx);
|
||||
struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_file_private *ctx,
|
||||
u32 id);
|
||||
|
@ -20,6 +20,7 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq,
|
||||
u32 flags)
|
||||
{
|
||||
struct msm_gpu *gpu = dev_to_gpu(dev);
|
||||
struct msm_gpu_devfreq *df = &gpu->devfreq;
|
||||
struct dev_pm_opp *opp;
|
||||
|
||||
/*
|
||||
@ -32,10 +33,13 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq,
|
||||
|
||||
trace_msm_gpu_freq_change(dev_pm_opp_get_freq(opp));
|
||||
|
||||
if (gpu->funcs->gpu_set_freq)
|
||||
gpu->funcs->gpu_set_freq(gpu, opp);
|
||||
else
|
||||
if (gpu->funcs->gpu_set_freq) {
|
||||
mutex_lock(&df->lock);
|
||||
gpu->funcs->gpu_set_freq(gpu, opp, df->suspended);
|
||||
mutex_unlock(&df->lock);
|
||||
} else {
|
||||
clk_set_rate(gpu->core_clk, *freq);
|
||||
}
|
||||
|
||||
dev_pm_opp_put(opp);
|
||||
|
||||
@ -58,18 +62,27 @@ static void get_raw_dev_status(struct msm_gpu *gpu,
|
||||
unsigned long sample_rate;
|
||||
ktime_t time;
|
||||
|
||||
mutex_lock(&df->lock);
|
||||
|
||||
status->current_frequency = get_freq(gpu);
|
||||
busy_cycles = gpu->funcs->gpu_busy(gpu, &sample_rate);
|
||||
time = ktime_get();
|
||||
|
||||
busy_time = busy_cycles - df->busy_cycles;
|
||||
status->total_time = ktime_us_delta(time, df->time);
|
||||
|
||||
df->busy_cycles = busy_cycles;
|
||||
df->time = time;
|
||||
|
||||
if (df->suspended) {
|
||||
mutex_unlock(&df->lock);
|
||||
status->busy_time = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
busy_cycles = gpu->funcs->gpu_busy(gpu, &sample_rate);
|
||||
busy_time = busy_cycles - df->busy_cycles;
|
||||
df->busy_cycles = busy_cycles;
|
||||
|
||||
mutex_unlock(&df->lock);
|
||||
|
||||
busy_time *= USEC_PER_SEC;
|
||||
do_div(busy_time, sample_rate);
|
||||
busy_time = div64_ul(busy_time, sample_rate);
|
||||
if (WARN_ON(busy_time > ~0LU))
|
||||
busy_time = ~0LU;
|
||||
|
||||
@ -175,6 +188,8 @@ void msm_devfreq_init(struct msm_gpu *gpu)
|
||||
if (!gpu->funcs->gpu_busy)
|
||||
return;
|
||||
|
||||
mutex_init(&df->lock);
|
||||
|
||||
dev_pm_qos_add_request(&gpu->pdev->dev, &df->idle_freq,
|
||||
DEV_PM_QOS_MAX_FREQUENCY,
|
||||
PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
|
||||
@ -244,12 +259,16 @@ void msm_devfreq_cleanup(struct msm_gpu *gpu)
|
||||
void msm_devfreq_resume(struct msm_gpu *gpu)
|
||||
{
|
||||
struct msm_gpu_devfreq *df = &gpu->devfreq;
|
||||
unsigned long sample_rate;
|
||||
|
||||
if (!has_devfreq(gpu))
|
||||
return;
|
||||
|
||||
df->busy_cycles = 0;
|
||||
mutex_lock(&df->lock);
|
||||
df->busy_cycles = gpu->funcs->gpu_busy(gpu, &sample_rate);
|
||||
df->time = ktime_get();
|
||||
df->suspended = false;
|
||||
mutex_unlock(&df->lock);
|
||||
|
||||
devfreq_resume_device(df->devfreq);
|
||||
}
|
||||
@ -261,6 +280,10 @@ void msm_devfreq_suspend(struct msm_gpu *gpu)
|
||||
if (!has_devfreq(gpu))
|
||||
return;
|
||||
|
||||
mutex_lock(&df->lock);
|
||||
df->suspended = true;
|
||||
mutex_unlock(&df->lock);
|
||||
|
||||
devfreq_suspend_device(df->devfreq);
|
||||
|
||||
cancel_idle_work(df);
|
||||
|
@ -314,6 +314,23 @@ struct drm_gem_object {
|
||||
const struct drm_gem_object_funcs *funcs;
|
||||
};
|
||||
|
||||
/**
|
||||
* DRM_GEM_FOPS - Default drm GEM file operations
|
||||
*
|
||||
* This macro provides a shorthand for setting the GEM file ops in the
|
||||
* &file_operations structure. If all you need are the default ops, use
|
||||
* DEFINE_DRM_GEM_FOPS instead.
|
||||
*/
|
||||
#define DRM_GEM_FOPS \
|
||||
.open = drm_open,\
|
||||
.release = drm_release,\
|
||||
.unlocked_ioctl = drm_ioctl,\
|
||||
.compat_ioctl = drm_compat_ioctl,\
|
||||
.poll = drm_poll,\
|
||||
.read = drm_read,\
|
||||
.llseek = noop_llseek,\
|
||||
.mmap = drm_gem_mmap
|
||||
|
||||
/**
|
||||
* DEFINE_DRM_GEM_FOPS() - macro to generate file operations for GEM drivers
|
||||
* @name: name for the generated structure
|
||||
@ -330,14 +347,7 @@ struct drm_gem_object {
|
||||
#define DEFINE_DRM_GEM_FOPS(name) \
|
||||
static const struct file_operations name = {\
|
||||
.owner = THIS_MODULE,\
|
||||
.open = drm_open,\
|
||||
.release = drm_release,\
|
||||
.unlocked_ioctl = drm_ioctl,\
|
||||
.compat_ioctl = drm_compat_ioctl,\
|
||||
.poll = drm_poll,\
|
||||
.read = drm_read,\
|
||||
.llseek = noop_llseek,\
|
||||
.mmap = drm_gem_mmap,\
|
||||
DRM_GEM_FOPS,\
|
||||
}
|
||||
|
||||
void drm_gem_object_release(struct drm_gem_object *obj);
|
||||
|
Loading…
Reference in New Issue
Block a user