Commit 1ff1da40 authored by Dmitry Baryshkov's avatar Dmitry Baryshkov

Merge branches 'msm-next-lumag-core', 'msm-next-lumag-dpu',...

Merge branches 'msm-next-lumag-core', 'msm-next-lumag-dpu', 'msm-next-lumag-dp', 'msm-next-lumag-dsi', 'msm-next-lumag-hdmi', 'msm-next-lumag-mdp5' and 'msm-next-lumag-mdp4' into msm-next-lumag

Changes in this merge:
Core:
- client utilization via fdinfo support
- fix fence rollover issue

DPU:
- constification of HW catalog
- support for using encoder as CRC source
- WB support on sc7180
- WB resolution fixes
- enable DSPP support for sc7280

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: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
......@@ -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>;
......
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>;
};
};
# 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>;
};
};
};
};
...
# 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>;
};
# 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>;
};
......@@ -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 \
......
......@@ -53,7 +53,7 @@ static u64 _dpu_core_perf_calc_bw(struct dpu_kms *kms,
crtc_plane_bw += pstate->plane_fetch_bw;
}
bw_factor = kms->catalog->perf.bw_inefficiency_factor;
bw_factor = kms->catalog->perf->bw_inefficiency_factor;
if (bw_factor) {
crtc_plane_bw *= bw_factor;
do_div(crtc_plane_bw, 100);
......@@ -90,7 +90,7 @@ static u64 _dpu_core_perf_calc_clk(struct dpu_kms *kms,
crtc_clk = max(pstate->plane_clk, crtc_clk);
}
clk_factor = kms->catalog->perf.clk_inefficiency_factor;
clk_factor = kms->catalog->perf->clk_inefficiency_factor;
if (clk_factor) {
crtc_clk *= clk_factor;
do_div(crtc_clk, 100);
......@@ -128,7 +128,7 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
perf->core_clk_rate = kms->perf.fix_core_clk_rate;
} else {
perf->bw_ctl = _dpu_core_perf_calc_bw(kms, crtc);
perf->max_per_pipe_ib = kms->catalog->perf.min_dram_ib;
perf->max_per_pipe_ib = kms->catalog->perf->min_dram_ib;
perf->core_clk_rate = _dpu_core_perf_calc_clk(kms, crtc, state);
}
......@@ -189,7 +189,7 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000);
DRM_DEBUG_ATOMIC("calculated bandwidth=%uk\n", bw);
threshold = kms->catalog->perf.max_bw_high;
threshold = kms->catalog->perf->max_bw_high;
DRM_DEBUG_ATOMIC("final threshold bw limit = %d\n", threshold);
......@@ -413,7 +413,7 @@ static ssize_t _dpu_core_perf_mode_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
struct dpu_core_perf *perf = file->private_data;
struct dpu_perf_cfg *cfg = &perf->catalog->perf;
const struct dpu_perf_cfg *cfg = perf->catalog->perf;
u32 perf_mode = 0;
int ret;
......@@ -468,7 +468,7 @@ static const struct file_operations dpu_core_perf_mode_fops = {
int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent)
{
struct dpu_core_perf *perf = &dpu_kms->perf;
struct dpu_mdss_cfg *catalog = perf->catalog;
const struct dpu_mdss_cfg *catalog = perf->catalog;
struct dentry *entry;
entry = debugfs_create_dir("core_perf", parent);
......@@ -480,15 +480,15 @@ int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent)
debugfs_create_u32("enable_bw_release", 0600, entry,
(u32 *)&perf->enable_bw_release);
debugfs_create_u32("threshold_low", 0600, entry,
(u32 *)&catalog->perf.max_bw_low);
(u32 *)&catalog->perf->max_bw_low);
debugfs_create_u32("threshold_high", 0600, entry,
(u32 *)&catalog->perf.max_bw_high);
(u32 *)&catalog->perf->max_bw_high);
debugfs_create_u32("min_core_ib", 0600, entry,
(u32 *)&catalog->perf.min_core_ib);
(u32 *)&catalog->perf->min_core_ib);
debugfs_create_u32("min_llcc_ib", 0600, entry,
(u32 *)&catalog->perf.min_llcc_ib);
(u32 *)&catalog->perf->min_llcc_ib);
debugfs_create_u32("min_dram_ib", 0600, entry,
(u32 *)&catalog->perf.min_dram_ib);
(u32 *)&catalog->perf->min_dram_ib);
debugfs_create_file("perf_mode", 0600, entry,
(u32 *)perf, &dpu_core_perf_mode_fops);
debugfs_create_u64("fix_core_clk_rate", 0600, entry,
......@@ -517,7 +517,7 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf)
int dpu_core_perf_init(struct dpu_core_perf *perf,
struct drm_device *dev,
struct dpu_mdss_cfg *catalog,
const struct dpu_mdss_cfg *catalog,
struct clk *core_clk)
{
perf->dev = dev;
......
......@@ -68,7 +68,7 @@ struct dpu_core_perf_tune {
struct dpu_core_perf {
struct drm_device *dev;
struct dentry *debugfs_root;
struct dpu_mdss_cfg *catalog;
const struct dpu_mdss_cfg *catalog;
struct clk *core_clk;
u64 core_clk_rate;
u64 max_core_clk_rate;
......@@ -119,7 +119,7 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf);
*/
int dpu_core_perf_init(struct dpu_core_perf *perf,
struct drm_device *dev,
struct dpu_mdss_cfg *catalog,
const struct dpu_mdss_cfg *catalog,
struct clk *core_clk);
struct dpu_kms;
......
// 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>
......@@ -78,6 +79,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;
}
......@@ -93,23 +96,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);
......@@ -146,16 +180,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);
......@@ -174,26 +204,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];
......@@ -214,6 +235,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,
......
/* 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>
......@@ -73,11 +74,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 +204,8 @@ struct dpu_crtc {
* @mixers : List of active mixers
* @num_ctls : Number of ctl paths in use
* @hw_ctls : List of active ctl paths
* @crc_source : CRC source
* @crc_frame_skip_count: Number of frames skipped before getting CRC
*/
struct dpu_crtc_state {
struct drm_crtc_state base;
......
......@@ -225,6 +225,70 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
return dpu_enc->wide_bus_en;
}
int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc)
{
struct dpu_encoder_virt *dpu_enc;
int i, num_intf = 0;
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (phys->hw_intf && phys->hw_intf->ops.setup_misr
&& phys->hw_intf->ops.collect_misr)
num_intf++;
}
return num_intf;
}
void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc)
{
struct dpu_encoder_virt *dpu_enc;
int i;
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (!phys->hw_intf || !phys->hw_intf->ops.setup_misr)
continue;
phys->hw_intf->ops.setup_misr(phys->hw_intf, true, 1);
}
}
int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos)
{
struct dpu_encoder_virt *dpu_enc;
int i, rc = 0, entries_added = 0;
if (!drm_enc->crtc) {
DRM_ERROR("no crtc found for encoder %d\n", drm_enc->index);
return -EINVAL;
}
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (!phys->hw_intf || !phys->hw_intf->ops.collect_misr)
continue;
rc = phys->hw_intf->ops.collect_misr(phys->hw_intf, &crcs[pos + entries_added]);
if (rc)
return rc;
entries_added++;
}
return entries_added;
}
static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned bpc)
{
struct dpu_hw_dither_cfg dither_cfg = { 0 };
......@@ -634,7 +698,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
}
if (hw_mdptop->ops.setup_vsync_source &&
disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
disp_info->is_cmd_mode) {
for (i = 0; i < dpu_enc->num_phys_encs; i++)
vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx;
......@@ -718,8 +782,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
}
dpu_enc = to_dpu_encoder_virt(drm_enc);
priv = drm_enc->dev->dev_private;
is_vid_mode = dpu_enc->disp_info.capabilities &
MSM_DISPLAY_CAP_VID_MODE;
is_vid_mode = !dpu_enc->disp_info.is_cmd_mode;
/*
* when idle_pc is not supported, process only KICKOFF, STOP and MODESET
......@@ -1048,24 +1111,6 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
phys->hw_pp = dpu_enc->hw_pp[i];
phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
if (phys->wb_idx >= WB_0 && phys->wb_idx < WB_MAX)
phys->hw_wb = dpu_rm_get_wb(&dpu_kms->rm, phys->wb_idx);
if (!phys->hw_intf && !phys->hw_wb) {
DPU_ERROR_ENC(dpu_enc,
"no intf or wb block assigned at idx: %d\n", i);
return;
}
if (phys->hw_intf && phys->hw_wb) {
DPU_ERROR_ENC(dpu_enc,
"invalid phys both intf and wb block at idx: %d\n", i);
return;
}
phys->cached_mode = crtc_state->adjusted_mode;
if (phys->ops.atomic_mode_set)
phys->ops.atomic_mode_set(phys, crtc_state, conn_state);
......@@ -1205,37 +1250,37 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
mutex_unlock(&dpu_enc->enc_lock);
}
static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
static enum dpu_intf dpu_encoder_get_intf(const struct dpu_mdss_cfg *catalog,
enum dpu_intf_type type, u32 controller_id)
{
int i = 0;
if (type != INTF_WB) {
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",
if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
enc = dpu_encoder_phys_wb_init(params);
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);
return 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) {
} else if (disp_info->is_cmd_mode) {
enc = dpu_encoder_phys_cmd_init(params);
if (IS_ERR_OR_NULL(enc)) {
if (IS_ERR(enc)) {
DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n",
PTR_ERR(enc));
return enc == NULL ? -EINVAL : PTR_ERR(enc);
return 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);
} else {
enc = dpu_encoder_phys_vid_init(params);
if (IS_ERR_OR_NULL(enc)) {
DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
if (IS_ERR(enc)) {
DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n",
PTR_ERR(enc));
return enc == NULL ? -EINVAL : 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;
......
/* 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
......
......@@ -20,8 +20,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)
......@@ -103,8 +101,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");
......@@ -118,11 +116,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)
......@@ -166,7 +164,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);
......@@ -278,9 +276,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;
}
......
......@@ -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 */
......@@ -61,7 +61,6 @@ static const struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl,
b->base_off = addr;
b->blk_off = m->ctl[i].base;
b->length = m->ctl[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_CTL;
return &m->ctl[i];
}
......
......@@ -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)
{
......@@ -169,7 +169,6 @@ static struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc,
b->base_off = addr;
b->blk_off = m->dsc[i].base;
b->length = m->dsc[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_DSC;
return &m->dsc[i];
}
......@@ -187,7 +186,7 @@ static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops,
};
struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
struct dpu_mdss_cfg *m)
const struct dpu_mdss_cfg *m)
{
struct dpu_hw_dsc *c;
struct dpu_dsc_cfg *cfg;
......
......@@ -64,7 +64,7 @@ struct dpu_hw_dsc {
* Returns: Error code or allocated dpu_hw_dsc context
*/
struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
struct dpu_mdss_cfg *m);
const struct dpu_mdss_cfg *m);
/**
* dpu_hw_dsc_destroy - destroys dsc driver context
......
......@@ -83,7 +83,6 @@ static const struct dpu_dspp_cfg *_dspp_offset(enum dpu_dspp dspp,
b->base_off = addr;
b->blk_off = m->dspp[i].base;
b->length = m->dspp[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_DSPP;
return &m->dspp[i];
}
......
......@@ -398,16 +398,15 @@ 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;
}
struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr,
struct dpu_mdss_cfg *m)
const struct dpu_mdss_cfg *m)
{
struct dpu_hw_intr *intr;
int nirq = MDP_INTR_MAX * 32;
......
......@@ -67,7 +67,7 @@ struct dpu_hw_intr {
* @m : pointer to mdss catalog data
*/
struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr,
struct dpu_mdss_cfg *m);
const struct dpu_mdss_cfg *m);
/**
* dpu_hw_intr_destroy(): Cleanup interrutps hw object
......
// 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,
......@@ -80,7 +85,6 @@ static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
b->base_off = addr;
b->blk_off = m->intf[i].base;
b->length = m->intf[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_INTF;
return &m->intf[i];
}
......@@ -319,6 +323,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 +343,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,
......
/* 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
......@@ -57,6 +59,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 +81,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 {
......
// 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,
......@@ -46,7 +42,6 @@ static const struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer,
b->base_off = addr;
b->blk_off = m->mixer[i].base;
b->length = m->mixer[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_LM;
return &m->mixer[i];
}
......@@ -108,47 +103,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 +167,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;
......
......@@ -26,7 +26,6 @@ static const struct dpu_merge_3d_cfg *_merge_3d_offset(enum dpu_merge_3d idx,
b->base_off = addr;
b->blk_off = m->merge_3d[i].base;
b->length = m->merge_3d[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_PINGPONG;
return &m->merge_3d[i];
}
......
......@@ -54,7 +54,6 @@ static const struct dpu_pingpong_cfg *_pingpong_offset(enum dpu_pingpong pp,
b->base_off = addr;
b->blk_off = m->pingpong[i].base;
b->length = m->pingpong[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_PINGPONG;
return &m->pingpong[i];
}
......
......@@ -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;
......@@ -772,7 +772,6 @@ static const struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp,
b->base_off = addr;
b->blk_off = catalog->sspp[i].base;
b->length = catalog->sspp[i].len;
b->hwversion = catalog->hwversion;
b->log_mask = DPU_DBG_MASK_SSPP;
return &catalog->sspp[i];
}
......@@ -783,7 +782,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;
......
......@@ -360,7 +360,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 +381,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);
/**
......
......@@ -288,7 +288,6 @@ static const struct dpu_mdp_cfg *_top_offset(enum dpu_mdp mdp,
b->base_off = addr;
b->blk_off = m->mdp[i].base;
b->length = m->mdp[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_TOP;
return &m->mdp[i];
}
......
// 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__
......@@ -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;
}
/* 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,6 +13,11 @@
#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
......@@ -21,14 +27,12 @@
* @blk_off: pipe offset relative to mdss offset
* @length length of register block offset
* @xin_id xin id
* @hwversion mdss hw version number
*/
struct dpu_hw_blk_reg_map {
void __iomem *base_off;
u32 blk_off;
u32 length;
u32 xin_id;
u32 hwversion;
u32 log_mask;
};
......@@ -343,4 +347,14 @@ void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c,
u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
u32 total_fl);
void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c,
u32 misr_ctrl_offset,
bool enable,
u32 frame_count);
int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c,
u32 misr_ctrl_offset,
u32 misr_signature_offset,
u32 *misr_value);
#endif /* _DPU_HW_UTIL_H */
......@@ -30,7 +30,7 @@
#define VBIF_XIN_HALT_CTRL0 0x0200
#define VBIF_XIN_HALT_CTRL1 0x0204
#define VBIF_XINL_QOS_RP_REMAP_000 0x0550
#define VBIF_XINL_QOS_LVL_REMAP_000(v) (v < DPU_HW_VER_400 ? 0x570 : 0x0590)
#define VBIF_XINL_QOS_LVL_REMAP_000(vbif) (VBIF_XINL_QOS_RP_REMAP_000 + (vbif)->cap->qos_rp_remap_size)
static void dpu_hw_clear_errors(struct dpu_hw_vbif *vbif,
u32 *pnd_errors, u32 *src_errors)
......@@ -163,7 +163,7 @@ static void dpu_hw_set_qos_remap(struct dpu_hw_vbif *vbif,
c = &vbif->hw;
reg_lvl = VBIF_XINL_QOS_LVL_REMAP_000(c->hwversion);
reg_lvl = VBIF_XINL_QOS_LVL_REMAP_000(vbif);
reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8);
reg_shift = (xin_id & 0x7) * 4;
......@@ -223,7 +223,6 @@ static const struct dpu_vbif_cfg *_top_offset(enum dpu_vbif vbif,
b->base_off = addr;
b->blk_off = m->vbif[i].base;
b->length = m->vbif[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_VBIF;
return &m->vbif[i];
}
......
......@@ -63,7 +63,6 @@ static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb,
b->base_off = addr;
b->blk_off = m->wb[i].base;
b->length = m->wb[i].len;
b->hwversion = m->hwversion;
return &m->wb[i];
}
}
......
......@@ -582,9 +582,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]);
......@@ -637,7 +635,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) {
......@@ -745,7 +742,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;
......@@ -842,8 +839,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])
......@@ -905,7 +900,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);
......
......@@ -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;
......
......@@ -106,7 +106,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[] = {
......@@ -160,7 +160,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;
......@@ -309,7 +309,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,
......@@ -336,9 +336,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(
......@@ -346,14 +346,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];
}
}
......@@ -1225,7 +1225,7 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
cdp_cfg.enable = pdpu->catalog->perf.cdp_cfg
cdp_cfg.enable = pdpu->catalog->perf->cdp_cfg
[DPU_PERF_CDP_USAGE_RT].rd_enable;
cdp_cfg.ubwc_meta_enable =
DPU_FORMAT_IS_UBWC(fmt);
......
......@@ -95,7 +95,7 @@ int dpu_rm_destroy(struct dpu_rm *rm)
}
int dpu_rm_init(struct dpu_rm *rm,
struct dpu_mdss_cfg *cat,
const struct dpu_mdss_cfg *cat,
void __iomem *mmio)
{
int rc, i;
......
......@@ -42,7 +42,7 @@ struct dpu_rm {
* @Return: 0 on Success otherwise -ERROR
*/
int dpu_rm_init(struct dpu_rm *rm,
struct dpu_mdss_cfg *cat,
const struct dpu_mdss_cfg *cat,
void __iomem *mmio);
/**
......
......@@ -13,8 +13,6 @@
#include "msm_mmu.h"
#include "mdp4_kms.h"
static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev);
static int mdp4_hw_init(struct msm_kms *kms)
{
struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
......@@ -386,13 +384,17 @@ static void read_mdp_hw_revision(struct mdp4_kms *mdp4_kms,
static int mdp4_kms_init(struct drm_device *dev)
{
struct platform_device *pdev = to_platform_device(dev->dev);
struct mdp4_platform_config *config = mdp4_get_config(pdev);
struct msm_drm_private *priv = dev->dev_private;
struct mdp4_kms *mdp4_kms;
struct msm_kms *kms = NULL;
struct iommu_domain *iommu;
struct msm_gem_address_space *aspace;
int irq, ret;
u32 major, minor;
unsigned long max_clk;
/* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
max_clk = 266667000;
mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL);
if (!mdp4_kms) {
......@@ -460,7 +462,7 @@ static int mdp4_kms_init(struct drm_device *dev)
goto fail;
}
clk_set_rate(mdp4_kms->clk, config->max_clk);
clk_set_rate(mdp4_kms->clk, max_clk);
read_mdp_hw_revision(mdp4_kms, &major, &minor);
......@@ -480,7 +482,7 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = PTR_ERR(mdp4_kms->lut_clk);
goto fail;
}
clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
clk_set_rate(mdp4_kms->lut_clk, max_clk);
}
pm_runtime_enable(dev->dev);
......@@ -497,9 +499,9 @@ static int mdp4_kms_init(struct drm_device *dev)
mdp4_disable(mdp4_kms);
mdelay(16);
if (config->iommu) {
struct msm_mmu *mmu = msm_iommu_new(&pdev->dev,
config->iommu);
iommu = iommu_domain_alloc(pdev->dev.bus);
if (iommu) {
struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, iommu);
aspace = msm_gem_address_space_create(mmu,
"mdp4", 0x1000, 0x100000000 - 0x1000);
......@@ -553,17 +555,6 @@ 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,
......
......@@ -42,12 +42,6 @@ struct mdp4_kms {
};
#define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base)
/* platform config data (ie. from DT, or pdata) */
struct mdp4_platform_config {
struct iommu_domain *iommu;
uint32_t max_clk;
};
static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data)
{
msm_writel(data, mdp4_kms->mmio + reg);
......
......@@ -837,6 +837,11 @@ static const struct mdp5_cfg_hw msm8x53_config = {
[2] = INTF_DSI,
},
},
.perf = {
.ab_inefficiency = 100,
.ib_inefficiency = 200,
.clk_inefficiency = 105
},
.max_clk = 400000000,
};
......
// 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;
}
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved.
*/
#ifndef __DP_CLK_UTIL_H__
#define __DP_CLK_UTIL_H__
#include <linux/platform_device.h>
#include <linux/types.h>
#define DEV_DBG(fmt, args...) pr_debug(fmt, ##args)
#define DEV_INFO(fmt, args...) pr_info(fmt, ##args)
#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args)
#define DEV_ERR(fmt, args...) pr_err(fmt, ##args)
enum dss_clk_type {
DSS_CLK_AHB, /* no set rate. rate controlled through rpm */
DSS_CLK_PCLK,
};
struct dss_clk {
struct clk *clk; /* clk handle */
char clk_name[32];
enum dss_clk_type type;
unsigned long rate;
unsigned long max_rate;
};
struct dss_module_power {
unsigned int num_clk;
struct dss_clk *clk_config;
};
int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
#endif /* __DP_CLK_UTIL_H__ */
......@@ -1321,9 +1321,9 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
enum dp_pm_type module, char *name, unsigned long rate)
{
u32 num = ctrl->parser->mp[module].num_clk;
struct dss_clk *cfg = ctrl->parser->mp[module].clk_config;
struct clk_bulk_data *cfg = ctrl->parser->mp[module].clocks;
while (num && strcmp(cfg->clk_name, name)) {
while (num && strcmp(cfg->id, name)) {
num--;
cfg++;
}
......@@ -1332,7 +1332,7 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
rate, name);
if (num)
cfg->rate = rate;
clk_set_rate(cfg->clk, rate);
else
DRM_ERROR("%s clock doesn't exit to set rate %lu\n",
name, rate);
......@@ -1349,12 +1349,11 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
opts_dp->lanes = ctrl->link->link_params.num_lanes;
opts_dp->link_rate = ctrl->link->link_params.rate / 100;
opts_dp->ssc = drm_dp_max_downspread(dpcd);
dp_ctrl_set_clock_rate(ctrl, DP_CTRL_PM, "ctrl_link",
ctrl->link->link_params.rate * 1000);
phy_configure(phy, &dp_io->phy_opts);
phy_power_on(phy);
dev_pm_opp_set_rate(ctrl->dev, ctrl->link->link_params.rate * 1000);
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, true);
if (ret)
DRM_ERROR("Unable to start link clocks. ret=%d\n", ret);
......@@ -1462,6 +1461,7 @@ static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)
* link clock might have been adjusted as part of the
* link maintenance.
*/
dev_pm_opp_set_rate(ctrl->dev, 0);
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
if (ret) {
DRM_ERROR("Failed to disable clocks. ret=%d\n", ret);
......@@ -1493,6 +1493,7 @@ static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
dp_catalog_ctrl_reset(ctrl->catalog);
dev_pm_opp_set_rate(ctrl->dev, 0);
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
if (ret) {
DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
......@@ -1929,6 +1930,7 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
}
}
dev_pm_opp_set_rate(ctrl->dev, 0);
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
if (ret) {
DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
......@@ -1997,6 +1999,7 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
if (ret)
DRM_ERROR("Failed to disable pixel clocks. ret=%d\n", ret);
dev_pm_opp_set_rate(ctrl->dev, 0);
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
if (ret) {
DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
......
......@@ -131,35 +131,43 @@ struct msm_dp_config {
size_t num_descs;
};
static const struct msm_dp_config sc7180_dp_cfg = {
.descs = (const struct msm_dp_desc[]) {
static const struct msm_dp_desc sc7180_dp_descs[] = {
[MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
},
.num_descs = 1,
};
static const struct msm_dp_config sc7280_dp_cfg = {
.descs = (const struct msm_dp_desc[]) {
static const struct msm_dp_config sc7180_dp_cfg = {
.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 },
},
.num_descs = 2,
};
static const struct msm_dp_config sc8180x_dp_cfg = {
.descs = (const struct msm_dp_desc[]) {
static const struct msm_dp_config sc7280_dp_cfg = {
.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 },
},
.num_descs = 3,
};
static const struct msm_dp_config sm8350_dp_cfg = {
.descs = (const struct msm_dp_desc[]) {
static const struct msm_dp_config sc8180x_dp_cfg = {
.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 },
},
.num_descs = 1,
};
static const struct msm_dp_config sm8350_dp_cfg = {
.descs = sm8350_dp_descs,
.num_descs = ARRAY_SIZE(sm8350_dp_descs),
};
static const struct of_device_id dp_dt_match[] = {
......@@ -992,7 +1000,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;
......@@ -1624,8 +1632,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 +1647,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,
......
......@@ -15,7 +15,6 @@ struct msm_dp {
struct device *codec_dev;
struct drm_bridge *bridge;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_bridge *next_bridge;
bool is_connected;
bool audio_enabled;
......
......@@ -116,7 +116,7 @@ struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *
}
if (dp_display->next_bridge) {
rc = drm_bridge_attach(dp_display->encoder,
rc = drm_bridge_attach(encoder,
dp_display->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (rc < 0) {
......@@ -130,15 +130,15 @@ struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *
}
/* connector initialization */
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder)
{
struct drm_connector *connector = NULL;
connector = drm_bridge_connector_init(dp_display->drm_dev, dp_display->encoder);
connector = drm_bridge_connector_init(dp_display->drm_dev, encoder);
if (IS_ERR(connector))
return connector;
drm_connector_attach_encoder(connector, dp_display->encoder);
drm_connector_attach_encoder(connector, encoder);
return connector;
}
......@@ -19,7 +19,7 @@ struct msm_dp_bridge {
#define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display);
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder);
struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder);
......
......@@ -162,11 +162,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) {
......@@ -175,12 +175,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 */
......@@ -190,12 +190,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;
......@@ -234,29 +234,16 @@ static int dp_parser_clock(struct dp_parser *parser)
}
if (dp_parser_check_prefix("core", clk_name) &&
core_clk_index < core_clk_count) {
struct dss_clk *clk =
&core_power->clk_config[core_clk_index];
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
clk->type = DSS_CLK_AHB;
core_power->clocks[core_clk_index].id = devm_kstrdup(dev, clk_name, GFP_KERNEL);
core_clk_index++;
} else if (dp_parser_check_prefix("stream", clk_name) &&
stream_clk_index < stream_clk_count) {
struct dss_clk *clk =
&stream_power->clk_config[stream_clk_index];
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
clk->type = DSS_CLK_PCLK;
stream_power->clocks[stream_clk_index].id = devm_kstrdup(dev, clk_name, GFP_KERNEL);
stream_clk_index++;
} else if (dp_parser_check_prefix("ctrl", clk_name) &&
ctrl_clk_index < ctrl_clk_count) {
struct dss_clk *clk =
&ctrl_power->clk_config[ctrl_clk_index];
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
ctrl_power->clocks[ctrl_clk_index].id = devm_kstrdup(dev, clk_name, GFP_KERNEL);
ctrl_clk_index++;
if (dp_parser_check_prefix("ctrl_link", clk_name) ||
dp_parser_check_prefix("stream_pixel", clk_name))
clk->type = DSS_CLK_PCLK;
else
clk->type = DSS_CLK_AHB;
}
}
......
......@@ -10,7 +10,6 @@
#include <linux/phy/phy.h>
#include <linux/phy/phy-dp.h>
#include "dp_clk_util.h"
#include "msm_drv.h"
#define DP_LABEL "MDSS DP DISPLAY"
......@@ -106,6 +105,11 @@ struct dp_regulator_cfg {
struct dp_reg_entry regs[DP_DEV_REGULATOR_MAX];
};
struct dss_module_power {
unsigned int num_clk;
struct clk_bulk_data *clocks;
};
/**
* struct dp_parser - DP parser's data exposed to clients
*
......
......@@ -106,107 +106,30 @@ static int dp_power_clk_init(struct dp_power_private *power)
ctrl = &power->parser->mp[DP_CTRL_PM];
stream = &power->parser->mp[DP_STREAM_PM];
rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk);
rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
if (rc) {
DRM_ERROR("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_CORE_PM), rc);
return rc;
}
rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk);
rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
if (rc) {
DRM_ERROR("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_CTRL_PM), rc);
msm_dss_put_clk(core->clk_config, core->num_clk);
return -ENODEV;
}
rc = msm_dss_get_clk(dev, stream->clk_config, stream->num_clk);
rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
if (rc) {
DRM_ERROR("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_CTRL_PM), rc);
msm_dss_put_clk(core->clk_config, core->num_clk);
return -ENODEV;
}
return 0;
}
static int dp_power_clk_deinit(struct dp_power_private *power)
{
struct dss_module_power *core, *ctrl, *stream;
core = &power->parser->mp[DP_CORE_PM];
ctrl = &power->parser->mp[DP_CTRL_PM];
stream = &power->parser->mp[DP_STREAM_PM];
if (!core || !ctrl || !stream) {
DRM_ERROR("invalid power_data\n");
return -EINVAL;
}
msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
msm_dss_put_clk(core->clk_config, core->num_clk);
msm_dss_put_clk(stream->clk_config, stream->num_clk);
return 0;
}
static int dp_power_clk_set_link_rate(struct dp_power_private *power,
struct dss_clk *clk_arry, int num_clk, int enable)
{
u32 rate;
int i, rc = 0;
for (i = 0; i < num_clk; i++) {
if (clk_arry[i].clk) {
if (clk_arry[i].type == DSS_CLK_PCLK) {
if (enable)
rate = clk_arry[i].rate;
else
rate = 0;
rc = dev_pm_opp_set_rate(power->dev, rate);
if (rc)
break;
}
}
}
return rc;
}
static int dp_power_clk_set_rate(struct dp_power_private *power,
enum dp_pm_type module, bool enable)
{
int rc = 0;
struct dss_module_power *mp = &power->parser->mp[module];
if (module == DP_CTRL_PM) {
rc = dp_power_clk_set_link_rate(power, mp->clk_config, mp->num_clk, enable);
if (rc) {
DRM_ERROR("failed to set link clks rate\n");
return rc;
}
} else {
if (enable) {
rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
if (rc) {
DRM_ERROR("failed to set clks rate\n");
return rc;
}
}
}
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
if (rc) {
DRM_ERROR("failed to %d clks, err: %d\n", enable, rc);
return rc;
}
return 0;
}
int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
{
struct dp_power_private *power;
......@@ -234,6 +157,7 @@ int dp_power_clk_enable(struct dp_power *dp_power,
{
int rc = 0;
struct dp_power_private *power;
struct dss_module_power *mp;
power = container_of(dp_power, struct dp_power_private, dp_power);
......@@ -266,8 +190,9 @@ int dp_power_clk_enable(struct dp_power *dp_power,
if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
drm_dbg_dp(power->drm_dev,
"Enable core clks before link clks\n");
mp = &power->parser->mp[DP_CORE_PM];
rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable);
rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
if (rc) {
DRM_ERROR("fail to enable clks: %s. err=%d\n",
dp_parser_pm_name(DP_CORE_PM), rc);
......@@ -277,13 +202,16 @@ int dp_power_clk_enable(struct dp_power *dp_power,
}
}
rc = dp_power_clk_set_rate(power, pm_type, enable);
mp = &power->parser->mp[pm_type];
if (enable) {
rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
if (rc) {
DRM_ERROR("failed to '%s' clks for: %s. err=%d\n",
enable ? "enable" : "disable",
dp_parser_pm_name(pm_type), 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)
dp_power->core_clks_on = enable;
......@@ -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)
......
......@@ -1080,12 +1080,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,
......@@ -1478,32 +1498,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 =
......@@ -1520,7 +1514,7 @@ static void dsi_err_worker(struct work_struct *work)
pr_err_ratelimited("%s: status=%x\n", __func__, status);
if (status & DSI_ERR_STATE_MDP_FIFO_UNDERFLOW)
dsi_sw_reset_restore(msm_host);
dsi_sw_reset(msm_host);
/* It is safe to clear here because error irq is disabled. */
msm_host->err_work_state = 0;
......
......@@ -9,6 +9,7 @@
#include <linux/of_gpio.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_of.h>
#include <sound/hdmi-codec.h>
#include "hdmi.h"
......@@ -133,6 +134,10 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
hdmi->config = config;
spin_lock_init(&hdmi->reg_lock);
ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge);
if (ret && ret != -ENODEV)
goto fail;
hdmi->mmio = msm_ioremap(pdev, config->mmio_name);
if (IS_ERR(hdmi->mmio)) {
ret = PTR_ERR(hdmi->mmio);
......@@ -180,6 +185,9 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
goto fail;
}
for (i = 0; i < config->pwr_reg_cnt; i++)
hdmi->pwr_regs[i].supply = config->pwr_reg_names[i];
ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs);
if (ret) {
DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %d\n", ret);
......@@ -230,6 +238,20 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
hdmi->pwr_clks[i] = clk;
}
hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
/* This will catch e.g. -EPROBE_DEFER */
if (IS_ERR(hdmi->hpd_gpiod)) {
ret = PTR_ERR(hdmi->hpd_gpiod);
DRM_DEV_ERROR(&pdev->dev, "failed to get hpd gpio: (%d)\n", ret);
goto fail;
}
if (!hdmi->hpd_gpiod)
DBG("failed to get HPD gpio");
if (hdmi->hpd_gpiod)
gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD");
pm_runtime_enable(&pdev->dev);
hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
......@@ -291,6 +313,15 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
goto fail;
}
if (hdmi->next_bridge) {
ret = drm_bridge_attach(hdmi->encoder, hdmi->next_bridge, hdmi->bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to attach next HDMI bridge: %d\n", ret);
goto fail;
}
}
hdmi->connector = drm_bridge_connector_init(hdmi->dev, encoder);
if (IS_ERR(hdmi->connector)) {
ret = PTR_ERR(hdmi->connector);
......@@ -353,12 +384,7 @@ 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 },
{}
};
......
......@@ -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 {
......
......@@ -159,14 +159,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);
......@@ -306,8 +298,6 @@ static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge
static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
.pre_enable = msm_hdmi_bridge_pre_enable,
.enable = msm_hdmi_bridge_enable,
.disable = msm_hdmi_bridge_disable,
.post_disable = msm_hdmi_bridge_post_disable,
.mode_set = msm_hdmi_bridge_mode_set,
.mode_valid = msm_hdmi_bridge_mode_valid,
......
......@@ -60,48 +60,6 @@ static void msm_hdmi_phy_reset(struct hdmi *hdmi)
}
}
static int gpio_config(struct hdmi *hdmi, bool on)
{
const struct hdmi_platform_config *config = hdmi->config;
int i;
if (on) {
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i];
if (gpio.gpiod) {
if (gpio.output) {
gpiod_direction_output(gpio.gpiod,
gpio.value);
} else {
gpiod_direction_input(gpio.gpiod);
gpiod_set_value_cansleep(gpio.gpiod,
gpio.value);
}
}
}
DBG("gpio on");
} else {
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i];
if (!gpio.gpiod)
continue;
if (gpio.output) {
int value = gpio.value ? 0 : 1;
gpiod_set_value_cansleep(gpio.gpiod, value);
}
}
DBG("gpio off");
}
return 0;
}
static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
{
const struct hdmi_platform_config *config = hdmi->config;
......@@ -154,11 +112,8 @@ int msm_hdmi_hpd_enable(struct drm_bridge *bridge)
goto fail;
}
ret = gpio_config(hdmi, true);
if (ret) {
DRM_DEV_ERROR(dev, "failed to configure GPIOs: %d\n", ret);
goto fail;
}
if (hdmi->hpd_gpiod)
gpiod_set_value_cansleep(hdmi->hpd_gpiod, 1);
pm_runtime_get_sync(dev);
enable_hpd_clocks(hdmi, true);
......@@ -207,10 +162,6 @@ void msm_hdmi_hpd_disable(struct hdmi_bridge *hdmi_bridge)
enable_hpd_clocks(hdmi, false);
pm_runtime_put(dev);
ret = gpio_config(hdmi, false);
if (ret)
dev_warn(dev, "failed to unconfigure GPIOs: %d\n", ret);
ret = pinctrl_pm_select_sleep_state(dev);
if (ret)
dev_warn(dev, "pinctrl state chg failed: %d\n", ret);
......@@ -269,10 +220,7 @@ static enum drm_connector_status detect_reg(struct hdmi *hdmi)
#define HPD_GPIO_INDEX 2
static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
{
const struct hdmi_platform_config *config = hdmi->config;
struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
return gpiod_get_value(hpd_gpio.gpiod) ?
return gpiod_get_value(hdmi->hpd_gpiod) ?
connector_status_connected :
connector_status_disconnected;
}
......@@ -282,8 +230,6 @@ enum drm_connector_status msm_hdmi_bridge_detect(
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
const struct hdmi_platform_config *config = hdmi->config;
struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
enum drm_connector_status stat_gpio, stat_reg;
int retry = 20;
......@@ -291,7 +237,7 @@ enum drm_connector_status msm_hdmi_bridge_detect(
* some platforms may not have hpd gpio. Rely only on the status
* provided by REG_HDMI_HPD_INT_STATUS in this case.
*/
if (!hpd_gpio.gpiod)
if (!hdmi->hpd_gpiod)
return detect_reg(hdmi);
do {
......
......@@ -122,8 +122,20 @@ static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy)
HDMI_8x60_PHY_REG2_PD_DESER);
}
static const char * const hdmi_phy_8x60_reg_names[] = {
"core-vdda",
};
static const char * const hdmi_phy_8x60_clk_names[] = {
"slave_iface",
};
const struct hdmi_phy_cfg msm_hdmi_phy_8x60_cfg = {
.type = MSM_HDMI_PHY_8x60,
.powerup = hdmi_phy_8x60_powerup,
.powerdown = hdmi_phy_8x60_powerdown,
.reg_names = hdmi_phy_8x60_reg_names,
.num_regs = ARRAY_SIZE(hdmi_phy_8x60_reg_names),
.clk_names = hdmi_phy_8x60_clk_names,
.num_clks = ARRAY_SIZE(hdmi_phy_8x60_clk_names),
};
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment