Merge tag 'drm-msm-next-2026-05-30' of https://gitlab.freedesktop.org/drm/msm into drm-next

Changes for v7.2

Core:
- Fixed documentation for msm_gem_shrinker functions
- IFPC related enablement/fixes for gen8
- PERFCNTR_CONFIG ioctl support

GPU
- Reworked handling of UBWC configuration
- a810 suppport

MDSS:
- Added Milos platform support
- Reworked handling of UBWC configuration

DisplayPort:
- Reworked HPD handling, preparing for the MST support

DPU:
- Added Milos platform support
- Reworked handling of UBWC configuration

DSI:
- Added Milos platform support

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Rob Clark <rob.clark@oss.qualcomm.com>
Link: https://patch.msgid.link/CACSVV00DXZcvFH2-C3fouve5DGs0DGa-vvsJPuaRmUZZVNKOfg@mail.gmail.com
This commit is contained in:
Dave Airlie 2026-06-04 06:41:21 +10:00
commit 44c460d2cc
68 changed files with 7401 additions and 2954 deletions

View File

@ -16,6 +16,7 @@ properties:
- enum:
- qcom,apq8064-dsi-ctrl
- qcom,kaanapali-dsi-ctrl
- qcom,milos-dsi-ctrl
- qcom,msm8226-dsi-ctrl
- qcom,msm8916-dsi-ctrl
- qcom,msm8953-dsi-ctrl
@ -339,6 +340,7 @@ allOf:
compatible:
contains:
enum:
- qcom,milos-dsi-ctrl
- qcom,msm8998-dsi-ctrl
- qcom,sa8775p-dsi-ctrl
- qcom,sar2130p-dsi-ctrl

View File

@ -300,6 +300,36 @@ allOf:
required:
- qcom,qmp
- if:
properties:
compatible:
contains:
const: qcom,adreno-gmu-810.0
then:
properties:
reg:
items:
- description: Core GMU registers
reg-names:
items:
- const: gmu
clocks:
items:
- description: GPU AHB clock
- description: GMU clock
- description: GPU CX clock
- description: GPU AXI clock
- description: GPU MEMNOC clock
- description: GMU HUB clock
clock-names:
items:
- const: ahb
- const: gmu
- const: cxo
- const: axi
- const: memnoc
- const: hub
- if:
properties:
compatible:

View File

@ -411,6 +411,23 @@ allOf:
- clocks
- clock-names
- if:
properties:
compatible:
contains:
enum:
- qcom,adreno-44010000
- qcom,adreno-44070001
then:
properties:
reg:
minItems: 2
maxItems: 2
reg-names:
minItems: 2
maxItems: 2
- if:
properties:
compatible:
@ -434,6 +451,8 @@ allOf:
- qcom,adreno-43050a01
- qcom,adreno-43050c01
- qcom,adreno-43051401
- qcom,adreno-44010000
- qcom,adreno-44070001
then: # Starting with A6xx, the clocks are usually defined in the GMU node
properties:

View File

@ -0,0 +1,286 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/msm/qcom,milos-mdss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Milos Display MDSS
maintainers:
- Luca Weiss <luca.weiss@fairphone.com>
description:
Milos MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like
DPU display controller, DSI and DP interfaces etc.
$ref: /schemas/display/msm/mdss-common.yaml#
properties:
compatible:
const: qcom,milos-mdss
clocks:
items:
- description: Display AHB
- description: Display hf AXI
- description: Display core
iommus:
maxItems: 1
interconnects:
items:
- description: Interconnect path from mdp0 port to the data bus
- description: Interconnect path from CPU to the reg bus
interconnect-names:
items:
- const: mdp0-mem
- const: cpu-cfg
patternProperties:
"^display-controller@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: qcom,milos-dpu
"^displayport-controller@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: qcom,milos-dp
"^dsi@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
contains:
const: qcom,milos-dsi-ctrl
"^phy@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: qcom,milos-dsi-phy-4nm
required:
- compatible
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,dsi-phy-28nm.h>
#include <dt-bindings/clock/qcom,milos-dispcc.h>
#include <dt-bindings/clock/qcom,milos-gcc.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/interconnect/qcom,icc.h>
#include <dt-bindings/interconnect/qcom,milos-rpmh.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/qcom,rpmhpd.h>
display-subsystem@ae00000 {
compatible = "qcom,milos-mdss";
reg = <0x0ae00000 0x1000>;
reg-names = "mdss";
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
<&gcc GCC_DISP_HF_AXI_CLK>,
<&dispcc DISP_CC_MDSS_MDP_CLK>;
resets = <&dispcc DISP_CC_MDSS_CORE_BCR>;
interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
&cnoc_main SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>;
interconnect-names = "mdp0-mem",
"cpu-cfg";
power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
iommus = <&apps_smmu 0x1c00 0x2>;
interrupt-controller;
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
display-controller@ae01000 {
compatible = "qcom,milos-dpu";
reg = <0x0ae01000 0x8f000>,
<0x0aeb0000 0x3000>;
reg-names = "mdp",
"vbif";
interrupts-extended = <&mdss 0>;
clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
<&dispcc DISP_CC_MDSS_AHB_CLK>,
<&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
<&dispcc DISP_CC_MDSS_MDP_CLK>,
<&dispcc DISP_CC_MDSS_VSYNC_CLK>;
clock-names = "nrt_bus",
"iface",
"lut",
"core",
"vsync";
assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
assigned-clock-rates = <19200000>;
operating-points-v2 = <&mdp_opp_table>;
power-domains = <&rpmhpd RPMHPD_CX>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dpu_intf1_out: endpoint {
remote-endpoint = <&mdss_dsi0_in>;
};
};
};
mdp_opp_table: opp-table {
compatible = "operating-points-v2";
opp-200000000 {
opp-hz = /bits/ 64 <200000000>;
required-opps = <&rpmhpd_opp_low_svs>;
};
opp-342000000 {
opp-hz = /bits/ 64 <342000000>;
required-opps = <&rpmhpd_opp_svs>;
};
opp-402000000 {
opp-hz = /bits/ 64 <402000000>;
required-opps = <&rpmhpd_opp_svs_l1>;
};
opp-535000000 {
opp-hz = /bits/ 64 <535000000>;
required-opps = <&rpmhpd_opp_nom>;
};
opp-600000000 {
opp-hz = /bits/ 64 <600000000>;
required-opps = <&rpmhpd_opp_nom_l1>;
};
opp-630000000 {
opp-hz = /bits/ 64 <630000000>;
required-opps = <&rpmhpd_opp_turbo>;
};
};
};
dsi@ae94000 {
compatible = "qcom,milos-dsi-ctrl", "qcom,mdss-dsi-ctrl";
reg = <0x0ae94000 0x1000>;
reg-names = "dsi_ctrl";
interrupts-extended = <&mdss 4>;
clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
<&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
<&dispcc DISP_CC_MDSS_PCLK0_CLK>,
<&dispcc DISP_CC_MDSS_ESC0_CLK>,
<&dispcc DISP_CC_MDSS_AHB_CLK>,
<&gcc GCC_DISP_HF_AXI_CLK>;
clock-names = "byte",
"byte_intf",
"pixel",
"core",
"iface",
"bus";
assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
<&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
assigned-clock-parents = <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>,
<&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>;
operating-points-v2 = <&mdss_dsi_opp_table>;
power-domains = <&rpmhpd RPMHPD_CX>;
phys = <&mdss_dsi0_phy>;
phy-names = "dsi";
#address-cells = <1>;
#size-cells = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
mdss_dsi0_in: endpoint {
remote-endpoint = <&dpu_intf1_out>;
};
};
port@1 {
reg = <1>;
mdss_dsi0_out: endpoint {
};
};
};
mdss_dsi_opp_table: opp-table {
compatible = "operating-points-v2";
opp-187500000 {
opp-hz = /bits/ 64 <187500000>;
required-opps = <&rpmhpd_opp_low_svs>;
};
opp-300000000 {
opp-hz = /bits/ 64 <300000000>;
required-opps = <&rpmhpd_opp_svs>;
};
opp-358000000 {
opp-hz = /bits/ 64 <358000000>;
required-opps = <&rpmhpd_opp_svs_l1>;
};
};
};
mdss_dsi0_phy: phy@ae95000 {
compatible = "qcom,milos-dsi-phy-4nm";
reg = <0x0ae95000 0x200>,
<0x0ae95200 0x300>,
<0x0ae95500 0x400>;
reg-names = "dsi_phy",
"dsi_phy_lane",
"dsi_pll";
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
<&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface",
"ref";
#clock-cells = <1>;
#phy-cells = <0>;
};
};
...

View File

@ -18,6 +18,7 @@ properties:
- qcom,eliza-dpu
- qcom,glymur-dpu
- qcom,kaanapali-dpu
- qcom,milos-dpu
- qcom,sa8775p-dpu
- qcom,sm8650-dpu
- qcom,sm8750-dpu

View File

@ -20,6 +20,7 @@ properties:
- qcom,dsi-phy-7nm
- qcom,dsi-phy-7nm-8150
- qcom,kaanapali-dsi-phy-3nm
- qcom,milos-dsi-phy-4nm
- qcom,sa8775p-dsi-phy-5nm
- qcom,sar2130p-dsi-phy-5nm
- qcom,sc7280-dsi-phy-7nm

View File

@ -386,6 +386,10 @@ linkcheck-docs:
rules:
- when: never
mr-label-maker-test:
rules:
- when: never
test-docs:
rules:
- when: never

View File

@ -122,7 +122,7 @@ msm-y += \
msm_gpu_devfreq.o \
msm_io_utils.o \
msm_iommu.o \
msm_perf.o \
msm_perfcntr.o \
msm_rd.o \
msm_ringbuffer.o \
msm_submitqueue.o \
@ -177,6 +177,11 @@ quiet_cmd_headergen = GENHDR $@
cmd_headergen = mkdir -p $(obj)/generated && $(PYTHON3) $(src)/registers/gen_header.py \
$(headergen-opts) --rnn $(src)/registers --xml $< c-defines > $@
# TODO how to do this for a2xx/a5xx which have different .xml arg?
quiet_cmd_headergen_json = GENHDRJSN $@
cmd_headergen_json = mkdir -p $(obj)/generated && $(PYTHON3) $(src)/registers/gen_header.py \
$(headergen-opts) --rnn $(src)/registers --xml $(filter %.xml,$^) perfcntrs --json $< > $@
$(obj)/generated/%.xml.h: $(src)/registers/adreno/%.xml \
$(src)/registers/adreno/adreno_common.xml \
$(src)/registers/adreno/adreno_pm4.xml \
@ -193,6 +198,24 @@ $(obj)/generated/%.xml.h: $(src)/registers/display/%.xml \
FORCE
$(call if_changed,headergen)
ADRENO_PERFCNTRS =
define adreno_perfcntrs
ADRENO_PERFCNTRS += generated/$(1)_perfcntrs.json.c
$$(obj)/generated/$(1)_perfcntrs.json.c: $$(src)/registers/adreno/$(1)_perfcntrs.json \
$$(src)/registers/adreno/$(2).xml \
FORCE
$$(call if_changed,headergen_json)
endef
$(eval $(call adreno_perfcntrs,a2xx,a2xx))
$(eval $(call adreno_perfcntrs,a5xx,a5xx))
$(eval $(call adreno_perfcntrs,a6xx,a6xx))
$(eval $(call adreno_perfcntrs,a7xx,a6xx))
$(eval $(call adreno_perfcntrs,a8xx,a6xx))
adreno-y += $(ADRENO_PERFCNTRS:.c=.o)
ADRENO_HEADERS = \
generated/a2xx.xml.h \
generated/a3xx.xml.h \
@ -224,7 +247,7 @@ DISPLAY_HEADERS = \
generated/mdss.xml.h \
generated/sfpb.xml.h
$(addprefix $(obj)/,$(adreno-y)): $(addprefix $(obj)/,$(ADRENO_HEADERS))
$(addprefix $(obj)/,$(msm-y)): $(addprefix $(obj)/,$(ADRENO_HEADERS))
$(addprefix $(obj)/,$(msm-display-y)): $(addprefix $(obj)/,$(DISPLAY_HEADERS))
targets += $(ADRENO_HEADERS) $(DISPLAY_HEADERS)
targets += $(ADRENO_HEADERS) $(DISPLAY_HEADERS) $(ADRENO_PERFCNTRS)

View File

@ -489,10 +489,6 @@ static u32 a2xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
return ring->memptrs->rptr;
}
static const struct msm_gpu_perfcntr perfcntrs[] = {
/* TODO */
};
static struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
{
struct a2xx_gpu *a2xx_gpu = NULL;
@ -518,9 +514,6 @@ static struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
adreno_gpu = &a2xx_gpu->base;
gpu = &adreno_gpu->base;
gpu->perfcntrs = perfcntrs;
gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, 1);
if (ret)
goto fail;

View File

@ -266,12 +266,6 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
/* Turn on performance counters: */
gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
/* Enable the perfcntrs that we use.. */
for (i = 0; i < gpu->num_perfcntrs; i++) {
const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val);
}
gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);
ret = adreno_hw_init(gpu);
@ -508,13 +502,6 @@ static u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
return ring->memptrs->rptr;
}
static const struct msm_gpu_perfcntr perfcntrs[] = {
{ REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO,
SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" },
{ REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO,
SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" },
};
static struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
{
struct a3xx_gpu *a3xx_gpu = NULL;
@ -542,9 +529,6 @@ static struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
adreno_gpu = &a3xx_gpu->base;
gpu = &adreno_gpu->base;
gpu->perfcntrs = perfcntrs;
gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
adreno_gpu->registers = a3xx_registers;
ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, 1);

View File

@ -652,9 +652,6 @@ static struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
adreno_gpu = &a4xx_gpu->base;
gpu = &adreno_gpu->base;
gpu->perfcntrs = NULL;
gpu->num_perfcntrs = 0;
ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, 1);
if (ret)
goto fail;

View File

@ -752,17 +752,13 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
gpu_write(gpu, REG_A5XX_UCHE_CACHE_WAYS, 0x02);
/* Disable L2 bypass in the UCHE */
gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_LO, lower_32_bits(adreno_gpu->uche_trap_base));
gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_HI, upper_32_bits(adreno_gpu->uche_trap_base));
gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_LO, lower_32_bits(adreno_gpu->uche_trap_base));
gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_HI, upper_32_bits(adreno_gpu->uche_trap_base));
gpu_write64(gpu, REG_A5XX_UCHE_TRAP_BASE, adreno_gpu->uche_trap_base);
gpu_write64(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE, adreno_gpu->uche_trap_base);
/* Set the GMEM VA range (0 to gpu->gmem) */
gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000);
gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_HI, 0x00000000);
gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_LO,
gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN, 0x00100000);
gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX,
0x00100000 + adreno_gpu->info->gmem - 1);
gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, 0x00000000);
if (adreno_is_a505(adreno_gpu) || adreno_is_a506(adreno_gpu) ||
adreno_is_a508(adreno_gpu) || adreno_is_a510(adreno_gpu)) {
@ -1217,9 +1213,7 @@ static void a5xx_rbbm_err_irq(struct msm_gpu *gpu, u32 status)
static void a5xx_uche_err_irq(struct msm_gpu *gpu)
{
uint64_t addr = (uint64_t) gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_HI);
addr |= gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_LO);
uint64_t addr = gpu_read64(gpu, REG_A5XX_UCHE_TRAP_LOG);
dev_err_ratelimited(gpu->dev->dev, "UCHE | Out of bounds access | addr=0x%llX\n",
addr);
@ -1725,7 +1719,6 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = priv->gpu_pdev;
struct adreno_platform_config *config = pdev->dev.platform_data;
const struct qcom_ubwc_cfg_data *common_cfg;
struct a5xx_gpu *a5xx_gpu = NULL;
struct adreno_gpu *adreno_gpu;
struct msm_gpu *gpu;
@ -1769,13 +1762,9 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
a5xx_preempt_init(gpu);
/* Inherit the common config and make some necessary fixups */
common_cfg = qcom_ubwc_config_get_data();
if (IS_ERR(common_cfg))
return ERR_CAST(common_cfg);
/* Copy the data into the internal struct to drop the const qualifier (temporarily) */
adreno_gpu->_ubwc_config = *common_cfg;
adreno_gpu->ubwc_config = &adreno_gpu->_ubwc_config;
adreno_gpu->ubwc_config = qcom_ubwc_config_get_data();
if (IS_ERR(adreno_gpu->ubwc_config))
return ERR_CAST(adreno_gpu->ubwc_config);
adreno_gpu->uche_trap_base = 0x0001ffffffff0000ull;

View File

@ -1799,6 +1799,261 @@ static const struct adreno_reglist_pipe x285_dyn_pwrup_reglist_regs[] = {
};
DECLARE_ADRENO_REGLIST_PIPE_LIST(x285_dyn_pwrup_reglist);
static const struct adreno_reglist_pipe a810_nonctxt_regs[] = {
{ REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
{ REG_A8XX_GRAS_DBG_ECO_CNTL, 0x00f80800, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_1, 0x00000003, BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_1, 0x00000023, BIT(PIPE_BV) }, /* Avoid partial waves at VFD */
{ REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_3, 0x00500000, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A7XX_RB_CCU_CNTL, 0x00000068, BIT(PIPE_BR) },
/* Partially enable perf clear, Disable DINT to c/z be data forwarding */
{ REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0x00002200, BIT(PIPE_BR) },
{ REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) },
{ REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) },
{ REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
{ REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
{ REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) },
{ REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) },
{ REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) },
{ REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) },
{ REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) },
/*
* BIT(22): Disable PS out of order retire
* BIT(23): Enable half wave mode and MM instruction src&dst is half precision
*/
{ REG_A7XX_SP_CHICKEN_BITS_2, BIT(22) | BIT(23), BIT(PIPE_NONE) },
{ REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) },
{ REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) },
{ REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) },
{ REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10100000, BIT(PIPE_NONE) },
{ REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x04000724, BIT(PIPE_NONE) },
{ REG_A6XX_UCHE_MODE_CNTL, 0x00020000, BIT(PIPE_NONE) },
{ REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) },
{ REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) },
/* Disable write slow pointer in data phase queue */
{ REG_A8XX_UCHE_HW_DBG_CNTL, BIT(8), BIT(PIPE_NONE) },
{ REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) },
{ REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00100020, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_RB_GC_GMEM_PROTECT, 0x00900000, BIT(PIPE_BR) },
{ },
};
static const u32 a810_protect_regs[] = {
A6XX_PROTECT_RDONLY(0x00000, 0x03a3),
A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
A6XX_PROTECT_NORDWR(0x00440, 0x001f),
A6XX_PROTECT_RDONLY(0x00580, 0x005f),
A6XX_PROTECT_NORDWR(0x005e0, 0x011f),
A6XX_PROTECT_RDONLY(0x0074a, 0x0005),
A6XX_PROTECT_RDONLY(0x00759, 0x0026),
A6XX_PROTECT_RDONLY(0x00789, 0x0000),
A6XX_PROTECT_RDONLY(0x0078c, 0x0013),
A6XX_PROTECT_NORDWR(0x00800, 0x0029),
A6XX_PROTECT_NORDWR(0x00837, 0x00af),
A6XX_PROTECT_RDONLY(0x008e7, 0x00c9),
A6XX_PROTECT_NORDWR(0x008ec, 0x00c3),
A6XX_PROTECT_NORDWR(0x009b1, 0x0250),
A6XX_PROTECT_RDONLY(0x00ce0, 0x0001),
A6XX_PROTECT_RDONLY(0x00df0, 0x0000),
A6XX_PROTECT_NORDWR(0x00df1, 0x0000),
A6XX_PROTECT_NORDWR(0x00e01, 0x0000),
A6XX_PROTECT_NORDWR(0x00e03, 0x1fff),
A6XX_PROTECT_NORDWR(0x03c00, 0x00c5),
A6XX_PROTECT_RDONLY(0x03cc6, 0x1fff),
A6XX_PROTECT_NORDWR(0x08600, 0x01ff),
A6XX_PROTECT_NORDWR(0x08e00, 0x00ff),
A6XX_PROTECT_RDONLY(0x08f00, 0x0000),
A6XX_PROTECT_NORDWR(0x08f01, 0x01be),
A6XX_PROTECT_NORDWR(0x09600, 0x01ff),
A6XX_PROTECT_RDONLY(0x0981a, 0x02e5),
A6XX_PROTECT_NORDWR(0x09e00, 0x01ff),
A6XX_PROTECT_NORDWR(0x0a600, 0x01ff),
A6XX_PROTECT_NORDWR(0x0ae00, 0x0006),
A6XX_PROTECT_NORDWR(0x0ae08, 0x0006),
A6XX_PROTECT_NORDWR(0x0ae10, 0x036f),
A6XX_PROTECT_NORDWR(0x0b600, 0x1fff),
A6XX_PROTECT_NORDWR(0x0dc00, 0x1fff),
A6XX_PROTECT_RDONLY(0x0fc00, 0x1fff),
A6XX_PROTECT_NORDWR(0x18400, 0x003f),
A6XX_PROTECT_RDONLY(0x18440, 0x013f),
A6XX_PROTECT_NORDWR(0x18580, 0x1fff),
A6XX_PROTECT_NORDWR(0x1b400, 0x1fff),
A6XX_PROTECT_NORDWR(0x1f400, 0x0477),
A6XX_PROTECT_RDONLY(0x1f878, 0x0787),
A6XX_PROTECT_NORDWR(0x1f930, 0x0329),
A6XX_PROTECT_NORDWR(0x20000, 0x1fff),
A6XX_PROTECT_NORDWR(0x27800, 0x007f),
A6XX_PROTECT_RDONLY(0x27880, 0x0381),
A6XX_PROTECT_NORDWR(0x27882, 0x0001),
A6XX_PROTECT_NORDWR(0x27c02, 0x0000),
};
DECLARE_ADRENO_PROTECT(a810_protect, 64);
static const uint32_t a810_pwrup_reglist_regs[] = {
REG_A6XX_UCHE_MODE_CNTL,
REG_A8XX_UCHE_VARB_IDLE_TIMEOUT,
REG_A8XX_UCHE_GBIF_GX_CONFIG,
REG_A8XX_UCHE_CACHE_WAYS,
REG_A8XX_UCHE_CCHE_MODE_CNTL,
REG_A8XX_UCHE_CCHE_CACHE_WAYS,
REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN,
REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN + 1,
REG_A8XX_UCHE_CCHE_TRAP_BASE,
REG_A8XX_UCHE_CCHE_TRAP_BASE + 1,
REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE,
REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE + 1,
REG_A8XX_UCHE_HW_DBG_CNTL,
REG_A8XX_UCHE_WRITE_THRU_BASE,
REG_A8XX_UCHE_WRITE_THRU_BASE + 1,
REG_A8XX_UCHE_TRAP_BASE,
REG_A8XX_UCHE_TRAP_BASE + 1,
REG_A8XX_UCHE_CLIENT_PF,
REG_A8XX_RB_CMP_NC_MODE_CNTL,
REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP,
REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN,
REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN + 1,
REG_A7XX_SP_READ_SEL,
REG_A6XX_TPL1_NC_MODE_CNTL,
REG_A6XX_TPL1_DBG_ECO_CNTL,
REG_A6XX_TPL1_DBG_ECO_CNTL1,
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(1),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(2),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(3),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(4),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(5),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(6),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(7),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(8),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(9),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(10),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(11),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(12),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(13),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(14),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(15),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(16),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(17),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(18),
REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(19),
};
DECLARE_ADRENO_REGLIST_LIST(a810_pwrup_reglist);
static const u32 a810_ifpc_reglist_regs[] = {
REG_A8XX_RBBM_NC_MODE_CNTL,
REG_A8XX_RBBM_PERFCTR_CNTL,
REG_A8XX_RBBM_SLICE_INTERFACE_HANG_INT_CNTL,
REG_A8XX_RBBM_SLICE_NC_MODE_CNTL,
REG_A6XX_SP_NC_MODE_CNTL,
REG_A7XX_SP_CHICKEN_BITS_2,
REG_A7XX_SP_CHICKEN_BITS_3,
REG_A6XX_SP_PERFCTR_SHADER_MASK,
REG_A8XX_CP_PROTECT_GLOBAL(0),
REG_A8XX_CP_PROTECT_GLOBAL(1),
REG_A8XX_CP_PROTECT_GLOBAL(2),
REG_A8XX_CP_PROTECT_GLOBAL(3),
REG_A8XX_CP_PROTECT_GLOBAL(4),
REG_A8XX_CP_PROTECT_GLOBAL(5),
REG_A8XX_CP_PROTECT_GLOBAL(6),
REG_A8XX_CP_PROTECT_GLOBAL(7),
REG_A8XX_CP_PROTECT_GLOBAL(8),
REG_A8XX_CP_PROTECT_GLOBAL(9),
REG_A8XX_CP_PROTECT_GLOBAL(10),
REG_A8XX_CP_PROTECT_GLOBAL(11),
REG_A8XX_CP_PROTECT_GLOBAL(12),
REG_A8XX_CP_PROTECT_GLOBAL(13),
REG_A8XX_CP_PROTECT_GLOBAL(14),
REG_A8XX_CP_PROTECT_GLOBAL(15),
REG_A8XX_CP_PROTECT_GLOBAL(16),
REG_A8XX_CP_PROTECT_GLOBAL(17),
REG_A8XX_CP_PROTECT_GLOBAL(18),
REG_A8XX_CP_PROTECT_GLOBAL(19),
REG_A8XX_CP_PROTECT_GLOBAL(20),
REG_A8XX_CP_PROTECT_GLOBAL(21),
REG_A8XX_CP_PROTECT_GLOBAL(22),
REG_A8XX_CP_PROTECT_GLOBAL(23),
REG_A8XX_CP_PROTECT_GLOBAL(24),
REG_A8XX_CP_PROTECT_GLOBAL(25),
REG_A8XX_CP_PROTECT_GLOBAL(26),
REG_A8XX_CP_PROTECT_GLOBAL(27),
REG_A8XX_CP_PROTECT_GLOBAL(28),
REG_A8XX_CP_PROTECT_GLOBAL(29),
REG_A8XX_CP_PROTECT_GLOBAL(30),
REG_A8XX_CP_PROTECT_GLOBAL(31),
REG_A8XX_CP_PROTECT_GLOBAL(32),
REG_A8XX_CP_PROTECT_GLOBAL(33),
REG_A8XX_CP_PROTECT_GLOBAL(34),
REG_A8XX_CP_PROTECT_GLOBAL(35),
REG_A8XX_CP_PROTECT_GLOBAL(36),
REG_A8XX_CP_PROTECT_GLOBAL(37),
REG_A8XX_CP_PROTECT_GLOBAL(38),
REG_A8XX_CP_PROTECT_GLOBAL(39),
REG_A8XX_CP_PROTECT_GLOBAL(40),
REG_A8XX_CP_PROTECT_GLOBAL(41),
REG_A8XX_CP_PROTECT_GLOBAL(42),
REG_A8XX_CP_PROTECT_GLOBAL(43),
REG_A8XX_CP_PROTECT_GLOBAL(44),
REG_A8XX_CP_PROTECT_GLOBAL(45),
REG_A8XX_CP_PROTECT_GLOBAL(46),
REG_A8XX_CP_PROTECT_GLOBAL(47),
REG_A8XX_CP_PROTECT_GLOBAL(48),
REG_A8XX_CP_PROTECT_GLOBAL(49),
REG_A8XX_CP_PROTECT_GLOBAL(50),
REG_A8XX_CP_PROTECT_GLOBAL(51),
REG_A8XX_CP_PROTECT_GLOBAL(52),
REG_A8XX_CP_PROTECT_GLOBAL(53),
REG_A8XX_CP_PROTECT_GLOBAL(54),
REG_A8XX_CP_PROTECT_GLOBAL(55),
REG_A8XX_CP_PROTECT_GLOBAL(56),
REG_A8XX_CP_PROTECT_GLOBAL(57),
REG_A8XX_CP_PROTECT_GLOBAL(58),
REG_A8XX_CP_PROTECT_GLOBAL(59),
REG_A8XX_CP_PROTECT_GLOBAL(60),
REG_A8XX_CP_PROTECT_GLOBAL(61),
REG_A8XX_CP_PROTECT_GLOBAL(62),
REG_A8XX_CP_PROTECT_GLOBAL(63),
};
DECLARE_ADRENO_REGLIST_LIST(a810_ifpc_reglist);
static const struct adreno_reglist_pipe a810_dyn_pwrup_reglist_regs[] = {
{ REG_A8XX_CP_PROTECT_CNTL_PIPE, 0, BIT(PIPE_BR) | BIT(PIPE_BV) },
{ REG_A8XX_CP_PROTECT_PIPE(15), 0, BIT(PIPE_BR) | BIT(PIPE_BV) },
{ REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_GRAS_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A7XX_RB_CCU_CNTL, 0, BIT(PIPE_BR) },
{ REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0, BIT(PIPE_BR) },
{ REG_A8XX_RB_CCU_NC_MODE_CNTL, 0, BIT(PIPE_BR) },
{ REG_A8XX_RB_CMP_NC_MODE_CNTL, 0, BIT(PIPE_BR) },
{ REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0, BIT(PIPE_BR) },
{ REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0, BIT(PIPE_BR) },
{ REG_A8XX_RB_GC_GMEM_PROTECT, 0, BIT(PIPE_BR) },
{ REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0, BIT(PIPE_BR) },
{ REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_2, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_3, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_PC_CHICKEN_BITS_4, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0, BIT(PIPE_BR) | BIT(PIPE_BV) },
{ REG_A8XX_PC_VIS_STREAM_CNTL, 0, BIT(PIPE_BR) | BIT(PIPE_BV) },
{ REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0, BIT(PIPE_BR) | BIT(PIPE_BV) },
{ REG_A8XX_VFD_CB_BV_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VFD_CB_BR_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_VFD_CB_LP_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A7XX_VFD_DBG_ECO_CNTL, 0, BIT(PIPE_BR) | BIT(PIPE_BV) },
};
DECLARE_ADRENO_REGLIST_PIPE_LIST(a810_dyn_pwrup_reglist);
static const struct adreno_reglist_pipe a840_nonctxt_regs[] = {
{ REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
{ REG_A8XX_GRAS_DBG_ECO_CNTL, 0x00000800, BIT(PIPE_BV) | BIT(PIPE_BR) },
@ -2193,6 +2448,48 @@ static const struct adreno_info a8xx_gpus[] = {
{ 252, 2 },
{ 221, 3 },
),
}, {
.chip_ids = ADRENO_CHIP_IDS(0x44010000),
.family = ADRENO_8XX_GEN1,
.fw = {
[ADRENO_FW_SQE] = "gen80300_sqe.fw",
[ADRENO_FW_GMU] = "gen80300_gmu.bin",
},
.gmem = SZ_512K + SZ_64K,
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
ADRENO_QUIRK_HAS_HW_APRIV |
ADRENO_QUIRK_PREEMPTION |
ADRENO_QUIRK_IFPC,
.funcs = &a8xx_gpu_funcs,
.zapfw = "gen80300_zap.mbn",
.a6xx = &(const struct a6xx_info) {
.protect = &a810_protect,
.nonctxt_reglist = a810_nonctxt_regs,
.pwrup_reglist = &a810_pwrup_reglist,
.dyn_pwrup_reglist = &a810_dyn_pwrup_reglist,
.ifpc_reglist = &a810_ifpc_reglist,
.gbif_cx = a840_gbif,
.max_slices = 1,
.gmu_chipid = 0x8030000,
.bcms = (const struct a6xx_bcm[]) {
{ .name = "SH0", .buswidth = 16 },
{ .name = "MC0", .buswidth = 4 },
{
.name = "ACV",
.fixed = true,
.perfmode = BIT(2),
.perfmode_bw = 10687500,
},
{ /* sentinel */ },
},
},
.preempt_record_size = 4558 * SZ_1K,
.speedbins = ADRENO_SPEEDBINS(
{ 0, 0 },
{ 242, 1 },
{ 221, 2 },
),
}
};
@ -2205,4 +2502,5 @@ static inline __always_unused void __build_asserts(void)
BUILD_BUG_ON(a660_protect.count > a660_protect.count_max);
BUILD_BUG_ON(a690_protect.count > a690_protect.count_max);
BUILD_BUG_ON(a730_protect.count > a730_protect.count_max);
BUILD_BUG_ON(a810_protect.count > a810_protect.count_max);
}

View File

@ -947,7 +947,7 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
/* Turn on TCM (Tightly Coupled Memory) retention */
if (adreno_is_a7xx(adreno_gpu))
a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_TCM_RET_CNTL, 1);
a6xx_cx_misc_write(a6xx_gpu, REG_A7XX_CX_MISC_TCM_RET_CNTL, 1);
else if (!adreno_is_a8xx(adreno_gpu))
gmu_write(gmu, REG_A6XX_GMU_GENERAL_7, 1);
@ -1215,7 +1215,7 @@ static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu)
if (!qcom_scm_is_available()) {
dev_warn_once(gpu->dev->dev,
"SCM is not available, poking fuse register\n");
a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE,
a6xx_cx_misc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE,
A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING |
A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND |
A7XX_CX_MISC_SW_FUSE_VALUE_LPAC);
@ -1236,7 +1236,7 @@ static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu)
* firmware, find out whether that's the case. The scm call
* above sets the fuse register.
*/
fuse_val = a6xx_llc_read(a6xx_gpu,
fuse_val = a6xx_cx_misc_read(a6xx_gpu,
REG_A7XX_CX_MISC_SW_FUSE_VALUE);
adreno_gpu->has_ray_tracing =
!!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING);
@ -1250,6 +1250,56 @@ static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu)
return 0;
}
static int a6xx_gmu_gxpd_get(struct a6xx_gmu *gmu)
{
struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
if (IS_ERR_OR_NULL(gmu->gxpd))
return 0;
/*
* On A8xx HW, GX GDSC is moved to a new clk controller block under GX
* power domain. The clock driver for this new block keeps the GX rail
* voted when gxpd is voted. So, use the gxpd only during gpu recovery.
*/
if (adreno_gpu->info->family >= ADRENO_8XX_GEN1)
return 0;
/*
* On A6x/A7x, "enable" the GX power domain which won't actually do
* anything but it will make sure that the refcounting is correct in
* case we need to bring down the GX after a GMU failure
*/
return pm_runtime_get_sync(gmu->gxpd);
}
static int a6xx_gmu_gxpd_put(struct a6xx_gmu *gmu)
{
struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
if (IS_ERR_OR_NULL(gmu->gxpd))
return 0;
if (adreno_gpu->info->family < ADRENO_8XX_GEN1)
return pm_runtime_put_sync(gmu->gxpd);
/*
* On A8x, GX GDSC collapse should be triggered only when it is stuck ON
*/
if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) {
pm_runtime_get_sync(gmu->gxpd);
/*
* Hint to gfxclkctl driver to do a hw collapse during the next
* RPM PUT. This is a special behavior in the gfxclkctl driver
*/
dev_pm_genpd_synced_poweroff(gmu->gxpd);
pm_runtime_put_sync(gmu->gxpd);
}
return 0;
}
int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
{
@ -1266,13 +1316,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
/* Turn on the resources */
pm_runtime_get_sync(gmu->dev);
/*
* "enable" the GX power domain which won't actually do anything but it
* will make sure that the refcounting is correct in case we need to
* bring down the GX after a GMU failure
*/
if (!IS_ERR_OR_NULL(gmu->gxpd))
pm_runtime_get_sync(gmu->gxpd);
a6xx_gmu_gxpd_get(gmu);
/* Use a known rate to bring up the GMU */
clk_set_rate(gmu->core_clk, 200000000);
@ -1299,7 +1343,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
/* Check to see if we are doing a cold or warm boot */
if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
status = a6xx_llc_read(a6xx_gpu, REG_A7XX_CX_MISC_TCM_RET_CNTL) == 1 ?
status = a6xx_cx_misc_read(a6xx_gpu, REG_A7XX_CX_MISC_TCM_RET_CNTL) == 1 ?
GMU_WARM_BOOT : GMU_COLD_BOOT;
} else if (gmu->legacy) {
status = gmu_read(gmu, REG_A6XX_GMU_GENERAL_7) == 1 ?
@ -1339,7 +1383,8 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
disable_clk:
clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks);
rpm_put:
pm_runtime_put(gmu->gxpd);
a6xx_gmu_gxpd_put(gmu);
pm_runtime_put(gmu->dev);
return ret;
@ -1455,8 +1500,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
* domain. Usually the GMU does this but only if the shutdown sequence
* was successful
*/
if (!IS_ERR_OR_NULL(gmu->gxpd))
pm_runtime_put_sync(gmu->gxpd);
a6xx_gmu_gxpd_put(gmu);
clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks);
@ -2034,12 +2078,12 @@ static int a6xx_gmu_get_irq(struct a6xx_gmu *gmu, struct platform_device *pdev,
return irq;
}
void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu)
void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu, bool force_on)
{
bool sysprof = msm_gpu_sysprof_no_ifpc(gpu) || force_on;
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
unsigned int sysprof_active;
/* Nothing to do if GPU is suspended. We will handle this during GMU resume */
if (!pm_runtime_get_if_active(&gpu->pdev->dev))
@ -2047,15 +2091,13 @@ void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu)
mutex_lock(&gmu->lock);
sysprof_active = refcount_read(&gpu->sysprof_active);
/*
* 'Perfcounter select' register values are lost during IFPC collapse. To avoid that,
* use the currently unused perfcounter oob vote to block IFPC when sysprof is active
*/
if ((sysprof_active > 1) && !test_and_set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status))
if (sysprof && !test_and_set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status))
a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
else if ((sysprof_active == 1) && test_and_clear_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status))
else if (!sysprof && test_and_clear_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status))
a6xx_gmu_clear_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
mutex_unlock(&gmu->lock);
@ -2357,7 +2399,12 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
goto err_mmio;
}
} else if (adreno_is_a8xx(adreno_gpu)) {
gmu->rscc = gmu->mmio + 0x19000;
/*
* On a8xx , RSCC lives at GPU base + 0x50000, which falls
* inside the GPU's kgsl_3d0_reg_memory range rather than the
* GMU's.
*/
gmu->rscc = gpu->mmio + 0x50000;
} else {
gmu->rscc = gmu->mmio + 0x23000;
}

View File

@ -5,6 +5,7 @@
#include "msm_gem.h"
#include "msm_mmu.h"
#include "msm_gpu_trace.h"
#include "msm_perfcntr.h"
#include "a6xx_gpu.h"
#include "a6xx_gmu.xml.h"
@ -188,6 +189,30 @@ void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
spin_unlock_irqrestore(&ring->preempt_lock, flags);
}
void
a6xx_flush_yield(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
/* If preemption is enabled */
if (gpu->nr_rings > 1) {
/* Yield the floor on command completion */
OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4);
/*
* If dword[2:1] are non zero, they specify an address for
* the CP to write the value of dword[3] to on preemption
* complete. Write 0 to skip the write
*/
OUT_RING(ring, 0x00);
OUT_RING(ring, 0x00);
/* Data value - not used if the address above is 0 */
OUT_RING(ring, 0x01);
/* generate interrupt on preemption completion */
OUT_RING(ring, 0x00);
}
a6xx_flush(gpu, ring);
}
static void get_stats_counter(struct msm_ringbuffer *ring, u32 counter,
u64 iova)
{
@ -202,7 +227,7 @@ static void get_stats_counter(struct msm_ringbuffer *ring, u32 counter,
static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,
struct msm_ringbuffer *ring, struct msm_gem_submit *submit)
{
bool sysprof = refcount_read(&a6xx_gpu->base.base.sysprof_active) > 1;
bool sysprof = msm_gpu_sysprof_no_perfcntr_zap(&a6xx_gpu->base.base);
struct msm_context *ctx = submit->queue->ctx;
struct drm_gpuvm *vm = msm_context_vm(submit->dev, ctx);
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
@ -596,28 +621,9 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_PKT7(ring, CP_SET_MARKER, 1);
OUT_RING(ring, 0x100); /* IFPC enable */
/* If preemption is enabled */
if (gpu->nr_rings > 1) {
/* Yield the floor on command completion */
OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4);
/*
* If dword[2:1] are non zero, they specify an address for
* the CP to write the value of dword[3] to on preemption
* complete. Write 0 to skip the write
*/
OUT_RING(ring, 0x00);
OUT_RING(ring, 0x00);
/* Data value - not used if the address above is 0 */
OUT_RING(ring, 0x01);
/* generate interrupt on preemption completion */
OUT_RING(ring, 0x00);
}
trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu));
a6xx_flush(gpu, ring);
a6xx_flush_yield(gpu, ring);
/* Check to see if we need to start preemption */
if (adreno_is_a8xx(adreno_gpu))
@ -733,82 +739,6 @@ static void a6xx_set_cp_protect(struct msm_gpu *gpu)
gpu_write(gpu, REG_A6XX_CP_PROTECT(protect->count_max - 1), protect->regs[i]);
}
static int a6xx_calc_ubwc_config(struct adreno_gpu *gpu)
{
const struct qcom_ubwc_cfg_data *common_cfg;
struct qcom_ubwc_cfg_data *cfg = &gpu->_ubwc_config;
/* Inherit the common config and make some necessary fixups */
common_cfg = qcom_ubwc_config_get_data();
if (IS_ERR(common_cfg))
return PTR_ERR(common_cfg);
/* Copy the data into the internal struct to drop the const qualifier (temporarily) */
*cfg = *common_cfg;
/* Use common config as is for A8x */
if (!adreno_is_a8xx(gpu)) {
cfg->ubwc_swizzle = 0x6;
cfg->highest_bank_bit = 15;
}
if (adreno_is_a610(gpu)) {
cfg->highest_bank_bit = 13;
cfg->ubwc_swizzle = 0x7;
}
if (adreno_is_a612(gpu))
cfg->highest_bank_bit = 14;
if (adreno_is_a618(gpu))
cfg->highest_bank_bit = 14;
if (adreno_is_a619(gpu))
/* TODO: Should be 14 but causes corruption at e.g. 1920x1200 on DP */
cfg->highest_bank_bit = 13;
if (adreno_is_a619_holi(gpu))
cfg->highest_bank_bit = 13;
if (adreno_is_a621(gpu))
cfg->highest_bank_bit = 13;
if (adreno_is_a623(gpu))
cfg->highest_bank_bit = 16;
if (adreno_is_a650(gpu) ||
adreno_is_a660(gpu) ||
adreno_is_a690(gpu) ||
adreno_is_a730(gpu) ||
adreno_is_a740_family(gpu)) {
/* TODO: get ddr type from bootloader and use 15 for LPDDR4 */
cfg->highest_bank_bit = 16;
}
if (adreno_is_a663(gpu)) {
cfg->highest_bank_bit = 13;
cfg->ubwc_swizzle = 0x4;
}
if (adreno_is_7c3(gpu))
cfg->highest_bank_bit = 14;
if (adreno_is_a702(gpu))
cfg->highest_bank_bit = 14;
if (cfg->highest_bank_bit != common_cfg->highest_bank_bit)
DRM_WARN_ONCE("Inconclusive highest_bank_bit value: %u (GPU) vs %u (UBWC_CFG)\n",
cfg->highest_bank_bit, common_cfg->highest_bank_bit);
if (cfg->ubwc_swizzle != common_cfg->ubwc_swizzle)
DRM_WARN_ONCE("Inconclusive ubwc_swizzle value: %u (GPU) vs %u (UBWC_CFG)\n",
cfg->ubwc_swizzle, common_cfg->ubwc_swizzle);
gpu->ubwc_config = &gpu->_ubwc_config;
return 0;
}
static void a6xx_set_ubwc_config(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@ -821,10 +751,10 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu)
BUG_ON(cfg->highest_bank_bit < 13);
u32 hbb = cfg->highest_bank_bit - 13;
bool rgb565_predicator = cfg->ubwc_enc_version >= UBWC_4_0;
u32 level2_swizzling_dis = !(cfg->ubwc_swizzle & UBWC_SWIZZLE_ENABLE_LVL2);
u32 level2_swizzling_dis = !(qcom_ubwc_swizzle(cfg) & UBWC_SWIZZLE_ENABLE_LVL2);
bool ubwc_mode = qcom_ubwc_get_ubwc_mode(cfg);
bool amsbc = cfg->ubwc_enc_version >= UBWC_3_0;
bool min_acc_len_64b = false;
bool amsbc = qcom_ubwc_enable_amsbc(cfg);
bool min_acc_len_64b;
u8 uavflagprd_inv = 0;
u32 hbb_hi = hbb >> 2;
u32 hbb_lo = hbb & 3;
@ -832,8 +762,7 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu)
if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu))
uavflagprd_inv = 2;
if (adreno_is_a610(adreno_gpu) || adreno_is_a702(adreno_gpu))
min_acc_len_64b = true;
min_acc_len_64b = qcom_ubwc_min_acc_length_64b(cfg);
gpu_write(gpu, REG_A6XX_RB_NC_MODE_CNTL,
level2_swizzling_dis << 12 |
@ -868,7 +797,7 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu)
min_acc_len_64b << 23 | hbb_lo << 21);
gpu_write(gpu, REG_A6XX_RBBM_NC_MODE_CNTL,
cfg->macrotile_mode);
qcom_ubwc_macrotile_mode(cfg));
}
static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu)
@ -940,6 +869,7 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu)
A7XX_CP_APERTURE_CNTL_HOST_PIPE(PIPE_NONE));
}
lock->dynamic_list_len = dyn_pwrup_reglist_count;
a6xx_gpu->dynamic_sel_reglist_offset = dyn_pwrup_reglist_count;
}
static int a7xx_preempt_start(struct msm_gpu *gpu)
@ -957,15 +887,7 @@ static int a7xx_preempt_start(struct msm_gpu *gpu)
a6xx_emit_set_pseudo_reg(ring, a6xx_gpu, NULL);
/* Yield the floor on command completion */
OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4);
OUT_RING(ring, 0x00);
OUT_RING(ring, 0x00);
OUT_RING(ring, 0x00);
/* Generate interrupt on preemption completion */
OUT_RING(ring, 0x00);
a6xx_flush(gpu, ring);
a6xx_flush_yield(gpu, ring);
return a6xx_idle(gpu, ring) ? 0 : -EINVAL;
}
@ -1185,7 +1107,7 @@ static int a6xx_ucode_load(struct msm_gpu *gpu)
msm_gem_object_set_name(a6xx_gpu->shadow_bo, "shadow");
}
a6xx_gpu->pwrup_reglist_ptr = msm_gem_kernel_new(gpu->dev, PAGE_SIZE,
a6xx_gpu->pwrup_reglist_ptr = msm_gem_kernel_new(gpu->dev, PWRUP_REGLIST_SIZE,
MSM_BO_WC | MSM_BO_MAP_PRIV,
gpu->vm, &a6xx_gpu->pwrup_reglist_bo,
&a6xx_gpu->pwrup_reglist_iova);
@ -1607,7 +1529,7 @@ static int hw_init(struct msm_gpu *gpu)
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER);
}
if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) {
if (!ret && msm_gpu_sysprof_no_ifpc(gpu)) {
ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
if (!ret)
set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
@ -2039,7 +1961,7 @@ static void a6xx_llc_activate(struct a6xx_gpu *a6xx_gpu)
struct msm_gpu *gpu = &adreno_gpu->base;
u32 cntl1_regval = 0;
if (IS_ERR(a6xx_gpu->llc_mmio))
if (IS_ERR_OR_NULL(a6xx_gpu->llc_slice) && IS_ERR_OR_NULL(a6xx_gpu->htw_llc_slice))
return;
if (!llcc_slice_activate(a6xx_gpu->llc_slice)) {
@ -2078,14 +2000,14 @@ static void a6xx_llc_activate(struct a6xx_gpu *a6xx_gpu)
* pagetables
*/
if (!a6xx_gpu->have_mmu500) {
a6xx_llc_write(a6xx_gpu,
a6xx_cx_misc_write(a6xx_gpu,
REG_A6XX_CX_MISC_SYSTEM_CACHE_CNTL_1, cntl1_regval);
/*
* Program cacheability overrides to not allocate cache
* lines on a write miss
*/
a6xx_llc_rmw(a6xx_gpu,
a6xx_cx_misc_rmw(a6xx_gpu,
REG_A6XX_CX_MISC_SYSTEM_CACHE_CNTL_0, 0xF, 0x03);
return;
}
@ -2098,7 +2020,7 @@ static void a7xx_llc_activate(struct a6xx_gpu *a6xx_gpu)
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
struct msm_gpu *gpu = &adreno_gpu->base;
if (IS_ERR(a6xx_gpu->llc_mmio))
if (IS_ERR_OR_NULL(a6xx_gpu->llc_slice) && IS_ERR_OR_NULL(a6xx_gpu->htw_llc_slice))
return;
if (!llcc_slice_activate(a6xx_gpu->llc_slice)) {
@ -2135,31 +2057,12 @@ static void a6xx_llc_slices_destroy(struct a6xx_gpu *a6xx_gpu)
static void a6xx_llc_slices_init(struct platform_device *pdev,
struct a6xx_gpu *a6xx_gpu, bool is_a7xx)
{
struct device_node *phandle;
/* No LLCC on non-RPMh (and by extension, non-GMU) SoCs */
if (adreno_has_gmu_wrapper(&a6xx_gpu->base))
return;
/*
* There is a different programming path for A6xx targets with an
* mmu500 attached, so detect if that is the case
*/
phandle = of_parse_phandle(pdev->dev.of_node, "iommus", 0);
a6xx_gpu->have_mmu500 = (phandle &&
of_device_is_compatible(phandle, "arm,mmu-500"));
of_node_put(phandle);
if (is_a7xx || !a6xx_gpu->have_mmu500)
a6xx_gpu->llc_mmio = msm_ioremap(pdev, "cx_mem");
else
a6xx_gpu->llc_mmio = NULL;
a6xx_gpu->llc_slice = llcc_slice_getd(LLCC_GPU);
a6xx_gpu->htw_llc_slice = llcc_slice_getd(LLCC_GPUHTW);
if (IS_ERR_OR_NULL(a6xx_gpu->llc_slice) && IS_ERR_OR_NULL(a6xx_gpu->htw_llc_slice))
a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL);
}
#define GBIF_CLIENT_HALT_MASK BIT(0)
@ -2537,6 +2440,142 @@ static bool a6xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
return progress;
}
static void
perfcntr_select(struct msm_ringbuffer *ring, enum adreno_pipe pipe,
uint32_t regidx, uint32_t *countables, uint32_t nr,
uint32_t **reglist)
{
OUT_PKT4(ring, regidx, nr);
for (unsigned i = 0; i < nr; i++)
OUT_RING(ring, countables[i]);
if (!*reglist)
return;
for (unsigned i = 0; i < nr; i++) {
/*
* Bitfield is in same position on a7xx, but only 2 bits..
* which is sufficient for NONE/BR/BV:
*/
*(*reglist)++ = A8XX_CP_APERTURE_CNTL_HOST_PIPEID(pipe);
*(*reglist)++ = regidx + i;
*(*reglist)++ = countables[i];
}
}
static void
a6xx_perfcntr_configure(struct msm_gpu *gpu, struct msm_ringbuffer *ring,
const struct msm_perfcntr_stream *stream)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
enum adreno_pipe pipe = PIPE_NONE;
uint32_t *reglist = NULL;
uint32_t *reglist_sel_start;
if (to_adreno_gpu(gpu)->info->family >= ADRENO_7XX_GEN1) {
WARN_ON(!a6xx_gpu->pwrup_reglist_emitted);
struct cpu_gpu_lock *lock = a6xx_gpu->pwrup_reglist_ptr;
int off = (2 * lock->ifpc_list_len) +
(2 * lock->preemption_list_len) +
(3 * a6xx_gpu->dynamic_sel_reglist_offset);
reglist = (uint32_t *)&lock->regs[0];
reglist += off;
reglist_sel_start = reglist;
/* Clear any previously configured SEL reg entries: */
lock->dynamic_list_len = a6xx_gpu->dynamic_sel_reglist_offset;
/*
* Ensure CP sees the dynamic_list_len update before we
* start modifying the SEL entries:
*/
dma_wmb();
}
for (unsigned i = 0; i < stream->nr_groups; i++) {
unsigned group_idx = msm_perfcntr_group_idx(stream, i);
unsigned base = msm_perfcntr_counter_base(stream, group_idx);
const struct msm_perfcntr_group *group =
&gpu->perfcntr_groups[group_idx];
struct msm_perfcntr_group_state *group_state =
gpu->perfcntrs->groups[group_idx];
if (group->pipe != pipe) {
pipe = group->pipe;
OUT_PKT7(ring, CP_THREAD_CONTROL, 1);
if (pipe == PIPE_BR) {
OUT_RING(ring, CP_SET_THREAD_BR);
} else if (pipe == PIPE_BV) {
OUT_RING(ring, CP_SET_THREAD_BV);
} else {
OUT_RING(ring, CP_SET_THREAD_BOTH);
}
}
const struct msm_perfcntr_counter *counter = &group->counters[base];
unsigned nr = group_state->allocated_counters;
perfcntr_select(ring, pipe, counter->select_reg,
group_state->countables, nr, &reglist);
for (unsigned s = 0; s < ARRAY_SIZE(counter->slice_select_regs); s++) {
if (!counter->slice_select_regs[s])
break;
perfcntr_select(ring, pipe, counter->slice_select_regs[s],
group_state->countables, nr, &reglist);
}
}
if (pipe != PIPE_NONE) {
OUT_PKT7(ring, CP_THREAD_CONTROL, 1);
OUT_RING(ring, CP_SET_THREAD_BOTH);
}
OUT_PKT7(ring, CP_MEM_WRITE, 3);
OUT_RING(ring, lower_32_bits(rbmemptr(ring, perfcntr_fence)));
OUT_RING(ring, upper_32_bits(rbmemptr(ring, perfcntr_fence)));
OUT_RING(ring, stream->sel_fence);
/*
* Update the pwrup reglist size before flushing. Kgsl does a shared-
* memory spinlock dance with SQE to avoid racing with IFPC exit. But
* we can skip that since the ringbuffer programming will be executed
* by SQE after dynamic reglist size is updated. So even if we lose
* the race, the register programming in the rb will overwrite/correct
* the SEL regs restored by SQE on IFPC exit, before sampling begins.
*/
if (reglist) {
struct cpu_gpu_lock *lock = a6xx_gpu->pwrup_reglist_ptr;
unsigned nr_regs = (reglist - reglist_sel_start) / 3;
/*
* Ensure CP sees updates to the pwrup_reglist before it
* sees the new (increased) length:
*/
dma_wmb();
/* Update dynamic reglist len to include new SEL reg programming: */
lock->dynamic_list_len = a6xx_gpu->dynamic_sel_reglist_offset + nr_regs;
WARN_ON_ONCE(reglist > (uint32_t *)((uint8_t *)lock + PWRUP_REGLIST_SIZE));
}
a6xx_flush_yield(gpu, ring);
/* Check to see if we need to start preemption */
if (adreno_is_a8xx(to_adreno_gpu(gpu)))
a8xx_preempt_trigger(gpu);
else
a6xx_preempt_trigger(gpu);
}
static u32 fuse_to_supp_hw(const struct adreno_info *info, u32 fuse)
{
if (!info->speedbins)
@ -2560,7 +2599,7 @@ static int a6xx_read_speedbin(struct device *dev, struct a6xx_gpu *a6xx_gpu,
return ret;
if (info->quirks & ADRENO_QUIRK_SOFTFUSE) {
*speedbin = a6xx_llc_read(a6xx_gpu, REG_A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS);
*speedbin = a6xx_cx_misc_read(a6xx_gpu, REG_A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS);
*speedbin = A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS_FINALFREQLIMIT(*speedbin);
return 0;
}
@ -2621,6 +2660,7 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
struct platform_device *pdev = priv->gpu_pdev;
struct adreno_platform_config *config = pdev->dev.platform_data;
const struct adreno_info *info = config->info;
struct device_node *phandle;
struct a6xx_gpu *a6xx_gpu;
struct adreno_gpu *adreno_gpu;
struct msm_gpu *gpu;
@ -2636,6 +2676,20 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
adreno_gpu = &a6xx_gpu->base;
gpu = &adreno_gpu->base;
if ((ADRENO_6XX_GEN1 <= config->info->family) &&
(config->info->family <= ADRENO_6XX_GEN4)) {
gpu->perfcntr_groups = a6xx_perfcntr_groups;
gpu->num_perfcntr_groups = a6xx_num_perfcntr_groups;
} else if ((ADRENO_7XX_GEN1 <= config->info->family) &&
(config->info->family <= ADRENO_7XX_GEN3)) {
gpu->perfcntr_groups = a7xx_perfcntr_groups;
gpu->num_perfcntr_groups = a7xx_num_perfcntr_groups;
} else if ((ADRENO_8XX_GEN1 <= config->info->family) &&
(config->info->family <= ADRENO_8XX_GEN2)) {
gpu->perfcntr_groups = a8xx_perfcntr_groups;
gpu->num_perfcntr_groups = a8xx_num_perfcntr_groups;
}
mutex_init(&a6xx_gpu->gmu.lock);
spin_lock_init(&a6xx_gpu->aperture_lock);
@ -2657,6 +2711,20 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
a6xx_llc_slices_init(pdev, a6xx_gpu, is_a7xx);
/*
* There is a different programming path for A6xx targets with an
* mmu500 attached, so detect if that is the case
*/
phandle = of_parse_phandle(pdev->dev.of_node, "iommus", 0);
a6xx_gpu->have_mmu500 = (phandle &&
of_device_is_compatible(phandle, "arm,mmu-500"));
of_node_put(phandle);
if (is_a7xx || !a6xx_gpu->have_mmu500)
a6xx_gpu->cx_misc_mmio = msm_ioremap(pdev, "cx_mem");
else
a6xx_gpu->cx_misc_mmio = NULL;
ret = a6xx_set_supported_hw(&pdev->dev, a6xx_gpu, info);
if (ret) {
a6xx_llc_slices_destroy(a6xx_gpu);
@ -2700,10 +2768,10 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu,
adreno_gpu->funcs->mmu_fault_handler);
ret = a6xx_calc_ubwc_config(adreno_gpu);
if (ret) {
adreno_gpu->ubwc_config = qcom_ubwc_config_get_data();
if (IS_ERR(adreno_gpu->ubwc_config)) {
a6xx_destroy(&(a6xx_gpu->base.base));
return ERR_PTR(ret);
return ERR_CAST(adreno_gpu->ubwc_config);
}
/* Set up the preemption specific bits and pieces for each ringbuffer */
@ -2740,6 +2808,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = {
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
.perfcntr_configure = a6xx_perfcntr_configure,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_gmu_get_timestamp,
@ -2773,6 +2842,7 @@ const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
.perfcntr_configure = a6xx_perfcntr_configure,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_get_timestamp,
@ -2809,6 +2879,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
.perfcntr_configure = a6xx_perfcntr_configure,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_gmu_get_timestamp,
@ -2838,6 +2909,9 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
.progress = a8xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
.perfcntr_configure = a6xx_perfcntr_configure,
.perfcntr_flush = a8xx_perfcntr_flush,
},
.init = a6xx_gpu_init,
.get_timestamp = a8xx_gmu_get_timestamp,

View File

@ -21,17 +21,19 @@ struct cpu_gpu_lock {
uint32_t cpu_req;
uint32_t turn;
union {
/* a6xx: */
struct {
uint16_t list_length;
uint16_t list_offset;
};
/* a7xx+: */
struct {
uint8_t ifpc_list_len;
uint8_t preemption_list_len;
uint16_t dynamic_list_len;
};
};
uint64_t regs[62];
uint64_t regs[];
};
/**
@ -96,13 +98,21 @@ struct a6xx_gpu {
uint32_t *shadow;
struct drm_gem_object *pwrup_reglist_bo;
#define PWRUP_REGLIST_SIZE (2 * PAGE_SIZE)
void *pwrup_reglist_ptr;
uint64_t pwrup_reglist_iova;
bool pwrup_reglist_emitted;
/*
* Offset of start of SEL regs appended to pwrup_reglist. This
* is equal to lock->dynamic_list_len if no SEL regs are appended
* to the end of the dynamic reglist.
*/
uint16_t dynamic_sel_reglist_offset;
bool has_whereami;
void __iomem *llc_mmio;
void __iomem *cx_misc_mmio;
void *llc_slice;
void *htw_llc_slice;
bool have_mmu500;
@ -240,19 +250,19 @@ static inline bool a6xx_has_gbif(struct adreno_gpu *gpu)
return true;
}
static inline void a6xx_llc_rmw(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 mask, u32 or)
static inline void a6xx_cx_misc_rmw(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 mask, u32 or)
{
return msm_rmw(a6xx_gpu->llc_mmio + (reg << 2), mask, or);
return msm_rmw(a6xx_gpu->cx_misc_mmio + (reg << 2), mask, or);
}
static inline u32 a6xx_llc_read(struct a6xx_gpu *a6xx_gpu, u32 reg)
static inline u32 a6xx_cx_misc_read(struct a6xx_gpu *a6xx_gpu, u32 reg)
{
return readl(a6xx_gpu->llc_mmio + (reg << 2));
return readl(a6xx_gpu->cx_misc_mmio + (reg << 2));
}
static inline void a6xx_llc_write(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 value)
static inline void a6xx_cx_misc_write(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 value)
{
writel(value, a6xx_gpu->llc_mmio + (reg << 2));
writel(value, a6xx_gpu->cx_misc_mmio + (reg << 2));
}
#define shadowptr(_a6xx_gpu, _ring) ((_a6xx_gpu)->shadow_iova + \
@ -271,7 +281,7 @@ 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);
int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node);
void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu);
void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu);
void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu, bool force_on);
void a6xx_preempt_init(struct msm_gpu *gpu);
void a6xx_preempt_hw_init(struct msm_gpu *gpu);
@ -317,6 +327,7 @@ void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_
void a6xx_gpu_sw_reset(struct msm_gpu *gpu, bool assert);
int a6xx_fenced_write(struct a6xx_gpu *gpu, u32 offset, u64 value, u32 mask, bool is_64b);
void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
void a6xx_flush_yield(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
int a6xx_zap_shader_init(struct msm_gpu *gpu);
void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off);
@ -333,5 +344,6 @@ void a8xx_preempt_hw_init(struct msm_gpu *gpu);
void a8xx_preempt_trigger(struct msm_gpu *gpu);
void a8xx_preempt_irq(struct msm_gpu *gpu);
bool a8xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
void a8xx_perfcntr_flush(struct msm_gpu *gpu);
void a8xx_recover(struct msm_gpu *gpu);
#endif /* __A6XX_GPU_H__ */

View File

@ -261,7 +261,7 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu)
mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000));
/* Enable or disable postamble as needed */
sysprof = refcount_read(&a6xx_gpu->base.base.sysprof_active) > 1;
sysprof = msm_gpu_sysprof_no_perfcntr_zap(gpu);
if (!sysprof && !a6xx_gpu->postamble_enabled)
preempt_prepare_postamble(a6xx_gpu);

View File

@ -104,7 +104,7 @@ void a8xx_gpu_get_slice_info(struct msm_gpu *gpu)
return;
}
slice_mask &= a6xx_llc_read(a6xx_gpu,
slice_mask &= a6xx_cx_misc_read(a6xx_gpu,
REG_A8XX_CX_MISC_SLICE_ENABLE_FINAL);
a6xx_gpu->slice_mask = slice_mask;
@ -265,8 +265,8 @@ static void a8xx_set_cp_protect(struct msm_gpu *gpu)
* Last span feature is only supported on PIPE specific register.
* So update those here
*/
a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_CP_PROTECT_PIPE(protect->count_max), final_cfg);
a8xx_write_pipe(gpu, PIPE_BV, REG_A8XX_CP_PROTECT_PIPE(protect->count_max), final_cfg);
a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_CP_PROTECT_PIPE(15), final_cfg);
a8xx_write_pipe(gpu, PIPE_BV, REG_A8XX_CP_PROTECT_PIPE(15), final_cfg);
a8xx_aperture_clear(gpu);
}
@ -275,41 +275,37 @@ static void a8xx_set_ubwc_config(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
const struct qcom_ubwc_cfg_data *cfg = adreno_gpu->ubwc_config;
u32 level2_swizzling_dis = !(cfg->ubwc_swizzle & UBWC_SWIZZLE_ENABLE_LVL2);
u32 level3_swizzling_dis = !(cfg->ubwc_swizzle & UBWC_SWIZZLE_ENABLE_LVL3);
u32 level2_swizzling_dis = !(qcom_ubwc_swizzle(cfg) & UBWC_SWIZZLE_ENABLE_LVL2);
u32 level3_swizzling_dis = !(qcom_ubwc_swizzle(cfg) & UBWC_SWIZZLE_ENABLE_LVL3);
bool rgba8888_lossless = false, fp16compoptdis = false;
bool yuvnotcomptofc = false, min_acc_len_64b = false;
bool rgb565_predicator = false, amsbc = false;
bool rgb565_predicator = false;
bool amsbc = qcom_ubwc_enable_amsbc(cfg);
bool ubwc_mode = qcom_ubwc_get_ubwc_mode(cfg);
u32 ubwc_version = cfg->ubwc_enc_version;
u32 hbb, hbb_hi, hbb_lo, mode = 1;
u32 hbb, hbb_hi, hbb_lo, mode;
u8 uavflagprd_inv = 2;
switch (ubwc_version) {
case UBWC_6_0:
yuvnotcomptofc = true;
mode = 5;
break;
case UBWC_5_0:
amsbc = true;
rgb565_predicator = true;
mode = 4;
break;
case UBWC_4_0:
amsbc = true;
rgb565_predicator = true;
fp16compoptdis = true;
rgba8888_lossless = true;
mode = 2;
break;
case UBWC_3_0:
amsbc = true;
mode = 1;
break;
default:
if (ubwc_version > UBWC_6_0)
dev_err(&gpu->pdev->dev, "Unknown UBWC version: 0x%x\n", ubwc_version);
break;
}
if (ubwc_version == UBWC_6_0)
yuvnotcomptofc = true;
if (ubwc_version < UBWC_5_0 &&
ubwc_version >= UBWC_4_0)
rgba8888_lossless = true;
if (ubwc_version < UBWC_4_3)
fp16compoptdis = true;
if (cfg->ubwc_enc_version >= UBWC_4_0)
rgb565_predicator = true;
if (ubwc_version < UBWC_3_0)
dev_err(&gpu->pdev->dev, "Unsupported UBWC version: 0x%x\n", ubwc_version);
mode = qcom_ubwc_version_tag(cfg);
/*
* We subtract 13 from the highest bank bit (13 is the minimum value
@ -468,6 +464,7 @@ static void a8xx_patch_pwrup_reglist(struct msm_gpu *gpu)
}
lock->dynamic_list_len = dyn_pwrup_reglist_count;
a6xx_gpu->dynamic_sel_reglist_offset = dyn_pwrup_reglist_count;
done:
a8xx_aperture_clear(gpu);
@ -488,15 +485,7 @@ static int a8xx_preempt_start(struct msm_gpu *gpu)
a6xx_emit_set_pseudo_reg(ring, a6xx_gpu, NULL);
/* Yield the floor on command completion */
OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4);
OUT_RING(ring, 0x00);
OUT_RING(ring, 0x00);
OUT_RING(ring, 0x00);
/* Generate interrupt on preemption completion */
OUT_RING(ring, 0x00);
a6xx_flush(gpu, ring);
a6xx_flush_yield(gpu, ring);
return a8xx_idle(gpu, ring) ? 0 : -EINVAL;
}
@ -849,7 +838,7 @@ static int hw_init(struct msm_gpu *gpu)
*/
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) {
if (!ret && msm_gpu_sysprof_no_perfcntr_zap(gpu)) {
ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
if (!ret)
set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
@ -886,17 +875,22 @@ void a8xx_recover(struct msm_gpu *gpu)
adreno_dump_info(gpu);
if (hang_debug)
a8xx_dump(gpu);
/*
* To handle recovery specific sequences during the rpm suspend we are
* about to trigger
*/
a6xx_gpu->hung = true;
/* Halt SQE first */
gpu_write(gpu, REG_A8XX_CP_SQE_CNTL, 3);
if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) {
/*
* Sometimes crashstate capture is skipped, so SQE should be
* halted here again
*/
gpu_write(gpu, REG_A8XX_CP_SQE_CNTL, 3);
if (hang_debug)
a8xx_dump(gpu);
}
pm_runtime_dont_use_autosuspend(&gpu->pdev->dev);
@ -1353,3 +1347,23 @@ bool a8xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
return true;
}
void a8xx_perfcntr_flush(struct msm_gpu *gpu)
{
u32 val;
/*
* Flush delta counters (both perf counters and pipe stats) present in
* RBBM_S and RBBM_US to perf RAM logic to get the latest data.
*/
gpu_write(gpu, REG_A8XX_RBBM_PERFCTR_FLUSH_HOST_CMD, BIT(0));
gpu_write(gpu, REG_A8XX_RBBM_SLICE_PERFCTR_FLUSH_HOST_CMD, BIT(0));
/* Ensure all writes are posted before polling status register */
wmb();
if (gpu_poll_timeout(gpu, REG_A8XX_RBBM_PERFCTR_FLUSH_HOST_STATUS, val,
val & BIT(0), 100, 100 * 1000)) {
dev_err(&gpu->pdev->dev, "Perfcounter flush timed out: status=0x%08x\n", val);
}
}

View File

@ -242,7 +242,7 @@ void a8xx_preempt_trigger(struct msm_gpu *gpu)
mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000));
/* Enable or disable postamble as needed */
sysprof = refcount_read(&a6xx_gpu->base.base.sysprof_active) > 1;
sysprof = msm_gpu_sysprof_no_perfcntr_zap(gpu);
if (!sysprof && !a6xx_gpu->postamble_enabled)
preempt_prepare_postamble(a6xx_gpu);

View File

@ -307,8 +307,10 @@ MODULE_DEVICE_TABLE(of, dt_match);
static int adreno_runtime_resume(struct device *dev)
{
struct msm_gpu *gpu = dev_to_gpu(dev);
return gpu->funcs->pm_resume(gpu);
int ret = gpu->funcs->pm_resume(gpu);
if (!ret)
ret = msm_perfcntr_resume(gpu);
return ret;
}
static int adreno_runtime_suspend(struct device *dev)
@ -322,6 +324,8 @@ static int adreno_runtime_suspend(struct device *dev)
*/
WARN_ON_ONCE(gpu->active_submits);
msm_perfcntr_suspend(gpu);
return gpu->funcs->pm_suspend(gpu);
}

View File

@ -434,12 +434,12 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
case MSM_PARAM_UBWC_SWIZZLE:
if (!adreno_gpu->ubwc_config)
return UERR(ENOENT, drm, "no UBWC on this platform");
*value = adreno_gpu->ubwc_config->ubwc_swizzle;
*value = qcom_ubwc_swizzle(adreno_gpu->ubwc_config);
return 0;
case MSM_PARAM_MACROTILE_MODE:
if (!adreno_gpu->ubwc_config)
return UERR(ENOENT, drm, "no UBWC on this platform");
*value = adreno_gpu->ubwc_config->macrotile_mode;
*value = qcom_ubwc_macrotile_mode(adreno_gpu->ubwc_config);
return 0;
case MSM_PARAM_UCHE_TRAP_BASE:
*value = adreno_gpu->uche_trap_base;
@ -500,7 +500,7 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_context *ctx,
return 0;
}
case MSM_PARAM_SYSPROF:
if (!capable(CAP_SYS_ADMIN))
if (!perfmon_capable())
return UERR(EPERM, drm, "invalid permissions");
return msm_context_set_sysprof(ctx, gpu, value);
case MSM_PARAM_EN_VM_BIND:
@ -708,11 +708,10 @@ void adreno_recover(struct msm_gpu *gpu)
struct drm_device *dev = gpu->dev;
int ret;
// XXX pm-runtime?? we *need* the device to be off after this
// so maybe continuing to call ->pm_suspend/resume() is better?
msm_perfcntr_suspend(gpu);
gpu->funcs->pm_suspend(gpu);
gpu->funcs->pm_resume(gpu);
msm_perfcntr_resume(gpu);
ret = msm_gpu_hw_init(gpu);
if (ret) {

View File

@ -236,12 +236,7 @@ struct adreno_gpu {
/* firmware: */
const struct firmware *fw[ADRENO_FW_MAX];
/*
* The migration to the central UBWC config db is still in flight - keep
* a copy containing some local fixups until that's done.
*/
const struct qcom_ubwc_cfg_data *ubwc_config;
struct qcom_ubwc_cfg_data _ubwc_config;
/*
* Register offsets are different between some GPUs.
@ -592,6 +587,11 @@ static inline int adreno_is_a8xx(struct adreno_gpu *gpu)
return gpu->info->family >= ADRENO_8XX_GEN1;
}
static inline int adreno_is_a810(struct adreno_gpu *gpu)
{
return gpu->info->chip_ids[0] == 0x44010000;
}
static inline int adreno_is_x285(struct adreno_gpu *gpu)
{
return gpu->info->chip_ids[0] == 0x44070001;

View File

@ -0,0 +1,279 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2026, Luca Weiss <luca.weiss@fairphone.com>
*/
#ifndef _DPU_10_2_MILOS_H
#define _DPU_10_2_MILOS_H
static const struct dpu_caps milos_dpu_caps = {
.max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.max_mixer_blendstages = 0x7,
.has_src_split = true,
.has_dim_layer = true,
.has_idle_pc = true,
.has_3d_merge = true,
.max_linewidth = 8192,
.pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
};
static const struct dpu_mdp_cfg milos_mdp = {
.name = "top_0",
.base = 0, .len = 0x494,
.clk_ctrls = {
[DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 },
},
};
static const struct dpu_ctl_cfg milos_ctl[] = {
{
.name = "ctl_0", .id = CTL_0,
.base = 0x15000, .len = 0x1000,
.intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9),
}, {
.name = "ctl_1", .id = CTL_1,
.base = 0x16000, .len = 0x1000,
.intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10),
}, {
.name = "ctl_2", .id = CTL_2,
.base = 0x17000, .len = 0x1000,
.intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11),
}, {
.name = "ctl_3", .id = CTL_3,
.base = 0x18000, .len = 0x1000,
.intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12),
},
};
static const struct dpu_sspp_cfg milos_sspp[] = {
{
.name = "sspp_0", .id = SSPP_VIG0,
.base = 0x4000, .len = 0x344,
.features = VIG_SDM845_MASK_SDMA,
.sblk = &dpu_vig_sblk_qseed3_3_3,
.xin_id = 0,
.type = SSPP_TYPE_VIG,
}, {
.name = "sspp_8", .id = SSPP_DMA0,
.base = 0x24000, .len = 0x344,
.features = DMA_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.xin_id = 1,
.type = SSPP_TYPE_DMA,
}, {
.name = "sspp_9", .id = SSPP_DMA1,
.base = 0x26000, .len = 0x344,
.features = DMA_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.xin_id = 5,
.type = SSPP_TYPE_DMA,
}, {
.name = "sspp_10", .id = SSPP_DMA2,
.base = 0x28000, .len = 0x344,
.features = DMA_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.xin_id = 9,
.type = SSPP_TYPE_DMA,
},
};
static const struct dpu_lm_cfg milos_lm[] = {
{
.name = "lm_0", .id = LM_0,
.base = 0x44000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.pingpong = PINGPONG_0,
.dspp = DSPP_0,
}, {
.name = "lm_2", .id = LM_2,
.base = 0x46000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_3,
.pingpong = PINGPONG_2,
}, {
.name = "lm_3", .id = LM_3,
.base = 0x47000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_2,
.pingpong = PINGPONG_3,
},
};
static const struct dpu_dspp_cfg milos_dspp[] = {
{
.name = "dspp_0", .id = DSPP_0,
.base = 0x54000, .len = 0x1800,
.sblk = &sdm845_dspp_sblk,
},
};
static const struct dpu_pingpong_cfg milos_pp[] = {
{
.name = "pingpong_0", .id = PINGPONG_0,
.base = 0x69000, .len = 0,
.sblk = &sc7280_pp_sblk,
.intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
}, {
.name = "pingpong_2", .id = PINGPONG_2,
.base = 0x6b000, .len = 0,
.sblk = &sc7280_pp_sblk,
.merge_3d = MERGE_3D_1,
.intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10),
}, {
.name = "pingpong_3", .id = PINGPONG_3,
.base = 0x6c000, .len = 0,
.sblk = &sc7280_pp_sblk,
.merge_3d = MERGE_3D_1,
.intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11),
}, {
.name = "pingpong_cwb_0", .id = PINGPONG_CWB_0,
.base = 0x66000, .len = 0,
.sblk = &sc7280_pp_sblk,
},
};
static const struct dpu_merge_3d_cfg milos_merge_3d[] = {
{
.name = "merge_3d_1", .id = MERGE_3D_1,
.base = 0x4f000, .len = 0x8,
},
};
/*
* NOTE: Each display compression engine (DCE) contains dual hard
* slice DSC encoders so both share same base address but with
* its own different sub block address.
*/
static const struct dpu_dsc_cfg milos_dsc[] = {
{
.name = "dce_0_0", .id = DSC_0,
.base = 0x80000, .len = 0x6,
.features = BIT(DPU_DSC_NATIVE_42x_EN),
.sblk = &milos_dsc_sblk_0,
}, {
.name = "dce_0_1", .id = DSC_1,
.base = 0x80000, .len = 0x6,
.features = BIT(DPU_DSC_NATIVE_42x_EN),
.sblk = &milos_dsc_sblk_1,
},
};
static const struct dpu_wb_cfg milos_wb[] = {
{
.name = "wb_2", .id = WB_2,
.base = 0x65000, .len = 0x2c8,
.features = WB_SDM845_MASK,
.format_list = wb2_formats_rgb_yuv,
.num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv),
.xin_id = 6,
.maxlinewidth = 4096,
.intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4),
},
};
static const struct dpu_cwb_cfg milos_cwb[] = {
{
.name = "cwb_0", .id = CWB_0,
.base = 0x66200, .len = 0x8,
},
};
static const struct dpu_intf_cfg milos_intf[] = {
{
.name = "intf_0", .id = INTF_0,
.base = 0x34000, .len = 0x300,
.type = INTF_DP,
.controller_id = MSM_DP_CONTROLLER_0,
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25),
}, {
.name = "intf_1", .id = INTF_1,
.base = 0x35000, .len = 0x300,
.type = INTF_DSI,
.controller_id = MSM_DSI_CONTROLLER_0,
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27),
.intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF1_TEAR_INTR, 2),
}, {
.name = "intf_3", .id = INTF_3,
.base = 0x37000, .len = 0x300,
.type = INTF_DP,
.controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31),
},
};
static const struct dpu_perf_cfg milos_perf_data = {
.max_bw_low = 7100000,
.max_bw_high = 9800000,
.min_core_ib = 2500000,
.min_llcc_ib = 0,
.min_dram_ib = 1600000,
.min_prefill_lines = 40,
/* FIXME: lut tables */
.danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0},
.safe_lut_tbl = {0xff00, 0xfff0, 0x0fff},
.qos_lut_tbl = {
{.nentry = ARRAY_SIZE(sc7180_qos_linear),
.entries = sc7180_qos_linear
},
{.nentry = ARRAY_SIZE(sc7180_qos_macrotile),
.entries = sc7180_qos_macrotile
},
{.nentry = ARRAY_SIZE(sc7180_qos_nrt),
.entries = sc7180_qos_nrt
},
/* TODO: macrotile-qseed is different from macrotile */
},
.cdp_cfg = {
{.rd_enable = 1, .wr_enable = 1},
{.rd_enable = 1, .wr_enable = 0}
},
.clk_inefficiency_factor = 105,
.bw_inefficiency_factor = 120,
};
static const struct dpu_mdss_version milos_mdss_ver = {
.core_major_ver = 10,
.core_minor_ver = 2,
};
const struct dpu_mdss_cfg dpu_milos_cfg = {
.mdss_ver = &milos_mdss_ver,
.caps = &milos_dpu_caps,
.mdp = &milos_mdp,
.cdm = &dpu_cdm_5_x,
.ctl_count = ARRAY_SIZE(milos_ctl),
.ctl = milos_ctl,
.sspp_count = ARRAY_SIZE(milos_sspp),
.sspp = milos_sspp,
.mixer_count = ARRAY_SIZE(milos_lm),
.mixer = milos_lm,
.dspp_count = ARRAY_SIZE(milos_dspp),
.dspp = milos_dspp,
.pingpong_count = ARRAY_SIZE(milos_pp),
.pingpong = milos_pp,
.dsc_count = ARRAY_SIZE(milos_dsc),
.dsc = milos_dsc,
.merge_3d_count = ARRAY_SIZE(milos_merge_3d),
.merge_3d = milos_merge_3d,
.wb_count = ARRAY_SIZE(milos_wb),
.wb = milos_wb,
.cwb_count = ARRAY_SIZE(milos_cwb),
.cwb = milos_cwb,
.intf_count = ARRAY_SIZE(milos_intf),
.intf = milos_intf,
.vbif = &milos_vbif,
.perf = &milos_perf_data,
};
#endif

View File

@ -454,6 +454,16 @@ static const struct dpu_dsc_sub_blks dsc_sblk_1 = {
.ctl = {.name = "ctl", .base = 0xF80, .len = 0x10},
};
static const struct dpu_dsc_sub_blks milos_dsc_sblk_0 = {
.enc = {.name = "enc", .base = 0x100, .len = 0x100},
.ctl = {.name = "ctl", .base = 0xF00, .len = 0x80},
};
static const struct dpu_dsc_sub_blks milos_dsc_sblk_1 = {
.enc = {.name = "enc", .base = 0x200, .len = 0x100},
.ctl = {.name = "ctl", .base = 0xF80, .len = 0x80},
};
static const struct dpu_dsc_sub_blks sm8750_dsc_sblk_0 = {
.enc = {.name = "enc", .base = 0x100, .len = 0x100},
.ctl = {.name = "ctl", .base = 0xF00, .len = 0x24},
@ -513,6 +523,23 @@ static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = {
},
};
static const struct dpu_vbif_cfg milos_vbif = {
.len = 0x1074,
.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,
},
.qos_nrt_tbl = {
.npriority_lvl = ARRAY_SIZE(sdm845_nrt_pri_lvl),
.priority_lvl = sdm845_nrt_pri_lvl,
},
.memtype_count = 16,
.memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
};
static const struct dpu_vbif_cfg msm8996_vbif = {
.len = 0x1040,
.default_ot_rd_limit = 32,
@ -754,6 +781,8 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = {
#include "catalog/dpu_9_2_x1e80100.h"
#include "catalog/dpu_10_0_sm8650.h"
#include "catalog/dpu_10_2_milos.h"
#include "catalog/dpu_12_0_sm8750.h"
#include "catalog/dpu_12_2_glymur.h"
#include "catalog/dpu_12_4_eliza.h"

View File

@ -766,6 +766,7 @@ struct dpu_mdss_cfg {
extern const struct dpu_mdss_cfg dpu_eliza_cfg;
extern const struct dpu_mdss_cfg dpu_glymur_cfg;
extern const struct dpu_mdss_cfg dpu_kaanapali_cfg;
extern const struct dpu_mdss_cfg dpu_milos_cfg;
extern const struct dpu_mdss_cfg dpu_msm8917_cfg;
extern const struct dpu_mdss_cfg dpu_msm8937_cfg;
extern const struct dpu_mdss_cfg dpu_msm8953_cfg;

View File

@ -310,34 +310,35 @@ void dpu_hw_setup_format_impl(struct dpu_sw_pipe *pipe, const struct msm_format
if (fmt->fetch_mode != MDP_FETCH_LINEAR) {
u32 hbb = ctx->ubwc->highest_bank_bit - 13;
u32 ctrl_val;
u32 ctrl_val = 0;
if (MSM_FORMAT_IS_UBWC(fmt))
opmode |= MDSS_MDP_OP_BWC_EN;
src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */
if (ctx->ubwc->ubwc_enc_version == UBWC_1_0) {
fast_clear = fmt->alpha_enable ? BIT(31) : 0;
ctrl_val = fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) |
BIT(8) | (hbb << 4);
} else if (ctx->ubwc->ubwc_enc_version == UBWC_2_0) {
fast_clear = fmt->alpha_enable ? BIT(31) : 0;
ctrl_val = fast_clear | ctx->ubwc->ubwc_swizzle | (hbb << 4);
} else if (ctx->ubwc->ubwc_enc_version == UBWC_3_0) {
ctrl_val = BIT(30) | (ctx->ubwc->ubwc_swizzle) | (hbb << 4);
} else if (ctx->ubwc->ubwc_enc_version == UBWC_4_0) {
ctrl_val = MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30);
} else if (ctx->ubwc->ubwc_enc_version <= UBWC_6_0) {
if (MSM_FORMAT_IS_YUV(fmt))
ctrl_val = 0;
else if (MSM_FORMAT_IS_DX(fmt)) /* or FP16, but it's unsupported */
if (ctx->ubwc->ubwc_enc_version > UBWC_6_0) {
DRM_WARN_ONCE("Unsupported UBWC version %x\n", ctx->ubwc->ubwc_enc_version);
} else if (ctx->ubwc->ubwc_enc_version >= UBWC_5_0) {
if (!MSM_FORMAT_IS_YUV(fmt)) {
ctrl_val = BIT(30);
else
ctrl_val = BIT(30) | BIT(31);
if (!MSM_FORMAT_IS_DX(fmt)) /* and not FP16, but it's unsupported */
ctrl_val |= BIT(31);
}
/* SDE also sets bits for lossy formats, but we don't support them yet */
} else if (ctx->ubwc->ubwc_enc_version >= UBWC_4_0) {
ctrl_val = MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30);
} else if (ctx->ubwc->ubwc_enc_version >= UBWC_3_0) {
ctrl_val = BIT(30) | qcom_ubwc_swizzle(ctx->ubwc) | (hbb << 4);
} else if (ctx->ubwc->ubwc_enc_version >= UBWC_2_0) {
fast_clear = fmt->alpha_enable ? BIT(31) : 0;
ctrl_val = fast_clear | qcom_ubwc_swizzle(ctx->ubwc) | (hbb << 4);
} else if (ctx->ubwc->ubwc_enc_version >= UBWC_1_0) {
fast_clear = fmt->alpha_enable ? BIT(31) : 0;
ctrl_val = fast_clear |
(qcom_ubwc_swizzle(ctx->ubwc) & UBWC_SWIZZLE_ENABLE_LVL1) |
BIT(8) | (hbb << 4);
} else {
DRM_WARN_ONCE("Unsupported UBWC version %x\n", ctx->ubwc->ubwc_enc_version);
ctrl_val = 0;
}
DPU_REG_WRITE(c, ubwc_ctrl_off, ctrl_val);

View File

@ -1483,6 +1483,7 @@ static const struct of_device_id dpu_dt_match[] = {
{ .compatible = "qcom,eliza-dpu", .data = &dpu_eliza_cfg, },
{ .compatible = "qcom,glymur-dpu", .data = &dpu_glymur_cfg, },
{ .compatible = "qcom,kaanapali-dpu", .data = &dpu_kaanapali_cfg, },
{ .compatible = "qcom,milos-dpu", .data = &dpu_milos_cfg, },
{ .compatible = "qcom,msm8917-mdp5", .data = &dpu_msm8917_cfg, },
{ .compatible = "qcom,msm8937-mdp5", .data = &dpu_msm8937_cfg, },
{ .compatible = "qcom,msm8953-mdp5", .data = &dpu_msm8953_cfg, },

View File

@ -1781,8 +1781,7 @@ static bool dpu_plane_format_mod_supported(struct drm_plane *plane,
uint32_t format, uint64_t modifier)
{
struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
bool has_no_ubwc = (dpu_kms->mdss->ubwc_enc_version == 0) &&
(dpu_kms->mdss->ubwc_dec_version == 0);
bool has_no_ubwc = (dpu_kms->mdss->ubwc_enc_version == 0);
if (modifier == DRM_FORMAT_MOD_LINEAR)
return true;

View File

@ -2583,22 +2583,6 @@ void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl)
phy_init(phy);
}
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl)
{
struct msm_dp_ctrl_private *ctrl;
struct phy *phy;
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
phy = ctrl->phy;
msm_dp_ctrl_mainlink_disable(ctrl);
dev_pm_opp_set_rate(ctrl->dev, 0);
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
phy_power_off(phy);
}
void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl)
{
struct msm_dp_ctrl_private *ctrl;

View File

@ -19,7 +19,6 @@ struct phy;
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl);
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train);
void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl);
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl);

File diff suppressed because it is too large Load Diff

View File

@ -16,12 +16,11 @@ struct msm_dp {
struct platform_device *pdev;
struct drm_connector *connector;
struct drm_bridge *next_bridge;
bool link_ready;
struct drm_bridge *bridge;
bool audio_enabled;
bool power_on;
unsigned int connector_type;
bool is_edp;
bool internal_hpd;
struct msm_dp_audio *msm_dp_audio;
bool psr_supported;

View File

@ -15,56 +15,6 @@
#include "dp_audio.h"
#include "dp_drm.h"
/**
* msm_dp_bridge_detect - callback to determine if connector is connected
* @bridge: Pointer to drm bridge structure
* @connector: Pointer to drm connector structure
* Returns: Bridge's 'is connected' status
*/
static enum drm_connector_status
msm_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
{
struct msm_dp *dp;
dp = to_dp_bridge(bridge)->msm_dp_display;
drm_dbg_dp(dp->drm_dev, "link_ready = %s\n",
str_true_false(dp->link_ready));
return (dp->link_ready) ? connector_status_connected :
connector_status_disconnected;
}
static int msm_dp_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct msm_dp *dp;
dp = to_dp_bridge(bridge)->msm_dp_display;
drm_dbg_dp(dp->drm_dev, "link_ready = %s\n",
str_true_false(dp->link_ready));
/*
* There is no protection in the DRM framework to check if the display
* pipeline has been already disabled before trying to disable it again.
* Hence if the sink is unplugged, the pipeline gets disabled, but the
* crtc->active is still true. Any attempt to set the mode or manually
* disable this encoder will result in the crash.
*
* TODO: add support for telling the DRM subsystem that the pipeline is
* disabled by the hardware and thus all access to it should be forbidden.
* After that this piece of code can be removed.
*/
if (bridge->ops & DRM_BRIDGE_OP_HPD)
return (dp->link_ready) ? 0 : -ENOTCONN;
return 0;
}
/**
* msm_dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add()
* @bridge: Poiner to drm bridge
@ -82,12 +32,10 @@ static int msm_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connect
dp = to_dp_bridge(bridge)->msm_dp_display;
/* pluggable case assumes EDID is read when HPD */
if (dp->link_ready) {
rc = msm_dp_display_get_modes(dp);
if (rc <= 0) {
DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc);
return rc;
}
rc = msm_dp_display_get_modes(dp);
if (rc <= 0) {
DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc);
return rc;
} else {
drm_dbg_dp(connector->dev, "No sink connected\n");
}
@ -112,7 +60,6 @@ static const struct drm_bridge_funcs msm_dp_bridge_ops = {
.mode_valid = msm_dp_bridge_mode_valid,
.get_modes = msm_dp_bridge_get_modes,
.detect = msm_dp_bridge_detect,
.atomic_check = msm_dp_bridge_atomic_check,
.hpd_enable = msm_dp_bridge_hpd_enable,
.hpd_disable = msm_dp_bridge_hpd_disable,
.hpd_notify = msm_dp_bridge_hpd_notify,
@ -360,6 +307,8 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
}
}
msm_dp_display->bridge = bridge;
return 0;
}

View File

@ -25,6 +25,8 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
struct drm_encoder *encoder,
bool yuv_supported);
enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
struct drm_connector *connector);
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state);
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,

View File

@ -293,6 +293,14 @@ int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
return rc;
}
void msm_dp_panel_unplugged(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector)
{
drm_edid_connector_update(connector, NULL);
drm_edid_free(msm_dp_panel->drm_edid);
msm_dp_panel->drm_edid = NULL;
}
u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel,
u32 mode_edid_bpp, u32 mode_pclk_khz)
{

View File

@ -49,6 +49,8 @@ int msm_dp_panel_deinit(struct msm_dp_panel *msm_dp_panel);
int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en);
int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector);
void msm_dp_panel_unplugged(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector);
u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel, u32 mode_max_bpp,
u32 mode_pclk_khz);
int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel,

View File

@ -68,8 +68,8 @@
#define DP_DP_IRQ_HPD_INT_ACK (0x00000002)
#define DP_DP_HPD_REPLUG_INT_ACK (0x00000004)
#define DP_DP_HPD_UNPLUG_INT_ACK (0x00000008)
#define DP_DP_HPD_STATE_STATUS_BITS_MASK (0x0000000F)
#define DP_DP_HPD_STATE_STATUS_BITS_SHIFT (0x1C)
#define DP_DP_HPD_STATE_STATUS_BITS_MASK (0x00000007)
#define DP_DP_HPD_STATE_STATUS_BITS_SHIFT (0x1D)
#define REG_DP_DP_HPD_INT_MASK (0x0000000C)
#define DP_DP_HPD_PLUG_INT_MASK (0x00000001)

View File

@ -571,6 +571,8 @@ static const struct of_device_id dsi_phy_dt_match[] = {
.data = &dsi_phy_5nm_8350_cfgs },
{ .compatible = "qcom,sm8450-dsi-phy-5nm",
.data = &dsi_phy_5nm_8450_cfgs },
{ .compatible = "qcom,milos-dsi-phy-4nm",
.data = &dsi_phy_4nm_milos_cfgs },
{ .compatible = "qcom,sm8550-dsi-phy-4nm",
.data = &dsi_phy_4nm_8550_cfgs },
{ .compatible = "qcom,sm8650-dsi-phy-4nm",

View File

@ -61,6 +61,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8775p_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_5nm_sar2130p_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_4nm_milos_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs;

View File

@ -1436,6 +1436,29 @@ const struct msm_dsi_phy_cfg dsi_phy_5nm_sar2130p_cfgs = {
.quirks = DSI_PHY_7NM_QUIRK_V5_2,
};
const struct msm_dsi_phy_cfg dsi_phy_4nm_milos_cfgs = {
.has_phy_lane = true,
.regulator_data = dsi_phy_7nm_98000uA_regulators,
.num_regulators = ARRAY_SIZE(dsi_phy_7nm_98000uA_regulators),
.ops = {
.enable = dsi_7nm_phy_enable,
.disable = dsi_7nm_phy_disable,
.pll_init = dsi_pll_7nm_init,
.save_pll_state = dsi_7nm_pll_save_state,
.restore_pll_state = dsi_7nm_pll_restore_state,
.set_continuous_clock = dsi_7nm_set_continuous_clock,
},
.min_pll_rate = 600000000UL,
#ifdef CONFIG_64BIT
.max_pll_rate = 5000000000UL,
#else
.max_pll_rate = ULONG_MAX,
#endif
.io_start = { 0xae95000 },
.num_dsi_phy = 1,
.quirks = DSI_PHY_7NM_QUIRK_V5_2,
};
const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs = {
.has_phy_lane = true,
.regulator_data = dsi_phy_7nm_98400uA_regulators,

View File

@ -344,12 +344,6 @@ static int late_init_minor(struct drm_minor *minor)
return ret;
}
ret = msm_perf_debugfs_init(minor);
if (ret) {
DRM_DEV_ERROR(dev->dev, "could not install perf debugfs\n");
return ret;
}
return 0;
}

View File

@ -87,7 +87,6 @@ static int msm_drm_uninit(struct device *dev, const struct component_ops *gpu_op
msm_gem_shrinker_cleanup(ddev);
msm_perf_debugfs_cleanup(priv);
msm_rd_debugfs_cleanup(priv);
if (priv->kms)
@ -801,6 +800,7 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_CLOSE, msm_ioctl_submitqueue_close, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_VM_BIND, msm_ioctl_vm_bind, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_PERFCNTR_CONFIG, msm_ioctl_perfcntr_config, DRM_RENDER_ALLOW),
};
static void msm_show_fdinfo(struct drm_printer *p, struct drm_file *file)

View File

@ -45,7 +45,6 @@ struct msm_gpu;
struct msm_mmu;
struct msm_mdss;
struct msm_rd_state;
struct msm_perf_state;
struct msm_gem_submit;
struct msm_fence_context;
struct msm_disp_state;
@ -89,7 +88,6 @@ struct msm_drm_private {
struct msm_rd_state *rd; /* debugfs to dump all submits */
struct msm_rd_state *hangrd; /* debugfs to dump hanging submits */
struct msm_perf_state *perf;
/**
* total_mem: Total/global amount of memory backing GEM objects.
@ -230,6 +228,14 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
int msm_ioctl_vm_bind(struct drm_device *dev, void *data,
struct drm_file *file);
int msm_perfcntr_resume(struct msm_gpu *gpu);
void msm_perfcntr_suspend(struct msm_gpu *gpu);
int msm_ioctl_perfcntr_config(struct drm_device *dev, void *data,
struct drm_file *file);
struct msm_perfcntr_state * msm_perfcntr_init(struct msm_gpu *gpu);
void msm_perfcntr_cleanup(struct msm_gpu *gpu);
#ifdef CONFIG_DEBUG_FS
unsigned long msm_gem_shrinker_shrink(struct drm_device *dev, unsigned long nr_to_scan);
#endif
@ -435,8 +441,6 @@ void msm_rd_debugfs_cleanup(struct msm_drm_private *priv);
__printf(3, 4)
void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
const char *fmt, ...);
int msm_perf_debugfs_init(struct drm_minor *minor);
void msm_perf_debugfs_cleanup(struct msm_drm_private *priv);
#else
static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; }
__printf(3, 4)
@ -444,7 +448,6 @@ static inline void msm_rd_dump_submit(struct msm_rd_state *rd,
struct msm_gem_submit *submit,
const char *fmt, ...) {}
static inline void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) {}
static inline void msm_perf_debugfs_cleanup(struct msm_drm_private *priv) {}
#endif
struct clk *msm_clk_get(struct platform_device *pdev, const char *name);

View File

@ -681,104 +681,6 @@ static void hangcheck_handler(struct timer_list *t)
msm_gpu_retire(gpu);
}
/*
* Performance Counters:
*/
/* called under perf_lock */
static int update_hw_cntrs(struct msm_gpu *gpu, uint32_t ncntrs, uint32_t *cntrs)
{
uint32_t current_cntrs[ARRAY_SIZE(gpu->last_cntrs)];
int i, n = min(ncntrs, gpu->num_perfcntrs);
/* read current values: */
for (i = 0; i < gpu->num_perfcntrs; i++)
current_cntrs[i] = gpu_read(gpu, gpu->perfcntrs[i].sample_reg);
/* update cntrs: */
for (i = 0; i < n; i++)
cntrs[i] = current_cntrs[i] - gpu->last_cntrs[i];
/* save current values: */
for (i = 0; i < gpu->num_perfcntrs; i++)
gpu->last_cntrs[i] = current_cntrs[i];
return n;
}
static void update_sw_cntrs(struct msm_gpu *gpu)
{
ktime_t time;
uint32_t elapsed;
unsigned long flags;
spin_lock_irqsave(&gpu->perf_lock, flags);
if (!gpu->perfcntr_active)
goto out;
time = ktime_get();
elapsed = ktime_to_us(ktime_sub(time, gpu->last_sample.time));
gpu->totaltime += elapsed;
if (gpu->last_sample.active)
gpu->activetime += elapsed;
gpu->last_sample.active = msm_gpu_active(gpu);
gpu->last_sample.time = time;
out:
spin_unlock_irqrestore(&gpu->perf_lock, flags);
}
void msm_gpu_perfcntr_start(struct msm_gpu *gpu)
{
unsigned long flags;
pm_runtime_get_sync(&gpu->pdev->dev);
spin_lock_irqsave(&gpu->perf_lock, flags);
/* we could dynamically enable/disable perfcntr registers too.. */
gpu->last_sample.active = msm_gpu_active(gpu);
gpu->last_sample.time = ktime_get();
gpu->activetime = gpu->totaltime = 0;
gpu->perfcntr_active = true;
update_hw_cntrs(gpu, 0, NULL);
spin_unlock_irqrestore(&gpu->perf_lock, flags);
}
void msm_gpu_perfcntr_stop(struct msm_gpu *gpu)
{
gpu->perfcntr_active = false;
pm_runtime_put_sync(&gpu->pdev->dev);
}
/* returns -errno or # of cntrs sampled */
int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&gpu->perf_lock, flags);
if (!gpu->perfcntr_active) {
ret = -EINVAL;
goto out;
}
*activetime = gpu->activetime;
*totaltime = gpu->totaltime;
gpu->activetime = gpu->totaltime = 0;
ret = update_hw_cntrs(gpu, ncntrs, cntrs);
out:
spin_unlock_irqrestore(&gpu->perf_lock, flags);
return ret;
}
/*
* Cmdstream submission/retirement:
*/
@ -881,7 +783,6 @@ void msm_gpu_retire(struct msm_gpu *gpu)
msm_update_fence(gpu->rb[i]->fctx, gpu->rb[i]->memptrs->fence);
kthread_queue_work(gpu->worker, &gpu->retire_work);
update_sw_cntrs(gpu);
}
/* add bo's to gpu's ring, and kick gpu: */
@ -898,8 +799,6 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
submit->seqno = submit->hw_fence->seqno;
update_sw_cntrs(gpu);
/*
* ring->submits holds a ref to the submit, to deal with the case
* that a submit completes before msm_ioctl_gem_submit() returns.
@ -991,9 +890,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
void *memptrs;
uint64_t memptrs_iova;
if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs)))
gpu->num_perfcntrs = ARRAY_SIZE(gpu->last_cntrs);
gpu->dev = drm;
gpu->funcs = funcs;
gpu->name = name;
@ -1025,9 +921,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
timer_setup(&gpu->hangcheck_timer, hangcheck_handler, 0);
spin_lock_init(&gpu->perf_lock);
/* Map registers: */
gpu->mmio = msm_ioremap(pdev, config->ioname);
if (IS_ERR(gpu->mmio)) {
@ -1117,6 +1010,17 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
refcount_set(&gpu->sysprof_active, 1);
mutex_init(&gpu->perfcntr_lock);
if (gpu->num_perfcntr_groups > 0) {
gpu->perfcntrs = msm_perfcntr_init(gpu);
if (IS_ERR(gpu->perfcntrs)) {
ret = PTR_ERR(gpu->perfcntrs);
gpu->perfcntrs = NULL;
goto fail;
}
}
return 0;
fail:
@ -1155,6 +1059,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)
}
msm_devfreq_cleanup(gpu);
msm_perfcntr_cleanup(gpu);
platform_set_drvdata(gpu->pdev, NULL);
}

View File

@ -22,9 +22,10 @@
struct msm_gem_submit;
struct msm_gem_vm_log_entry;
struct msm_gpu_perfcntr;
struct msm_gpu_state;
struct msm_context;
struct msm_perfcntr_group;
struct msm_perfcntr_stream;
struct msm_gpu_config {
const char *ioname;
@ -92,7 +93,14 @@ struct msm_gpu_funcs {
* for cmdstream that is buffered in this FIFO upstream of the CP fw.
*/
bool (*progress)(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
void (*sysprof_setup)(struct msm_gpu *gpu);
void (*sysprof_setup)(struct msm_gpu *gpu, bool force_on);
/* Configure perfcntr SELect regs: */
void (*perfcntr_configure)(struct msm_gpu *gpu, struct msm_ringbuffer *ring,
const struct msm_perfcntr_stream *stream);
/* Flush perfcntrs before reading (optional): */
void (*perfcntr_flush)(struct msm_gpu *gpu);
};
/* Additional state for iommu faults: */
@ -168,18 +176,6 @@ struct msm_gpu {
struct adreno_smmu_priv adreno_smmu;
/* performance counters (hw & sw): */
spinlock_t perf_lock;
bool perfcntr_active;
struct {
bool active;
ktime_t time;
} last_sample;
uint32_t totaltime, activetime; /* sw counters */
uint32_t last_cntrs[5]; /* hw counters */
const struct msm_gpu_perfcntr *perfcntrs;
uint32_t num_perfcntrs;
struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS];
int nr_rings;
@ -275,6 +271,14 @@ struct msm_gpu {
bool allow_relocs;
struct thermal_cooling_device *cooling;
const struct msm_perfcntr_group *perfcntr_groups;
unsigned num_perfcntr_groups;
struct msm_perfcntr_state *perfcntrs;
/** @perfcntr_lock: protects perfcntr related state */
struct mutex perfcntr_lock;
};
static inline struct msm_gpu *dev_to_gpu(struct device *dev)
@ -320,19 +324,63 @@ static inline bool msm_gpu_active(struct msm_gpu *gpu)
return false;
}
/* Perf-Counters:
* The select_reg and select_val are just there for the benefit of the child
* class that actually enables the perf counter.. but msm_gpu base class
* will handle sampling/displaying the counters.
/**
* struct msm_perfcntr_group_state - Tracking for the currently allocated counter state
*/
struct msm_perfcntr_group_state {
/**
* @allocated_counters:
*
* allocated counters for global counter collection. The
* corresponding counters are allocated from highest to
* lowest, to minimize chance of conflict with old userspace
* allocating from lowest to highest.
*/
unsigned allocated_counters;
struct msm_gpu_perfcntr {
uint32_t select_reg;
uint32_t sample_reg;
uint32_t select_val;
const char *name;
/**
* @countables:
*
* The corresponding SELect reg values for the allocated counters
*/
uint32_t countables[];
};
/**
* struct msm_perfcntr_state - overall global perfcntr state
*/
struct msm_perfcntr_state {
/** @stream: current global counter stream if active */
struct msm_perfcntr_stream *stream;
/** @sel_seqno: counter for sel_fence */
uint32_t sel_seqno;
/**
* @groups: Global perfcntr stream group state.
*
* Conceptually this is part of msm_perfcntr_stream state, but is
* statically pre-allocated when the gpu is initialized to simplify
* error path cleanup in PERFCNTR_CONFIG ioctl. (__free(kfree)
* doesn't really help with variable length arrays of allocated
* pointers.)
*/
struct msm_perfcntr_group_state *groups[];
};
static inline bool
msm_gpu_sysprof_no_perfcntr_zap(struct msm_gpu *gpu)
{
return (refcount_read(&gpu->sysprof_active) > 1) ||
(gpu->perfcntrs && READ_ONCE(gpu->perfcntrs->stream));
}
static inline bool
msm_gpu_sysprof_no_ifpc(struct msm_gpu *gpu)
{
return refcount_read(&gpu->sysprof_active) > 1;
}
/*
* The number of priority levels provided by drm gpu scheduler. The
* DRM_SCHED_PRIORITY_KERNEL priority level is treated specially in some
@ -438,6 +486,11 @@ struct msm_context {
* this context.
*/
atomic64_t ctx_mem;
/**
* @perfcntrs: Per-context reserved perfcntrs state
*/
struct msm_perfcntr_context_state *perfctx;
};
struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx);
@ -689,11 +742,6 @@ void msm_devfreq_idle(struct msm_gpu *gpu);
int msm_gpu_hw_init(struct msm_gpu *gpu);
void msm_gpu_perfcntr_start(struct msm_gpu *gpu);
void msm_gpu_perfcntr_stop(struct msm_gpu *gpu);
int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs);
void msm_gpu_retire(struct msm_gpu *gpu);
void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit);

View File

@ -166,90 +166,72 @@ static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss)
return 0;
}
static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss)
static void msm_mdss_4x_setup_ubwc(struct msm_mdss *msm_mdss)
{
const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) |
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(qcom_ubwc_swizzle(data) &
UBWC_SWIZZLE_ENABLE_LVL1) |
MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13);
if (data->ubwc_bank_spread)
value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD;
if (data->ubwc_enc_version == UBWC_1_0)
value |= MDSS_UBWC_STATIC_UBWC_MIN_ACC_LEN(1);
value |= MDSS_UBWC_STATIC_UBWC_MIN_ACC_LEN(qcom_ubwc_min_acc_length_64b(data));
writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);
}
static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss)
static void msm_mdss_5x_setup_ubwc(struct msm_mdss *msm_mdss)
{
const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle & 0x1) |
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(qcom_ubwc_swizzle(data) &
UBWC_SWIZZLE_ENABLE_LVL1) |
MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13);
if (data->macrotile_mode)
if (qcom_ubwc_macrotile_mode(data))
value |= MDSS_UBWC_STATIC_MACROTILE_MODE;
if (data->ubwc_enc_version == UBWC_3_0)
if (qcom_ubwc_enable_amsbc(data))
value |= MDSS_UBWC_STATIC_UBWC_AMSBC;
if (data->ubwc_enc_version == UBWC_1_0)
value |= MDSS_UBWC_STATIC_UBWC_MIN_ACC_LEN(1);
value |= MDSS_UBWC_STATIC_UBWC_MIN_ACC_LEN(qcom_ubwc_min_acc_length_64b(data));
writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);
}
static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss)
static void msm_mdss_6x_setup_ubwc(struct msm_mdss *msm_mdss)
{
const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) |
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(qcom_ubwc_swizzle(data)) |
MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13);
u32 prediction_mode;
if (data->ubwc_bank_spread)
if (qcom_ubwc_bank_spread(data))
value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD;
if (data->macrotile_mode)
if (qcom_ubwc_macrotile_mode(data))
value |= MDSS_UBWC_STATIC_MACROTILE_MODE;
value |= MDSS_UBWC_STATIC_UBWC_MIN_ACC_LEN(qcom_ubwc_min_acc_length_64b(data));
writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);
if (data->ubwc_enc_version == UBWC_3_0) {
writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
writel_relaxed(0, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
} else {
if (data->ubwc_dec_version == UBWC_4_3)
writel_relaxed(3, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
else
writel_relaxed(2, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
}
}
static void msm_mdss_setup_ubwc_dec_50(struct msm_mdss *msm_mdss)
{
const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) |
MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13);
if (data->ubwc_bank_spread)
value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD;
if (data->macrotile_mode)
value |= MDSS_UBWC_STATIC_MACROTILE_MODE;
writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);
if (data->ubwc_dec_version == UBWC_6_0)
writel_relaxed(5, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
if (data->ubwc_enc_version < UBWC_4_0)
prediction_mode = 0;
else
writel_relaxed(4, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
prediction_mode = 1;
writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
writel_relaxed(qcom_ubwc_version_tag(data),
msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
writel_relaxed(prediction_mode, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
}
#define MDSS_HW_VER(major, minor, step) \
((((major) & 0xf) << 28) | \
(((minor) & 0xfff) << 16) | \
((step) & 0xffff))
static int msm_mdss_enable(struct msm_mdss *msm_mdss)
{
int ret, i;
u32 hw_rev;
/*
* Several components have AXI clocks that can only be turned on if
@ -283,43 +265,15 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss)
if (msm_mdss->is_mdp5 || !msm_mdss->mdss_data)
return 0;
/*
* ubwc config is part of the "mdss" region which is not accessible
* from the rest of the driver. hardcode known configurations here
*
* Decoder version can be read from the UBWC_DEC_HW_VERSION reg,
* UBWC_n and the rest of params comes from hw data.
*/
switch (msm_mdss->mdss_data->ubwc_dec_version) {
case 0: /* no UBWC */
case UBWC_1_0:
/* do nothing */
break;
case UBWC_2_0:
msm_mdss_setup_ubwc_dec_20(msm_mdss);
break;
case UBWC_3_0:
msm_mdss_setup_ubwc_dec_30(msm_mdss);
break;
case UBWC_4_0:
case UBWC_4_3:
msm_mdss_setup_ubwc_dec_40(msm_mdss);
break;
case UBWC_5_0:
msm_mdss_setup_ubwc_dec_50(msm_mdss);
break;
case UBWC_6_0:
msm_mdss_setup_ubwc_dec_50(msm_mdss);
break;
default:
dev_err(msm_mdss->dev, "Unsupported UBWC decoder version %x\n",
msm_mdss->mdss_data->ubwc_dec_version);
dev_err(msm_mdss->dev, "HW_REV: 0x%x\n",
readl_relaxed(msm_mdss->mmio + REG_MDSS_HW_VERSION));
dev_err(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n",
readl_relaxed(msm_mdss->mmio + REG_MDSS_UBWC_DEC_HW_VERSION));
break;
}
hw_rev = readl_relaxed(msm_mdss->mmio + REG_MDSS_HW_VERSION);
if (hw_rev >= MDSS_HW_VER(6, 0, 0))
msm_mdss_6x_setup_ubwc(msm_mdss);
else if (hw_rev >= MDSS_HW_VER(5, 0, 0))
msm_mdss_5x_setup_ubwc(msm_mdss);
else if (hw_rev >= MDSS_HW_VER(4, 0, 0))
msm_mdss_4x_setup_ubwc(msm_mdss);
/* else UBWC 1.0 or none, no params to program */
return ret;
}
@ -550,6 +504,10 @@ static void mdss_remove(struct platform_device *pdev)
msm_mdss_destroy(mdss);
}
static const struct msm_mdss_data data_14k = {
.reg_bus_bw = 14000,
};
static const struct msm_mdss_data data_57k = {
.reg_bus_bw = 57000,
};
@ -571,6 +529,7 @@ static const struct of_device_id mdss_dt_match[] = {
{ .compatible = "qcom,eliza-mdss", .data = &data_57k },
{ .compatible = "qcom,glymur-mdss", .data = &data_57k },
{ .compatible = "qcom,kaanapali-mdss", .data = &data_57k },
{ .compatible = "qcom,milos-mdss", .data = &data_14k },
{ .compatible = "qcom,msm8998-mdss", .data = &data_76k8 },
{ .compatible = "qcom,qcm2290-mdss", .data = &data_76k8 },
{ .compatible = "qcom,qcs8300-mdss", .data = &data_74k },

View File

@ -1,235 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*/
/* For profiling, userspace can:
*
* tail -f /sys/kernel/debug/dri/<minor>/gpu
*
* This will enable performance counters/profiling to track the busy time
* and any gpu specific performance counters that are supported.
*/
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <drm/drm_file.h>
#include "msm_drv.h"
#include "msm_gpu.h"
struct msm_perf_state {
struct drm_device *dev;
bool open;
int cnt;
struct mutex read_lock;
char buf[256];
int buftot, bufpos;
unsigned long next_jiffies;
};
#define SAMPLE_TIME (HZ/4)
/* wait for next sample time: */
static int wait_sample(struct msm_perf_state *perf)
{
unsigned long start_jiffies = jiffies;
if (time_after(perf->next_jiffies, start_jiffies)) {
unsigned long remaining_jiffies =
perf->next_jiffies - start_jiffies;
int ret = schedule_timeout_interruptible(remaining_jiffies);
if (ret > 0) {
/* interrupted */
return -ERESTARTSYS;
}
}
perf->next_jiffies += SAMPLE_TIME;
return 0;
}
static int refill_buf(struct msm_perf_state *perf)
{
struct msm_drm_private *priv = perf->dev->dev_private;
struct msm_gpu *gpu = priv->gpu;
char *ptr = perf->buf;
int rem = sizeof(perf->buf);
int i, n;
if ((perf->cnt++ % 32) == 0) {
/* Header line: */
n = scnprintf(ptr, rem, "%%BUSY");
ptr += n;
rem -= n;
for (i = 0; i < gpu->num_perfcntrs; i++) {
const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
n = scnprintf(ptr, rem, "\t%s", perfcntr->name);
ptr += n;
rem -= n;
}
} else {
/* Sample line: */
uint32_t activetime = 0, totaltime = 0;
uint32_t cntrs[5];
uint32_t val;
int ret;
/* sleep until next sample time: */
ret = wait_sample(perf);
if (ret)
return ret;
ret = msm_gpu_perfcntr_sample(gpu, &activetime, &totaltime,
ARRAY_SIZE(cntrs), cntrs);
if (ret < 0)
return ret;
val = totaltime ? 1000 * activetime / totaltime : 0;
n = scnprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10);
ptr += n;
rem -= n;
for (i = 0; i < ret; i++) {
/* cycle counters (I think).. convert to MHz.. */
val = cntrs[i] / 10000;
n = scnprintf(ptr, rem, "\t%5d.%02d",
val / 100, val % 100);
ptr += n;
rem -= n;
}
}
n = scnprintf(ptr, rem, "\n");
ptr += n;
rem -= n;
perf->bufpos = 0;
perf->buftot = ptr - perf->buf;
return 0;
}
static ssize_t perf_read(struct file *file, char __user *buf,
size_t sz, loff_t *ppos)
{
struct msm_perf_state *perf = file->private_data;
int n = 0, ret = 0;
mutex_lock(&perf->read_lock);
if (perf->bufpos >= perf->buftot) {
ret = refill_buf(perf);
if (ret)
goto out;
}
n = min((int)sz, perf->buftot - perf->bufpos);
if (copy_to_user(buf, &perf->buf[perf->bufpos], n)) {
ret = -EFAULT;
goto out;
}
perf->bufpos += n;
*ppos += n;
out:
mutex_unlock(&perf->read_lock);
if (ret)
return ret;
return n;
}
static int perf_open(struct inode *inode, struct file *file)
{
struct msm_perf_state *perf = inode->i_private;
struct drm_device *dev = perf->dev;
struct msm_drm_private *priv = dev->dev_private;
struct msm_gpu *gpu = priv->gpu;
int ret = 0;
if (!gpu)
return -ENODEV;
mutex_lock(&gpu->lock);
if (perf->open) {
ret = -EBUSY;
goto out;
}
file->private_data = perf;
perf->open = true;
perf->cnt = 0;
perf->buftot = 0;
perf->bufpos = 0;
msm_gpu_perfcntr_start(gpu);
perf->next_jiffies = jiffies + SAMPLE_TIME;
out:
mutex_unlock(&gpu->lock);
return ret;
}
static int perf_release(struct inode *inode, struct file *file)
{
struct msm_perf_state *perf = inode->i_private;
struct msm_drm_private *priv = perf->dev->dev_private;
msm_gpu_perfcntr_stop(priv->gpu);
perf->open = false;
return 0;
}
static const struct file_operations perf_debugfs_fops = {
.owner = THIS_MODULE,
.open = perf_open,
.read = perf_read,
.release = perf_release,
};
int msm_perf_debugfs_init(struct drm_minor *minor)
{
struct msm_drm_private *priv = minor->dev->dev_private;
struct msm_perf_state *perf;
/* only create on first minor: */
if (priv->perf)
return 0;
perf = kzalloc_obj(*perf);
if (!perf)
return -ENOMEM;
perf->dev = minor->dev;
mutex_init(&perf->read_lock);
priv->perf = perf;
debugfs_create_file("perf", S_IFREG | S_IRUGO, minor->debugfs_root,
perf, &perf_debugfs_fops);
return 0;
}
void msm_perf_debugfs_cleanup(struct msm_drm_private *priv)
{
struct msm_perf_state *perf = priv->perf;
if (!perf)
return;
priv->perf = NULL;
mutex_destroy(&perf->read_lock);
kfree(perf);
}
#endif

View File

@ -0,0 +1,670 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "drm/drm_file.h"
#include "drm/msm_drm.h"
#include "linux/anon_inodes.h"
#include "linux/gfp_types.h"
#include "linux/poll.h"
#include "linux/slab.h"
#include "msm_drv.h"
#include "msm_gpu.h"
#include "msm_perfcntr.h"
#include "adreno/adreno_gpu.h"
/* space used: */
#define fifo_count(stream) \
(CIRC_CNT((stream)->fifo.head, (stream)->fifo.tail, (stream)->fifo_size))
#define fifo_count_to_end(stream) \
(CIRC_CNT_TO_END(smp_load_acquire(&(stream)->fifo.head), (stream)->fifo.tail, (stream)->fifo_size))
/* space available: */
#define fifo_space(stream) \
(CIRC_SPACE((stream)->fifo.head, (stream)->fifo.tail, (stream)->fifo_size))
static int
msm_perfcntr_resume_locked(struct msm_perfcntr_stream *stream)
{
if (!stream)
return 0;
/* Reprogram SEL regs on highest priority rb: */
struct msm_ringbuffer *ring = stream->gpu->rb[0];
queue_work(ring->sched.submit_wq, &stream->sel_work);
hrtimer_start(&stream->sample_timer,
ns_to_ktime(stream->sample_period_ns),
HRTIMER_MODE_REL_PINNED);
return 0;
}
int
msm_perfcntr_resume(struct msm_gpu *gpu)
{
if (!gpu->perfcntrs)
return 0;
guard(mutex)(&gpu->perfcntr_lock);
return msm_perfcntr_resume_locked(gpu->perfcntrs->stream);
}
static void
msm_perfcntr_suspend_locked(struct msm_perfcntr_stream *stream)
{
if (!stream)
return;
hrtimer_cancel(&stream->sample_timer);
kthread_cancel_work_sync(&stream->sample_work);
/*
* We can't use cancel_work_sync() here, since sel_work acquires
* gpu->lock which (a) in suspend path can already be held, or
* (b) in release path would invert the order of gpu->lock and
* gpu->perfcntr_lock. Either would cause deadlock.
*/
cancel_work(&stream->sel_work);
stream->sel_fence = ++stream->gpu->perfcntrs->sel_seqno;
stream->seqno = 0;
}
void
msm_perfcntr_suspend(struct msm_gpu *gpu)
{
if (!gpu->perfcntrs)
return;
guard(mutex)(&gpu->perfcntr_lock);
msm_perfcntr_suspend_locked(gpu->perfcntrs->stream);
}
static int
msm_perfcntrs_stream_release(struct inode *inode, struct file *file)
{
struct msm_perfcntr_stream *stream = file->private_data;
struct msm_gpu *gpu = stream->gpu;
scoped_guard (mutex, &gpu->perfcntr_lock) {
struct msm_perfcntr_state *perfcntrs = gpu->perfcntrs;
msm_perfcntr_suspend_locked(stream);
perfcntrs->stream = NULL;
/* release previously allocated counters: */
for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++)
perfcntrs->groups[i]->allocated_counters = 0;
}
/*
* In the suspend path we use async cancel_work(), to avoid blocking
* on sel_work, which acquires gpu->lock (which could deadlock since
* other paths acquire gpu->lock before perfcntr_lock) or already
* hold gpu->lock.
*
* But since we are freeing the stream, after dropping perfcntr_lock
* we need to block until sel_work is done:
*/
cancel_work_sync(&stream->sel_work);
kfree(stream->group_idx);
kfree(stream->fifo.buf);
kfree(stream);
return 0;
}
static __poll_t
msm_perfcntrs_stream_poll(struct file *file, poll_table *wait)
{
struct msm_perfcntr_stream *stream = file->private_data;
__poll_t events = 0;
poll_wait(file, &stream->poll_wq, wait);
/* Are there samples to read? */
if (fifo_count(stream) > 0)
events |= EPOLLIN;
return events;
}
static ssize_t
msm_perfcntrs_stream_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct msm_perfcntr_stream *stream = file->private_data;
int ret;
if (!(file->f_flags & O_NONBLOCK)) {
ret = wait_event_interruptible(stream->poll_wq,
fifo_count(stream) > 0);
if (ret)
return ret;
}
guard(mutex)(&stream->read_lock);
struct circ_buf *fifo = &stream->fifo;
const char *fptr = &fifo->buf[fifo->tail];
count = min_t(size_t, count, fifo_count_to_end(stream));
if (!count)
return -EAGAIN;
if (copy_to_user(buf, fptr, count))
return -EFAULT;
smp_store_release(&fifo->tail, (fifo->tail + count) & (stream->fifo_size - 1));
*ppos += count;
return count;
}
static const struct file_operations stream_fops = {
.owner = THIS_MODULE,
.release = msm_perfcntrs_stream_release,
.poll = msm_perfcntrs_stream_poll,
.read = msm_perfcntrs_stream_read,
};
static void
sel_worker(struct work_struct *w)
{
struct msm_perfcntr_stream *stream =
container_of(w, typeof(*stream), sel_work);
struct msm_gpu *gpu = stream->gpu;
/* Reprogram SEL regs on highest priority rb: */
struct msm_ringbuffer *ring = stream->gpu->rb[0];
/*
* If in the process of resuming, wait for that. Otherwise sel_worker
* which is enqueued in the resume path can be scheduled before the
* resume completes.
*/
pm_runtime_barrier(&gpu->pdev->dev);
/*
* sel_work could end up scheduled before suspend, but running
* after. See msm_perfcntr_suspend_locked()
*
* So if we end up running sel_work after the GPU is already
* suspended, just bail. It will be scheduled again after
* the GPU is resumed.
*/
if (!pm_runtime_get_if_active(&gpu->pdev->dev))
return;
scoped_guard (mutex, &gpu->lock) {
guard(mutex)(&gpu->perfcntr_lock);
if (stream == gpu->perfcntrs->stream) {
msm_gpu_hw_init(gpu);
gpu->funcs->perfcntr_configure(gpu, ring, stream);
}
}
pm_runtime_put_autosuspend(&gpu->pdev->dev);
}
static void
sample_write(struct msm_perfcntr_stream *stream, int *head, const void *buf, size_t sz)
{
/*
* FIFO size is power-of-two, and guaranteed to have enough space to
* fit what we are writing. So we should not hit the wrap-around
* point writing things that are power-of-two sized
*/
WARN_ON(CIRC_SPACE_TO_END(*head, stream->fifo.tail, stream->fifo_size) < sz);
memcpy(&stream->fifo.buf[*head], buf, sz);
/* Advance head, wrapping around if necessary: */
*head = (*head + sz) & (stream->fifo_size - 1);
}
static void
sample_write_u32(struct msm_perfcntr_stream *stream, int *head, uint32_t val)
{
sample_write(stream, head, &val, sizeof(val));
}
static void
sample_write_u64(struct msm_perfcntr_stream *stream, int *head, uint64_t val)
{
sample_write(stream, head, &val, sizeof(val));
}
static void
sample_worker(struct kthread_work *work)
{
struct msm_perfcntr_stream *stream =
container_of(work, typeof(*stream), sample_work);
struct msm_gpu *gpu = stream->gpu;
struct msm_rbmemptrs *memptrs = gpu->rb[0]->memptrs;
if (memptrs->perfcntr_fence != stream->sel_fence)
return;
/*
* Ensure we have enough space to capture a sample period's
* worth of data:
*/
if (stream->period_size > fifo_space(stream)) {
stream->seqno = 0;
return;
}
/* Inhibit IFPC while accessing registers: */
if (gpu->funcs->sysprof_setup)
gpu->funcs->sysprof_setup(gpu, true);
if (gpu->funcs->perfcntr_flush)
gpu->funcs->perfcntr_flush(gpu);
/* Keep local copy of head to avoid updating fifo until the end: */
int head = stream->fifo.head;
/*
* We expect the GPU to be powered at this point, as the timer
* and kthread work are canceled/flushed in the suspend path:
*/
sample_write_u64(stream, &head,
to_adreno_gpu(gpu)->funcs->get_timestamp(gpu));
sample_write_u32(stream, &head, stream->seqno++);
sample_write_u32(stream, &head, 0);
for (unsigned i = 0; i < stream->nr_groups; i++) {
unsigned group_idx = msm_perfcntr_group_idx(stream, i);
unsigned base = msm_perfcntr_counter_base(stream, group_idx);
const struct msm_perfcntr_group *group =
&gpu->perfcntr_groups[group_idx];
struct msm_perfcntr_group_state *group_state =
gpu->perfcntrs->groups[group_idx];
unsigned nr = group_state->allocated_counters;
for (unsigned j = 0; j < nr; j++) {
const struct msm_perfcntr_counter *counter =
&group->counters[j + base];
uint64_t val = gpu_read64(gpu, counter->counter_reg_lo);
sample_write_u64(stream, &head, val);
}
}
/* Re-enable IFPC: */
if (gpu->funcs->sysprof_setup)
gpu->funcs->sysprof_setup(gpu, false);
smp_store_release(&stream->fifo.head, head);
wake_up_all(&stream->poll_wq);
}
static enum hrtimer_restart
sample_timer(struct hrtimer *hrtimer)
{
struct msm_perfcntr_stream *stream =
container_of(hrtimer, typeof(*stream), sample_timer);
kthread_queue_work(stream->gpu->worker, &stream->sample_work);
hrtimer_forward_now(hrtimer, ns_to_ktime(stream->sample_period_ns));
return HRTIMER_RESTART;
}
static int
get_group_idx(struct msm_gpu *gpu, const char *name, size_t len)
{
for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++) {
const struct msm_perfcntr_group *group =
&gpu->perfcntr_groups[i];
if (!strncmp(group->name, name, len))
return i;
}
return -1;
}
static int
get_available_counters(struct msm_gpu *gpu, int group_idx, uint32_t flags)
{
struct msm_perfcntr_state *perfcntrs = gpu->perfcntrs;
/*
* For local counter reservation, anything that is not used by
* global perfcntr stream is available:
*/
if (!(flags & MSM_PERFCNTR_STREAM)) {
return gpu->perfcntr_groups[group_idx].num_counters -
perfcntrs->groups[group_idx]->allocated_counters;
}
/*
* For global counter collection, anything that is not reserved by
* one or more contexts is available:
*/
guard(mutex)(&gpu->dev->filelist_mutex);
unsigned reserved_counters = 0;
struct drm_file *file;
list_for_each_entry (file, &gpu->dev->filelist, lhead) {
struct msm_context *ctx = file->driver_priv;
if (!ctx || !ctx->perfctx)
continue;
unsigned n = ctx->perfctx->reserved_counters[group_idx];
reserved_counters = max(reserved_counters, n);
}
return gpu->perfcntr_groups[group_idx].num_counters - reserved_counters;
}
int
msm_ioctl_perfcntr_config(struct drm_device *dev, void *data, struct drm_file *file)
{
struct msm_drm_private *priv = dev->dev_private;
const struct drm_msm_perfcntr_config *args = data;
struct msm_context *ctx = file->driver_priv;
struct msm_gpu *gpu = priv->gpu;
int stream_fd = 0;
if (!gpu || !gpu->num_perfcntr_groups)
return -ENXIO;
struct msm_perfcntr_state *perfcntrs = gpu->perfcntrs;
/*
* Validate args that don't require locks/power first:
*/
if (args->flags & ~MSM_PERFCNTR_FLAGS)
return UERR(EINVAL, dev, "invalid flags");
if (args->nr_groups && !args->group_stride)
return UERR(EINVAL, dev, "invalid group_stride");
if (args->nr_groups > gpu->num_perfcntr_groups)
return UERR(EINVAL, dev, "too many groups");
if (args->nr_groups && !args->groups)
return UERR(EINVAL, dev, "no groups");
if (args->flags & MSM_PERFCNTR_STREAM) {
if (!perfmon_capable())
return UERR(EPERM, dev, "invalid permissions");
if (!args->nr_groups)
return UERR(EINVAL, dev, "invalid nr_groups");
if (!args->period)
return UERR(EINVAL, dev, "invalid sampling period");
if (args->bufsz_shift > const_ilog2(SZ_128M))
return UERR(EINVAL, dev, "buffer size too big (>128M)");
} else {
if (args->period)
return UERR(EINVAL, dev, "sampling period not allowed");
if (args->bufsz_shift)
return UERR(EINVAL, dev, "sample buf size not allowed");
}
/*
* To avoid iterating over the groups multiple times, allocate and setup
* both a ctx and global stream object. Only one of the two will be
* kept in the end.
*/
struct msm_perfcntr_context_state *perfctx __free(kfree) = kzalloc(
struct_size(perfctx, reserved_counters, gpu->num_perfcntr_groups),
GFP_KERNEL);
if (!perfctx)
return -ENOMEM;
struct msm_perfcntr_stream *stream __free(kfree) = kzalloc_obj(*stream);
if (!stream)
return -ENOMEM;
uint8_t *nr_counters __free(kfree) = kzalloc_objs(uint8_t, gpu->num_perfcntr_groups);
if (!nr_counters)
return -ENOMEM;
uint32_t *group_idx __free(kfree) = kzalloc_objs(uint32_t, args->nr_groups);
if (!group_idx)
return -ENOMEM;
stream->gpu = gpu;
stream->sample_period_ns = args->period;
stream->nr_groups = args->nr_groups;
stream->fifo_size = 1ull << args->bufsz_shift;
mutex_init(&stream->read_lock);
guard(mutex)(&gpu->perfcntr_lock);
if (args->flags & MSM_PERFCNTR_STREAM) {
if (perfcntrs->stream)
return UERR(EBUSY, dev, "perfcntr stream already open");
}
size_t bufsz = 16; /* header size includes seqno and 64b timestamp: */
int ret = 0;
for (unsigned i = 0; i < args->nr_groups; i++) {
struct drm_msm_perfcntr_group g = {0};
size_t sz = min_t(size_t, args->group_stride, sizeof(g));
void __user *userptr =
u64_to_user_ptr(args->groups + (i * args->group_stride));
if (copy_from_user(&g, userptr, sz))
return -EFAULT;
if (g.pad)
return UERR(EINVAL, dev, "groups[%d]: invalid pad", i);
int idx = get_group_idx(gpu, g.group_name, sizeof(g.group_name));
if (idx < 0)
return UERR(EINVAL, dev, "groups[%d]: unknown group", i);
if (nr_counters[idx])
return UERR(EINVAL, dev, "groups[%d]: duplicate group", i);
if (g.nr_countables > gpu->perfcntr_groups[idx].num_counters)
return UERR(EINVAL, dev, "groups[%d]: too many counters", i);
if (args->flags & MSM_PERFCNTR_STREAM) {
if (g.nr_countables && !g.countables)
return UERR(EINVAL, dev, "groups[%d]: no countables", i);
} else {
if (g.countables)
return UERR(EINVAL, dev, "groups[%d]: countables should be NULL", i);
}
int avail_counters = get_available_counters(gpu, idx, args->flags);
if (g.nr_countables > avail_counters) {
/*
* Defer error return until we process all groups, in
* case there are other E2BIG groups:
*/
ret = UERR(E2BIG, dev, "groups[%d]: too few counters available", i);
if (args->flags & MSM_PERFCNTR_UPDATE) {
/* Let userspace know how many counters are actually avail: */
g.nr_countables = avail_counters;
if (copy_to_user(userptr, &g, sz))
return -EFAULT;
}
}
group_idx[i] = idx;
perfctx->reserved_counters[idx] = g.nr_countables;
/* +1 to catch duplicate zero sized groups: */
nr_counters[idx] = g.nr_countables + 1;
if (args->flags & MSM_PERFCNTR_STREAM) {
size_t sz = sizeof(uint32_t) * g.nr_countables;
void __user *userptr = u64_to_user_ptr(g.countables);
if (copy_from_user(perfcntrs->groups[idx]->countables, userptr, sz))
return -EFAULT;
/* Samples are 64b per countable: */
bufsz += 2 * sz;
}
}
if (ret)
return ret;
if (args->flags & MSM_PERFCNTR_STREAM) {
/*
* Validate requested buffer size is large enough for at least
* a single sample period.
*
* Note the circ_buf implementation needs to be 1 byte larger
* than max it can hold (see CIRC_SPACE()).
*/
if (stream->fifo_size <= bufsz)
return UERR(EINVAL, dev, "required buffer size: %zu", bufsz);
/* There aren't enough counters to hit this limit: */
WARN_ON(bufsz > SZ_128M);
stream->period_size = bufsz;
void *buf __free(kfree) = kmalloc(stream->fifo_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
FD_PREPARE(fdf, O_CLOEXEC,
anon_inode_getfile("[msm_perfcntrs]", &stream_fops, stream, 0));
if (fdf.err)
return fdf.err;
INIT_WORK(&stream->sel_work, sel_worker);
kthread_init_work(&stream->sample_work, sample_worker);
init_waitqueue_head(&stream->poll_wq);
hrtimer_setup(&stream->sample_timer, sample_timer,
CLOCK_MONOTONIC, HRTIMER_MODE_REL);
stream->sel_fence = ++perfcntrs->sel_seqno;
stream->group_idx = no_free_ptr(group_idx);
stream->fifo.buf = no_free_ptr(buf);
/* commit the allocated counters, subtracting off original +1: */
for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++)
perfcntrs->groups[i]->allocated_counters = nr_counters[i] - 1;
perfcntrs->stream = no_free_ptr(stream);
msm_perfcntr_resume_locked(perfcntrs->stream);
stream_fd = fd_publish(fdf);
} else {
kfree(ctx->perfctx);
ctx->perfctx = no_free_ptr(perfctx);
}
return stream_fd;
}
/**
* msm_perfcntr_group_idx - map idx of perfcntr group to group_idx
* @stream: The global perfcntr stream
* @n: The requested group_idx
*
* The PERFCNTR_CONFIG ioctl requested N counters/countables per perfcntr
* group, but the order of groups is not required to match the order they
* are defined in the perfcntr tables (which is not stable/UABI, only the
* group names are UABI).
*
* But the order samples are returned in the stream should match the
* order they are requested in the PERFCNTR_CONFIG ioctl. This helper
* handles the order remapping.
*
* Returns an index into gpu->perfcntr_groups[] and perfcntrs->groups[].
*/
uint32_t
msm_perfcntr_group_idx(const struct msm_perfcntr_stream *stream, uint32_t n)
{
WARN_ON_ONCE(n >= stream->nr_groups);
return stream->group_idx[n];
}
/**
* msm_perfcntr_counter_base - get idx of the first counter in group
* @stream: The global perfcntr stream
* @group_idx: the index of the counter group
*
* For global counter collection, counters are allocated from the end
* (last counter) while UMD allocates them from the start (0..N-1).
* Since UMD always allocated them from the start this also minimizes
* the chance of conflict when using old UMD which predates
* PERFCNTR_CONFIG ioctl.
*
* Returns the index of first counter to use. An index into
* msm_perfcntr_group::counters[].
*/
uint32_t
msm_perfcntr_counter_base(const struct msm_perfcntr_stream *stream, uint32_t group_idx)
{
struct msm_gpu *gpu = stream->gpu;
struct msm_perfcntr_state *perfcntrs = gpu->perfcntrs;
unsigned num_counters = gpu->perfcntr_groups[group_idx].num_counters;
unsigned allocated_counters = perfcntrs->groups[group_idx]->allocated_counters;
return num_counters - allocated_counters;
}
static void
__msm_perfcntr_cleanup(struct msm_gpu *gpu, struct msm_perfcntr_state *perfcntrs)
{
struct device *dev = &gpu->pdev->dev;
for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++)
devm_kfree(dev, perfcntrs->groups[i]);
devm_kfree(dev, perfcntrs);
}
void
msm_perfcntr_cleanup(struct msm_gpu *gpu)
{
if (!gpu->perfcntrs)
return;
__msm_perfcntr_cleanup(gpu, gpu->perfcntrs);
gpu->perfcntrs = NULL;
}
struct msm_perfcntr_state *
msm_perfcntr_init(struct msm_gpu *gpu)
{
struct msm_perfcntr_state *perfcntrs;
struct device *dev = &gpu->pdev->dev;
size_t sz;
sz = struct_size(perfcntrs, groups, gpu->num_perfcntr_groups);
perfcntrs = devm_kzalloc(dev, sz, GFP_KERNEL);
if (!perfcntrs)
return ERR_PTR(-ENOMEM);
for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++) {
const struct msm_perfcntr_group *group =
&gpu->perfcntr_groups[i];
sz = struct_size(perfcntrs->groups[i], countables, group->num_counters);
perfcntrs->groups[i] = devm_kzalloc(dev, sz, GFP_KERNEL);
if (!perfcntrs->groups[i]) {
__msm_perfcntr_cleanup(gpu, perfcntrs);
return ERR_PTR(-ENOMEM);
}
}
return perfcntrs;
}

View File

@ -0,0 +1,155 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef __MSM_PERFCNTR_H__
#define __MSM_PERFCNTR_H__
#include "linux/array_size.h"
#include "linux/circ_buf.h"
#include "linux/hrtimer.h"
#include "linux/kthread.h"
#include "linux/wait.h"
#include "linux/workqueue.h"
#include "adreno_common.xml.h"
/*
* This is a subset of the tables used by mesa. We don't need to
* enumerate the countables on the kernel side.
*/
/* Describes a single counter: */
struct msm_perfcntr_counter {
/* offset of the SELect register to choose what to count: */
unsigned select_reg;
/* additional SEL regs to enable slice counters (gen8+) */
unsigned slice_select_regs[2];
/* offset of the lo/hi 32b to read current counter value: */
unsigned counter_reg_lo;
unsigned counter_reg_hi;
/* TODO some counters have enable/clear registers */
};
/* Describes an entire counter group: */
struct msm_perfcntr_group {
const char *name;
enum adreno_pipe pipe;
unsigned num_counters;
const struct msm_perfcntr_counter *counters;
};
/**
* struct msm_perfcntr_stream - state for a single open stream fd
*/
struct msm_perfcntr_stream {
/** @gpu: Back-link to the GPU */
struct msm_gpu *gpu;
/** @sample_timer: Timer to sample counters */
struct hrtimer sample_timer;
/** @poll_wq: Wait queue for waiting for OA data to be available */
wait_queue_head_t poll_wq;
/** @sample_period_ns: Sampling period */
uint64_t sample_period_ns;
/** @nr_groups: # of counter groups with enabled counters */
uint32_t nr_groups;
/** @seqno: counter for collected samples */
uint32_t seqno;
/** @sel_fence: Fence for SEL reg programming */
uint32_t sel_fence;
/**
* @sel_work: Worker for SEL reg programming
*
* Initial SEL reg programming (as opposed to restoring the SEL
* regs on runpm resume) must run on the same ordered wq as is
* used by drm_sched, to serialize it with GEM_SUBMITs written
* into the same ringbuffer.
*/
struct work_struct sel_work;
/**
* @sample_work: Worker for collecting samples
*/
struct kthread_work sample_work;
/**
* @read_lock:
*
* Fifo access is synchronied on the producer side by virtue
* of there being a single timer collecting samples and writing
* into the fifo. It is protected on the consumer side by
* @read_lock.
*/
struct mutex read_lock;
/**
* @group_idx: array of nr_groups
*
* Maps the order of groups in PERFCNTR_CONFIG ioctl to group idx,
* so that results in the results stream can be ordered to match
* the ioctl call that setup the stream
*/
uint32_t *group_idx;
/** @fifo: circular buffer for samples */
struct circ_buf fifo;
/** @fifo_size: circular buffer size */
size_t fifo_size;
/** @period_size: size of data for single sampling period */
size_t period_size;
};
uint32_t msm_perfcntr_group_idx(const struct msm_perfcntr_stream *stream, uint32_t n);
uint32_t msm_perfcntr_counter_base(const struct msm_perfcntr_stream *stream, uint32_t group_idx);
/**
* struct msm_perfcntr_context_state - per-msm_context counter state
*
* A given counter can either be unused, reserved for global counter
* collection exclusively, or reserved for local per-context counter
* collection inclusively. Multiple contexts can reserve the same
* counter, since SEL reg programming and counter begin/end sampling
* happen locally (within a single GEM_SUBMIT ioctl).
*/
struct msm_perfcntr_context_state {
/** @dummy: Some compilers dislike structs with only a flex array */
unsigned dummy;
/**
* @reserved_counters:
*
* The number of reserved counters indexed by perfcntr group.
*/
unsigned reserved_counters[];
};
extern const struct msm_perfcntr_group a6xx_perfcntr_groups[];
extern const unsigned a6xx_num_perfcntr_groups;
extern const struct msm_perfcntr_group a7xx_perfcntr_groups[];
extern const unsigned a7xx_num_perfcntr_groups;
extern const struct msm_perfcntr_group a8xx_perfcntr_groups[];
extern const unsigned a8xx_num_perfcntr_groups;
#define GROUP(_name, _pipe, _counters, _countables) { \
.name = _name, \
.pipe = _pipe, \
.num_counters = ARRAY_SIZE(_counters), \
.counters = _counters, \
}
#define fd_perfcntr_counter msm_perfcntr_counter
#define fd_perfcntr_group msm_perfcntr_group
#endif /* __MSM_PERFCNTR_H__ */

View File

@ -37,6 +37,8 @@ struct msm_rbmemptrs {
volatile struct msm_gpu_submit_stats stats[MSM_GPU_SUBMIT_STATS_COUNT];
volatile u64 ttbr0;
volatile u32 context_idr;
volatile u32 perfcntr_fence;
};
struct msm_cp_state {

View File

@ -42,7 +42,7 @@ int msm_context_set_sysprof(struct msm_context *ctx, struct msm_gpu *gpu, int sy
/* Some gpu families require additional setup for sysprof */
if (gpu->funcs->sysprof_setup)
gpu->funcs->sysprof_setup(gpu);
gpu->funcs->sysprof_setup(gpu, false);
ctx->sysprof = sysprof;
@ -66,6 +66,7 @@ void __msm_context_destroy(struct kref *kref)
drm_gpuvm_put(ctx->vm);
kfree(ctx->comm);
kfree(ctx->cmdline);
kfree(ctx->perfctx);
kfree(ctx);
}

View File

@ -0,0 +1,109 @@
{
"chip": "A2XX",
"groups": [
{
"name": "CP",
"num": 1,
"select": "CP_PERFCOUNTER_SELECT",
"counter_lo": "CP_PERFCOUNTER_LO",
"counter_hi": "CP_PERFCOUNTER_HI",
"countable_type": "a2xx_cp_perfcount_sel"
},
{
"name": "PA_SU",
"num": 4,
"select": "PA_SU_PERFCOUNTER{}_SELECT",
"counter_lo": "PA_SU_PERFCOUNTER{}_LOW",
"counter_hi": "PA_SU_PERFCOUNTER{}_HI",
"countable_type": "a2xx_su_perfcnt_select"
},
{
"name": "PA_SC",
"num": 1,
"select": "PA_SC_PERFCOUNTER{}_SELECT",
"counter_lo": "PA_SC_PERFCOUNTER{}_LOW",
"counter_hi": "PA_SC_PERFCOUNTER{}_HI",
"countable_type": "a2xx_sc_perfcnt_select"
},
{
"name": "VGT",
"num": 4,
"select": "VGT_PERFCOUNTER{}_SELECT",
"counter_lo": "VGT_PERFCOUNTER{}_LOW",
"counter_hi": "VGT_PERFCOUNTER{}_HI",
"countable_type": "a2xx_vgt_perfcount_select"
},
{
"name": "TCR",
"num": 2,
"select": "TCR_PERFCOUNTER{}_SELECT",
"counter_lo": "TCR_PERFCOUNTER{}_LOW",
"counter_hi": "TCR_PERFCOUNTER{}_HI",
"countable_type": "a2xx_tcr_perfcount_select"
},
{
"name": "TP0",
"num": 2,
"select": "TP0_PERFCOUNTER{}_SELECT",
"counter_lo": "TP0_PERFCOUNTER{}_LOW",
"counter_hi": "TP0_PERFCOUNTER{}_HI",
"countable_type": "a2xx_tp_perfcount_select"
},
{
"name": "TCM",
"num": 2,
"select": "TCM_PERFCOUNTER{}_SELECT",
"counter_lo": "TCM_PERFCOUNTER{}_LOW",
"counter_hi": "TCM_PERFCOUNTER{}_HI",
"countable_type": "a2xx_tcm_perfcount_select"
},
{
"name": "TCF",
"num": 12,
"select": "TCF_PERFCOUNTER{}_SELECT",
"counter_lo": "TCF_PERFCOUNTER{}_LOW",
"counter_hi": "TCF_PERFCOUNTER{}_HI",
"countable_type": "a2xx_tcf_perfcount_select"
},
{
"name": "SQ",
"num": 4,
"select": "SQ_PERFCOUNTER{}_SELECT",
"counter_lo": "SQ_PERFCOUNTER{}_LOW",
"counter_hi": "SQ_PERFCOUNTER{}_HI",
"countable_type": "a2xx_sq_perfcnt_select"
},
{
"name": "SX",
"num": 1,
"select": "SX_PERFCOUNTER{}_SELECT",
"counter_lo": "SX_PERFCOUNTER{}_LOW",
"counter_hi": "SX_PERFCOUNTER{}_HI",
"countable_type": "a2xx_sx_perfcnt_select"
},
{
"name": "MH",
"num": 2,
"select": "MH_PERFCOUNTER{}_SELECT",
"counter_lo": "MH_PERFCOUNTER{}_LOW",
"counter_hi": "MH_PERFCOUNTER{}_HI",
"countable_type": "a2xx_mh_perfcnt_select"
},
{
"name": "RBBM",
"num": 2,
"select": "RBBM_PERFCOUNTER{}_SELECT",
"counter_lo": "RBBM_PERFCOUNTER{}_LO",
"counter_hi": "RBBM_PERFCOUNTER{}_HI",
"countable_type": "a2xx_rbbm_perfcount1_sel"
},
{
"name": "RB",
"num": 4,
"select": "RB_PERFCOUNTER{}_SELECT",
"counter_lo": "RB_PERFCOUNTER{}_LOW",
"counter_hi": "RB_PERFCOUNTER{}_HI",
"countable_type": "a2xx_rb_perfcnt_select"
}
]
}

View File

@ -1330,11 +1330,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
</reg32>
<reg32 offset="0x22c5" name="SP_VS_CTRL_REG1">
<bitfield name="CONSTLENGTH" low="0" high="9" type="uint"/>
<!--
not sure about full vs half const.. I can't get blob generate
something with a mediump/lowp uniform.
-->
<bitfield name="CONSTFOOTPRINT" low="10" high="19" type="uint"/>
<bitfield name="CONSTMAXID" low="10" high="19" type="uint"/>
<bitfield name="INITIALOUTSTANDING" low="24" high="30" type="uint"/>
</reg32>
<reg32 offset="0x22c6" name="SP_VS_PARAM_REG">
@ -1420,7 +1416,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
</reg32>
<reg32 offset="0x22e1" name="SP_FS_CTRL_REG1">
<bitfield name="CONSTLENGTH" low="0" high="9" type="uint"/>
<bitfield name="CONSTFOOTPRINT" low="10" high="19" type="uint"/>
<bitfield name="CONSTMAXID" low="10" high="19" type="uint"/>
<bitfield name="INITIALOUTSTANDING" low="20" high="23" type="uint"/>
<bitfield name="HALFPRECVAROFFSET" low="24" high="30" type="uint"/>
</reg32>

View File

@ -1418,8 +1418,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<bitfield name="HEIGHT" low="9" high="16" shr="5" type="uint"/>
<!-- b17 maybe BYPASS like RB_CNTL, but reg not written for bypass -->
</reg32>
<reg32 offset="0x0bc3" name="VSC_SIZE_ADDRESS_LO"/>
<reg32 offset="0x0bc4" name="VSC_SIZE_ADDRESS_HI"/>
<reg64 offset="0x0bc3" name="VSC_SIZE_ADDRESS" type="waddress"/>
<reg32 offset="0x0bc5" name="UNKNOWN_0BC5"/> <!-- always 00000000? -->
<reg32 offset="0x0bc6" name="UNKNOWN_0BC6"/> <!-- always 00000000? -->
<array offset="0x0bd0" name="VSC_PIPE_CONFIG" stride="1" length="16">
@ -1498,12 +1497,10 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
</reg32>
<reg32 offset="0x0d01" name="PC_ADDR_MODE_CNTL" type="a5xx_address_mode"/>
<reg32 offset="0x0d02" name="PC_MODE_CNTL"/> <!-- always 0000001f? -->
<reg32 offset="0x0d04" name="PC_INDEX_BUF_LO"/>
<reg32 offset="0x0d05" name="PC_INDEX_BUF_HI"/>
<reg64 offset="0x0d04" name="PC_INDEX_BUF" type="waddress"/>
<reg32 offset="0x0d06" name="PC_START_INDEX"/>
<reg32 offset="0x0d07" name="PC_MAX_INDEX"/>
<reg32 offset="0x0d08" name="PC_TESSFACTOR_ADDR_LO"/>
<reg32 offset="0x0d09" name="PC_TESSFACTOR_ADDR_HI"/>
<reg64 offset="0x0d08" name="PC_TESSFACTOR_ADDR" type="waddress"/>
<reg32 offset="0x0d10" name="PC_PERFCTR_PC_SEL_0" type="a5xx_pc_perfcounter_select"/>
<reg32 offset="0x0d11" name="PC_PERFCTR_PC_SEL_1" type="a5xx_pc_perfcounter_select"/>
<reg32 offset="0x0d12" name="PC_PERFCTR_PC_SEL_2" type="a5xx_pc_perfcounter_select"/>
@ -1555,20 +1552,14 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x0e80" name="UCHE_ADDR_MODE_CNTL" type="a5xx_address_mode"/>
<reg32 offset="0x0e81" name="UCHE_MODE_CNTL"/>
<reg32 offset="0x0e82" name="UCHE_SVM_CNTL"/>
<reg32 offset="0x0e87" name="UCHE_WRITE_THRU_BASE_LO"/>
<reg32 offset="0x0e88" name="UCHE_WRITE_THRU_BASE_HI"/>
<reg32 offset="0x0e89" name="UCHE_TRAP_BASE_LO"/>
<reg32 offset="0x0e8a" name="UCHE_TRAP_BASE_HI"/>
<reg32 offset="0x0e8b" name="UCHE_GMEM_RANGE_MIN_LO"/>
<reg32 offset="0x0e8c" name="UCHE_GMEM_RANGE_MIN_HI"/>
<reg32 offset="0x0e8d" name="UCHE_GMEM_RANGE_MAX_LO"/>
<reg32 offset="0x0e8e" name="UCHE_GMEM_RANGE_MAX_HI"/>
<reg64 offset="0x0e87" name="UCHE_WRITE_THRU_BASE" type="waddress"/>
<reg64 offset="0x0e89" name="UCHE_TRAP_BASE" type="waddress"/>
<reg64 offset="0x0e8b" name="UCHE_GMEM_RANGE_MIN" type="waddress"/>
<reg64 offset="0x0e8d" name="UCHE_GMEM_RANGE_MAX" type="waddress"/>
<reg32 offset="0x0e8f" name="UCHE_DBG_ECO_CNTL_2"/>
<reg32 offset="0x0e90" name="UCHE_DBG_ECO_CNTL"/>
<reg32 offset="0x0e91" name="UCHE_CACHE_INVALIDATE_MIN_LO"/>
<reg32 offset="0x0e92" name="UCHE_CACHE_INVALIDATE_MIN_HI"/>
<reg32 offset="0x0e93" name="UCHE_CACHE_INVALIDATE_MAX_LO"/>
<reg32 offset="0x0e94" name="UCHE_CACHE_INVALIDATE_MAX_HI"/>
<reg64 offset="0x0e91" name="UCHE_CACHE_INVALIDATE_MIN" type="address"/>
<reg64 offset="0x0e93" name="UCHE_CACHE_INVALIDATE_MAX" type="address"/>
<reg32 offset="0x0e95" name="UCHE_CACHE_INVALIDATE"/>
<reg32 offset="0x0e96" name="UCHE_CACHE_WAYS"/>
<reg32 offset="0x0ea0" name="UCHE_PERFCTR_UCHE_SEL_0" type="a5xx_uche_perfcounter_select"/>
@ -1583,8 +1574,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x0ea9" name="UCHE_POWERCTR_UCHE_SEL_1"/>
<reg32 offset="0x0eaa" name="UCHE_POWERCTR_UCHE_SEL_2"/>
<reg32 offset="0x0eab" name="UCHE_POWERCTR_UCHE_SEL_3"/>
<reg32 offset="0x0eb1" name="UCHE_TRAP_LOG_LO"/>
<reg32 offset="0x0eb2" name="UCHE_TRAP_LOG_HI"/>
<reg64 offset="0x0eb1" name="UCHE_TRAP_LOG" type="waddress"/>
<reg32 offset="0x0ec0" name="SP_DBG_ECO_CNTL"/>
<reg32 offset="0x0ec1" name="SP_ADDR_MODE_CNTL" type="a5xx_address_mode"/>
@ -1923,8 +1913,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
invalidates the LRZ buffer? (Or just the covered positions?
-->
</reg32>
<reg32 offset="0xe101" name="GRAS_LRZ_BUFFER_BASE_LO"/>
<reg32 offset="0xe102" name="GRAS_LRZ_BUFFER_BASE_HI"/>
<reg64 offset="0xe101" name="GRAS_LRZ_BUFFER_BASE" type="waddress"/>
<!--
lzr pitch is depth pitch (in pixels) / 8 (aligned to 32)..
-->
@ -1933,8 +1922,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
is also divided by 8 (ie. covers 8x8 pixels)
</doc>
<reg32 offset="0xe103" name="GRAS_LRZ_BUFFER_PITCH" shr="5" type="uint"/>
<reg32 offset="0xe104" name="GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_LO"/>
<reg32 offset="0xe105" name="GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_HI"/>
<reg64 offset="0xe104" name="GRAS_LRZ_FAST_CLEAR_BUFFER_BASE" type="waddress"/>
<reg32 offset="0xe140" name="RB_CNTL">
<bitfield name="WIDTH" low="0" high="7" shr="5" type="uint"/>
@ -2035,8 +2023,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
-->
<reg32 offset="0x3" name="PITCH" shr="6" type="uint"/>
<reg32 offset="0x4" name="ARRAY_PITCH" shr="6" type="uint"/>
<reg32 offset="0x5" name="BASE_LO"/>
<reg32 offset="0x6" name="BASE_HI"/>
<reg64 offset="0x5" name="BASE" type="waddress"/>
</array>
<reg32 offset="0xe1a0" name="RB_BLEND_RED">
<bitfield name="UINT" low="0" high="7" type="hex"/>
@ -2089,8 +2076,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<reg32 offset="0xe1b2" name="RB_DEPTH_BUFFER_INFO">
<bitfield name="DEPTH_FORMAT" low="0" high="2" type="a5xx_depth_format"/>
</reg32>
<reg32 offset="0xe1b3" name="RB_DEPTH_BUFFER_BASE_LO"/>
<reg32 offset="0xe1b4" name="RB_DEPTH_BUFFER_BASE_HI"/>
<reg64 offset="0xe1b3" name="RB_DEPTH_BUFFER_BASE" type="waddress"/>
<reg32 offset="0xe1b5" name="RB_DEPTH_BUFFER_PITCH" shr="6" type="uint">
<doc>stride of depth/stencil buffer</doc>
</reg32>
@ -2119,8 +2105,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<reg32 offset="0xe1c1" name="RB_STENCIL_INFO">
<bitfield name="SEPARATE_STENCIL" pos="0" type="boolean"/>
</reg32>
<reg32 offset="0xe1c2" name="RB_STENCIL_BASE_LO"/>
<reg32 offset="0xe1c3" name="RB_STENCIL_BASE_HI"/>
<reg64 offset="0xe1c2" name="RB_STENCIL_BASE" type="waddress"/>
<reg32 offset="0xe1c4" name="RB_STENCIL_PITCH" shr="6" type="uint"/>
<reg32 offset="0xe1c5" name="RB_STENCIL_ARRAY_PITCH" shr="6" type="uint"/>
<reg32 offset="0xe1c6" name="RB_STENCILREFMASK" type="adreno_rb_stencilrefmask"/>
@ -2163,8 +2148,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
also for gmem->mem preserving tiling
-->
</reg32>
<reg32 offset="0xe214" name="RB_BLIT_DST_LO"/>
<reg32 offset="0xe215" name="RB_BLIT_DST_HI"/>
<reg64 offset="0xe214" name="RB_BLIT_DST" type="waddress"/>
<reg32 offset="0xe216" name="RB_BLIT_DST_PITCH" shr="6" type="uint"/>
<!-- array-pitch is size of layer -->
<reg32 offset="0xe217" name="RB_BLIT_DST_ARRAY_PITCH" shr="6" type="uint"/>
@ -2235,25 +2219,22 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
</doc>
<reg32 offset="0xe240" name="RB_DEPTH_FLAG_BUFFER_BASE_LO"/>
<reg32 offset="0xe241" name="RB_DEPTH_FLAG_BUFFER_BASE_HI"/>
<reg64 offset="0xe240" name="RB_DEPTH_FLAG_BUFFER_BASE" type="waddress"/>
<reg32 offset="0xe242" name="RB_DEPTH_FLAG_BUFFER_PITCH">
</reg32>
<array offset="0xe243" name="RB_MRT_FLAG_BUFFER" stride="4" length="8">
<reg32 offset="0" name="ADDR_LO"/>
<reg64 offset="0" name="ADDR" type="waddress"/>
<reg32 offset="1" name="ADDR_HI"/>
<reg32 offset="2" name="PITCH" shr="6" type="uint"/>
<!-- array-pitch is size of layer -->
<reg32 offset="3" name="ARRAY_PITCH" shr="6" type="uint"/>
</array>
<reg32 offset="0xe263" name="RB_BLIT_FLAG_DST_LO"/>
<reg32 offset="0xe264" name="RB_BLIT_FLAG_DST_HI"/>
<reg64 offset="0xe263" name="RB_BLIT_FLAG_DST" type="waddress"/>
<reg32 offset="0xe265" name="RB_BLIT_FLAG_DST_PITCH" shr="6" type="uint"/>
<!-- array-pitch is size of layer -->
<reg32 offset="0xe266" name="RB_BLIT_FLAG_DST_ARRAY_PITCH" shr="6" type="uint"/>
<reg32 offset="0xe267" name="RB_SAMPLE_COUNT_ADDR_LO"/>
<reg32 offset="0xe268" name="RB_SAMPLE_COUNT_ADDR_HI"/>
<reg64 offset="0xe267" name="RB_SAMPLE_COUNT_ADDR" type="waddress"/>
<reg32 offset="0xe280" name="VPC_CNTL_0">
<doc>
@ -2357,13 +2338,11 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<bitfield name="B_EN" pos="23" type="boolean"/>
</reg32>
<array offset="0xe2a7" name="VPC_SO" stride="7" length="4">
<reg32 offset="0" name="BUFFER_BASE_LO"/>
<reg32 offset="1" name="BUFFER_BASE_HI"/>
<reg64 offset="0" name="BUFFER_BASE" type="waddress"/>
<reg32 offset="2" name="BUFFER_SIZE"/>
<reg32 offset="3" name="NCOMP"/> <!-- component count -->
<reg32 offset="4" name="BUFFER_OFFSET"/>
<reg32 offset="5" name="FLUSH_BASE_LO"/>
<reg32 offset="6" name="FLUSH_BASE_HI"/>
<reg64 offset="5" name="FLUSH_BASE" type="waddress"/>
</array>
<reg32 offset="0xe384" name="PC_PRIMITIVE_CNTL">
@ -2423,8 +2402,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<reg32 offset="0xe408" name="VFD_INDEX_OFFSET"/>
<reg32 offset="0xe409" name="VFD_INSTANCE_START_OFFSET"/>
<array offset="0xe40a" name="VFD_FETCH" stride="4" length="32">
<reg32 offset="0x0" name="BASE_LO"/>
<reg32 offset="0x1" name="BASE_HI"/>
<reg64 offset="0x0" name="BASE" type="address"/>
<reg32 offset="0x2" name="SIZE" type="uint"/>
<reg32 offset="0x3" name="STRIDE" type="uint"/>
</array>
@ -2475,7 +2453,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<bitfield name="VARYING" pos="16" type="boolean"/>
<bitfield name="PIXLODENABLE" pos="20" type="boolean"/>
<!-- seems to be nesting level for flow control:.. -->
<bitfield name="BRANCHSTACK" low="25" high="31" type="uint"/>
<bitfield name="BRANCHSTACK" low="24" high="31" type="uint"/>
</bitset>
<!-- assuming things appear in same relative order as a4xx: -->
<!-- duplicated exactly w/ corresponding HLSQ_ regs starting at 0xe78b.. -->
@ -2516,8 +2494,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
</reg32>
</array>
<reg32 offset="0xe5ab" name="UNKNOWN_E5AB"/>
<reg32 offset="0xe5ac" name="SP_VS_OBJ_START_LO"/>
<reg32 offset="0xe5ad" name="SP_VS_OBJ_START_HI"/>
<reg64 offset="0xe5ac" name="SP_VS_OBJ_START" type="address"/>
<bitset name="a5xx_sp_xs_pvt_mem_param" inline="yes">
<bitfield name="MEMSIZEPERITEM" low="0" high="7" shr="9">
@ -2538,8 +2515,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<reg32 offset="0xe5b1" name="SP_VS_PVT_MEM_SIZE" type="a5xx_sp_xs_pvt_mem_size"/>
<reg32 offset="0xe5c0" name="SP_FS_CTRL_REG0" type="a5xx_sp_xs_ctrl_reg0"/>
<reg32 offset="0xe5c2" name="UNKNOWN_E5C2"/>
<reg32 offset="0xe5c3" name="SP_FS_OBJ_START_LO"/>
<reg32 offset="0xe5c4" name="SP_FS_OBJ_START_HI"/>
<reg64 offset="0xe5c3" name="SP_FS_OBJ_START" type="address"/>
<reg32 offset="0xe5c5" name="SP_FS_PVT_MEM_PARAM" type="a5xx_sp_xs_pvt_mem_param"/>
<reg64 offset="0xe5c6" name="SP_FS_PVT_MEM_ADDR" type="waddress" align="32"/>
<reg32 offset="0xe5c8" name="SP_FS_PVT_MEM_SIZE" type="a5xx_sp_xs_pvt_mem_size"/>
@ -2577,8 +2553,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<reg32 offset="0xe5db" name="UNKNOWN_E5DB"/>
<reg32 offset="0xe5f0" name="SP_CS_CTRL_REG0" type="a5xx_sp_xs_ctrl_reg0"/>
<reg32 offset="0xe5f2" name="UNKNOWN_E5F2"/>
<reg32 offset="0xe5f3" name="SP_CS_OBJ_START_LO"/>
<reg32 offset="0xe5f4" name="SP_CS_OBJ_START_HI"/>
<reg64 offset="0xe5f3" name="SP_CS_OBJ_START" type="address"/>
<reg32 offset="0xe5f5" name="SP_CS_PVT_MEM_PARAM" type="a5xx_sp_xs_pvt_mem_param"/>
<reg64 offset="0xe5f6" name="SP_CS_PVT_MEM_ADDR" type="waddress" align="32"/>
<reg32 offset="0xe5f8" name="SP_CS_PVT_MEM_SIZE" type="a5xx_sp_xs_pvt_mem_size"/>
@ -2587,22 +2562,19 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<reg32 offset="0xe600" name="SP_HS_CTRL_REG0" type="a5xx_sp_xs_ctrl_reg0"/>
<reg32 offset="0xe602" name="UNKNOWN_E602"/>
<reg32 offset="0xe603" name="SP_HS_OBJ_START_LO"/>
<reg32 offset="0xe604" name="SP_HS_OBJ_START_HI"/>
<reg64 offset="0xe603" name="SP_HS_OBJ_START" type="address"/>
<reg32 offset="0xe605" name="SP_HS_PVT_MEM_PARAM" type="a5xx_sp_xs_pvt_mem_param"/>
<reg64 offset="0xe606" name="SP_HS_PVT_MEM_ADDR" type="waddress" align="32"/>
<reg32 offset="0xe608" name="SP_HS_PVT_MEM_SIZE" type="a5xx_sp_xs_pvt_mem_size"/>
<reg32 offset="0xe610" name="SP_DS_CTRL_REG0" type="a5xx_sp_xs_ctrl_reg0"/>
<reg32 offset="0xe62b" name="UNKNOWN_E62B"/>
<reg32 offset="0xe62c" name="SP_DS_OBJ_START_LO"/>
<reg32 offset="0xe62d" name="SP_DS_OBJ_START_HI"/>
<reg64 offset="0xe62c" name="SP_DS_OBJ_START" type="address"/>
<reg32 offset="0xe62e" name="SP_DS_PVT_MEM_PARAM" type="a5xx_sp_xs_pvt_mem_param"/>
<reg64 offset="0xe62f" name="SP_DS_PVT_MEM_ADDR" type="waddress" align="32"/>
<reg32 offset="0xe631" name="SP_DS_PVT_MEM_SIZE" type="a5xx_sp_xs_pvt_mem_size"/>
<reg32 offset="0xe640" name="SP_GS_CTRL_REG0" type="a5xx_sp_xs_ctrl_reg0"/>
<reg32 offset="0xe65b" name="UNKNOWN_E65B"/>
<reg32 offset="0xe65c" name="SP_GS_OBJ_START_LO"/>
<reg32 offset="0xe65d" name="SP_GS_OBJ_START_HI"/>
<reg64 offset="0xe65c" name="SP_GS_OBJ_START" type="address"/>
<reg32 offset="0xe65e" name="SP_GS_PVT_MEM_PARAM" type="a5xx_sp_xs_pvt_mem_param"/>
<reg64 offset="0xe65f" name="SP_GS_PVT_MEM_ADDR" type="waddress" align="32"/>
<reg32 offset="0xe661" name="SP_GS_PVT_MEM_SIZE" type="a5xx_sp_xs_pvt_mem_size"/>
@ -2615,8 +2587,7 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<bitfield name="MSAA_DISABLE" pos="2" type="boolean"/>
</reg32>
<!-- either blob is doing it wrong, or this is not per-stage anymore: -->
<reg32 offset="0xe706" name="TPL1_TP_BORDER_COLOR_BASE_ADDR_LO"/>
<reg32 offset="0xe707" name="TPL1_TP_BORDER_COLOR_BASE_ADDR_HI"/>
<reg64 offset="0xe706" name="TPL1_TP_BORDER_COLOR_BASE_ADDR" type="address"/>
<!--
so these have the same info that is normally in the CP_LOAD_STATE
@ -2628,35 +2599,23 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
<reg32 offset="0xe702" name="TPL1_DS_TEX_COUNT" type="uint"/>
<reg32 offset="0xe703" name="TPL1_GS_TEX_COUNT" type="uint"/>
<reg32 offset="0xe722" name="TPL1_VS_TEX_SAMP_LO"/>
<reg32 offset="0xe723" name="TPL1_VS_TEX_SAMP_HI"/>
<reg32 offset="0xe724" name="TPL1_HS_TEX_SAMP_LO"/>
<reg32 offset="0xe725" name="TPL1_HS_TEX_SAMP_HI"/>
<reg32 offset="0xe726" name="TPL1_DS_TEX_SAMP_LO"/>
<reg32 offset="0xe727" name="TPL1_DS_TEX_SAMP_HI"/>
<reg32 offset="0xe728" name="TPL1_GS_TEX_SAMP_LO"/>
<reg32 offset="0xe729" name="TPL1_GS_TEX_SAMP_HI"/>
<reg64 offset="0xe722" name="TPL1_VS_TEX_SAMP" type="address"/>
<reg64 offset="0xe724" name="TPL1_HS_TEX_SAMP" type="address"/>
<reg64 offset="0xe726" name="TPL1_DS_TEX_SAMP" type="address"/>
<reg64 offset="0xe728" name="TPL1_GS_TEX_SAMP" type="address"/>
<reg32 offset="0xe72a" name="TPL1_VS_TEX_CONST_LO"/>
<reg32 offset="0xe72b" name="TPL1_VS_TEX_CONST_HI"/>
<reg32 offset="0xe72c" name="TPL1_HS_TEX_CONST_LO"/>
<reg32 offset="0xe72d" name="TPL1_HS_TEX_CONST_HI"/>
<reg32 offset="0xe72e" name="TPL1_DS_TEX_CONST_LO"/>
<reg32 offset="0xe72f" name="TPL1_DS_TEX_CONST_HI"/>
<reg32 offset="0xe730" name="TPL1_GS_TEX_CONST_LO"/>
<reg32 offset="0xe731" name="TPL1_GS_TEX_CONST_HI"/>
<reg64 offset="0xe72a" name="TPL1_VS_TEX_CONST" type="address"/>
<reg64 offset="0xe72c" name="TPL1_HS_TEX_CONST" type="address"/>
<reg64 offset="0xe72e" name="TPL1_DS_TEX_CONST" type="address"/>
<reg64 offset="0xe730" name="TPL1_GS_TEX_CONST" type="address"/>
<reg32 offset="0xe750" name="TPL1_FS_TEX_COUNT" type="uint"/>
<reg32 offset="0xe751" name="TPL1_CS_TEX_COUNT" type="uint"/>
<reg32 offset="0xe75a" name="TPL1_FS_TEX_SAMP_LO"/>
<reg32 offset="0xe75b" name="TPL1_FS_TEX_SAMP_HI"/>
<reg32 offset="0xe75c" name="TPL1_CS_TEX_SAMP_LO"/>
<reg32 offset="0xe75d" name="TPL1_CS_TEX_SAMP_HI"/>
<reg32 offset="0xe75e" name="TPL1_FS_TEX_CONST_LO"/>
<reg32 offset="0xe75f" name="TPL1_FS_TEX_CONST_HI"/>
<reg32 offset="0xe760" name="TPL1_CS_TEX_CONST_LO"/>
<reg32 offset="0xe761" name="TPL1_CS_TEX_CONST_HI"/>
<reg64 offset="0xe75a" name="TPL1_FS_TEX_SAMP" type="address"/>
<reg64 offset="0xe75c" name="TPL1_CS_TEX_SAMP" type="address"/>
<reg64 offset="0xe75e" name="TPL1_FS_TEX_CONST" type="address"/>
<reg64 offset="0xe760" name="TPL1_CS_TEX_CONST" type="address"/>
<reg32 offset="0xe764" name="TPL1_TP_FS_ROTATION_CNTL"/>
@ -2809,25 +2768,21 @@ bit 7 for RECTLIST (clear) when z32s8 (used for clear of depth32? not set
</bitset>
<reg32 offset="0x2107" name="RB_2D_SRC_INFO" type="a5xx_2d_surf_info"/>
<reg32 offset="0x2108" name="RB_2D_SRC_LO"/>
<reg32 offset="0x2109" name="RB_2D_SRC_HI"/>
<reg64 offset="0x2108" name="RB_2D_SRC" type="address"/>
<reg32 offset="0x210a" name="RB_2D_SRC_SIZE">
<bitfield name="PITCH" low="0" high="15" shr="6" type="uint"/>
<bitfield name="ARRAY_PITCH" low="16" high="31" shr="6" type="uint"/>
</reg32>
<reg32 offset="0x2110" name="RB_2D_DST_INFO" type="a5xx_2d_surf_info"/>
<reg32 offset="0x2111" name="RB_2D_DST_LO"/>
<reg32 offset="0x2112" name="RB_2D_DST_HI"/>
<reg64 offset="0x2111" name="RB_2D_DST" type="address"/>
<reg32 offset="0x2113" name="RB_2D_DST_SIZE">
<bitfield name="PITCH" low="0" high="15" shr="6" type="uint"/>
<bitfield name="ARRAY_PITCH" low="16" high="31" shr="6" type="uint"/>
</reg32>
<reg32 offset="0x2140" name="RB_2D_SRC_FLAGS_LO"/>
<reg32 offset="0x2141" name="RB_2D_SRC_FLAGS_HI"/>
<reg64 offset="0x2140" name="RB_2D_SRC_FLAGS" type="address"/>
<reg32 offset="0x2142" name="RB_2D_SRC_FLAGS_PITCH" shr="6" type="uint"/>
<reg32 offset="0x2143" name="RB_2D_DST_FLAGS_LO"/>
<reg32 offset="0x2144" name="RB_2D_DST_FLAGS_HI"/>
<reg64 offset="0x2143" name="RB_2D_DST_FLAGS" type="address"/>
<reg32 offset="0x2145" name="RB_2D_DST_FLAGS_PITCH" shr="6" type="uint"/>
<reg32 offset="0x2180" name="GRAS_2D_BLIT_CNTL"/> <!-- same as 0x2100 -->
<!-- looks same as 0x2107: -->

View File

@ -0,0 +1,128 @@
{
"chip": "A5XX",
"groups": [
{
"name": "CP",
"num": 8,
"reserved": [ 0 ],
"select": "CP_PERFCTR_CP_SEL_{}",
"counter_lo": "RBBM_PERFCTR_CP_{}_LO",
"counter_hi": "RBBM_PERFCTR_CP_{}_HI",
"countable_type": "a5xx_cp_perfcounter_select"
},
{
"name": "CCU",
"num": 4,
"select": "RB_PERFCTR_CCU_SEL_{}",
"counter_lo": "RBBM_PERFCTR_CCU_{}_LO",
"counter_hi": "RBBM_PERFCTR_CCU_{}_HI",
"countable_type": "a5xx_ccu_perfcounter_select"
},
{
"name": "TSE",
"num": 4,
"select": "GRAS_PERFCTR_TSE_SEL_{}",
"counter_lo": "RBBM_PERFCTR_TSE_{}_LO",
"counter_hi": "RBBM_PERFCTR_TSE_{}_HI",
"countable_type": "a5xx_tse_perfcounter_select"
},
{
"name": "RAS",
"num": 4,
"select": "GRAS_PERFCTR_RAS_SEL_{}",
"counter_lo": "RBBM_PERFCTR_RAS_{}_LO",
"counter_hi": "RBBM_PERFCTR_RAS_{}_HI",
"countable_type": "a5xx_ras_perfcounter_select"
},
{
"name": "LRZ",
"num": 4,
"select": "GRAS_PERFCTR_LRZ_SEL_{}",
"counter_lo": "RBBM_PERFCTR_LRZ_{}_LO",
"counter_hi": "RBBM_PERFCTR_LRZ_{}_HI",
"countable_type": "a5xx_lrz_perfcounter_select"
},
{
"name": "HLSQ",
"num": 8,
"select": "HLSQ_PERFCTR_HLSQ_SEL_{}",
"counter_lo": "RBBM_PERFCTR_HLSQ_{}_LO",
"counter_hi": "RBBM_PERFCTR_HLSQ_{}_HI",
"countable_type": "a5xx_hlsq_perfcounter_select"
},
{
"name": "PC",
"num": 8,
"select": "PC_PERFCTR_PC_SEL_{}",
"counter_lo": "RBBM_PERFCTR_PC_{}_LO",
"counter_hi": "RBBM_PERFCTR_PC_{}_HI",
"countable_type": "a5xx_pc_perfcounter_select"
},
{
"name": "RB",
"num": 8,
"select": "RB_PERFCTR_RB_SEL_{}",
"counter_lo": "RBBM_PERFCTR_RB_{}_LO",
"counter_hi": "RBBM_PERFCTR_RB_{}_HI",
"countable_type": "a5xx_rb_perfcounter_select"
},
{
"name": "RBBM",
"num": 4,
"reserved": [ 0 ],
"select": "RBBM_PERFCTR_RBBM_SEL_{}",
"counter_lo": "RBBM_PERFCTR_RBBM_{}_LO",
"counter_hi": "RBBM_PERFCTR_RBBM_{}_HI",
"countable_type": "a5xx_rbbm_perfcounter_select"
},
{
"name": "SP",
"num": 12,
"reserved": [ 0 ],
"select": "SP_PERFCTR_SP_SEL_{}",
"counter_lo": "RBBM_PERFCTR_SP_{}_LO",
"counter_hi": "RBBM_PERFCTR_SP_{}_HI",
"countable_type": "a5xx_sp_perfcounter_select"
},
{
"name": "TP",
"num": 8,
"select": "TPL1_PERFCTR_TP_SEL_{}",
"counter_lo": "RBBM_PERFCTR_TP_{}_LO",
"counter_hi": "RBBM_PERFCTR_TP_{}_HI",
"countable_type": "a5xx_tp_perfcounter_select"
},
{
"name": "UCHE",
"num": 8,
"select": "UCHE_PERFCTR_UCHE_SEL_{}",
"counter_lo": "RBBM_PERFCTR_UCHE_{}_LO",
"counter_hi": "RBBM_PERFCTR_UCHE_{}_HI",
"countable_type": "a5xx_uche_perfcounter_select"
},
{
"name": "VFD",
"num": 8,
"select": "VFD_PERFCTR_VFD_SEL_{}",
"counter_lo": "RBBM_PERFCTR_VFD_{}_LO",
"counter_hi": "RBBM_PERFCTR_VFD_{}_HI",
"countable_type": "a5xx_vfd_perfcounter_select"
},
{
"name": "VPC",
"num": 4,
"select": "VPC_PERFCTR_VPC_SEL_{}",
"counter_lo": "RBBM_PERFCTR_VPC_{}_LO",
"counter_hi": "RBBM_PERFCTR_VPC_{}_HI",
"countable_type": "a5xx_vpc_perfcounter_select"
},
{
"name": "VSC",
"num": 2,
"select": "VSC_PERFCTR_VSC_SEL_{}",
"counter_lo": "RBBM_PERFCTR_VSC_{}_LO",
"counter_hi": "RBBM_PERFCTR_VSC_{}_HI",
"countable_type": "a5xx_vsc_perfcounter_select"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -45,19 +45,21 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="3" name="3"/>
</domain>
<domain name="A6XX_TEX_CONST" width="32" varset="chip">
<domain name="A6XX_TEX_MEMOBJ" width="32" varset="desctype">
<doc>Texture constant dwords</doc>
<reg32 offset="0" name="0">
<bitfield name="TILE_MODE" low="0" high="1" type="a6xx_tile_mode"/>
<bitfield name="SRGB" pos="2" type="boolean"/>
<bitfield name="SWIZ_X" low="4" high="6" type="a6xx_tex_swiz"/>
<bitfield name="SWIZ_Y" low="7" high="9" type="a6xx_tex_swiz"/>
<bitfield name="SWIZ_Z" low="10" high="12" type="a6xx_tex_swiz"/>
<bitfield name="SWIZ_W" low="13" high="15" type="a6xx_tex_swiz"/>
<bitfield name="MIPLVLS" low="16" high="19" type="uint"/>
<bitfield name="SWIZ_X" low="4" high="6" type="a6xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
<bitfield name="SWIZ_Y" low="7" high="9" type="a6xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
<bitfield name="SWIZ_Z" low="10" high="12" type="a6xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
<bitfield name="SWIZ_W" low="13" high="15" type="a6xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
<bitfield name="MIPLVLS" low="16" high="19" type="uint" variants="DESC_SINGLE_PLANE DESC_BUFFER DESC_WEIGHT"/>
<!-- overlaps with MIPLVLS -->
<bitfield name="CHROMA_MIDPOINT_X" pos="16" type="boolean"/>
<bitfield name="CHROMA_MIDPOINT_Y" pos="18" type="boolean"/>
<bitfield name="CHROMA_MIDPOINT_X" pos="16" type="boolean" variants="DESC_MULTI_PLANE"/>
<bitfield name="CHROMA_MIDPOINT_Y" pos="18" type="boolean" variants="DESC_MULTI_PLANE"/>
<bitfield name="SAMPLES" low="20" high="21" type="a3xx_msaa_samples"/>
<bitfield name="FMT" low="22" high="29" type="a6xx_format"/>
<!--
@ -68,9 +70,10 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<bitfield name="SWAP" low="30" high="31" type="a3xx_color_swap"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="WIDTH" low="0" high="14" type="uint"/>
<bitfield name="HEIGHT" low="15" high="29" type="uint"/>
<bitfield name="MUTABLEEN" pos="31" type="boolean" variants="A7XX-"/>
<bitfield name="WIDTH" low="0" high="14" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="HEIGHT" low="15" high="29" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="NUM_ELEMENTS" low="0" high="29" type="uint" variants="DESC_BUFFER"/>
<bitfield name="MUTABLEEN" pos="31" type="boolean"/> <!-- a7xx+ -->
</reg32>
<reg32 offset="2" name="2">
<!--
@ -78,13 +81,13 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
PITCH/PITCHALIGN when TYPE is A6XX_TEX_BUFFER.
-->
<doc> probably for D3D structured UAVs, normally set to 1 </doc>
<bitfield name="STRUCTSIZETEXELS" low="4" high="15" type="uint"/>
<bitfield name="STARTOFFSETTEXELS" low="16" high="21" type="uint"/>
<bitfield name="STRUCTSIZETEXELS" low="4" high="15" type="uint" variants="DESC_BUFFER"/>
<bitfield name="STARTOFFSETTEXELS" low="16" high="21" type="uint" variants="DESC_BUFFER"/>
<!-- minimum pitch (for mipmap levels): log2(pitchalign / 64) -->
<bitfield name="PITCHALIGN" low="0" high="3" type="uint"/>
<bitfield name="PITCHALIGN" low="0" high="3" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<doc>Pitch in bytes (so actually stride)</doc>
<bitfield name="PITCH" low="7" high="28" type="uint"/>
<bitfield name="PITCH" low="7" high="28" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="TYPE" low="29" high="31" type="a6xx_tex_type"/>
</reg32>
<reg32 offset="3" name="3">
@ -94,15 +97,15 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
layer size at the point that it stops being reduced moving to
higher (smaller) mipmap levels
-->
<bitfield name="ARRAY_PITCH" low="0" high="22" shr="12" type="uint"/>
<bitfield name="MIN_LAYERSZ" low="23" high="26" shr="12"/>
<bitfield name="ARRAY_PITCH" low="0" high="22" shr="12" type="uint" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/>
<bitfield name="MIN_LAYERSZ" low="23" high="26" shr="12" variants="DESC_SINGLE_PLANE"/>
<!--
by default levels with w < 16 are linear
TILE_ALL makes all levels have tiling
seems required when using UBWC, since all levels have UBWC (can possibly be disabled?)
-->
<bitfield name="TILE_ALL" pos="27" type="boolean"/>
<bitfield name="FLAG" pos="28" type="boolean"/>
<bitfield name="TILE_ALL" pos="27" type="boolean" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="FLAG" pos="28" type="boolean" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
</reg32>
<!-- for 2-3 plane format, BASE is flag buffer address (if enabled)
the address of the non-flag base buffer is determined automatically,
@ -113,30 +116,42 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
</reg32>
<reg32 offset="5" name="5">
<bitfield name="BASE_HI" low="0" high="16"/>
<bitfield name="DEPTH" low="17" high="29" type="uint"/>
<bitfield name="DEPTH" low="17" high="29" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
</reg32>
<reg32 offset="6" name="6">
<!-- overlaps with PLANE_PITCH -->
<bitfield name="MIN_LOD_CLAMP" low="0" high="11" type="ufixed" radix="8"/>
<bitfield name="MIN_LOD_CLAMP" low="0" high="11" type="ufixed" radix="8" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE"/>
<!-- pitch for plane 2 / plane 3 -->
<bitfield name="PLANE_PITCH" low="8" high="31" type="uint"/>
<bitfield name="PLANE_PITCH" low="8" high="31" type="uint" variants="DESC_MULTI_PLANE"/>
<!-- QCOM_image_filtering sample weights descriptor fields, overlapping the others. -->
<bitfield name="LOG2_PHASES" low="0" high="2" type="uint" variants="DESC_WEIGHT"/>
<bitfield name="DILATION" low="8" high="11" type="uint" variants="DESC_WEIGHT"/>
</reg32>
<!-- 7/8 is plane 2 address for planar formats -->
<reg32 offset="7" name="7">
<bitfield name="FLAG_LO" low="5" high="31" shr="5"/>
<bitfield name="FLAG_LO" low="5" high="31" shr="5" variants="DESC_SINGLE_PLANE"/>
<bitfield name="BASE_U_LO" low="5" high="31" shr="5" variants="DESC_MULTI_PLANE"/>
</reg32>
<reg32 offset="8" name="8">
<bitfield name="FLAG_HI" low="0" high="16"/>
<bitfield name="FLAG_HI" low="0" high="16" variants="DESC_SINGLE_PLANE"/>
<bitfield name="BASE_U_HI" low="0" high="16" variants="DESC_MULTI_PLANE"/>
<bitfield name="FILTER_SIZE_X" low="17" high="23" variants="DESC_WEIGHT"/>
<bitfield name="FILTER_SIZE_Y" low="24" high="30" variants="DESC_WEIGHT"/>
</reg32>
<!-- 9/10 is plane 3 address for planar formats -->
<reg32 offset="9" name="9">
<bitfield name="FLAG_BUFFER_ARRAY_PITCH" low="0" high="16" shr="4" type="uint"/>
<bitfield name="FLAG_BUFFER_ARRAY_PITCH" low="0" high="16" shr="4" type="uint" variants="DESC_SINGLE_PLANE"/>
<bitfield name="BASE_V_LO" low="5" high="31" shr="5" variants="DESC_MULTI_PLANE"/>
</reg32>
<reg32 offset="10" name="10">
<bitfield name="FLAG_BUFFER_PITCH" low="0" high="6" shr="6" type="uint"/>
<bitfield name="FLAG_BUFFER_PITCH" low="0" high="6" shr="6" type="uint" variants="DESC_SINGLE_PLANE"/>
<!-- log2 size of the first level, required for mipmapping -->
<bitfield name="FLAG_BUFFER_LOGW" low="8" high="11" type="uint"/>
<bitfield name="FLAG_BUFFER_LOGH" low="12" high="15" type="uint"/>
<bitfield name="FLAG_BUFFER_LOGW" low="8" high="11" type="uint" variants="DESC_SINGLE_PLANE"/>
<bitfield name="FLAG_BUFFER_LOGH" low="12" high="15" type="uint" variants="DESC_SINGLE_PLANE"/>
<bitfield name="BASE_V_HI" low="0" high="16" variants="DESC_MULTI_PLANE"/>
<bitfield name="FILTER_OFFSET_X" low="17" high="22" variants="DESC_WEIGHT"/>
<bitfield name="FILTER_OFFSET_Y" low="23" high="28" variants="DESC_WEIGHT"/>
</reg32>
<reg32 offset="11" name="11"/>
<reg32 offset="12" name="12"/>

View File

@ -328,6 +328,9 @@ to upconvert to 32b float internally?
<value value="0x2" name="R2D_SNORM8"/>
<value value="0x1" name="R2D_UNORM8_SRGB"/>
<value value="0x0" name="R2D_UNORM8"/>
<!-- Not a hw enum, used internally in driver -->
<value value="0xff" name="R2D_NONE"/>
</enum>
<enum name="a6xx_tex_type">

View File

@ -0,0 +1,112 @@
{
"chip": "A6XX",
"groups": [
{
"name": "CP",
"num": 14,
"reserved": [ 0 ],
"select": "CP_PERFCTR_CP_SEL",
"counter": "RBBM_PERFCTR_CP",
"countable_type": "a6xx_cp_perfcounter_select"
},
{
"name": "CCU",
"num": 5,
"select": "RB_PERFCTR_CCU_SEL",
"counter": "RBBM_PERFCTR_CCU",
"countable_type": "a6xx_ccu_perfcounter_select"
},
{
"name": "TSE",
"num": 4,
"select": "GRAS_PERFCTR_TSE_SEL",
"counter": "RBBM_PERFCTR_TSE",
"countable_type": "a6xx_tse_perfcounter_select"
},
{
"name": "RAS",
"num": 4,
"select": "GRAS_PERFCTR_RAS_SEL",
"counter": "RBBM_PERFCTR_RAS",
"countable_type": "a6xx_ras_perfcounter_select"
},
{
"name": "LRZ",
"num": 4,
"select": "GRAS_PERFCTR_LRZ_SEL",
"counter": "RBBM_PERFCTR_LRZ",
"countable_type": "a6xx_lrz_perfcounter_select"
},
{
"name": "CMP",
"num": 4,
"select": "RB_PERFCTR_CMP_SEL",
"counter": "RBBM_PERFCTR_CMP",
"countable_type": "a6xx_cmp_perfcounter_select"
},
{
"name": "HLSQ",
"num": 6,
"select": "HLSQ_PERFCTR_HLSQ_SEL",
"counter": "RBBM_PERFCTR_HLSQ",
"countable_type": "a6xx_hlsq_perfcounter_select"
},
{
"name": "PC",
"num": 8,
"select": "PC_PERFCTR_PC_SEL",
"counter": "RBBM_PERFCTR_PC",
"countable_type": "a6xx_pc_perfcounter_select"
},
{
"name": "RB",
"num": 8,
"select": "RB_PERFCTR_RB_SEL",
"counter": "RBBM_PERFCTR_RB",
"countable_type": "a6xx_rb_perfcounter_select"
},
{
"name": "SP",
"num": 24,
"reserved": [ 0 ],
"select": "SP_PERFCTR_SP_SEL",
"counter": "RBBM_PERFCTR_SP",
"countable_type": "a6xx_sp_perfcounter_select"
},
{
"name": "TP",
"num": 12,
"select": "TPL1_PERFCTR_TP_SEL",
"counter": "RBBM_PERFCTR_TP",
"countable_type": "a6xx_tp_perfcounter_select"
},
{
"name": "UCHE",
"num": 12,
"select": "UCHE_PERFCTR_UCHE_SEL",
"counter": "RBBM_PERFCTR_UCHE",
"countable_type": "a6xx_uche_perfcounter_select"
},
{
"name": "VFD",
"num": 8,
"select": "VFD_PERFCTR_VFD_SEL",
"counter": "RBBM_PERFCTR_VFD",
"countable_type": "a6xx_vfd_perfcounter_select"
},
{
"name": "VPC",
"num": 6,
"select": "VPC_PERFCTR_VPC_SEL",
"counter": "RBBM_PERFCTR_VPC",
"countable_type": "a6xx_vpc_perfcounter_select"
},
{
"name": "VSC",
"num": 2,
"select": "VSC_PERFCTR_VSC_SEL",
"counter": "RBBM_PERFCTR_VSC",
"countable_type": "a6xx_vsc_perfcounter_select"
}
]
}

View File

@ -0,0 +1,228 @@
{
"chip": "A7XX",
"groups": [
{
"name": "CP",
"num": 14,
"reserved": [ 0 ],
"select": "CP_PERFCTR_CP_SEL",
"counter": "RBBM_PERFCTR_CP",
"countable_type": "a7xx_cp_perfcounter_select"
},
{
"name": "RBBM",
"num": 4,
"select": "RBBM_PERFCTR_RBBM_SEL",
"counter": "RBBM_PERFCTR_RBBM",
"countable_type": "a7xx_rbbm_perfcounter_select"
},
{
"name": "PC",
"pipe": "BR",
"num": 8,
"select": "PC_PERFCTR_PC_SEL",
"counter": "RBBM_PERFCTR_PC",
"countable_type": "a7xx_pc_perfcounter_select"
},
{
"name": "VFD",
"pipe": "BR",
"num": 8,
"select": "VFD_PERFCTR_VFD_SEL",
"counter": "RBBM_PERFCTR_VFD",
"countable_type": "a7xx_vfd_perfcounter_select"
},
{
"name": "HLSQ",
"pipe": "BR",
"num": 6,
"select": "SP_PERFCTR_HLSQ_SEL",
"counter": "RBBM_PERFCTR_HLSQ",
"countable_type": "a7xx_hlsq_perfcounter_select"
},
{
"name": "VPC",
"pipe": "BR",
"num": 6,
"select": "VPC_PERFCTR_VPC_SEL",
"counter": "RBBM_PERFCTR_VPC",
"countable_type": "a7xx_vpc_perfcounter_select"
},
{
"name": "TSE",
"pipe": "BR",
"num": 4,
"select": "GRAS_PERFCTR_TSE_SEL",
"counter": "RBBM_PERFCTR_TSE",
"countable_type": "a7xx_tse_perfcounter_select"
},
{
"name": "RAS",
"pipe": "BR",
"num": 4,
"select": "GRAS_PERFCTR_RAS_SEL",
"counter": "RBBM_PERFCTR_RAS",
"countable_type": "a7xx_ras_perfcounter_select"
},
{
"name": "UCHE",
"num": 12,
"select": "UCHE_PERFCTR_UCHE_SEL",
"counter": "RBBM_PERFCTR_UCHE",
"countable_type": "a7xx_uche_perfcounter_select"
},
{
"name": "TP",
"pipe": "BR",
"num": 12,
"select": "TPL1_PERFCTR_TP_SEL",
"counter": "RBBM_PERFCTR_TP",
"countable_type": "a7xx_tp_perfcounter_select"
},
{
"name": "SP",
"pipe": "BR",
"num": 24,
"select": "SP_PERFCTR_SP_SEL",
"counter": "RBBM_PERFCTR_SP",
"countable_type": "a7xx_sp_perfcounter_select"
},
{
"name": "RB",
"num": 8,
"select": "RB_PERFCTR_RB_SEL",
"counter": "RBBM_PERFCTR_RB",
"countable_type": "a7xx_rb_perfcounter_select"
},
{
"name": "VSC",
"num": 2,
"select": "VSC_PERFCTR_VSC_SEL",
"counter": "RBBM_PERFCTR_VSC",
"countable_type": "a7xx_vsc_perfcounter_select"
},
{
"name": "CCU",
"num": 5,
"select": "RB_PERFCTR_CCU_SEL",
"counter": "RBBM_PERFCTR_CCU",
"countable_type": "a7xx_ccu_perfcounter_select"
},
{
"name": "LRZ",
"pipe": "BR",
"num": 4,
"select": "GRAS_PERFCTR_LRZ_SEL",
"counter": "RBBM_PERFCTR_LRZ",
"countable_type": "a7xx_lrz_perfcounter_select"
},
{
"name": "CMP",
"num": 4,
"select": "RB_PERFCTR_CMP_SEL",
"counter": "RBBM_PERFCTR_CMP",
"countable_type": "a7xx_cmp_perfcounter_select"
},
{
"name": "UFC",
"pipe": "BR",
"num": 4,
"select": "RB_PERFCTR_UFC_SEL",
"counter": "RBBM_PERFCTR_UFC",
"countable_type": "a7xx_ufc_perfcounter_select"
},
{
"name": "BV_CP",
"num": 7,
"select": "CP_BV_PERFCTR_CP_SEL",
"counter": "RBBM_PERFCTR2_CP",
"countable_type": "a7xx_cp_perfcounter_select"
},
{
"name": "BV_PC",
"pipe": "BV",
"num": 8,
"select_offset": 8,
"select": "PC_PERFCTR_PC_SEL",
"counter": "RBBM_PERFCTR_BV_PC",
"countable_type": "a7xx_pc_perfcounter_select"
},
{
"name": "BV_VFD",
"pipe": "BV",
"num": 8,
"select_offset": 8,
"select": "VFD_PERFCTR_VFD_SEL",
"counter": "RBBM_PERFCTR_BV_VFD",
"countable_type": "a7xx_vfd_perfcounter_select"
},
{
"name": "BV_VPC",
"pipe": "BV",
"num": 6,
"select_offset": 6,
"select": "VPC_PERFCTR_VPC_SEL",
"counter": "RBBM_PERFCTR_BV_VPC",
"countable_type": "a7xx_vpc_perfcounter_select"
},
{
"name": "BV_TP",
"pipe": "BV",
"num": 6,
"select_offset": 12,
"select": "TPL1_PERFCTR_TP_SEL",
"counter": "RBBM_PERFCTR2_TP",
"countable_type": "a7xx_tp_perfcounter_select"
},
{
"name": "BV_SP",
"pipe": "BV",
"num": 12,
"select_offset": 24,
"select": "SP_PERFCTR_SP_SEL",
"counter": "RBBM_PERFCTR2_SP",
"countable_type": "a7xx_sp_perfcounter_select"
},
{
"name": "BV_UFC",
"pipe": "BV",
"num": 2,
"select_offset": 4,
"select": "RB_PERFCTR_UFC_SEL",
"counter": "RBBM_PERFCTR2_UFC",
"countable_type": "a7xx_ufc_perfcounter_select"
},
{
"name": "BV_TSE",
"pipe": "BV",
"num": 4,
"select": "GRAS_PERFCTR_TSE_SEL",
"counter": "RBBM_PERFCTR_BV_TSE",
"countable_type": "a7xx_tse_perfcounter_select"
},
{
"name": "BV_RAS",
"pipe": "BV",
"num": 4,
"select": "GRAS_PERFCTR_RAS_SEL",
"counter": "RBBM_PERFCTR_BV_RAS",
"countable_type": "a7xx_ras_perfcounter_select"
},
{
"name": "BV_LRZ",
"pipe": "BV",
"num": 4,
"select": "GRAS_PERFCTR_LRZ_SEL",
"counter": "RBBM_PERFCTR_BV_LRZ",
"countable_type": "a7xx_lrz_perfcounter_select"
},
{
"name": "BV_HLSQ",
"pipe": "BV",
"num": 6,
"select": "SP_PERFCTR_HLSQ_SEL",
"counter": "RBBM_PERFCTR2_HLSQ",
"countable_type": "a7xx_hlsq_perfcounter_select"
}
]
}

View File

@ -39,76 +39,92 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="3" name="3"/>
</domain>
<domain name="A8XX_TEX_MEMOBJ" width="32" varset="chip">
<domain name="A8XX_TEX_MEMOBJ" width="32" varset="desctype">
<doc>Texture memobj dwords</doc>
<reg32 offset="0" name="0">
<bitfield name="BASE_LO" low="6" high="31" shr="6"/>
<bitfield name="BASE_LO" low="6" high="31" shr="6" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<doc>for type TEX_BUFFER</doc>
<bitfield name="INSTANCE_DESC_BASE_LO" low="0" high="31" variants="DESC_BUFFER"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="BASE_HI" low="0" high="16"/>
<bitfield name="BASE_HI" low="0" high="16" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="INSTANCE_DESC_BASE_HI" low="0" high="16" variants="DESC_BUFFER"/>
<bitfield name="TYPE" low="17" high="19" type="a6xx_tex_type"/>
<bitfield name="DEPTH" low="20" high="31" type="uint"/>
<bitfield name="DEPTH" low="20" high="31" type="uint" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/>
<doc> for type TEX_BUFFER, probably for D3D structured UAVs, normally set to 1 </doc>
<bitfield name="STRUCTSIZETEXELS" low="20" high="31" type="uint" variants="DESC_BUFFER"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="WIDTH" low="0" high="14" type="uint"/>
<bitfield name="HEIGHT" low="15" high="29" type="uint"/>
<bitfield name="SAMPLES" low="30" high="31" type="a3xx_msaa_samples"/>
<bitfield name="WIDTH" low="0" high="14" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="HEIGHT" low="15" high="29" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="SAMPLES" low="30" high="31" type="a3xx_msaa_samples" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/>
<bitfield name="NUM_ELEMENTS" low="0" high="31" type="uint" variants="DESC_BUFFER"/>
</reg32>
<reg32 offset="3" name="3">
<bitfield name="FMT" low="0" high="7" type="a6xx_format"/>
<bitfield name="SWAP" low="8" high="9" type="a3xx_color_swap"/>
<bitfield name="SWIZ_X" low="10" high="12" type="a8xx_tex_swiz"/>
<bitfield name="SWIZ_Y" low="13" high="15" type="a8xx_tex_swiz"/>
<bitfield name="SWIZ_Z" low="16" high="18" type="a8xx_tex_swiz"/>
<bitfield name="SWIZ_W" low="19" high="21" type="a8xx_tex_swiz"/>
<bitfield name="SWIZ_X" low="10" high="12" type="a8xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
<bitfield name="SWIZ_Y" low="13" high="15" type="a8xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
<bitfield name="SWIZ_Z" low="16" high="18" type="a8xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
<bitfield name="SWIZ_W" low="19" high="21" type="a8xx_tex_swiz" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_BUFFER"/>
</reg32>
<reg32 offset="4" name="4">
<bitfield name="TILE_MODE" low="0" high="1" type="a6xx_tile_mode"/>
<bitfield name="FLAG" pos="2" type="boolean"/>
<bitfield name="PRT_EN" pos="3" type="boolean"/>
<bitfield name="TILE_ALL" pos="4" type="boolean"/>
<bitfield name="TILE_MODE" low="0" high="1" type="a6xx_tile_mode" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="FLAG" pos="2" type="boolean" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<bitfield name="PRT_EN" pos="3" type="boolean" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/>
<bitfield name="TILE_ALL" pos="4" type="boolean" variants="DESC_SINGLE_PLANE"/>
<bitfield name="SRGB" pos="5" type="boolean"/>
<bitfield name="FLAG_LO" low="6" high="31" shr="6"/>
<bitfield name="FLAG_LO" low="6" high="31" shr="6" variants="DESC_SINGLE_PLANE"/>
<!-- For multiplanar: -->
<bitfield name="BASE_U_LO" low="6" high="31" shr="6"/>
<bitfield name="BASE_U_LO" low="6" high="31" shr="6" variants="DESC_MULTI_PLANE"/>
</reg32>
<reg32 offset="5" name="5">
<bitfield name="FLAG_HI" low="0" high="16"/>
<bitfield name="FLAG_HI" low="0" high="16" variants="DESC_SINGLE_PLANE"/>
<!-- For multiplanar: -->
<bitfield name="BASE_U_HI" low="0" high="16"/>
<bitfield name="FLAG_BUFFER_PITCH" low="17" high="24" shr="6" type="uint"/>
<bitfield name="ALL_SAMPLES_CENTER" pos="29" type="boolean"/>
<bitfield name="MUTABLEEN" pos="31" type="boolean"/>
<bitfield name="BASE_U_HI" low="0" high="16" variants="DESC_MULTI_PLANE"/>
<bitfield name="FLAG_BUFFER_PITCH" low="17" high="24" shr="6" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE"/>
<bitfield name="ALL_SAMPLES_CENTER" pos="29" type="boolean" variants="DESC_SINGLE_PLANE"/>
<bitfield name="MUTABLEEN" pos="31" type="boolean" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/>
<!-- QCOM_image_filtering sample weights descriptor fields, overlapping the others. -->
<bitfield name="FILTER_SIZE_X" low="0" high="6" type="uint" variants="DESC_WEIGHT"/>
<bitfield name="FILTER_SIZE_Y" low="7" high="13" type="uint" variants="DESC_WEIGHT"/>
<bitfield name="FILTER_OFFSET_X" low="19" high="24" type="uint" variants="DESC_WEIGHT"/>
<bitfield name="FILTER_OFFSET_Y" low="25" high="30" type="uint" variants="DESC_WEIGHT"/>
</reg32>
<reg32 offset="6" name="6">
<bitfield name="TEX_LINE_OFFSET" low="0" high="23" type="uint"/> <!-- PITCH -->
<bitfield name="MIN_LINE_OFFSET" low="24" high="27" type="uint"/> <!-- PITCHALIGN -->
<bitfield name="MIPLVLS" low="28" high="31" type="uint"/>
<bitfield name="TEX_LINE_OFFSET" low="0" high="23" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/> <!-- PITCH -->
<bitfield name="MIN_LINE_OFFSET" low="24" high="27" type="uint" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/> <!-- PITCHALIGN -->
<bitfield name="MIPLVLS" low="28" high="31" type="uint" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/>
</reg32>
<reg32 offset="7" name="7">
<bitfield name="ARRAY_SLICE_OFFSET" low="0" high="22" shr="12" type="uint"/> <!-- ARRAY_PITCH -->
<bitfield name="ASO_UNIT" pos="23"/> <!-- 4KB or 32B ? -->
<bitfield name="MIN_ARRAY_SLIZE_OFFSET" low="24" high="27" shr="12"/> <!-- MIN_LAYERSZ -->
<bitfield name="GMEM_TILING_FALLBACK_EN" pos="28" type="boolean"/>
<bitfield name="CORNER_BASED_EN" pos="30" type="boolean"/>
<bitfield name="GMEM_FULL_SURF" pos="31" type="boolean"/>
<bitfield name="ARRAY_SLICE_OFFSET" low="0" high="22" shr="12" type="uint" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/> <!-- ARRAY_PITCH -->
<bitfield name="ASO_UNIT" pos="23" variants="DESC_SINGLE_PLANE DESC_WEIGHT"/> <!-- 4KB or 32B ? -->
<bitfield name="MIN_ARRAY_SLIZE_OFFSET" low="24" high="27" shr="12" variants="DESC_SINGLE_PLANE"/> <!-- MIN_LAYERSZ -->
<bitfield name="GMEM_TILING_FALLBACK_EN" pos="28" type="boolean" variants="DESC_SINGLE_PLANE"/>
<bitfield name="CORNER_BASED_EN" pos="30" type="boolean" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE"/>
<bitfield name="GMEM_FULL_SURF" pos="31" type="boolean" variants="DESC_SINGLE_PLANE DESC_MULTI_PLANE DESC_WEIGHT"/>
<!-- For multiplanar. This overlaps other single-planar fields: -->
<bitfield name="UV_OFFSET_H" low="24" high="25" type="ufixed" radix="2"/> <!-- CHROMA_MIDPOINT_X -->
<bitfield name="UV_OFFSET_V" low="26" high="27" type="ufixed" radix="2"/> <!-- CHROMA_MIDPOINT_Y -->
<bitfield name="UV_OFFSET_H" low="24" high="25" type="ufixed" radix="2" variants="DESC_MULTI_PLANE"/> <!-- CHROMA_MIDPOINT_X -->
<bitfield name="UV_OFFSET_V" low="26" high="27" type="ufixed" radix="2" variants="DESC_MULTI_PLANE"/> <!-- CHROMA_MIDPOINT_Y -->
<!-- QCOM_image_filtering sample weights descriptor fields, overlapping the others. -->
<bitfield name="DILATION" low="24" high="27" type="uint" variants="DESC_WEIGHT"/>
<bitfield name="LOG2_PHASES" low="28" high="30" type="uint" variants="DESC_WEIGHT"/>
</reg32>
<reg32 offset="8" name="8">
<bitfield name="FLAG_ARRAY_PITCH" low="0" high="14" shr="12" type="uint"/> <!-- FLAG_BUFFER_ARRAY_PITCH -->
<bitfield name="FLAG_ARRAY_PITCH" low="0" high="14" shr="12" type="uint" variants="DESC_SINGLE_PLANE"/> <!-- FLAG_BUFFER_ARRAY_PITCH -->
<!-- log2 size of the first level, required for mipmapping -->
<bitfield name="FLAG_BUFFER_LOGW" low="24" high="27" type="uint"/>
<bitfield name="FLAG_BUFFER_LOGH" low="28" high="31" type="uint"/>
<bitfield name="FLAG_BUFFER_LOGW" low="24" high="27" type="uint" variants="DESC_SINGLE_PLANE"/>
<bitfield name="FLAG_BUFFER_LOGH" low="28" high="31" type="uint" variants="DESC_SINGLE_PLANE"/>
<!-- For multiplanar. This overlaps other single-planar fields: -->
<bitfield name="BASE_V_LO" low="6" high="31" shr="6"/>
<bitfield name="BASE_V_LO" low="6" high="31" shr="6" variants="DESC_MULTI_PLANE"/>
</reg32>
<reg32 offset="9" name="9">
<bitfield name="MIN_LOD_CLAMP" low="19" high="30" type="ufixed" radix="8"/>
<bitfield name="MIN_LOD_CLAMP" low="19" high="30" type="ufixed" radix="8" variants="DESC_SINGLE_PLANE"/>
<!-- For multiplanar, this overlaps other fields: -->
<bitfield name="BASE_V_HI" low="0" high="16"/>
<bitfield name="UV_PITCH" low="17" high="26"/> <!-- PLANE_PITCH -->
<bitfield name="BASE_V_HI" low="0" high="16" variants="DESC_MULTI_PLANE"/>
<bitfield name="UV_PITCH" shr="6" low="17" high="26" variants="DESC_MULTI_PLANE"/> <!-- PLANE_PITCH -->
</reg32>
<reg32 offset="10" name="10"/>
<reg32 offset="11" name="11"/>

View File

@ -0,0 +1,241 @@
{
"chip": "A8XX",
"groups": [
{
"name": "CP",
"num": 14,
"reserved": [ 0 ],
"select": "CP_PERFCTR_CP_SEL",
"counter": "RBBM_PERFCTR_CP",
"countable_type": "a8xx_cp_perfcounter_select"
},
{
"name": "RBBM",
"num": 4,
"select": "RBBM_PERFCTR_RBBM_SEL",
"slice_select": [ "RBBM_SLICE_PERFCTR_RBBM_SEL" ],
"counter": "RBBM_PERFCTR_RBBM",
"countable_type": "a8xx_rbbm_perfcounter_select"
},
{
"name": "PC",
"pipe": "BR",
"num": 8,
"select": "PC_PERFCTR_PC_SEL",
"slice_select": [ "PC_SLICE_PERFCTR_PC_SEL" ],
"counter": "RBBM_PERFCTR_PC",
"countable_type": "a8xx_pc_perfcounter_select"
},
{
"name": "VFD",
"pipe": "BR",
"num": 8,
"select": "VFD_PERFCTR_VFD_SEL",
"counter": "RBBM_PERFCTR_VFD",
"countable_type": "a8xx_vfd_perfcounter_select"
},
{
"name": "HLSQ",
"pipe": "BR",
"num": 6,
"select": "SP_PERFCTR_HLSQ_SEL",
"slice_select": [ "SP_PERFCTR_HLSQ_SEL_2" ],
"counter": "RBBM_PERFCTR_HLSQ",
"countable_type": "a8xx_hlsq_perfcounter_select"
},
{
"name": "VPC",
"pipe": "BR",
"num": 6,
"select": "VPC_PERFCTR_VPC_SEL",
"slice_select": [ "VPC_PERFCTR_VPC_SEL_1", "VPC_PERFCTR_VPC_SEL_2" ],
"counter": "RBBM_PERFCTR_VPC",
"countable_type": "a8xx_vpc_perfcounter_select"
},
{
"name": "TSE",
"pipe": "BR",
"num": 4,
"select": "GRAS_PERFCTR_TSE_SEL",
"slice_select": [ "GRAS_PERFCTR_TSEFE_SEL" ],
"counter": "RBBM_PERFCTR_TSE",
"countable_type": "a8xx_tse_perfcounter_select"
},
{
"name": "RAS",
"pipe": "BR",
"num": 4,
"select": "GRAS_PERFCTR_RAS_SEL",
"counter": "RBBM_PERFCTR_RAS",
"countable_type": "a8xx_ras_perfcounter_select"
},
{
"name": "UCHE",
"num": 24,
"select": "UCHE_PERFCTR_UCHE_SEL",
"counter": "RBBM_PERFCTR_UCHE",
"countable_type": "a8xx_uche_perfcounter_select"
},
{
"name": "TP",
"pipe": "BR",
"num": 12,
"select": "TPL1_PERFCTR_TP_SEL",
"counter": "RBBM_PERFCTR_TP",
"countable_type": "a8xx_tp_perfcounter_select"
},
{
"name": "SP",
"pipe": "BR",
"num": 24,
"select": "SP_PERFCTR_SP_SEL",
"counter": "RBBM_PERFCTR_SP",
"countable_type": "a8xx_sp_perfcounter_select"
},
{
"name": "RB",
"pipe": "BR",
"num": 8,
"select": "RB_PERFCTR_RB_SEL",
"counter": "RBBM_PERFCTR_RB",
"countable_type": "a8xx_rb_perfcounter_select"
},
{
"name": "VSC",
"num": 2,
"select": "VSC_PERFCTR_VSC_SEL",
"counter": "RBBM_PERFCTR_VSC",
"countable_type": "a8xx_vsc_perfcounter_select"
},
{
"name": "CCU",
"pipe": "BR",
"num": 5,
"select": "RB_PERFCTR_CCU_SEL",
"counter": "RBBM_PERFCTR_CCU",
"countable_type": "a8xx_ccu_perfcounter_select"
},
{
"name": "LRZ",
"pipe": "BR",
"num": 4,
"select": "GRAS_PERFCTR_LRZ_SEL",
"counter": "RBBM_PERFCTR_LRZ",
"countable_type": "a8xx_lrz_perfcounter_select"
},
{
"name": "CMP",
"pipe": "BR",
"num": 4,
"select": "RB_PERFCTR_CMP_SEL",
"counter": "RBBM_PERFCTR_CMP",
"countable_type": "a8xx_cmp_perfcounter_select"
},
{
"name": "UFC",
"pipe": "BR",
"num": 4,
"select": "RB_PERFCTR_UFC_SEL",
"counter": "RBBM_PERFCTR_UFC",
"countable_type": "a8xx_ufc_perfcounter_select"
},
{
"name": "BV_CP",
"num": 7,
"select_offset": 14,
"select": "CP_PERFCTR_CP_SEL",
"counter": "RBBM_PERFCTR2_CP",
"countable_type": "a8xx_cp_perfcounter_select"
},
{
"name": "BV_PC",
"pipe": "BV",
"num": 8,
"select_offset": 8,
"select": "PC_PERFCTR_PC_SEL",
"slice_select": [ "PC_SLICE_PERFCTR_PC_SEL" ],
"counter": "RBBM_PERFCTR_BV_PC",
"countable_type": "a8xx_pc_perfcounter_select"
},
{
"name": "BV_VFD",
"pipe": "BV",
"num": 8,
"select_offset": 8,
"select": "VFD_PERFCTR_VFD_SEL",
"counter": "RBBM_PERFCTR_BV_VFD",
"countable_type": "a8xx_vfd_perfcounter_select"
},
{
"name": "BV_VPC",
"pipe": "BV",
"num": 6,
"select_offset": 6,
"select": "VPC_PERFCTR_VPC_SEL",
"slice_select": [ "VPC_PERFCTR_VPC_SEL_1", "VPC_PERFCTR_VPC_SEL_2" ],
"counter": "RBBM_PERFCTR_BV_VPC",
"countable_type": "a8xx_vpc_perfcounter_select"
},
{
"name": "BV_TP",
"pipe": "BV",
"num": 8,
"select_offset": 12,
"select": "TPL1_PERFCTR_TP_SEL",
"counter": "RBBM_PERFCTR2_TP",
"countable_type": "a8xx_tp_perfcounter_select"
},
{
"name": "BV_SP",
"pipe": "BV",
"num": 12,
"select_offset": 24,
"select": "SP_PERFCTR_SP_SEL",
"counter": "RBBM_PERFCTR2_SP",
"countable_type": "a8xx_sp_perfcounter_select"
},
{
"name": "BV_UFC",
"pipe": "BV",
"num": 2,
"select_offset": 4,
"select": "RB_PERFCTR_UFC_SEL",
"counter": "RBBM_PERFCTR2_UFC",
"countable_type": "a8xx_ufc_perfcounter_select"
},
{
"name": "BV_TSE",
"pipe": "BV",
"num": 4,
"select": "GRAS_PERFCTR_TSE_SEL",
"slice_select": [ "GRAS_PERFCTR_TSEFE_SEL" ],
"counter": "RBBM_PERFCTR_BV_TSE",
"countable_type": "a8xx_tse_perfcounter_select"
},
{
"name": "BV_RAS",
"pipe": "BV",
"num": 4,
"select": "GRAS_PERFCTR_RAS_SEL",
"counter": "RBBM_PERFCTR_BV_RAS",
"countable_type": "a8xx_ras_perfcounter_select"
},
{
"name": "BV_LRZ",
"pipe": "BV",
"num": 4,
"select": "GRAS_PERFCTR_LRZ_SEL",
"counter": "RBBM_PERFCTR_BV_LRZ",
"countable_type": "a8xx_lrz_perfcounter_select"
},
{
"name": "BV_HLSQ",
"pipe": "BV",
"num": 6,
"select": "SP_PERFCTR_HLSQ_SEL",
"slice_select": [ "SP_PERFCTR_HLSQ_SEL_2" ],
"counter": "RBBM_PERFCTR2_HLSQ",
"countable_type": "a8xx_hlsq_perfcounter_select"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,27 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<value name="A8XX" value="8"/>
</enum>
<enum name="desctype" bare="yes">
<value name="DESC_NONE" value="0"/>
<doc>
TEX_MEMOBJ descriptor types. These are used
to mark fields that only apply to certain
descriptor types, and potentially overlap
with fields in other types.
</doc>
<value name="DESC_SINGLE_PLANE" value="1"/>
<value name="DESC_MULTI_PLANE" value="2"/>
<value name="DESC_BUFFER" value="3"/>
<value name="DESC_WEIGHT" value="4"/>
<doc>
Additional descriptor types not part of
TEX_MEMOBJ. These are described by their
own toplevel domain.
</doc>
<value name="DESC_SAMPLER" value="10"/> <!-- AxXX_UBO -->
<value name="DESC_UBO" value="11"/> <!-- A6XX_UBO, same on gen8 -->
</enum>
<enum name="adreno_pa_su_sc_draw">
<value name="PC_DRAW_POINTS" value="0"/>
<value name="PC_DRAW_LINES" value="1"/>
@ -409,4 +430,25 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<value value="7" name="PIPE_DDE_BV"/>
</enum>
<!--
A fake domain for giving lua scripts access to the shader_stats struct
-->
<domain name="ir3_shader_stats" width="32">
<!-- indx 0 is bindful, indx N+1 is .baseN -->
<array offset="0" name="descriptor_stats" stride="8" length="9">
<reg64 offset="0" name="img"/>
<reg64 offset="2" name="tex"/>
<reg64 offset="4" name="samp"/>
<reg64 offset="6" name="ubo"/>
</array>
<reg32 offset="72" name="has_img"/>
<reg32 offset="73" name="has_tex"/>
<reg32 offset="74" name="has_samp"/>
<reg32 offset="74" name="has_ubo"/>
<!--
other following fields can be added as needed, but we
might need to take care of padding/alignment.
-->
</domain>
</database>

View File

@ -152,6 +152,8 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<!-- TODO: deal with name conflicts with other gens -->
<value name="CACHE_FLUSH7" value="0x32" variants="A7XX-"/>
<value name="CACHE_INVALIDATE7" value="0x33" variants="A7XX-"/>
<value name="SUBPASS_FENCE" value="0x35" variants="A7XX-"/>
<value name="SUBPASS_SLICE_FENCE" value="0x36" variants="A8XX-"/>
<value name="DEPTH_BUFFER_FLIP" value="0x3d" variants="A8XX-"/>
<value name="CCH_FAST_CLEAR_CLEAN" value="0x1b" variants="A8XX-"/>
</enum>
@ -1095,7 +1097,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<bitfield name="DIRTY" pos="16" type="boolean"/>
<bitfield name="DISABLE" pos="17" type="boolean"/>
<bitfield name="DISABLE_ALL_GROUPS" pos="18" type="boolean"/>
<bitfield name="LOAD_IMMED" pos="19" type="boolean"/>
<bitfield name="LOAD_IMMED" pos="19" type="boolean" variants="A5XX"/>
<bitfield name="BINNING" pos="20" varset="chip" variants="A6XX-" type="boolean"/>
<bitfield name="GMEM" pos="21" varset="chip" variants="A6XX-" type="boolean"/>
<bitfield name="SYSMEM" pos="22" varset="chip" variants="A6XX-" type="boolean"/>
@ -1275,8 +1277,15 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<domain name="CP_REG_TO_MEM" width="32" prefix="chip">
<reg32 offset="0" name="0">
<bitfield name="REG" low="0" high="17" type="hex"/>
<!-- number of registers/dwords copied is max(CNT, 1). -->
<!--
Number of registers/dwords copied is max(CNT, 1).
With 64B it gets rounded to the next 64B boundary.
-->
<bitfield name="CNT" low="18" high="29" type="uint"/>
<!--
Treat things as 64B, allowing for a 64B atomic read of
registers.
-->
<bitfield name="64B" pos="30" type="boolean"/>
<bitfield name="ACCUMULATE" pos="31" type="boolean"/>
</reg32>
@ -1469,6 +1478,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<value value="1" name="POLL_MEMORY"/>
<value value="2" name="POLL_SCRATCH"/>
<value value="3" name="POLL_ON_CHIP" varset="chip" variants="A7XX-"/>
<value value="4" name="POLL_SYSTEM_VARIABLE" varset="chip" variants="A8XX-"/>
</enum>
<domain name="CP_COND_WRITE5" width="32">
@ -1476,7 +1486,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<bitfield name="FUNCTION" low="0" high="2" type="cp_cond_function"/>
<bitfield name="SIGNED_COMPARE" pos="3" type="boolean"/>
<!-- POLL_REGISTER polls a register at POLL_ADDR_LO. -->
<bitfield name="POLL" low="4" high="5" type="poll_memory_type"/>
<bitfield name="POLL" low="4" high="6" type="poll_memory_type"/>
<bitfield name="WRITE_MEMORY" pos="8" type="boolean"/>
</reg32>
<reg64 offset="1" name="POLL_ADDR" type="address"/>
@ -2055,28 +2065,20 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<domain name="CP_COND_EXEC" width="32">
<doc>
Executes the following DWORDs of commands if the dword at ADDR0
is not equal to 0 and the dword at ADDR1 is less than REF
(signed comparison).
Executes the following DWORDs of commands if the dword
at BOOL_ADDR is not equal to 0 and the the timestamp
value ACTIVE_TIMESTAMP is ahead of the value fetched
from TIMESTAMP_ADDR.
The timestamp comparision is an unsigned compare with
wraparound, ie:
(ACTIVE_TIMESTAMP - *TIMESTAMP_ADDR) &lt; 0x80000000
</doc>
<reg32 offset="0" name="0">
<bitfield name="ADDR0_LO" low="0" high="31"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="ADDR0_HI" low="0" high="31"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="ADDR1_LO" low="0" high="31"/>
</reg32>
<reg32 offset="3" name="3">
<bitfield name="ADDR1_HI" low="0" high="31"/>
</reg32>
<reg32 offset="4" name="4">
<bitfield name="REF" low="0" high="31"/>
</reg32>
<reg32 offset="5" name="5">
<bitfield name="DWORDS" low="0" high="31" type="uint"/>
</reg32>
<reg64 offset="0" name="BOOL_ADDR" type="address"/>
<reg64 offset="2" name="TIMESTAMP_ADDR" type="address"/>
<reg32 offset="4" name="ACTIVE_TIMESTAMP"/>
<reg32 offset="5" name="DWORDS"/>
</domain>
<domain name="CP_SET_AMBLE" width="32">

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,7 @@ struct qcom_ubwc_cfg_data {
#define UBWC_1_0 0x10000000
#define UBWC_2_0 0x20000000
#define UBWC_3_0 0x30000000
#define UBWC_3_1 0x30010000 /* UBWC 3.0 + Macrotile mode */
#define UBWC_4_0 0x40000000
#define UBWC_4_3 0x40030000
#define UBWC_5_0 0x50000000
@ -99,4 +100,25 @@ static inline u32 qcom_ubwc_swizzle(const struct qcom_ubwc_cfg_data *cfg)
return cfg->ubwc_swizzle;
}
static inline u32 qcom_ubwc_version_tag(const struct qcom_ubwc_cfg_data *cfg)
{
if (cfg->ubwc_enc_version >= UBWC_6_0)
return 5;
if (cfg->ubwc_enc_version >= UBWC_5_0)
return 4;
if (cfg->ubwc_enc_version >= UBWC_4_3)
return 3;
if (cfg->ubwc_enc_version >= UBWC_4_0)
return 2;
if (cfg->ubwc_enc_version >= UBWC_3_0)
return 1;
return 0;
}
static inline bool qcom_ubwc_enable_amsbc(const struct qcom_ubwc_cfg_data *cfg)
{
return cfg->ubwc_enc_version >= UBWC_3_0;
}
#endif /* __QCOM_UBWC_H__ */

View File

@ -491,6 +491,52 @@ struct drm_msm_submitqueue_query {
__u32 pad;
};
#define MSM_PERFCNTR_STREAM 0x00000001
#define MSM_PERFCNTR_UPDATE 0x00000002
#define MSM_PERFCNTR_FLAGS ( \
MSM_PERFCNTR_STREAM | \
MSM_PERFCNTR_UPDATE | \
0)
struct drm_msm_perfcntr_group {
char group_name[16];
__u32 nr_countables;
__u32 pad; /* mbz */
__u64 countables; /* pointer to an array of nr_countables u32 */
};
/*
* Note, for MSM_PERFCNTR_STREAM, the ioctl returns an fd to read recorded
* counters. This only works because the ioctl is DRM_IOW(), if we returned
* a out param in the ioctl struct the copy_to_user() (in drm_ioctl())
* could fault, causing us to leak the fd.
*
* If the ioctl returns with error E2BIG, that means more counters/countables
* are requested than are currently available. If MSM_PERFCNTR_UPDATE flag
* is set, drm_msm_perfcntr_group::nr_countables will be updated to return
* the actual # of counters available.
*
* The data read from the has the following format for each sampling period:
*
* uint64_t timestamp; // CP_ALWAYS_ON_COUNTER captured at sample time
* uint32_t seqno; // increments by 1 each period, reset to 0 on discontinuity
* uint32_t mbz; // pad out counters to 64b
* struct {
* uint64_t counter[nr_countables];
* } groups[nr_groups];
*
* The ordering of groups and counters matches the order in PERFCNTR_CONFIG
* ioctl.
*/
struct drm_msm_perfcntr_config {
__u32 flags; /* bitmask of MSM_PERFCNTR_x */
__u32 nr_groups; /* # of entries in groups array */
__u64 groups; /* pointer to array of drm_msm_perfcntr_group */
__u64 period; /* sampling period in ns */
__u32 bufsz_shift; /* sample buffer size in bytes is 1<<bufsz_shift */
__u32 group_stride; /* sizeof(struct drm_msm_perfcntr_group) */
};
#define DRM_MSM_GET_PARAM 0x00
#define DRM_MSM_SET_PARAM 0x01
#define DRM_MSM_GEM_NEW 0x02
@ -507,6 +553,7 @@ struct drm_msm_submitqueue_query {
#define DRM_MSM_SUBMITQUEUE_CLOSE 0x0B
#define DRM_MSM_SUBMITQUEUE_QUERY 0x0C
#define DRM_MSM_VM_BIND 0x0D
#define DRM_MSM_PERFCNTR_CONFIG 0x0E
#define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
#define DRM_IOCTL_MSM_SET_PARAM DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SET_PARAM, struct drm_msm_param)
@ -521,6 +568,7 @@ struct drm_msm_submitqueue_query {
#define DRM_IOCTL_MSM_SUBMITQUEUE_CLOSE DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_CLOSE, __u32)
#define DRM_IOCTL_MSM_SUBMITQUEUE_QUERY DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_QUERY, struct drm_msm_submitqueue_query)
#define DRM_IOCTL_MSM_VM_BIND DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_VM_BIND, struct drm_msm_vm_bind)
#define DRM_IOCTL_MSM_PERFCNTR_CONFIG DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_PERFCNTR_CONFIG, struct drm_msm_perfcntr_config)
#if defined(__cplusplus)
}