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:
Dave Airlie 2022-07-13 10:55:52 +10:00
commit d9e019bb39
87 changed files with 1758 additions and 1460 deletions

View file

@ -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>;

View file

@ -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>;
};
};

View 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>;
};
};
};
};
...

View 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>;
};

View 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>;
};

View file

@ -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
===============================

View file

@ -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 \

View file

@ -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;
}

View file

@ -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;

View file

@ -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) \

View file

@ -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);

View file

@ -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,

View file

@ -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))

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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];
}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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];
}

View file

@ -5,8 +5,6 @@
#ifndef _DPU_HW_DSPP_H
#define _DPU_HW_DSPP_H
#include "dpu_hw_blk.h"
struct dpu_hw_dspp;
/**

View file

@ -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;

View file

@ -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

View file

@ -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,

View file

@ -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 {

View file

@ -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;

View file

@ -8,7 +8,6 @@
#include "dpu_hw_mdss.h"
#include "dpu_hw_util.h"
#include "dpu_hw_blk.h"
struct dpu_hw_mixer;

View file

@ -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];
}

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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);
/**

View file

@ -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];
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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 */

View file

@ -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];
}

View file

@ -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];
}
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);
/**

View file

@ -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 @@ static int mdp4_kms_init(struct drm_device *dev)
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,

View file

@ -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);

View file

@ -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 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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);

View file

@ -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) {

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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
*

View file

@ -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)

View file

@ -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;

View file

@ -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 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
.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 },
{}
};

View file

@ -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 {

View file

@ -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,

View file

@ -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 {

View file

@ -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),
};

View file

@ -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 |

View file

@ -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,

View file

@ -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);
}

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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)) {

View file

@ -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);

View file

@ -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);

View file

@ -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);