Merge tag 'drm-msm-next-2025-09-12' of https://gitlab.freedesktop.org/drm/msm into drm-next

Changes for v6.18

GPU and Core:
- in DT bindings describe clocks per GPU type
- GMU bandwidth voting for x1-85
- a663 speedbins
- a623 speedbins
- cleanup some remaining no-iommu leftovers after VM_BIND conversion
- fix GEM obj 32b size truncation
- add missing VM_BIND param validation
- various fixes
- IFPC for x1-85 and a750
- register xml and gen_header.py sync from mesa

Display:
- add missing bindings for display on SC8180X
- added DisplayPort MST bindings
- conversion from round_rate() to determine_rate()
- DSI PHY fixes, correcting programming glitches
- misc small fixes

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Rob Clark <rob.clark@oss.qualcomm.com>
Link: https://lore.kernel.org/r/CACSVV01FgXN+fD6U1Hi6Tj4WCf=V-+NO8BXi+80iS4qOZwpaGg@mail.gmail.com
This commit is contained in:
Dave Airlie 2025-09-16 10:21:37 +10:00
commit 8299ee7ff7
67 changed files with 2347 additions and 953 deletions

View file

@ -29,15 +29,30 @@ properties:
- qcom,sdm845-dp
- qcom,sm8350-dp
- qcom,sm8650-dp
- qcom,x1e80100-dp
- items:
- enum:
- qcom,sm6350-dp
- const: qcom,sc7180-dp
# deprecated entry for compatibility with old DT
- items:
- enum:
- qcom,sm6350-dp
- const: qcom,sm8350-dp
deprecated: true
- items:
- enum:
- qcom,sar2130p-dp
- qcom,sm6350-dp
- qcom,sm7150-dp
- qcom,sm8150-dp
- qcom,sm8250-dp
- qcom,sm8450-dp
- qcom,sm8550-dp
- const: qcom,sm8350-dp
- items:
- enum:
- qcom,sm8750-dp
@ -51,35 +66,37 @@ properties:
- description: link register block
- description: p0 register block
- description: p1 register block
- description: p2 register block
- description: p3 register block
- description: mst2link register block
- description: mst3link register block
interrupts:
maxItems: 1
clocks:
minItems: 5
items:
- description: AHB clock to enable register access
- description: Display Port AUX clock
- description: Display Port Link clock
- description: Link interface clock between DP and PHY
- description: Display Port Pixel clock
- description: Display Port stream 0 Pixel clock
- description: Display Port stream 1 Pixel clock
- description: Display Port stream 2 Pixel clock
- description: Display Port stream 3 Pixel clock
clock-names:
minItems: 5
items:
- const: core_iface
- const: core_aux
- const: ctrl_link
- const: ctrl_link_iface
- const: stream_pixel
assigned-clocks:
items:
- description: link clock source
- description: pixel clock source
assigned-clock-parents:
items:
- description: phy 0 parent
- description: phy 1 parent
- const: stream_1_pixel
- const: stream_2_pixel
- const: stream_3_pixel
phys:
maxItems: 1
@ -161,7 +178,6 @@ required:
allOf:
# AUX BUS does not exist on DP controllers
# Audio output also is present only on DP output
# p1 regions is present on DP, but not on eDP
- if:
properties:
compatible:
@ -174,12 +190,110 @@ allOf:
properties:
"#sound-dai-cells": false
else:
if:
properties:
compatible:
contains:
enum:
- qcom,sa8775p-dp
- qcom,x1e80100-dp
then:
oneOf:
- required:
- aux-bus
- required:
- "#sound-dai-cells"
else:
properties:
aux-bus: false
required:
- "#sound-dai-cells"
- if:
properties:
compatible:
contains:
enum:
# these platforms support SST only
- qcom,sc7180-dp
- qcom,sc7280-dp
- qcom,sc7280-edp
- qcom,sc8180x-edp
- qcom,sc8280xp-edp
then:
properties:
aux-bus: false
reg:
minItems: 5
required:
- "#sound-dai-cells"
maxItems: 5
clocks:
minItems: 5
maxItems: 5
clocks-names:
minItems: 5
maxItems: 5
- if:
properties:
compatible:
contains:
enum:
# these platforms support 2 streams MST on some interfaces,
# others are SST only
- qcom,sc8280xp-dp
- qcom,x1e80100-dp
then:
properties:
reg:
minItems: 5
maxItems: 5
clocks:
minItems: 5
maxItems: 6
clocks-names:
minItems: 5
maxItems: 6
- if:
properties:
compatible:
contains:
# 2 streams MST
enum:
- qcom,sc8180x-dp
- qcom,sdm845-dp
- qcom,sm8350-dp
- qcom,sm8650-dp
then:
properties:
reg:
minItems: 5
maxItems: 5
clocks:
minItems: 6
maxItems: 6
clocks-names:
minItems: 6
maxItems: 6
- if:
properties:
compatible:
contains:
enum:
# these platforms support 4 stream MST on first DP,
# 2 streams MST on the second one.
- qcom,sa8775p-dp
then:
properties:
reg:
minItems: 9
maxItems: 9
clocks:
minItems: 6
maxItems: 8
clocks-names:
minItems: 6
maxItems: 8
additionalProperties: false

View file

@ -27,6 +27,7 @@ properties:
- qcom,sar2130p-dsi-ctrl
- qcom,sc7180-dsi-ctrl
- qcom,sc7280-dsi-ctrl
- qcom,sc8180x-dsi-ctrl
- qcom,sdm660-dsi-ctrl
- qcom,sdm670-dsi-ctrl
- qcom,sdm845-dsi-ctrl
@ -332,6 +333,7 @@ allOf:
- qcom,sar2130p-dsi-ctrl
- qcom,sc7180-dsi-ctrl
- qcom,sc7280-dsi-ctrl
- qcom,sc8180x-dsi-ctrl
- qcom,sdm845-dsi-ctrl
- qcom,sm6115-dsi-ctrl
- qcom,sm6125-dsi-ctrl

View file

@ -124,6 +124,40 @@ allOf:
contains:
enum:
- qcom,adreno-gmu-623.0
then:
properties:
reg:
items:
- description: Core GMU registers
- description: Resource controller registers
- description: GMU PDC registers
reg-names:
items:
- const: gmu
- const: rscc
- const: gmu_pdc
clocks:
items:
- description: GMU clock
- description: GPU CX clock
- description: GPU AXI clock
- description: GPU MEMNOC clock
- description: GPU AHB clock
- description: GPU HUB CX clock
clock-names:
items:
- const: gmu
- const: cxo
- const: axi
- const: memnoc
- const: ahb
- const: hub
- if:
properties:
compatible:
contains:
enum:
- qcom,adreno-gmu-635.0
- qcom,adreno-gmu-660.1
- qcom,adreno-gmu-663.0

View file

@ -146,39 +146,209 @@ allOf:
properties:
compatible:
contains:
pattern: '^qcom,adreno-[3-5][0-9][0-9]\.[0-9]+$'
oneOf:
- pattern: '^qcom,adreno-305\.[0-9]+$'
- pattern: '^qcom,adreno-330\.[0-9]+$'
then:
properties:
clocks:
minItems: 2
maxItems: 7
minItems: 3
maxItems: 3
clock-names:
items:
anyOf:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem
description: GPU Memory clock
- const: mem_iface
description: GPU Memory Interface clock
- const: alt_mem_iface
description: GPU Alternative Memory Interface clock
- const: gfx3d
description: GPU 3D engine clock
- const: rbbmtimer
description: GPU RBBM Timer for Adreno 5xx series
- const: rbcpr
description: GPU RB Core Power Reduction clock
minItems: 2
maxItems: 7
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem_iface
description: GPU Memory Interface clock
required:
- clocks
- clock-names
- if:
properties:
compatible:
contains:
pattern: '^qcom,adreno-306\.[0-9]+$'
then:
properties:
clocks:
minItems: 5
maxItems: 6
clock-names:
oneOf:
- items:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem_iface
description: GPU Memory Interface clock
- const: alt_mem_iface
description: GPU Alternative Memory Interface clock
- const: gfx3d
description: GPU 3D engine clock
- items:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem
description: GPU Memory clock
- const: mem_iface
description: GPU Memory Interface clock
- const: alt_mem_iface
description: GPU Alternative Memory Interface clock
- const: gfx3d
description: GPU 3D engine clock
- if:
properties:
compatible:
contains:
pattern: '^qcom,adreno-320\.[0-9]+$'
then:
properties:
clocks:
minItems: 4
maxItems: 4
clock-names:
items:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem
description: GPU Memory clock
- const: mem_iface
description: GPU Memory Interface clock
- if:
properties:
compatible:
contains:
pattern: '^qcom,adreno-405\.[0-9]+$'
then:
properties:
clocks:
minItems: 7
maxItems: 7
clock-names:
items:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem
description: GPU Memory clock
- const: mem_iface
description: GPU Memory Interface clock
- const: alt_mem_iface
description: GPU Alternative Memory Interface clock
- const: gfx3d
description: GPU 3D engine clock
- const: rbbmtimer
description: GPU RBBM Timer for Adreno 5xx series
- if:
properties:
compatible:
contains:
pattern: '^qcom,adreno-50[56]\.[0-9]+$'
then:
properties:
clocks:
minItems: 6
maxItems: 6
clock-names:
items:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem_iface
description: GPU Memory Interface clock
- const: alt_mem_iface
description: GPU Alternative Memory Interface clock
- const: rbbmtimer
description: GPU RBBM Timer for Adreno 5xx series
- const: alwayson
description: GPU AON clock
- if:
properties:
compatible:
contains:
oneOf:
- pattern: '^qcom,adreno-508\.[0-9]+$'
- pattern: '^qcom,adreno-509\.[0-9]+$'
- pattern: '^qcom,adreno-512\.[0-9]+$'
- pattern: '^qcom,adreno-540\.[0-9]+$'
then:
properties:
clocks:
minItems: 6
maxItems: 6
clock-names:
items:
- const: iface
description: GPU Interface clock
- const: rbbmtimer
description: GPU RBBM Timer for Adreno 5xx series
- const: mem
description: GPU Memory clock
- const: mem_iface
description: GPU Memory Interface clock
- const: rbcpr
description: GPU RB Core Power Reduction clock
- const: core
description: GPU Core clock
- if:
properties:
compatible:
contains:
pattern: '^qcom,adreno-510\.[0-9]+$'
then:
properties:
clocks:
minItems: 6
maxItems: 6
clock-names:
items:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: mem
description: GPU Memory clock
- const: mem_iface
description: GPU Memory Interface clock
- const: rbbmtimer
description: GPU RBBM Timer for Adreno 5xx series
- const: alwayson
description: GPU AON clock
- if:
properties:
compatible:
contains:
pattern: '^qcom,adreno-530\.[0-9]+$'
then:
properties:
clocks:
minItems: 5
maxItems: 5
clock-names:
items:
- const: core
description: GPU Core clock
- const: iface
description: GPU Interface clock
- const: rbbmtimer
description: GPU RBBM Timer for Adreno 5xx series
- const: mem
description: GPU Memory clock
- const: mem_iface
description: GPU Memory Interface clock
- if:
properties:
@ -187,6 +357,7 @@ allOf:
enum:
- qcom,adreno-610.0
- qcom,adreno-619.1
- qcom,adreno-07000200
then:
properties:
clocks:
@ -222,7 +393,9 @@ allOf:
properties:
compatible:
contains:
pattern: '^qcom,adreno-[67][0-9][0-9]\.[0-9]+$'
oneOf:
- pattern: '^qcom,adreno-[67][0-9][0-9]\.[0-9]+$'
- pattern: '^qcom,adreno-[0-9a-f]{8}$'
then: # Starting with A6xx, the clocks are usually defined in the GMU node
properties:

View file

@ -375,7 +375,11 @@ examples:
<0xaf54200 0x0c0>,
<0xaf55000 0x770>,
<0xaf56000 0x09c>,
<0xaf57000 0x09c>;
<0xaf57000 0x09c>,
<0xaf58000 0x09c>,
<0xaf59000 0x09c>,
<0xaf5a000 0x23c>,
<0xaf5b000 0x23c>;
interrupt-parent = <&mdss0>;
interrupts = <12>;
@ -384,16 +388,28 @@ examples:
<&dispcc_dptx0_aux_clk>,
<&dispcc_dptx0_link_clk>,
<&dispcc_dptx0_link_intf_clk>,
<&dispcc_dptx0_pixel0_clk>;
<&dispcc_dptx0_pixel0_clk>,
<&dispcc_dptx0_pixel1_clk>,
<&dispcc_dptx0_pixel2_clk>,
<&dispcc_dptx0_pixel3_clk>;
clock-names = "core_iface",
"core_aux",
"ctrl_link",
"ctrl_link_iface",
"stream_pixel";
"stream_pixel",
"stream_1_pixel",
"stream_2_pixel",
"stream_3_pixel";
assigned-clocks = <&dispcc_mdss_dptx0_link_clk_src>,
<&dispcc_mdss_dptx0_pixel0_clk_src>;
assigned-clock-parents = <&mdss0_dp0_phy 0>, <&mdss0_dp0_phy 1>;
<&dispcc_mdss_dptx0_pixel0_clk_src>,
<&dispcc_mdss_dptx0_pixel1_clk_src>,
<&dispcc_mdss_dptx0_pixel2_clk_src>,
<&dispcc_mdss_dptx0_pixel3_clk_src>;
assigned-clock-parents = <&mdss0_dp0_phy 0>,
<&mdss0_dp0_phy 1>,
<&mdss0_dp0_phy 1>,
<&mdss0_dp0_phy 1>;
phys = <&mdss0_dp0_phy>;
phy-names = "dp";

View file

@ -207,16 +207,20 @@ examples:
<&dispcc_disp_cc_mdss_dptx0_aux_clk>,
<&dispcc_disp_cc_mdss_dptx0_link_clk>,
<&dispcc_disp_cc_mdss_dptx0_link_intf_clk>,
<&dispcc_disp_cc_mdss_dptx0_pixel0_clk>;
<&dispcc_disp_cc_mdss_dptx0_pixel0_clk>,
<&dispcc_disp_cc_mdss_dptx0_pixel1_clk>;
clock-names = "core_iface",
"core_aux",
"ctrl_link",
"ctrl_link_iface",
"stream_pixel";
"stream_pixel",
"stream_1_pixel";
assigned-clocks = <&dispcc_disp_cc_mdss_dptx0_link_clk_src>,
<&dispcc_disp_cc_mdss_dptx0_pixel0_clk_src>;
<&dispcc_disp_cc_mdss_dptx0_pixel0_clk_src>,
<&dispcc_disp_cc_mdss_dptx0_pixel1_clk_src>;
assigned-clock-parents = <&usb_dp_qmpphy_QMP_USB43DP_DP_LINK_CLK>,
<&usb_dp_qmpphy_QMP_USB43DP_DP_VCO_DIV_CLK>,
<&usb_dp_qmpphy_QMP_USB43DP_DP_VCO_DIV_CLK>;
phys = <&usb_dp_qmpphy QMP_USB43DP_DP_PHY>;

View file

@ -281,7 +281,8 @@ examples:
reg = <0xaea0000 0x200>,
<0xaea0200 0x200>,
<0xaea0400 0xc00>,
<0xaea1000 0x400>;
<0xaea1000 0x400>,
<0xaea1400 0x400>;
interrupt-parent = <&mdss>;
interrupts = <14>;

View file

@ -0,0 +1,103 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/msm/qcom,sc8180x-dpu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SC8180X Display DPU
maintainers:
- Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
$ref: /schemas/display/msm/dpu-common.yaml#
properties:
compatible:
const: qcom,sc8180x-dpu
reg:
items:
- description: Address offset and size for mdp register set
- description: Address offset and size for vbif register set
reg-names:
items:
- const: mdp
- const: vbif
clocks:
items:
- description: Display AHB clock
- description: Display HF AXI clock
- description: Display core clock
- description: Display vsync clock
- description: Display rotator clock
- description: Display LUT clock
clock-names:
items:
- const: iface
- const: bus
- const: core
- const: vsync
- const: rot
- const: lut
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,dispcc-sm8250.h>
#include <dt-bindings/clock/qcom,gcc-sc8180x.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interconnect/qcom,sc8180x.h>
#include <dt-bindings/power/qcom-rpmpd.h>
display-controller@ae01000 {
compatible = "qcom,sc8180x-dpu";
reg = <0x0ae01000 0x8f000>,
<0x0aeb0000 0x2008>;
reg-names = "mdp", "vbif";
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
<&gcc GCC_DISP_HF_AXI_CLK>,
<&dispcc DISP_CC_MDSS_MDP_CLK>,
<&dispcc DISP_CC_MDSS_VSYNC_CLK>,
<&dispcc DISP_CC_MDSS_ROT_CLK>,
<&dispcc DISP_CC_MDSS_MDP_LUT_CLK>;
clock-names = "iface",
"bus",
"core",
"vsync",
"rot",
"lut";
assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
assigned-clock-rates = <19200000>;
operating-points-v2 = <&mdp_opp_table>;
power-domains = <&rpmhpd SC8180X_MMCX>;
interrupt-parent = <&mdss>;
interrupts = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
endpoint {
remote-endpoint = <&dsi0_in>;
};
};
port@1 {
reg = <1>;
endpoint {
remote-endpoint = <&dsi1_in>;
};
};
};
};
...

View file

@ -0,0 +1,359 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/msm/qcom,sc8180x-mdss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SC8180X Display MDSS
maintainers:
- Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
description:
Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
bindings of MDSS are mentioned for SC8180X target.
$ref: /schemas/display/msm/mdss-common.yaml#
properties:
compatible:
items:
- const: qcom,sc8180x-mdss
clocks:
items:
- description: Display AHB clock from gcc
- description: Display hf axi clock
- description: Display sf axi clock
- description: Display core clock
clock-names:
items:
- const: iface
- const: bus
- const: nrt_bus
- const: core
iommus:
maxItems: 1
interconnects:
maxItems: 3
interconnect-names:
maxItems: 3
patternProperties:
"^display-controller@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: qcom,sc8180x-dpu
"^displayport-controller@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
enum:
- qcom,sc8180x-dp
- qcom,sc8180x-edp
"^dsi@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
contains:
const: qcom,sc8180x-dsi-ctrl
"^phy@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: qcom,dsi-phy-7nm
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,dispcc-sm8250.h>
#include <dt-bindings/clock/qcom,gcc-sc8180x.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interconnect/qcom,sc8180x.h>
#include <dt-bindings/power/qcom-rpmpd.h>
display-subsystem@ae00000 {
compatible = "qcom,sc8180x-mdss";
reg = <0x0ae00000 0x1000>;
reg-names = "mdss";
interconnects = <&mmss_noc MASTER_MDP_PORT0 &mc_virt SLAVE_EBI_CH0>,
<&mmss_noc MASTER_MDP_PORT1 &mc_virt SLAVE_EBI_CH0>,
<&gem_noc MASTER_AMPSS_M0 &config_noc SLAVE_DISPLAY_CFG>;
interconnect-names = "mdp0-mem",
"mdp1-mem",
"cpu-cfg";
power-domains = <&dispcc MDSS_GDSC>;
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
<&gcc GCC_DISP_HF_AXI_CLK>,
<&gcc GCC_DISP_SF_AXI_CLK>,
<&dispcc DISP_CC_MDSS_MDP_CLK>;
clock-names = "iface", "bus", "nrt_bus", "core";
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <1>;
iommus = <&apps_smmu 0x800 0x420>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
display-controller@ae01000 {
compatible = "qcom,sc8180x-dpu";
reg = <0x0ae01000 0x8f000>,
<0x0aeb0000 0x2008>;
reg-names = "mdp", "vbif";
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
<&gcc GCC_DISP_HF_AXI_CLK>,
<&dispcc DISP_CC_MDSS_MDP_CLK>,
<&dispcc DISP_CC_MDSS_VSYNC_CLK>,
<&dispcc DISP_CC_MDSS_ROT_CLK>,
<&dispcc DISP_CC_MDSS_MDP_LUT_CLK>;
clock-names = "iface",
"bus",
"core",
"vsync",
"rot",
"lut";
assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
assigned-clock-rates = <19200000>;
operating-points-v2 = <&mdp_opp_table>;
power-domains = <&rpmhpd SC8180X_MMCX>;
interrupt-parent = <&mdss>;
interrupts = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dpu_intf1_out: endpoint {
remote-endpoint = <&dsi0_in>;
};
};
port@1 {
reg = <1>;
dpu_intf2_out: endpoint {
remote-endpoint = <&dsi1_in>;
};
};
};
mdp_opp_table: opp-table {
compatible = "operating-points-v2";
opp-171428571 {
opp-hz = /bits/ 64 <171428571>;
required-opps = <&rpmhpd_opp_low_svs>;
};
opp-300000000 {
opp-hz = /bits/ 64 <300000000>;
required-opps = <&rpmhpd_opp_svs>;
};
opp-345000000 {
opp-hz = /bits/ 64 <345000000>;
required-opps = <&rpmhpd_opp_svs_l1>;
};
opp-460000000 {
opp-hz = /bits/ 64 <460000000>;
required-opps = <&rpmhpd_opp_nom>;
};
};
};
dsi@ae94000 {
compatible = "qcom,sc8180x-dsi-ctrl",
"qcom,mdss-dsi-ctrl";
reg = <0x0ae94000 0x400>;
reg-names = "dsi_ctrl";
interrupt-parent = <&mdss>;
interrupts = <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 = <&dsi0_phy 0>, <&dsi0_phy 1>;
operating-points-v2 = <&dsi_opp_table>;
power-domains = <&rpmhpd SC8180X_MMCX>;
phys = <&dsi0_phy>;
phy-names = "dsi";
#address-cells = <1>;
#size-cells = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dsi0_in: endpoint {
remote-endpoint = <&dpu_intf1_out>;
};
};
port@1 {
reg = <1>;
dsi0_out: endpoint {
};
};
};
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>;
};
};
};
dsi0_phy: phy@ae94400 {
compatible = "qcom,dsi-phy-7nm";
reg = <0x0ae94400 0x200>,
<0x0ae94600 0x280>,
<0x0ae94900 0x260>;
reg-names = "dsi_phy",
"dsi_phy_lane",
"dsi_pll";
#clock-cells = <1>;
#phy-cells = <0>;
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
<&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "ref";
vdds-supply = <&vreg_dsi_phy>;
};
dsi@ae96000 {
compatible = "qcom,sc8180x-dsi-ctrl",
"qcom,mdss-dsi-ctrl";
reg = <0x0ae96000 0x400>;
reg-names = "dsi_ctrl";
interrupt-parent = <&mdss>;
interrupts = <5>;
clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>,
<&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>,
<&dispcc DISP_CC_MDSS_PCLK1_CLK>,
<&dispcc DISP_CC_MDSS_ESC1_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_BYTE1_CLK_SRC>,
<&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>;
assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>;
operating-points-v2 = <&dsi_opp_table>;
power-domains = <&rpmhpd SC8180X_MMCX>;
phys = <&dsi1_phy>;
phy-names = "dsi";
#address-cells = <1>;
#size-cells = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dsi1_in: endpoint {
remote-endpoint = <&dpu_intf2_out>;
};
};
port@1 {
reg = <1>;
dsi1_out: endpoint {
};
};
};
};
dsi1_phy: phy@ae96400 {
compatible = "qcom,dsi-phy-7nm";
reg = <0x0ae96400 0x200>,
<0x0ae96600 0x280>,
<0x0ae96900 0x260>;
reg-names = "dsi_phy",
"dsi_phy_lane",
"dsi_pll";
#clock-cells = <1>;
#phy-cells = <0>;
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
<&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "ref";
vdds-supply = <&vreg_dsi_phy>;
};
};
...

View file

@ -61,7 +61,8 @@ patternProperties:
additionalProperties: true
properties:
compatible:
const: qcom,sm7150-dp
contains:
const: qcom,sm7150-dp
"^dsi@[0-9a-f]+$":
type: object
@ -378,7 +379,8 @@ examples:
};
displayport-controller@ae90000 {
compatible = "qcom,sm7150-dp";
compatible = "qcom,sm7150-dp",
"qcom,sm8350-dp";
reg = <0xae90000 0x200>,
<0xae90200 0x200>,
<0xae90400 0xc00>,
@ -392,16 +394,20 @@ examples:
<&dispcc_mdss_dp_aux_clk>,
<&dispcc_mdss_dp_link_clk>,
<&dispcc_mdss_dp_link_intf_clk>,
<&dispcc_mdss_dp_pixel_clk>;
<&dispcc_mdss_dp_pixel_clk>,
<&dispcc_mdss_dp_pixel1_clk>;
clock-names = "core_iface",
"core_aux",
"ctrl_link",
"ctrl_link_iface",
"stream_pixel";
"stream_pixel",
"stream_1_pixel";
assigned-clocks = <&dispcc_mdss_dp_link_clk_src>,
<&dispcc_mdss_dp_pixel_clk_src>;
<&dispcc_mdss_dp_pixel_clk_src>,
<&dispcc_mdss_dp_pixel1_clk_src>;
assigned-clock-parents = <&dp_phy 0>,
<&dp_phy 1>,
<&dp_phy 1>;
operating-points-v2 = <&dp_opp_table>;

View file

@ -401,16 +401,20 @@ examples:
<&disp_cc_mdss_dptx0_aux_clk>,
<&disp_cc_mdss_dptx0_link_clk>,
<&disp_cc_mdss_dptx0_link_intf_clk>,
<&disp_cc_mdss_dptx0_pixel0_clk>;
<&disp_cc_mdss_dptx0_pixel0_clk>,
<&disp_cc_mdss_dptx0_pixel1_clk>;
clock-names = "core_iface",
"core_aux",
"ctrl_link",
"ctrl_link_iface",
"stream_pixel";
"stream_pixel",
"stream_1_pixel";
assigned-clocks = <&disp_cc_mdss_dptx0_link_clk_src>,
<&disp_cc_mdss_dptx0_pixel0_clk_src>;
<&disp_cc_mdss_dptx0_pixel0_clk_src>,
<&disp_cc_mdss_dptx0_pixel1_clk_src>;
assigned-clock-parents = <&usb_dp_qmpphy QMP_USB43DP_DP_LINK_CLK>,
<&usb_dp_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>,
<&usb_dp_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>;
operating-points-v2 = <&dp_opp_table>;

View file

@ -170,11 +170,11 @@ examples:
displayport-controller@ae90000 {
compatible = "qcom,x1e80100-dp";
reg = <0 0xae90000 0 0x200>,
<0 0xae90200 0 0x200>,
<0 0xae90400 0 0x600>,
<0 0xae91000 0 0x400>,
<0 0xae91400 0 0x400>;
reg = <0xae90000 0x200>,
<0xae90200 0x200>,
<0xae90400 0x600>,
<0xae91000 0x400>,
<0xae91400 0x400>;
interrupt-parent = <&mdss>;
interrupts = <12>;
@ -183,15 +183,19 @@ examples:
<&dispcc_dptx0_aux_clk>,
<&dispcc_dptx0_link_clk>,
<&dispcc_dptx0_link_intf_clk>,
<&dispcc_dptx0_pixel0_clk>;
<&dispcc_dptx0_pixel0_clk>,
<&dispcc_dptx0_pixel1_clk>;
clock-names = "core_iface", "core_aux",
"ctrl_link",
"ctrl_link_iface",
"stream_pixel";
"stream_pixel",
"stream_1_pixel";
assigned-clocks = <&dispcc_mdss_dptx0_link_clk_src>,
<&dispcc_mdss_dptx0_pixel0_clk_src>;
<&dispcc_mdss_dptx0_pixel0_clk_src>,
<&dispcc_mdss_dptx0_pixel1_clk_src>;
assigned-clock-parents = <&usb_1_ss0_qmpphy QMP_USB43DP_DP_LINK_CLK>,
<&usb_1_ss0_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>,
<&usb_1_ss0_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>;
operating-points-v2 = <&mdss_dp0_opp_table>;

View file

@ -913,6 +913,11 @@ static const struct adreno_info a6xx_gpus[] = {
{ /* sentinel */ },
},
},
.speedbins = ADRENO_SPEEDBINS(
{ 0, 0 },
{ 185, 0 },
{ 127, 1 },
),
}, {
.chip_ids = ADRENO_CHIP_IDS(
0x06030001,
@ -1024,6 +1029,11 @@ static const struct adreno_info a6xx_gpus[] = {
.gmu_cgc_mode = 0x00020200,
.prim_fifo_threshold = 0x00300200,
},
.speedbins = ADRENO_SPEEDBINS(
{ 0, 0 },
{ 169, 0 },
{ 113, 1 },
),
}, {
.chip_ids = ADRENO_CHIP_IDS(0x06030500),
.family = ADRENO_6XX_GEN4,
@ -1343,6 +1353,69 @@ static const uint32_t a7xx_pwrup_reglist_regs[] = {
DECLARE_ADRENO_REGLIST_LIST(a7xx_pwrup_reglist);
/* Applicable for X185, A750 */
static const u32 a750_ifpc_reglist_regs[] = {
REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(0),
REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(1),
REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(2),
REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(3),
REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(4),
REG_A6XX_TPL1_NC_MODE_CNTL,
REG_A6XX_SP_NC_MODE_CNTL,
REG_A6XX_CP_DBG_ECO_CNTL,
REG_A6XX_CP_PROTECT_CNTL,
REG_A6XX_CP_PROTECT(0),
REG_A6XX_CP_PROTECT(1),
REG_A6XX_CP_PROTECT(2),
REG_A6XX_CP_PROTECT(3),
REG_A6XX_CP_PROTECT(4),
REG_A6XX_CP_PROTECT(5),
REG_A6XX_CP_PROTECT(6),
REG_A6XX_CP_PROTECT(7),
REG_A6XX_CP_PROTECT(8),
REG_A6XX_CP_PROTECT(9),
REG_A6XX_CP_PROTECT(10),
REG_A6XX_CP_PROTECT(11),
REG_A6XX_CP_PROTECT(12),
REG_A6XX_CP_PROTECT(13),
REG_A6XX_CP_PROTECT(14),
REG_A6XX_CP_PROTECT(15),
REG_A6XX_CP_PROTECT(16),
REG_A6XX_CP_PROTECT(17),
REG_A6XX_CP_PROTECT(18),
REG_A6XX_CP_PROTECT(19),
REG_A6XX_CP_PROTECT(20),
REG_A6XX_CP_PROTECT(21),
REG_A6XX_CP_PROTECT(22),
REG_A6XX_CP_PROTECT(23),
REG_A6XX_CP_PROTECT(24),
REG_A6XX_CP_PROTECT(25),
REG_A6XX_CP_PROTECT(26),
REG_A6XX_CP_PROTECT(27),
REG_A6XX_CP_PROTECT(28),
REG_A6XX_CP_PROTECT(29),
REG_A6XX_CP_PROTECT(30),
REG_A6XX_CP_PROTECT(31),
REG_A6XX_CP_PROTECT(32),
REG_A6XX_CP_PROTECT(33),
REG_A6XX_CP_PROTECT(34),
REG_A6XX_CP_PROTECT(35),
REG_A6XX_CP_PROTECT(36),
REG_A6XX_CP_PROTECT(37),
REG_A6XX_CP_PROTECT(38),
REG_A6XX_CP_PROTECT(39),
REG_A6XX_CP_PROTECT(40),
REG_A6XX_CP_PROTECT(41),
REG_A6XX_CP_PROTECT(42),
REG_A6XX_CP_PROTECT(43),
REG_A6XX_CP_PROTECT(44),
REG_A6XX_CP_PROTECT(45),
REG_A6XX_CP_PROTECT(46),
REG_A6XX_CP_PROTECT(47),
};
DECLARE_ADRENO_REGLIST_LIST(a750_ifpc_reglist);
static const struct adreno_info a7xx_gpus[] = {
{
.chip_ids = ADRENO_CHIP_IDS(0x07000200),
@ -1432,14 +1505,27 @@ static const struct adreno_info a7xx_gpus[] = {
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
ADRENO_QUIRK_HAS_HW_APRIV |
ADRENO_QUIRK_PREEMPTION,
ADRENO_QUIRK_PREEMPTION |
ADRENO_QUIRK_IFPC,
.init = a6xx_gpu_init,
.a6xx = &(const struct a6xx_info) {
.hwcg = a740_hwcg,
.protect = &a730_protect,
.pwrup_reglist = &a7xx_pwrup_reglist,
.ifpc_reglist = &a750_ifpc_reglist,
.gmu_chipid = 0x7050001,
.gmu_cgc_mode = 0x00020202,
.bcms = (const struct a6xx_bcm[]) {
{ .name = "SH0", .buswidth = 16 },
{ .name = "MC0", .buswidth = 4 },
{
.name = "ACV",
.fixed = true,
.perfmode = BIT(3),
.perfmode_bw = 16500000,
},
{ /* sentinel */ },
},
},
.preempt_record_size = 4192 * SZ_1K,
.speedbins = ADRENO_SPEEDBINS(
@ -1460,12 +1546,14 @@ static const struct adreno_info a7xx_gpus[] = {
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
ADRENO_QUIRK_HAS_HW_APRIV |
ADRENO_QUIRK_PREEMPTION,
ADRENO_QUIRK_PREEMPTION |
ADRENO_QUIRK_IFPC,
.init = a6xx_gpu_init,
.zapfw = "gen70900_zap.mbn",
.a6xx = &(const struct a6xx_info) {
.protect = &a730_protect,
.pwrup_reglist = &a7xx_pwrup_reglist,
.ifpc_reglist = &a750_ifpc_reglist,
.gmu_chipid = 0x7090100,
.gmu_cgc_mode = 0x00020202,
.bcms = (const struct a6xx_bcm[]) {

View file

@ -93,14 +93,25 @@ bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu)
/* Check to see if the GX rail is still powered */
bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
{
struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
u32 val;
/* This can be called from gpu state code so make sure GMU is valid */
if (!gmu->initialized)
return false;
/* If GMU is absent, then GX power domain is ON as long as GPU is in active state */
if (adreno_has_gmu_wrapper(adreno_gpu))
return true;
val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
if (adreno_is_a7xx(adreno_gpu))
return !(val &
(A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF |
A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
return !(val &
(A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF |
A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
@ -272,6 +283,8 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu)
if (ret)
DRM_DEV_ERROR(gmu->dev, "GMU firmware initialization timed out\n");
set_bit(GMU_STATUS_FW_START, &gmu->status);
return ret;
}
@ -403,7 +416,10 @@ int a6xx_sptprac_enable(struct a6xx_gmu *gmu)
int ret;
u32 val;
if (!gmu->legacy)
WARN_ON(!gmu->legacy);
/* Nothing to do if GMU does the power management */
if (gmu->idle_level > GMU_IDLE_STATE_ACTIVE)
return 0;
gmu_write(gmu, REG_A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, 0x778000);
@ -518,6 +534,9 @@ static int a6xx_rpmh_start(struct a6xx_gmu *gmu)
int ret;
u32 val;
if (!test_and_clear_bit(GMU_STATUS_PDC_SLEEP, &gmu->status))
return 0;
gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, BIT(1));
ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_RSCC_CONTROL_ACK, val,
@ -545,6 +564,9 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)
int ret;
u32 val;
if (test_and_clear_bit(GMU_STATUS_FW_START, &gmu->status))
return;
gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 1);
ret = gmu_poll_timeout_rscc(gmu, REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0,
@ -553,6 +575,8 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)
DRM_DEV_ERROR(gmu->dev, "Unable to power off the GPU RSC\n");
gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 0);
set_bit(GMU_STATUS_PDC_SLEEP, &gmu->status);
}
static inline void pdc_write(void __iomem *ptr, u32 offset, u32 value)
@ -681,8 +705,6 @@ setup_pdc:
/* ensure no writes happen before the uCode is fully written */
wmb();
a6xx_rpmh_stop(gmu);
err:
if (!IS_ERR_OR_NULL(pdcptr))
iounmap(pdcptr);
@ -842,19 +864,15 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
else
gmu_write(gmu, REG_A6XX_GMU_GENERAL_7, 1);
if (state == GMU_WARM_BOOT) {
ret = a6xx_rpmh_start(gmu);
if (ret)
return ret;
} else {
ret = a6xx_rpmh_start(gmu);
if (ret)
return ret;
if (state == GMU_COLD_BOOT) {
if (WARN(!adreno_gpu->fw[ADRENO_FW_GMU],
"GMU firmware is not loaded\n"))
return -ENOENT;
ret = a6xx_rpmh_start(gmu);
if (ret)
return ret;
ret = a6xx_gmu_fw_load(gmu);
if (ret)
return ret;
@ -925,10 +943,7 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
ret = a6xx_gmu_gfx_rail_on(gmu);
if (ret)
return ret;
}
/* Enable SPTP_PC if the CPU is responsible for it */
if (gmu->idle_level < GMU_IDLE_STATE_SPTP) {
ret = a6xx_sptprac_enable(gmu);
if (ret)
return ret;
@ -980,6 +995,22 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
val, (val & 1), 100, 10000);
gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 1000);
if (!adreno_is_a740_family(adreno_gpu))
return;
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS4_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 10000);
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS5_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 10000);
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS6_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 10000);
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS7_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 1000);
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS8_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 10000);
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS9_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 1000);
}
/* Force the GMU off in case it isn't responsive */
@ -1023,6 +1054,8 @@ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu)
/* Reset GPU core blocks */
a6xx_gpu_sw_reset(gpu, true);
a6xx_rpmh_stop(gmu);
}
static void a6xx_gmu_set_initial_freq(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
@ -1128,6 +1161,11 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
/* Set the GPU to the current freq */
a6xx_gmu_set_initial_freq(gpu, gmu);
if (refcount_read(&gpu->sysprof_active) > 1) {
ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
if (!ret)
set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
}
out:
/* On failure, shut down the GMU to leave it in a good state */
if (ret) {
@ -1175,6 +1213,9 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
}
if (test_and_clear_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status))
a6xx_gmu_clear_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
ret = a6xx_gmu_wait_for_idle(gmu);
/* If the GMU isn't responding assume it is hung */
@ -1318,8 +1359,6 @@ static int a6xx_gmu_memory_probe(struct drm_device *drm, struct a6xx_gmu *gmu)
struct msm_mmu *mmu;
mmu = msm_iommu_new(gmu->dev, 0);
if (!mmu)
return -ENODEV;
if (IS_ERR(mmu))
return PTR_ERR(mmu);
@ -1692,6 +1731,7 @@ static int a6xx_gmu_acd_probe(struct a6xx_gmu *gmu)
u32 val;
freq = gmu->gpu_freqs[i];
/* This is unlikely to fail because we are passing back a known freq */
opp = dev_pm_opp_find_freq_exact(&gpu->pdev->dev, freq, true);
np = dev_pm_opp_get_of_node(opp);
@ -1790,6 +1830,35 @@ 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)
{
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))
return;
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))
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))
a6xx_gmu_clear_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
mutex_unlock(&gmu->lock);
pm_runtime_put(&gpu->pdev->dev);
}
void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
@ -1932,8 +2001,9 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
if (ret)
return ret;
/* Fow now, don't do anything fancy until we get our feet under us */
gmu->idle_level = GMU_IDLE_STATE_ACTIVE;
/* Set GMU idle level */
gmu->idle_level = (adreno_gpu->info->quirks & ADRENO_QUIRK_IFPC) ?
GMU_IDLE_STATE_IFPC : GMU_IDLE_STATE_ACTIVE;
pm_runtime_enable(gmu->dev);

View file

@ -50,6 +50,9 @@ struct a6xx_bcm {
/* The GMU does not do any idle state management */
#define GMU_IDLE_STATE_ACTIVE 0
/* Unknown power state. Not exposed by the firmware. For documentation purpose only */
#define GMU_IDLE_STATE_RESERVED 1
/* The GMU manages SPTP power collapse */
#define GMU_IDLE_STATE_SPTP 2
@ -117,6 +120,14 @@ struct a6xx_gmu {
struct qmp *qmp;
struct a6xx_hfi_msg_bw_table *bw_table;
/* To check if we can trigger sleep seq at PDC. Cleared in a6xx_rpmh_stop() */
#define GMU_STATUS_FW_START 0
/* To track if PDC sleep seq was done */
#define GMU_STATUS_PDC_SLEEP 1
/* To track Perfcounter OOB set status */
#define GMU_STATUS_OOB_PERF_SET 2
unsigned long status;
};
static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset)
@ -158,6 +169,9 @@ static inline u64 gmu_read64(struct a6xx_gmu *gmu, u32 lo, u32 hi)
#define gmu_poll_timeout(gmu, addr, val, cond, interval, timeout) \
readl_poll_timeout((gmu)->mmio + ((addr) << 2), val, cond, \
interval, timeout)
#define gmu_poll_timeout_atomic(gmu, addr, val, cond, interval, timeout) \
readl_poll_timeout_atomic((gmu)->mmio + ((addr) << 2), val, cond, \
interval, timeout)
static inline u32 gmu_read_rscc(struct a6xx_gmu *gmu, u32 offset)
{

View file

@ -16,6 +16,97 @@
#define GPU_PAS_ID 13
static u64 read_gmu_ao_counter(struct a6xx_gpu *a6xx_gpu)
{
u64 count_hi, count_lo, temp;
do {
count_hi = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_H);
count_lo = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_L);
temp = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_H);
} while (unlikely(count_hi != temp));
return (count_hi << 32) | count_lo;
}
static bool fence_status_check(struct msm_gpu *gpu, u32 offset, u32 value, u32 status, u32 mask)
{
/* Success if !writedropped0/1 */
if (!(status & mask))
return true;
udelay(10);
/* Try to update fenced register again */
gpu_write(gpu, offset, value);
/* We can't do a posted write here because the power domain could be
* in collapse state. So use the heaviest barrier instead
*/
mb();
return false;
}
static int fenced_write(struct a6xx_gpu *a6xx_gpu, u32 offset, u32 value, u32 mask)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
struct msm_gpu *gpu = &adreno_gpu->base;
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
u32 status;
gpu_write(gpu, offset, value);
/* Nothing else to be done in the case of no-GMU */
if (adreno_has_gmu_wrapper(adreno_gpu))
return 0;
/* We can't do a posted write here because the power domain could be
* in collapse state. So use the heaviest barrier instead
*/
mb();
if (!gmu_poll_timeout(gmu, REG_A6XX_GMU_AHB_FENCE_STATUS, status,
fence_status_check(gpu, offset, value, status, mask), 0, 1000))
return 0;
/* Try again for another 1ms before failing */
gpu_write(gpu, offset, value);
mb();
if (!gmu_poll_timeout(gmu, REG_A6XX_GMU_AHB_FENCE_STATUS, status,
fence_status_check(gpu, offset, value, status, mask), 0, 1000)) {
/*
* The 'delay' warning is here because the pause to print this
* warning will allow gpu to move to power collapse which
* defeats the purpose of continuous polling for 2 ms
*/
dev_err_ratelimited(gmu->dev, "delay in fenced register write (0x%x)\n",
offset);
return 0;
}
dev_err_ratelimited(gmu->dev, "fenced register write (0x%x) fail\n",
offset);
return -ETIMEDOUT;
}
int a6xx_fenced_write(struct a6xx_gpu *a6xx_gpu, u32 offset, u64 value, u32 mask, bool is_64b)
{
int ret;
ret = fenced_write(a6xx_gpu, offset, lower_32_bits(value), mask);
if (ret)
return ret;
if (!is_64b)
return 0;
ret = fenced_write(a6xx_gpu, offset + 1, upper_32_bits(value), mask);
return ret;
}
static inline bool _a6xx_check_idle(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@ -86,7 +177,7 @@ static void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
/* Update HW if this is the current ring and we are not in preempt*/
if (!a6xx_in_preempt(a6xx_gpu)) {
if (a6xx_gpu->cur_ring == ring)
gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr);
a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
else
ring->restore_wptr = true;
} else {
@ -173,8 +264,8 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,
* Needed for preemption
*/
OUT_PKT7(ring, CP_MEM_WRITE, 5);
OUT_RING(ring, CP_MEM_WRITE_0_ADDR_LO(lower_32_bits(memptr)));
OUT_RING(ring, CP_MEM_WRITE_1_ADDR_HI(upper_32_bits(memptr)));
OUT_RING(ring, A5XX_CP_MEM_WRITE_ADDR_LO(lower_32_bits(memptr)));
OUT_RING(ring, A5XX_CP_MEM_WRITE_ADDR_HI(upper_32_bits(memptr)));
OUT_RING(ring, lower_32_bits(ttbr));
OUT_RING(ring, upper_32_bits(ttbr));
OUT_RING(ring, ctx->seqno);
@ -204,9 +295,9 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,
*/
OUT_PKT7(ring, CP_WAIT_REG_MEM, 6);
OUT_RING(ring, CP_WAIT_REG_MEM_0_FUNCTION(WRITE_EQ));
OUT_RING(ring, CP_WAIT_REG_MEM_1_POLL_ADDR_LO(
OUT_RING(ring, CP_WAIT_REG_MEM_POLL_ADDR_LO(
REG_A6XX_RBBM_PERFCTR_SRAM_INIT_STATUS));
OUT_RING(ring, CP_WAIT_REG_MEM_2_POLL_ADDR_HI(0));
OUT_RING(ring, CP_WAIT_REG_MEM_POLL_ADDR_HI(0));
OUT_RING(ring, CP_WAIT_REG_MEM_3_REF(0x1));
OUT_RING(ring, CP_WAIT_REG_MEM_4_MASK(0x1));
OUT_RING(ring, CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(0));
@ -298,8 +389,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence)));
OUT_RING(ring, submit->seqno);
trace_msm_gpu_submit_flush(submit,
gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER));
trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu));
a6xx_flush(gpu, ring);
}
@ -499,8 +589,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
}
trace_msm_gpu_submit_flush(submit,
gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER));
trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu));
a6xx_flush(gpu, ring);
@ -739,11 +828,10 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu)
u32 *dest = (u32 *)&lock->regs[0];
int i;
reglist = adreno_gpu->info->a6xx->pwrup_reglist;
lock->gpu_req = lock->cpu_req = lock->turn = 0;
lock->ifpc_list_len = 0;
lock->preemption_list_len = reglist->count;
reglist = adreno_gpu->info->a6xx->ifpc_reglist;
lock->ifpc_list_len = reglist->count;
/*
* For each entry in each of the lists, write the offset and the current
@ -754,6 +842,14 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu)
*dest++ = gpu_read(gpu, reglist->regs[i]);
}
reglist = adreno_gpu->info->a6xx->pwrup_reglist;
lock->preemption_list_len = reglist->count;
for (i = 0; i < reglist->count; i++) {
*dest++ = reglist->regs[i];
*dest++ = gpu_read(gpu, reglist->regs[i]);
}
/*
* The overall register list is composed of
* 1. Static IFPC-only registers
@ -1241,14 +1337,14 @@ static int hw_init(struct msm_gpu *gpu)
/* Set weights for bicubic filtering */
if (adreno_is_a650_family(adreno_gpu) || adreno_is_x185(adreno_gpu)) {
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_0, 0);
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_1,
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(0), 0);
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(1),
0x3fe05ff4);
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_2,
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(2),
0x3fa0ebee);
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_3,
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(3),
0x3f5193ed);
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_4,
gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(4),
0x3f0243f0);
}
@ -1448,21 +1544,25 @@ static void a6xx_recover(struct msm_gpu *gpu)
adreno_dump_info(gpu);
for (i = 0; i < 8; i++)
DRM_DEV_INFO(&gpu->pdev->dev, "CP_SCRATCH_REG%d: %u\n", i,
gpu_read(gpu, REG_A6XX_CP_SCRATCH_REG(i)));
if (a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) {
/* Sometimes crashstate capture is skipped, so SQE should be halted here again */
gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3);
if (hang_debug)
a6xx_dump(gpu);
for (i = 0; i < 8; i++)
DRM_DEV_INFO(&gpu->pdev->dev, "CP_SCRATCH_REG%d: %u\n", i,
gpu_read(gpu, REG_A6XX_CP_SCRATCH_REG(i)));
if (hang_debug)
a6xx_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_A6XX_CP_SQE_CNTL, 3);
a6xx_gpu->hung = true;
pm_runtime_dont_use_autosuspend(&gpu->pdev->dev);
@ -1693,8 +1793,6 @@ static void a6xx_cp_hw_err_irq(struct msm_gpu *gpu)
static void a6xx_fault_detect_irq(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu);
/*
@ -1706,13 +1804,6 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu)
if (gpu_read(gpu, REG_A6XX_RBBM_STATUS3) & A6XX_RBBM_STATUS3_SMMU_STALLED_ON_FAULT)
return;
/*
* Force the GPU to stay on until after we finish
* collecting information
*/
if (!adreno_has_gmu_wrapper(adreno_gpu))
gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_GMU_PWR_COL_KEEPALIVE, 1);
DRM_DEV_ERROR(&gpu->pdev->dev,
"gpu fault ring %d fence %x status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n",
ring ? ring->id : -1, ring ? ring->fctx->last_fence : 0,
@ -1727,6 +1818,9 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu)
/* Turn off the hangcheck timer to keep it from bothering us */
timer_delete(&gpu->hangcheck_timer);
/* Turn off interrupts to avoid triggering recovery again */
gpu_write(gpu, REG_A6XX_RBBM_INT_0_MASK, 0);
kthread_queue_work(gpu->worker, &gpu->recover_work);
}
@ -1751,9 +1845,49 @@ static void a7xx_sw_fuse_violation_irq(struct msm_gpu *gpu)
}
}
static void a6xx_gpu_keepalive_vote(struct msm_gpu *gpu, bool on)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
if (adreno_has_gmu_wrapper(adreno_gpu))
return;
gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_GMU_PWR_COL_KEEPALIVE, on);
}
static int irq_poll_fence(struct msm_gpu *gpu)
{
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;
u32 status;
if (adreno_has_gmu_wrapper(adreno_gpu))
return 0;
if (gmu_poll_timeout_atomic(gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, status, !status, 1, 100)) {
u32 rbbm_unmasked = gmu_read(gmu, REG_A6XX_GMU_RBBM_INT_UNMASKED_STATUS);
dev_err_ratelimited(&gpu->pdev->dev,
"irq fence poll timeout, fence_ctrl=0x%x, unmasked_status=0x%x\n",
status, rbbm_unmasked);
return -ETIMEDOUT;
}
return 0;
}
static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
{
struct msm_drm_private *priv = gpu->dev->dev_private;
/* Set keepalive vote to avoid power collapse after RBBM_INT_0_STATUS is read */
a6xx_gpu_keepalive_vote(gpu, true);
if (irq_poll_fence(gpu))
goto done;
u32 status = gpu_read(gpu, REG_A6XX_RBBM_INT_0_STATUS);
gpu_write(gpu, REG_A6XX_RBBM_INT_CLEAR_CMD, status);
@ -1790,6 +1924,9 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
if (status & A6XX_RBBM_INT_0_MASK_CP_SW)
a6xx_preempt_irq(gpu);
done:
a6xx_gpu_keepalive_vote(gpu, false);
return IRQ_HANDLED;
}
@ -2179,16 +2316,7 @@ static int a6xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
mutex_lock(&a6xx_gpu->gmu.lock);
/* Force the GPU power on so we can read this register */
a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
*value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER);
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
mutex_unlock(&a6xx_gpu->gmu.lock);
*value = read_gmu_ao_counter(a6xx_gpu);
return 0;
}
@ -2298,18 +2426,36 @@ static uint32_t a6xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
if (adreno_gpu->base.hw_apriv || a6xx_gpu->has_whereami)
return a6xx_gpu->shadow[ring->id];
/*
* This is true only on an A6XX_GEN1 with GMU, has IFPC enabled and a super old SQE firmware
* without 'whereami' support
*/
WARN_ONCE((to_adreno_gpu(gpu)->info->quirks & ADRENO_QUIRK_IFPC),
"Can't read CP_RB_RPTR register reliably\n");
return ring->memptrs->rptr = gpu_read(gpu, REG_A6XX_CP_RB_RPTR);
}
static bool a6xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
struct msm_cp_state cp_state = {
struct msm_cp_state cp_state;
bool progress;
/*
* With IFPC, KMD doesn't know whether GX power domain is collapsed
* or not. So, we can't blindly read the below registers in GX domain.
* Lets trust the hang detection in HW and lie to the caller that
* there was progress.
*/
if (to_adreno_gpu(gpu)->info->quirks & ADRENO_QUIRK_IFPC)
return true;
cp_state = (struct msm_cp_state) {
.ib1_base = gpu_read64(gpu, REG_A6XX_CP_IB1_BASE),
.ib2_base = gpu_read64(gpu, REG_A6XX_CP_IB2_BASE),
.ib1_rem = gpu_read(gpu, REG_A6XX_CP_IB1_REM_SIZE),
.ib2_rem = gpu_read(gpu, REG_A6XX_CP_IB2_REM_SIZE),
};
bool progress;
/*
* Adjust the remaining data to account for what has already been
@ -2408,6 +2554,7 @@ static const struct adreno_gpu_funcs funcs = {
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
},
.get_timestamp = a6xx_gmu_get_timestamp,
};
@ -2468,6 +2615,7 @@ static const struct adreno_gpu_funcs funcs_a7xx = {
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
},
.get_timestamp = a6xx_gmu_get_timestamp,
};

View file

@ -45,6 +45,7 @@ struct a6xx_info {
const struct adreno_reglist *hwcg;
const struct adreno_protect *protect;
const struct adreno_reglist_list *pwrup_reglist;
const struct adreno_reglist_list *ifpc_reglist;
u32 gmu_chipid;
u32 gmu_cgc_mode;
u32 prim_fifo_threshold;
@ -254,6 +255,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_preempt_init(struct msm_gpu *gpu);
void a6xx_preempt_hw_init(struct msm_gpu *gpu);
@ -295,5 +297,6 @@ int a6xx_gpu_state_put(struct msm_gpu_state *state);
void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off);
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);
#endif /* __A6XX_GPU_H__ */

View file

@ -1586,8 +1586,7 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
struct a6xx_gpu_state *a6xx_state = kzalloc(sizeof(*a6xx_state),
GFP_KERNEL);
bool stalled = !!(gpu_read(gpu, REG_A6XX_RBBM_STATUS3) &
A6XX_RBBM_STATUS3_SMMU_STALLED_ON_FAULT);
bool stalled;
if (!a6xx_state)
return ERR_PTR(-ENOMEM);
@ -1608,15 +1607,20 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
}
/* If GX isn't on the rest of the data isn't going to be accessible */
if (!adreno_has_gmu_wrapper(adreno_gpu) && !a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
return &a6xx_state->base;
/* Halt SQE first */
gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3);
/* Get the banks of indexed registers */
if (adreno_is_a7xx(adreno_gpu))
a7xx_get_indexed_registers(gpu, a6xx_state);
else
a6xx_get_indexed_registers(gpu, a6xx_state);
stalled = !!(gpu_read(gpu, REG_A6XX_RBBM_STATUS3) &
A6XX_RBBM_STATUS3_SMMU_STALLED_ON_FAULT);
/*
* Try to initialize the crashdumper, if we are not dumping state
* with the SMMU stalled. The crashdumper needs memory access to

View file

@ -21,6 +21,7 @@ static const char * const a6xx_hfi_msg_id[] = {
HFI_MSG_ID(HFI_H2F_MSG_PERF_TABLE),
HFI_MSG_ID(HFI_H2F_MSG_TEST),
HFI_MSG_ID(HFI_H2F_MSG_START),
HFI_MSG_ID(HFI_H2F_FEATURE_CTRL),
HFI_MSG_ID(HFI_H2F_MSG_CORE_FW_START),
HFI_MSG_ID(HFI_H2F_MSG_GX_BW_PERF_VOTE),
HFI_MSG_ID(HFI_H2F_MSG_PREPARE_SLUMBER),
@ -765,23 +766,40 @@ send:
NULL, 0);
}
static int a6xx_hfi_feature_ctrl_msg(struct a6xx_gmu *gmu, u32 feature, u32 enable, u32 data)
{
struct a6xx_hfi_msg_feature_ctrl msg = {
.feature = feature,
.enable = enable,
.data = data,
};
return a6xx_hfi_send_msg(gmu, HFI_H2F_FEATURE_CTRL, &msg, sizeof(msg), NULL, 0);
}
#define HFI_FEATURE_IFPC 9
#define IFPC_LONG_HYST 0x1680
static int a6xx_hfi_enable_ifpc(struct a6xx_gmu *gmu)
{
if (gmu->idle_level != GMU_IDLE_STATE_IFPC)
return 0;
return a6xx_hfi_feature_ctrl_msg(gmu, HFI_FEATURE_IFPC, 1, IFPC_LONG_HYST);
}
#define HFI_FEATURE_ACD 12
static int a6xx_hfi_enable_acd(struct a6xx_gmu *gmu)
{
struct a6xx_hfi_acd_table *acd_table = &gmu->acd_table;
struct a6xx_hfi_msg_feature_ctrl msg = {
.feature = HFI_FEATURE_ACD,
.enable = 1,
.data = 0,
};
int ret;
if (!acd_table->enable_by_level)
return 0;
/* Enable ACD feature at GMU */
ret = a6xx_hfi_send_msg(gmu, HFI_H2F_FEATURE_CTRL, &msg, sizeof(msg), NULL, 0);
ret = a6xx_hfi_feature_ctrl_msg(gmu, HFI_FEATURE_ACD, 1, 0);
if (ret) {
DRM_DEV_ERROR(gmu->dev, "Unable to enable ACD (%d)\n", ret);
return ret;
@ -898,6 +916,10 @@ int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state)
if (ret)
return ret;
ret = a6xx_hfi_enable_ifpc(gmu);
if (ret)
return ret;
ret = a6xx_hfi_send_core_fw_start(gmu);
if (ret)
return ret;

View file

@ -41,7 +41,7 @@ static inline void set_preempt_state(struct a6xx_gpu *gpu,
}
/* Write the most recent wptr for the given ring into the hardware */
static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
static inline void update_wptr(struct a6xx_gpu *a6xx_gpu, struct msm_ringbuffer *ring)
{
unsigned long flags;
uint32_t wptr;
@ -51,7 +51,7 @@ static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
if (ring->restore_wptr) {
wptr = get_wptr(ring);
gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr);
a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
ring->restore_wptr = false;
}
@ -111,9 +111,9 @@ static void preempt_prepare_postamble(struct a6xx_gpu *a6xx_gpu)
postamble[count++] = PKT7(CP_WAIT_REG_MEM, 6);
postamble[count++] = CP_WAIT_REG_MEM_0_FUNCTION(WRITE_EQ);
postamble[count++] = CP_WAIT_REG_MEM_1_POLL_ADDR_LO(
postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_LO(
REG_A6XX_RBBM_PERFCTR_SRAM_INIT_STATUS);
postamble[count++] = CP_WAIT_REG_MEM_2_POLL_ADDR_HI(0);
postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_HI(0);
postamble[count++] = CP_WAIT_REG_MEM_3_REF(0x1);
postamble[count++] = CP_WAIT_REG_MEM_4_MASK(0x1);
postamble[count++] = CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(0);
@ -136,6 +136,21 @@ static void preempt_disable_postamble(struct a6xx_gpu *a6xx_gpu)
a6xx_gpu->postamble_enabled = false;
}
/*
* Set preemption keepalive vote. Please note that this vote is different from the one used in
* a6xx_irq()
*/
static void a6xx_preempt_keepalive_vote(struct msm_gpu *gpu, bool on)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
if (adreno_has_gmu_wrapper(adreno_gpu))
return;
gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_PWR_COL_PREEMPT_KEEPALIVE, on);
}
void a6xx_preempt_irq(struct msm_gpu *gpu)
{
uint32_t status;
@ -172,10 +187,12 @@ void a6xx_preempt_irq(struct msm_gpu *gpu)
set_preempt_state(a6xx_gpu, PREEMPT_FINISH);
update_wptr(gpu, a6xx_gpu->cur_ring);
update_wptr(a6xx_gpu, a6xx_gpu->cur_ring);
set_preempt_state(a6xx_gpu, PREEMPT_NONE);
a6xx_preempt_keepalive_vote(gpu, false);
trace_msm_gpu_preemption_irq(a6xx_gpu->cur_ring->id);
/*
@ -268,7 +285,7 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu)
*/
if (!ring || (a6xx_gpu->cur_ring == ring)) {
set_preempt_state(a6xx_gpu, PREEMPT_FINISH);
update_wptr(gpu, a6xx_gpu->cur_ring);
update_wptr(a6xx_gpu, a6xx_gpu->cur_ring);
set_preempt_state(a6xx_gpu, PREEMPT_NONE);
spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags);
return;
@ -302,13 +319,16 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu)
spin_unlock_irqrestore(&ring->preempt_lock, flags);
gpu_write64(gpu,
REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO,
a6xx_gpu->preempt_smmu_iova[ring->id]);
/* Set the keepalive bit to keep the GPU ON until preemption is complete */
a6xx_preempt_keepalive_vote(gpu, true);
gpu_write64(gpu,
a6xx_fenced_write(a6xx_gpu,
REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO, a6xx_gpu->preempt_smmu_iova[ring->id],
BIT(1), true);
a6xx_fenced_write(a6xx_gpu,
REG_A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR,
a6xx_gpu->preempt_iova[ring->id]);
a6xx_gpu->preempt_iova[ring->id], BIT(1), true);
a6xx_gpu->next_ring = ring;
@ -328,7 +348,7 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu)
set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED);
/* Trigger the preemption */
gpu_write(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL, cntl);
a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL, cntl, BIT(1), false);
}
static int preempt_init_ring(struct a6xx_gpu *a6xx_gpu,

View file

@ -24,6 +24,10 @@ bool disable_acd;
MODULE_PARM_DESC(disable_acd, "Forcefully disable GPU ACD");
module_param_unsafe(disable_acd, bool, 0400);
static bool skip_gpu;
MODULE_PARM_DESC(no_gpu, "Disable GPU driver register (0=enable GPU driver register (default), 1=skip GPU driver register");
module_param(skip_gpu, bool, 0400);
extern const struct adreno_gpulist a2xx_gpulist;
extern const struct adreno_gpulist a3xx_gpulist;
extern const struct adreno_gpulist a4xx_gpulist;
@ -184,6 +188,9 @@ bool adreno_has_gpu(struct device_node *node)
uint32_t chip_id;
int ret;
if (skip_gpu)
return false;
ret = find_chipid(node, &chip_id);
if (ret)
return false;
@ -404,10 +411,16 @@ static struct platform_driver adreno_driver = {
void __init adreno_register(void)
{
if (skip_gpu)
return;
platform_driver_register(&adreno_driver);
}
void __exit adreno_unregister(void)
{
if (skip_gpu)
return;
platform_driver_unregister(&adreno_driver);
}

View file

@ -10,7 +10,7 @@
#include <linux/interconnect.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/soc/qcom/mdt_loader.h>
@ -33,7 +33,7 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
struct device *dev = &gpu->pdev->dev;
const struct firmware *fw;
const char *signed_fwname = NULL;
struct device_node *np, *mem_np;
struct device_node *np;
struct resource r;
phys_addr_t mem_phys;
ssize_t mem_size;
@ -51,18 +51,11 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
return -ENODEV;
}
mem_np = of_parse_phandle(np, "memory-region", 0);
of_node_put(np);
if (!mem_np) {
ret = of_reserved_mem_region_to_resource(np, 0, &r);
if (ret) {
zap_available = false;
return -EINVAL;
}
ret = of_address_to_resource(mem_np, 0, &r);
of_node_put(mem_np);
if (ret)
return ret;
}
mem_phys = r.start;
/*
@ -209,9 +202,7 @@ adreno_iommu_create_vm(struct msm_gpu *gpu,
u64 start, size;
mmu = msm_iommu_gpu_new(&pdev->dev, gpu, quirks);
if (!mmu)
return ERR_PTR(-ENODEV);
else if (IS_ERR_OR_NULL(mmu))
if (IS_ERR(mmu))
return ERR_CAST(mmu);
geometry = msm_iommu_get_geometry(mmu);

View file

@ -59,6 +59,7 @@ enum adreno_family {
#define ADRENO_QUIRK_HAS_CACHED_COHERENT BIT(4)
#define ADRENO_QUIRK_PREEMPTION BIT(5)
#define ADRENO_QUIRK_4GB_VA BIT(6)
#define ADRENO_QUIRK_IFPC BIT(7)
/* Helper for formating the chip_id in the way that userspace tools like
* crashdec expect.

View file

@ -31,6 +31,26 @@ enum dpu_perf_mode {
DPU_PERF_MODE_MAX
};
/**
* dpu_core_perf_adjusted_mode_clk - Adjust given mode clock rate according to
* the perf clock factor.
* @crtc_clk_rate - Unadjusted mode clock rate
* @perf_cfg: performance configuration
*/
u64 dpu_core_perf_adjusted_mode_clk(u64 mode_clk_rate,
const struct dpu_perf_cfg *perf_cfg)
{
u32 clk_factor;
clk_factor = perf_cfg->clk_inefficiency_factor;
if (clk_factor) {
mode_clk_rate *= clk_factor;
do_div(mode_clk_rate, 100);
}
return mode_clk_rate;
}
/**
* _dpu_core_perf_calc_bw() - to calculate BW per crtc
* @perf_cfg: performance configuration
@ -75,28 +95,21 @@ static u64 _dpu_core_perf_calc_clk(const struct dpu_perf_cfg *perf_cfg,
struct drm_plane *plane;
struct dpu_plane_state *pstate;
struct drm_display_mode *mode;
u64 crtc_clk;
u32 clk_factor;
u64 mode_clk;
mode = &state->adjusted_mode;
crtc_clk = (u64)mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode);
mode_clk = (u64)mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode);
drm_atomic_crtc_for_each_plane(plane, crtc) {
pstate = to_dpu_plane_state(plane->state);
if (!pstate)
continue;
crtc_clk = max(pstate->plane_clk, crtc_clk);
mode_clk = max(pstate->plane_clk, mode_clk);
}
clk_factor = perf_cfg->clk_inefficiency_factor;
if (clk_factor) {
crtc_clk *= clk_factor;
do_div(crtc_clk, 100);
}
return crtc_clk;
return dpu_core_perf_adjusted_mode_clk(mode_clk, perf_cfg);
}
static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)

View file

@ -54,6 +54,9 @@ struct dpu_core_perf {
u32 fix_core_ab_vote;
};
u64 dpu_core_perf_adjusted_mode_clk(u64 clk_rate,
const struct dpu_perf_cfg *perf_cfg);
int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
struct drm_crtc_state *state);

View file

@ -377,11 +377,10 @@ static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer,
static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc)
{
struct dpu_crtc_state *crtc_state;
int lm_idx, lm_horiz_position;
int lm_idx;
crtc_state = to_dpu_crtc_state(crtc->state);
lm_horiz_position = 0;
for (lm_idx = 0; lm_idx < crtc_state->num_mixers; lm_idx++) {
const struct drm_rect *lm_roi = &crtc_state->lm_bounds[lm_idx];
struct dpu_hw_mixer *hw_lm = crtc_state->mixers[lm_idx].hw_lm;
@ -392,7 +391,7 @@ static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc)
cfg.out_width = drm_rect_width(lm_roi);
cfg.out_height = drm_rect_height(lm_roi);
cfg.right_mixer = lm_horiz_position++;
cfg.right_mixer = lm_idx & 0x1;
cfg.flags = 0;
hw_lm->ops.setup_mixer_out(hw_lm, &cfg);
}
@ -1534,6 +1533,7 @@ static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
u64 adjusted_mode_clk;
/* if there is no 3d_mux block we cannot merge LMs so we cannot
* split the large layer into 2 LMs, filter out such modes
@ -1541,6 +1541,17 @@ static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc,
if (!dpu_kms->catalog->caps->has_3d_merge &&
mode->hdisplay > dpu_kms->catalog->caps->max_mixer_width)
return MODE_BAD_HVALUE;
adjusted_mode_clk = dpu_core_perf_adjusted_mode_clk(mode->clock,
dpu_kms->perf.perf_cfg);
/*
* The given mode, adjusted for the perf clock factor, should not exceed
* the max core clock rate
*/
if (dpu_kms->perf.max_core_clk_rate < adjusted_mode_clk * 1000)
return MODE_CLOCK_HIGH;
/*
* max crtc width is equal to the max mixer width * 2 and max height is 4K
*/

View file

@ -446,7 +446,7 @@ static void _dpu_encoder_phys_wb_handle_wbdone_timeout(
static int dpu_encoder_phys_wb_wait_for_commit_done(
struct dpu_encoder_phys *phys_enc)
{
unsigned long ret;
int ret;
struct dpu_encoder_wait_info wait_info;
struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);

View file

@ -338,7 +338,6 @@ static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK();
*************************************************************/
static const struct dpu_lm_sub_blks msm8998_lm_sblk = {
.maxwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.maxblendstages = 7, /* excluding base layer */
.blendstage_base = { /* offsets relative to mixer base */
0x20, 0x50, 0x80, 0xb0, 0x230,
@ -347,7 +346,6 @@ static const struct dpu_lm_sub_blks msm8998_lm_sblk = {
};
static const struct dpu_lm_sub_blks sdm845_lm_sblk = {
.maxwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.maxblendstages = 11, /* excluding base layer */
.blendstage_base = { /* offsets relative to mixer base */
0x20, 0x38, 0x50, 0x68, 0x80, 0x98,
@ -356,7 +354,6 @@ static const struct dpu_lm_sub_blks sdm845_lm_sblk = {
};
static const struct dpu_lm_sub_blks sc7180_lm_sblk = {
.maxwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.maxblendstages = 7, /* excluding base layer */
.blendstage_base = { /* offsets relative to mixer base */
0x20, 0x38, 0x50, 0x68, 0x80, 0x98, 0xb0
@ -364,7 +361,6 @@ static const struct dpu_lm_sub_blks sc7180_lm_sblk = {
};
static const struct dpu_lm_sub_blks sm8750_lm_sblk = {
.maxwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.maxblendstages = 11, /* excluding base layer */
.blendstage_base = { /* offsets relative to mixer base */
/* 0x40 + n*0x30 */
@ -374,7 +370,6 @@ static const struct dpu_lm_sub_blks sm8750_lm_sblk = {
};
static const struct dpu_lm_sub_blks qcm2290_lm_sblk = {
.maxwidth = DEFAULT_DPU_LINE_WIDTH,
.maxblendstages = 4, /* excluding base layer */
.blendstage_base = { /* offsets relative to mixer base */
0x20, 0x38, 0x50, 0x68

View file

@ -307,7 +307,6 @@ struct dpu_sspp_sub_blks {
* @blendstage_base: Blend-stage register base offset
*/
struct dpu_lm_sub_blks {
u32 maxwidth;
u32 maxblendstages;
u32 blendstage_base[MAX_BLOCKS];
};

View file

@ -1110,7 +1110,7 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms)
{
struct drm_gpuvm *vm;
vm = msm_kms_init_vm(dpu_kms->dev);
vm = msm_kms_init_vm(dpu_kms->dev, dpu_kms->dev->dev->parent);
if (IS_ERR(vm))
return PTR_ERR(vm);

View file

@ -922,6 +922,9 @@ static int dpu_plane_is_multirect_capable(struct dpu_hw_sspp *sspp,
if (MSM_FORMAT_IS_YUV(fmt))
return false;
if (!sspp)
return true;
if (!test_bit(DPU_SSPP_SMART_DMA_V1, &sspp->cap->features) &&
!test_bit(DPU_SSPP_SMART_DMA_V2, &sspp->cap->features))
return false;
@ -1028,6 +1031,7 @@ static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate,
prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
return false;
/* Do not validate SSPP of current plane when it is not ready */
if (!dpu_plane_is_multirect_capable(pipe->sspp, pipe_cfg, fmt) ||
!dpu_plane_is_multirect_capable(prev_pipe->sspp, prev_pipe_cfg, prev_fmt))
return false;

View file

@ -865,6 +865,21 @@ void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
}
static char *dpu_hw_blk_type_name[] = {
[DPU_HW_BLK_TOP] = "TOP",
[DPU_HW_BLK_SSPP] = "SSPP",
[DPU_HW_BLK_LM] = "LM",
[DPU_HW_BLK_CTL] = "CTL",
[DPU_HW_BLK_PINGPONG] = "pingpong",
[DPU_HW_BLK_INTF] = "INTF",
[DPU_HW_BLK_WB] = "WB",
[DPU_HW_BLK_DSPP] = "DSPP",
[DPU_HW_BLK_MERGE_3D] = "merge_3d",
[DPU_HW_BLK_DSC] = "DSC",
[DPU_HW_BLK_CDM] = "CDM",
[DPU_HW_BLK_MAX] = "unknown",
};
/**
* dpu_rm_get_assigned_resources - Get hw resources of the given type that are
* assigned to this encoder
@ -946,13 +961,13 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
}
if (num_blks == blks_size) {
DPU_ERROR("More than %d resources assigned to crtc %d\n",
blks_size, crtc_id);
DPU_ERROR("More than %d %s assigned to crtc %d\n",
blks_size, dpu_hw_blk_type_name[type], crtc_id);
break;
}
if (!hw_blks[i]) {
DPU_ERROR("Allocated resource %d unavailable to assign to crtc %d\n",
type, crtc_id);
DPU_ERROR("%s unavailable to assign to crtc %d\n",
dpu_hw_blk_type_name[type], crtc_id);
break;
}
blks[num_blks++] = hw_blks[i];

View file

@ -80,7 +80,6 @@ static int dpu_wb_conn_atomic_check(struct drm_connector *connector,
static const struct drm_connector_funcs dpu_wb_conn_funcs = {
.reset = drm_atomic_helper_connector_reset,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
@ -131,12 +130,9 @@ int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
drm_connector_helper_add(&dpu_wb_conn->base.base, &dpu_wb_conn_helper_funcs);
/* DPU initializes the encoder and sets it up completely for writeback
* cases and hence should use the new API drm_writeback_connector_init_with_encoder
* to initialize the writeback connector
*/
rc = drm_writeback_connector_init_with_encoder(dev, &dpu_wb_conn->base, enc,
&dpu_wb_conn_funcs, format_list, num_formats);
rc = drmm_writeback_connector_init(dev, &dpu_wb_conn->base,
&dpu_wb_conn_funcs, enc,
format_list, num_formats);
if (!rc)
dpu_wb_conn->wb_enc = enc;

View file

@ -391,11 +391,9 @@ static void read_mdp_hw_revision(struct mdp4_kms *mdp4_kms,
static int mdp4_kms_init(struct drm_device *dev)
{
struct platform_device *pdev = to_platform_device(dev->dev);
struct msm_drm_private *priv = dev->dev_private;
struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(priv->kms));
struct msm_kms *kms = NULL;
struct msm_mmu *mmu;
struct drm_gpuvm *vm;
int ret;
u32 major, minor;
@ -458,29 +456,14 @@ static int mdp4_kms_init(struct drm_device *dev)
mdp4_disable(mdp4_kms);
mdelay(16);
mmu = msm_iommu_new(&pdev->dev, 0);
if (IS_ERR(mmu)) {
ret = PTR_ERR(mmu);
vm = msm_kms_init_vm(mdp4_kms->dev, NULL);
if (IS_ERR(vm)) {
ret = PTR_ERR(vm);
goto fail;
} else if (!mmu) {
DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys "
"contig buffers for scanout\n");
vm = NULL;
} else {
vm = msm_gem_vm_create(dev, mmu, "mdp4",
0x1000, 0x100000000 - 0x1000,
true);
if (IS_ERR(vm)) {
if (!IS_ERR(mmu))
mmu->funcs->destroy(mmu);
ret = PTR_ERR(vm);
goto fail;
}
kms->vm = vm;
}
kms->vm = vm;
ret = modeset_init(mdp4_kms);
if (ret) {
DRM_DEV_ERROR(dev->dev, "modeset_init failed: %d\n", ret);
@ -529,7 +512,7 @@ static int mdp4_probe(struct platform_device *pdev)
mdp4_kms = devm_kzalloc(dev, sizeof(*mdp4_kms), GFP_KERNEL);
if (!mdp4_kms)
return dev_err_probe(dev, -ENOMEM, "failed to allocate kms\n");
return -ENOMEM;
mdp4_kms->mmio = msm_ioremap(pdev, NULL);
if (IS_ERR(mdp4_kms->mmio))

View file

@ -202,6 +202,6 @@ static inline struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
}
#endif
struct clk *mpd4_get_lcdc_clock(struct drm_device *dev);
struct clk *mdp4_get_lcdc_clock(struct drm_device *dev);
#endif /* __MDP4_KMS_H__ */

View file

@ -375,7 +375,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev)
drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs);
mdp4_lcdc_encoder->lcdc_clk = mpd4_get_lcdc_clock(dev);
mdp4_lcdc_encoder->lcdc_clk = mdp4_get_lcdc_clock(dev);
if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) {
DRM_DEV_ERROR(dev->dev, "failed to get lvds_clk\n");
return ERR_CAST(mdp4_lcdc_encoder->lcdc_clk);

View file

@ -54,7 +54,7 @@ static const struct pll_rate *find_rate(unsigned long rate)
return &freqtbl[i-1];
}
static int mpd4_lvds_pll_enable(struct clk_hw *hw)
static int mdp4_lvds_pll_enable(struct clk_hw *hw)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
@ -80,7 +80,7 @@ static int mpd4_lvds_pll_enable(struct clk_hw *hw)
return 0;
}
static void mpd4_lvds_pll_disable(struct clk_hw *hw)
static void mdp4_lvds_pll_disable(struct clk_hw *hw)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
@ -91,21 +91,24 @@ static void mpd4_lvds_pll_disable(struct clk_hw *hw)
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x0);
}
static unsigned long mpd4_lvds_pll_recalc_rate(struct clk_hw *hw,
static unsigned long mdp4_lvds_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
return lvds_pll->pixclk;
}
static long mpd4_lvds_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
static int mdp4_lvds_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
const struct pll_rate *pll_rate = find_rate(rate);
return pll_rate->rate;
const struct pll_rate *pll_rate = find_rate(req->rate);
req->rate = pll_rate->rate;
return 0;
}
static int mpd4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
static int mdp4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
@ -114,26 +117,26 @@ static int mpd4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
}
static const struct clk_ops mpd4_lvds_pll_ops = {
.enable = mpd4_lvds_pll_enable,
.disable = mpd4_lvds_pll_disable,
.recalc_rate = mpd4_lvds_pll_recalc_rate,
.round_rate = mpd4_lvds_pll_round_rate,
.set_rate = mpd4_lvds_pll_set_rate,
static const struct clk_ops mdp4_lvds_pll_ops = {
.enable = mdp4_lvds_pll_enable,
.disable = mdp4_lvds_pll_disable,
.recalc_rate = mdp4_lvds_pll_recalc_rate,
.determine_rate = mdp4_lvds_pll_determine_rate,
.set_rate = mdp4_lvds_pll_set_rate,
};
static const struct clk_parent_data mpd4_lvds_pll_parents[] = {
static const struct clk_parent_data mdp4_lvds_pll_parents[] = {
{ .fw_name = "pxo", .name = "pxo", },
};
static struct clk_init_data pll_init = {
.name = "mpd4_lvds_pll",
.ops = &mpd4_lvds_pll_ops,
.parent_data = mpd4_lvds_pll_parents,
.num_parents = ARRAY_SIZE(mpd4_lvds_pll_parents),
.name = "mdp4_lvds_pll",
.ops = &mdp4_lvds_pll_ops,
.parent_data = mdp4_lvds_pll_parents,
.num_parents = ARRAY_SIZE(mdp4_lvds_pll_parents),
};
static struct clk_hw *mpd4_lvds_pll_init(struct drm_device *dev)
static struct clk_hw *mdp4_lvds_pll_init(struct drm_device *dev)
{
struct mdp4_lvds_pll *lvds_pll;
int ret;
@ -156,14 +159,14 @@ static struct clk_hw *mpd4_lvds_pll_init(struct drm_device *dev)
return &lvds_pll->pll_hw;
}
struct clk *mpd4_get_lcdc_clock(struct drm_device *dev)
struct clk *mdp4_get_lcdc_clock(struct drm_device *dev)
{
struct clk_hw *hw;
struct clk *clk;
/* TODO: do we need different pll in other cases? */
hw = mpd4_lvds_pll_init(dev);
hw = mdp4_lvds_pll_init(dev);
if (IS_ERR(hw)) {
DRM_DEV_ERROR(dev->dev, "failed to register LVDS PLL\n");
return ERR_CAST(hw);

View file

@ -534,7 +534,7 @@ static int mdp5_kms_init(struct drm_device *dev)
}
mdelay(16);
vm = msm_kms_init_vm(mdp5_kms->dev);
vm = msm_kms_init_vm(mdp5_kms->dev, pdev->dev.parent);
if (IS_ERR(vm)) {
ret = PTR_ERR(vm);
goto fail;

View file

@ -109,6 +109,7 @@ struct msm_dsi_phy {
struct msm_dsi_dphy_timing timing;
const struct msm_dsi_phy_cfg *cfg;
void *tuning_cfg;
void *pll_data;
enum msm_dsi_phy_usecase usecase;
bool regulator_ldo_mode;

View file

@ -444,21 +444,19 @@ static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw,
return (unsigned long)vco_rate;
}
static long dsi_pll_10nm_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate)
static int dsi_pll_10nm_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct dsi_pll_10nm *pll_10nm = to_pll_10nm(hw);
if (rate < pll_10nm->phy->cfg->min_pll_rate)
return pll_10nm->phy->cfg->min_pll_rate;
else if (rate > pll_10nm->phy->cfg->max_pll_rate)
return pll_10nm->phy->cfg->max_pll_rate;
else
return rate;
req->rate = clamp_t(unsigned long, req->rate,
pll_10nm->phy->cfg->min_pll_rate, pll_10nm->phy->cfg->max_pll_rate);
return 0;
}
static const struct clk_ops clk_ops_dsi_pll_10nm_vco = {
.round_rate = dsi_pll_10nm_clk_round_rate,
.determine_rate = dsi_pll_10nm_clk_determine_rate,
.set_rate = dsi_pll_10nm_vco_set_rate,
.recalc_rate = dsi_pll_10nm_vco_recalc_rate,
.prepare = dsi_pll_10nm_vco_prepare,

View file

@ -578,21 +578,19 @@ static void dsi_pll_14nm_vco_unprepare(struct clk_hw *hw)
pll_14nm->phy->pll_on = false;
}
static long dsi_pll_14nm_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate)
static int dsi_pll_14nm_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct dsi_pll_14nm *pll_14nm = to_pll_14nm(hw);
if (rate < pll_14nm->phy->cfg->min_pll_rate)
return pll_14nm->phy->cfg->min_pll_rate;
else if (rate > pll_14nm->phy->cfg->max_pll_rate)
return pll_14nm->phy->cfg->max_pll_rate;
else
return rate;
req->rate = clamp_t(unsigned long, req->rate,
pll_14nm->phy->cfg->min_pll_rate, pll_14nm->phy->cfg->max_pll_rate);
return 0;
}
static const struct clk_ops clk_ops_dsi_pll_14nm_vco = {
.round_rate = dsi_pll_14nm_clk_round_rate,
.determine_rate = dsi_pll_14nm_clk_determine_rate,
.set_rate = dsi_pll_14nm_vco_set_rate,
.recalc_rate = dsi_pll_14nm_vco_recalc_rate,
.prepare = dsi_pll_14nm_vco_prepare,
@ -622,18 +620,20 @@ static unsigned long dsi_pll_14nm_postdiv_recalc_rate(struct clk_hw *hw,
postdiv->flags, width);
}
static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *prate)
static int dsi_pll_14nm_postdiv_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw);
struct dsi_pll_14nm *pll_14nm = postdiv->pll;
DBG("DSI%d PLL parent rate=%lu", pll_14nm->phy->id, rate);
DBG("DSI%d PLL parent rate=%lu", pll_14nm->phy->id, req->rate);
return divider_round_rate(hw, rate, prate, NULL,
postdiv->width,
postdiv->flags);
req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate,
NULL,
postdiv->width,
postdiv->flags);
return 0;
}
static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
@ -680,7 +680,7 @@ static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_ops_dsi_pll_14nm_postdiv = {
.recalc_rate = dsi_pll_14nm_postdiv_recalc_rate,
.round_rate = dsi_pll_14nm_postdiv_round_rate,
.determine_rate = dsi_pll_14nm_postdiv_determine_rate,
.set_rate = dsi_pll_14nm_postdiv_set_rate,
};

View file

@ -533,21 +533,20 @@ static void dsi_pll_28nm_vco_unprepare(struct clk_hw *hw)
pll_28nm->phy->pll_on = false;
}
static long dsi_pll_28nm_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate)
static int dsi_pll_28nm_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
if (rate < pll_28nm->phy->cfg->min_pll_rate)
return pll_28nm->phy->cfg->min_pll_rate;
else if (rate > pll_28nm->phy->cfg->max_pll_rate)
return pll_28nm->phy->cfg->max_pll_rate;
else
return rate;
req->rate = clamp_t(unsigned long, req->rate,
pll_28nm->phy->cfg->min_pll_rate,
pll_28nm->phy->cfg->max_pll_rate);
return 0;
}
static const struct clk_ops clk_ops_dsi_pll_28nm_vco_hpm = {
.round_rate = dsi_pll_28nm_clk_round_rate,
.determine_rate = dsi_pll_28nm_clk_determine_rate,
.set_rate = dsi_pll_28nm_clk_set_rate,
.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
.prepare = dsi_pll_28nm_vco_prepare_hpm,
@ -556,7 +555,7 @@ static const struct clk_ops clk_ops_dsi_pll_28nm_vco_hpm = {
};
static const struct clk_ops clk_ops_dsi_pll_28nm_vco_lp = {
.round_rate = dsi_pll_28nm_clk_round_rate,
.determine_rate = dsi_pll_28nm_clk_determine_rate,
.set_rate = dsi_pll_28nm_clk_set_rate,
.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
.prepare = dsi_pll_28nm_vco_prepare_lp,
@ -565,7 +564,7 @@ static const struct clk_ops clk_ops_dsi_pll_28nm_vco_lp = {
};
static const struct clk_ops clk_ops_dsi_pll_28nm_vco_8226 = {
.round_rate = dsi_pll_28nm_clk_round_rate,
.determine_rate = dsi_pll_28nm_clk_determine_rate,
.set_rate = dsi_pll_28nm_clk_set_rate,
.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
.prepare = dsi_pll_28nm_vco_prepare_8226,

View file

@ -231,21 +231,19 @@ static void dsi_pll_28nm_vco_unprepare(struct clk_hw *hw)
pll_28nm->phy->pll_on = false;
}
static long dsi_pll_28nm_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate)
static int dsi_pll_28nm_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
if (rate < pll_28nm->phy->cfg->min_pll_rate)
return pll_28nm->phy->cfg->min_pll_rate;
else if (rate > pll_28nm->phy->cfg->max_pll_rate)
return pll_28nm->phy->cfg->max_pll_rate;
else
return rate;
req->rate = clamp_t(unsigned long, req->rate,
pll_28nm->phy->cfg->min_pll_rate, pll_28nm->phy->cfg->max_pll_rate);
return 0;
}
static const struct clk_ops clk_ops_dsi_pll_28nm_vco = {
.round_rate = dsi_pll_28nm_clk_round_rate,
.determine_rate = dsi_pll_28nm_clk_determine_rate,
.set_rate = dsi_pll_28nm_clk_set_rate,
.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
.prepare = dsi_pll_28nm_vco_prepare,
@ -296,18 +294,20 @@ static unsigned int get_vco_mul_factor(unsigned long byte_clk_rate)
return 8;
}
static long clk_bytediv_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
static int clk_bytediv_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
unsigned long best_parent;
unsigned int factor;
factor = get_vco_mul_factor(rate);
factor = get_vco_mul_factor(req->rate);
best_parent = rate * factor;
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
best_parent = req->rate * factor;
req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
return *prate / factor;
req->rate = req->best_parent_rate / factor;
return 0;
}
static int clk_bytediv_set_rate(struct clk_hw *hw, unsigned long rate,
@ -328,7 +328,7 @@ static int clk_bytediv_set_rate(struct clk_hw *hw, unsigned long rate,
/* Our special byte clock divider ops */
static const struct clk_ops clk_bytediv_ops = {
.round_rate = clk_bytediv_round_rate,
.determine_rate = clk_bytediv_determine_rate,
.set_rate = clk_bytediv_set_rate,
.recalc_rate = clk_bytediv_recalc_rate,
};

View file

@ -90,6 +90,13 @@ struct dsi_pll_7nm {
/* protects REG_DSI_7nm_PHY_CMN_CLK_CFG1 register */
spinlock_t pclk_mux_lock;
/*
* protects REG_DSI_7nm_PHY_CMN_CTRL_0 register and pll_enable_cnt
* member
*/
spinlock_t pll_enable_lock;
int pll_enable_cnt;
struct pll_7nm_cached_state cached_state;
struct dsi_pll_7nm *slave;
@ -103,6 +110,9 @@ struct dsi_pll_7nm {
*/
static struct dsi_pll_7nm *pll_7nm_list[DSI_MAX];
static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll);
static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll);
static void dsi_pll_setup_config(struct dsi_pll_config *config)
{
config->ssc_freq = 31500;
@ -340,6 +350,7 @@ static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
struct dsi_pll_config config;
dsi_pll_enable_pll_bias(pll_7nm);
DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_7nm->phy->id, rate,
parent_rate);
@ -357,6 +368,7 @@ static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
dsi_pll_ssc_commit(pll_7nm, &config);
dsi_pll_disable_pll_bias(pll_7nm);
/* flush, ensure all register writes are done*/
wmb();
@ -385,19 +397,47 @@ static int dsi_pll_7nm_lock_status(struct dsi_pll_7nm *pll)
static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll)
{
u32 data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
unsigned long flags;
u32 data;
spin_lock_irqsave(&pll->pll_enable_lock, flags);
--pll->pll_enable_cnt;
if (pll->pll_enable_cnt < 0) {
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
DRM_DEV_ERROR_RATELIMITED(&pll->phy->pdev->dev,
"bug: imbalance in disabling PLL bias\n");
return;
} else if (pll->pll_enable_cnt > 0) {
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
return;
} /* else: == 0 */
data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
data &= ~DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
writel(0, pll->phy->pll_base + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES);
writel(data & ~BIT(5), pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
writel(data, pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
ndelay(250);
}
static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll)
{
u32 data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
unsigned long flags;
u32 data;
spin_lock_irqsave(&pll->pll_enable_lock, flags);
if (pll->pll_enable_cnt++) {
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
WARN_ON(pll->pll_enable_cnt == INT_MAX);
return;
}
data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
data |= DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
writel(data, pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
writel(data | BIT(5), pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
writel(0xc0, pll->phy->pll_base + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES);
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
ndelay(250);
}
@ -491,6 +531,10 @@ static int dsi_pll_7nm_vco_prepare(struct clk_hw *hw)
if (pll_7nm->slave)
dsi_pll_enable_global_clk(pll_7nm->slave);
writel(0x1, pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_RBUF_CTRL);
if (pll_7nm->slave)
writel(0x1, pll_7nm->slave->phy->base + REG_DSI_7nm_PHY_CMN_RBUF_CTRL);
error:
return rc;
}
@ -534,6 +578,7 @@ static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw,
u32 dec;
u64 pll_freq, tmp64;
dsi_pll_enable_pll_bias(pll_7nm);
dec = readl(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1);
dec &= 0xff;
@ -558,24 +603,24 @@ static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw,
DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
pll_7nm->phy->id, (unsigned long)vco_rate, dec, frac);
dsi_pll_disable_pll_bias(pll_7nm);
return (unsigned long)vco_rate;
}
static long dsi_pll_7nm_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate)
static int dsi_pll_7nm_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
if (rate < pll_7nm->phy->cfg->min_pll_rate)
return pll_7nm->phy->cfg->min_pll_rate;
else if (rate > pll_7nm->phy->cfg->max_pll_rate)
return pll_7nm->phy->cfg->max_pll_rate;
else
return rate;
req->rate = clamp_t(unsigned long, req->rate,
pll_7nm->phy->cfg->min_pll_rate, pll_7nm->phy->cfg->max_pll_rate);
return 0;
}
static const struct clk_ops clk_ops_dsi_pll_7nm_vco = {
.round_rate = dsi_pll_7nm_clk_round_rate,
.determine_rate = dsi_pll_7nm_clk_determine_rate,
.set_rate = dsi_pll_7nm_vco_set_rate,
.recalc_rate = dsi_pll_7nm_vco_recalc_rate,
.prepare = dsi_pll_7nm_vco_prepare,
@ -593,6 +638,7 @@ static void dsi_7nm_pll_save_state(struct msm_dsi_phy *phy)
void __iomem *phy_base = pll_7nm->phy->base;
u32 cmn_clk_cfg0, cmn_clk_cfg1;
dsi_pll_enable_pll_bias(pll_7nm);
cached->pll_out_div = readl(pll_7nm->phy->pll_base +
REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE);
cached->pll_out_div &= 0x3;
@ -604,6 +650,7 @@ static void dsi_7nm_pll_save_state(struct msm_dsi_phy *phy)
cmn_clk_cfg1 = readl(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
cached->pll_mux = FIELD_GET(DSI_7nm_PHY_CMN_CLK_CFG1_DSICLK_SEL__MASK, cmn_clk_cfg1);
dsi_pll_disable_pll_bias(pll_7nm);
DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x",
pll_7nm->phy->id, cached->pll_out_div, cached->bit_clk_div,
cached->pix_clk_div, cached->pll_mux);
@ -826,8 +873,10 @@ static int dsi_pll_7nm_init(struct msm_dsi_phy *phy)
spin_lock_init(&pll_7nm->postdiv_lock);
spin_lock_init(&pll_7nm->pclk_mux_lock);
spin_lock_init(&pll_7nm->pll_enable_lock);
pll_7nm->phy = phy;
phy->pll_data = pll_7nm;
ret = pll_7nm_register(pll_7nm, phy->provided_clocks->hws);
if (ret) {
@ -839,6 +888,12 @@ static int dsi_pll_7nm_init(struct msm_dsi_phy *phy)
/* TODO: Remove this when we have proper display handover support */
msm_dsi_phy_pll_save_state(phy);
/*
* Store also proper vco_current_rate, because its value will be used in
* dsi_7nm_pll_restore_state().
*/
if (!dsi_pll_7nm_vco_recalc_rate(&pll_7nm->clk_hw, VCO_REF_CLK_RATE))
pll_7nm->vco_current_rate = pll_7nm->phy->cfg->min_pll_rate;
return 0;
}
@ -910,8 +965,10 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
u32 const delay_us = 5;
u32 const timeout_us = 1000;
struct msm_dsi_dphy_timing *timing = &phy->timing;
struct dsi_pll_7nm *pll = phy->pll_data;
void __iomem *base = phy->base;
bool less_than_1500_mhz;
unsigned long flags;
u32 vreg_ctrl_0, vreg_ctrl_1, lane_ctrl0;
u32 glbl_pemph_ctrl_0;
u32 glbl_str_swi_cal_sel_ctrl, glbl_hstx_str_ctrl_0;
@ -1033,9 +1090,13 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
glbl_rescode_bot_ctrl = 0x3c;
}
spin_lock_irqsave(&pll->pll_enable_lock, flags);
pll->pll_enable_cnt = 1;
/* de-assert digital and pll power down */
data = BIT(6) | BIT(5);
data = DSI_7nm_PHY_CMN_CTRL_0_DIGTOP_PWRDN_B |
DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
/* Assert PLL core reset */
writel(0x00, base + REG_DSI_7nm_PHY_CMN_PLL_CNTRL);
@ -1148,7 +1209,9 @@ static bool dsi_7nm_set_continuous_clock(struct msm_dsi_phy *phy, bool enable)
static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
{
struct dsi_pll_7nm *pll = phy->pll_data;
void __iomem *base = phy->base;
unsigned long flags;
u32 data;
DBG("");
@ -1175,8 +1238,12 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
writel(0, base + REG_DSI_7nm_PHY_CMN_LANE_CTRL0);
spin_lock_irqsave(&pll->pll_enable_lock, flags);
pll->pll_enable_cnt = 0;
/* Turn off all PHY blocks */
writel(0x00, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
/* make sure phy is turned off */
wmb();

View file

@ -629,16 +629,12 @@ static int hdmi_8996_pll_prepare(struct clk_hw *hw)
return 0;
}
static long hdmi_8996_pll_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
static int hdmi_8996_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
if (rate < HDMI_PCLK_MIN_FREQ)
return HDMI_PCLK_MIN_FREQ;
else if (rate > HDMI_PCLK_MAX_FREQ)
return HDMI_PCLK_MAX_FREQ;
else
return rate;
req->rate = clamp_t(unsigned long, req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ);
return 0;
}
static unsigned long hdmi_8996_pll_recalc_rate(struct clk_hw *hw,
@ -684,7 +680,7 @@ static int hdmi_8996_pll_is_enabled(struct clk_hw *hw)
static const struct clk_ops hdmi_8996_pll_ops = {
.set_rate = hdmi_8996_pll_set_clk_rate,
.round_rate = hdmi_8996_pll_round_rate,
.determine_rate = hdmi_8996_pll_determine_rate,
.recalc_rate = hdmi_8996_pll_recalc_rate,
.prepare = hdmi_8996_pll_prepare,
.unprepare = hdmi_8996_pll_unprepare,

View file

@ -646,16 +646,12 @@ static int hdmi_8998_pll_prepare(struct clk_hw *hw)
return 0;
}
static long hdmi_8998_pll_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
static int hdmi_8998_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
if (rate < HDMI_PCLK_MIN_FREQ)
return HDMI_PCLK_MIN_FREQ;
else if (rate > HDMI_PCLK_MAX_FREQ)
return HDMI_PCLK_MAX_FREQ;
else
return rate;
req->rate = clamp_t(unsigned long, req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ);
return 0;
}
static unsigned long hdmi_8998_pll_recalc_rate(struct clk_hw *hw,
@ -688,7 +684,7 @@ static int hdmi_8998_pll_is_enabled(struct clk_hw *hw)
static const struct clk_ops hdmi_8998_pll_ops = {
.set_rate = hdmi_8998_pll_set_clk_rate,
.round_rate = hdmi_8998_pll_round_rate,
.determine_rate = hdmi_8998_pll_determine_rate,
.recalc_rate = hdmi_8998_pll_recalc_rate,
.prepare = hdmi_8998_pll_prepare,
.unprepare = hdmi_8998_pll_unprepare,

View file

@ -373,12 +373,14 @@ static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw,
return pll->pixclk;
}
static long hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
static int hdmi_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
const struct pll_rate *pll_rate = find_rate(rate);
const struct pll_rate *pll_rate = find_rate(req->rate);
return pll_rate->rate;
req->rate = pll_rate->rate;
return 0;
}
static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
@ -402,7 +404,7 @@ static const struct clk_ops hdmi_pll_ops = {
.enable = hdmi_pll_enable,
.disable = hdmi_pll_disable,
.recalc_rate = hdmi_pll_recalc_rate,
.round_rate = hdmi_pll_round_rate,
.determine_rate = hdmi_pll_determine_rate,
.set_rate = hdmi_pll_set_rate,
};

View file

@ -826,6 +826,7 @@ static const struct file_operations fops = {
#define DRIVER_FEATURES_KMS ( \
DRIVER_GEM | \
DRIVER_GEM_GPUVA | \
DRIVER_ATOMIC | \
DRIVER_MODESET | \
0 )

View file

@ -229,7 +229,7 @@ void msm_crtc_disable_vblank(struct drm_crtc *crtc);
int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu);
struct drm_gpuvm *msm_kms_init_vm(struct drm_device *dev);
struct drm_gpuvm *msm_kms_init_vm(struct drm_device *dev, struct device *mdss_dev);
bool msm_use_mmu(struct drm_device *dev);
int msm_ioctl_gem_submit(struct drm_device *dev, void *data,

View file

@ -191,7 +191,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
if (!msm_obj->pages) {
struct drm_device *dev = obj->dev;
struct page **p;
int npages = obj->size >> PAGE_SHIFT;
size_t npages = obj->size >> PAGE_SHIFT;
p = drm_gem_get_pages(obj);
@ -1148,7 +1148,7 @@ static int msm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
/* convenience method to construct a GEM buffer object, and userspace handle */
int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
uint32_t size, uint32_t flags, uint32_t *handle,
size_t size, uint32_t flags, uint32_t *handle,
char *name)
{
struct drm_gem_object *obj;
@ -1214,9 +1214,8 @@ static const struct drm_gem_object_funcs msm_gem_object_funcs = {
.vm_ops = &vm_ops,
};
static int msm_gem_new_impl(struct drm_device *dev,
uint32_t size, uint32_t flags,
struct drm_gem_object **obj)
static int msm_gem_new_impl(struct drm_device *dev, uint32_t flags,
struct drm_gem_object **obj)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_object *msm_obj;
@ -1250,7 +1249,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
return 0;
}
struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32_t flags)
struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t flags)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_object *msm_obj;
@ -1265,7 +1264,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32
if (size == 0)
return ERR_PTR(-EINVAL);
ret = msm_gem_new_impl(dev, size, flags, &obj);
ret = msm_gem_new_impl(dev, flags, &obj);
if (ret)
return ERR_PTR(ret);
@ -1305,12 +1304,12 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_object *msm_obj;
struct drm_gem_object *obj;
uint32_t size;
int ret, npages;
size_t size, npages;
int ret;
size = PAGE_ALIGN(dmabuf->size);
ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
ret = msm_gem_new_impl(dev, MSM_BO_WC, &obj);
if (ret)
return ERR_PTR(ret);
@ -1353,7 +1352,7 @@ fail:
return ERR_PTR(ret);
}
void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size, uint32_t flags,
void *msm_gem_kernel_new(struct drm_device *dev, size_t size, uint32_t flags,
struct drm_gpuvm *vm, struct drm_gem_object **bo,
uint64_t *iova)
{

View file

@ -297,10 +297,10 @@ bool msm_gem_active(struct drm_gem_object *obj);
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout);
int msm_gem_cpu_fini(struct drm_gem_object *obj);
int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
uint32_t size, uint32_t flags, uint32_t *handle, char *name);
size_t size, uint32_t flags, uint32_t *handle, char *name);
struct drm_gem_object *msm_gem_new(struct drm_device *dev,
uint32_t size, uint32_t flags);
void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size, uint32_t flags,
size_t size, uint32_t flags);
void *msm_gem_kernel_new(struct drm_device *dev, size_t size, uint32_t flags,
struct drm_gpuvm *vm, struct drm_gem_object **bo,
uint64_t *iova);
void msm_gem_kernel_put(struct drm_gem_object *bo, struct drm_gpuvm *vm);

View file

@ -15,7 +15,7 @@
struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
int npages = obj->size >> PAGE_SHIFT;
size_t npages = obj->size >> PAGE_SHIFT;
if (msm_obj->flags & MSM_BO_NO_SHARE)
return ERR_PTR(-EINVAL);

View file

@ -1030,6 +1030,7 @@ vm_bind_job_lookup_ops(struct msm_vm_bind_job *job, struct drm_msm_vm_bind *args
struct drm_device *dev = job->vm->drm;
int ret = 0;
int cnt = 0;
int i = -1;
if (args->nr_ops == 1) {
/* Single op case, the op is inlined: */
@ -1063,11 +1064,12 @@ vm_bind_job_lookup_ops(struct msm_vm_bind_job *job, struct drm_msm_vm_bind *args
spin_lock(&file->table_lock);
for (unsigned i = 0; i < args->nr_ops; i++) {
for (i = 0; i < args->nr_ops; i++) {
struct msm_vm_bind_op *op = &job->ops[i];
struct drm_gem_object *obj;
if (!job->ops[i].handle) {
job->ops[i].obj = NULL;
if (!op->handle) {
op->obj = NULL;
continue;
}
@ -1075,16 +1077,22 @@ vm_bind_job_lookup_ops(struct msm_vm_bind_job *job, struct drm_msm_vm_bind *args
* normally use drm_gem_object_lookup(), but for bulk lookup
* all under single table_lock just hit object_idr directly:
*/
obj = idr_find(&file->object_idr, job->ops[i].handle);
obj = idr_find(&file->object_idr, op->handle);
if (!obj) {
ret = UERR(EINVAL, dev, "invalid handle %u at index %u\n", job->ops[i].handle, i);
ret = UERR(EINVAL, dev, "invalid handle %u at index %u\n", op->handle, i);
goto out_unlock;
}
drm_gem_object_get(obj);
job->ops[i].obj = obj;
op->obj = obj;
cnt++;
if ((op->range + op->obj_offset) > obj->size) {
ret = UERR(EINVAL, dev, "invalid range: %016llx + %016llx > %016zx\n",
op->range, op->obj_offset, obj->size);
goto out_unlock;
}
}
*nr_bos = cnt;
@ -1092,6 +1100,17 @@ vm_bind_job_lookup_ops(struct msm_vm_bind_job *job, struct drm_msm_vm_bind *args
out_unlock:
spin_unlock(&file->table_lock);
if (ret) {
for (; i >= 0; i--) {
struct msm_vm_bind_op *op = &job->ops[i];
if (!op->obj)
continue;
drm_gem_object_put(op->obj);
op->obj = NULL;
}
}
out:
return ret;
}

View file

@ -304,7 +304,7 @@ static void crashstate_get_bos(struct msm_gpu_state *state, struct msm_gem_submi
sizeof(struct msm_gpu_state_bo), GFP_KERNEL);
for (int i = 0; state->bos && i < submit->nr_bos; i++) {
struct drm_gem_object *obj = submit->bos[i].obj;;
struct drm_gem_object *obj = submit->bos[i].obj;
bool dump = rd_full || (submit->bos[i].flags & MSM_SUBMIT_BO_DUMP);
msm_gem_lock(obj);

View file

@ -16,6 +16,7 @@
#include "msm_drv.h"
#include "msm_fence.h"
#include "msm_gpu_trace.h"
#include "msm_ringbuffer.h"
#include "msm_gem.h"
@ -91,6 +92,7 @@ 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);
};
/* Additional state for iommu faults: */
@ -613,16 +615,19 @@ struct msm_gpu_state {
static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data)
{
trace_msm_gpu_regaccess(reg);
writel(data, gpu->mmio + (reg << 2));
}
static inline u32 gpu_read(struct msm_gpu *gpu, u32 reg)
{
trace_msm_gpu_regaccess(reg);
return readl(gpu->mmio + (reg << 2));
}
static inline void gpu_rmw(struct msm_gpu *gpu, u32 reg, u32 mask, u32 or)
{
trace_msm_gpu_regaccess(reg);
msm_rmw(gpu->mmio + (reg << 2), mask, or);
}
@ -644,7 +649,9 @@ static inline u64 gpu_read64(struct msm_gpu *gpu, u32 reg)
* when the lo is read, so make sure to read the lo first to trigger
* that
*/
trace_msm_gpu_regaccess(reg);
val = (u64) readl(gpu->mmio + (reg << 2));
trace_msm_gpu_regaccess(reg+1);
val |= ((u64) readl(gpu->mmio + ((reg + 1) << 2)) << 32);
return val;
@ -652,8 +659,10 @@ static inline u64 gpu_read64(struct msm_gpu *gpu, u32 reg)
static inline void gpu_write64(struct msm_gpu *gpu, u32 reg, u64 val)
{
trace_msm_gpu_regaccess(reg);
/* Why not a writeq here? Read the screed above */
writel(lower_32_bits(val), gpu->mmio + (reg << 2));
trace_msm_gpu_regaccess(reg+1);
writel(upper_32_bits(val), gpu->mmio + ((reg + 1) << 2));
}

View file

@ -219,6 +219,18 @@ TRACE_EVENT(msm_mmu_prealloc_cleanup,
TP_printk("count=%u, remaining=%u", __entry->count, __entry->remaining)
);
TRACE_EVENT(msm_gpu_regaccess,
TP_PROTO(u32 offset),
TP_ARGS(offset),
TP_STRUCT__entry(
__field(u32, offset)
),
TP_fast_assign(
__entry->offset = offset;
),
TP_printk("offset=0x%x", __entry->offset)
);
#endif
#undef TRACE_INCLUDE_PATH

View file

@ -721,7 +721,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks)
int ret;
if (!device_iommu_mapped(dev))
return NULL;
return ERR_PTR(-ENODEV);
domain = iommu_paging_domain_alloc(dev);
if (IS_ERR(domain))
@ -756,7 +756,7 @@ struct msm_mmu *msm_iommu_disp_new(struct device *dev, unsigned long quirks)
struct msm_mmu *mmu;
mmu = msm_iommu_new(dev, quirks);
if (IS_ERR_OR_NULL(mmu))
if (IS_ERR(mmu))
return mmu;
iommu = to_msm_iommu(mmu);
@ -772,11 +772,11 @@ struct msm_mmu *msm_iommu_gpu_new(struct device *dev, struct msm_gpu *gpu, unsig
struct msm_mmu *mmu;
mmu = msm_iommu_new(dev, quirks);
if (IS_ERR_OR_NULL(mmu))
if (IS_ERR(mmu))
return mmu;
iommu = to_msm_iommu(mmu);
if (adreno_smmu && adreno_smmu->cookie) {
if (adreno_smmu->cookie) {
const struct io_pgtable_cfg *cfg =
adreno_smmu->get_ttbr1_cfg(adreno_smmu->cookie);
size_t tblsz = get_tblsz(cfg);

View file

@ -177,12 +177,11 @@ static int msm_kms_fault_handler(void *arg, unsigned long iova, int flags, void
return -ENOSYS;
}
struct drm_gpuvm *msm_kms_init_vm(struct drm_device *dev)
struct drm_gpuvm *msm_kms_init_vm(struct drm_device *dev, struct device *mdss_dev)
{
struct drm_gpuvm *vm;
struct msm_mmu *mmu;
struct device *mdp_dev = dev->dev;
struct device *mdss_dev = mdp_dev->parent;
struct msm_drm_private *priv = dev->dev_private;
struct msm_kms *kms = priv->kms;
struct device *iommu_dev;
@ -193,18 +192,17 @@ struct drm_gpuvm *msm_kms_init_vm(struct drm_device *dev)
*/
if (device_iommu_mapped(mdp_dev))
iommu_dev = mdp_dev;
else
else if (mdss_dev && device_iommu_mapped(mdss_dev))
iommu_dev = mdss_dev;
else {
drm_info(dev, "no IOMMU, bailing out\n");
return ERR_PTR(-ENODEV);
}
mmu = msm_iommu_disp_new(iommu_dev, 0);
if (IS_ERR(mmu))
return ERR_CAST(mmu);
if (!mmu) {
drm_info(dev, "no IOMMU, fallback to phys contig buffers for scanout\n");
return NULL;
}
vm = msm_gem_vm_create(dev, mmu, "mdp_kms",
0x1000, 0x100000000 - 0x1000, true);
if (IS_ERR(vm)) {

View file

@ -154,8 +154,7 @@ static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss)
dev = msm_mdss->dev;
domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), 32,
&msm_mdss_irqdomain_ops, msm_mdss);
domain = irq_domain_create_linear(dev_fwnode(dev), 32, &msm_mdss_irqdomain_ops, msm_mdss);
if (!domain) {
dev_err(dev, "failed to add irq_domain\n");
return -EINVAL;

View file

@ -40,6 +40,10 @@ int msm_context_set_sysprof(struct msm_context *ctx, struct msm_gpu *gpu, int sy
break;
}
/* Some gpu families require additional setup for sysprof */
if (gpu->funcs->sysprof_setup)
gpu->funcs->sysprof_setup(gpu);
ctx->sysprof = sysprof;
return 0;

File diff suppressed because it is too large Load diff

View file

@ -9,38 +9,6 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<domain name="A6XX_TEX_SAMP" width="32">
<doc>Texture sampler dwords</doc>
<enum name="a6xx_tex_filter"> <!-- same as a4xx? -->
<value name="A6XX_TEX_NEAREST" value="0"/>
<value name="A6XX_TEX_LINEAR" value="1"/>
<value name="A6XX_TEX_ANISO" value="2"/>
<value name="A6XX_TEX_CUBIC" value="3"/> <!-- a650 only -->
</enum>
<enum name="a6xx_tex_clamp"> <!-- same as a4xx? -->
<value name="A6XX_TEX_REPEAT" value="0"/>
<value name="A6XX_TEX_CLAMP_TO_EDGE" value="1"/>
<value name="A6XX_TEX_MIRROR_REPEAT" value="2"/>
<value name="A6XX_TEX_CLAMP_TO_BORDER" value="3"/>
<value name="A6XX_TEX_MIRROR_CLAMP" value="4"/>
</enum>
<enum name="a6xx_tex_aniso"> <!-- same as a4xx? -->
<value name="A6XX_TEX_ANISO_1" value="0"/>
<value name="A6XX_TEX_ANISO_2" value="1"/>
<value name="A6XX_TEX_ANISO_4" value="2"/>
<value name="A6XX_TEX_ANISO_8" value="3"/>
<value name="A6XX_TEX_ANISO_16" value="4"/>
</enum>
<enum name="a6xx_reduction_mode">
<value name="A6XX_REDUCTION_MODE_AVERAGE" value="0"/>
<value name="A6XX_REDUCTION_MODE_MIN" value="1"/>
<value name="A6XX_REDUCTION_MODE_MAX" value="2"/>
</enum>
<enum name="a6xx_fast_border_color">
<!-- R B G A -->
<value name="A6XX_BORDER_COLOR_0_0_0_0" value="0"/>
<value name="A6XX_BORDER_COLOR_0_0_0_1" value="1"/>
<value name="A6XX_BORDER_COLOR_1_1_1_0" value="2"/>
<value name="A6XX_BORDER_COLOR_1_1_1_1" value="3"/>
</enum>
<reg32 offset="0" name="0">
<bitfield name="MIPFILTER_LINEAR_NEAR" pos="0" type="boolean"/>
@ -79,14 +47,6 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<domain name="A6XX_TEX_CONST" width="32" varset="chip">
<doc>Texture constant dwords</doc>
<enum name="a6xx_tex_swiz"> <!-- same as a4xx? -->
<value name="A6XX_TEX_X" value="0"/>
<value name="A6XX_TEX_Y" value="1"/>
<value name="A6XX_TEX_Z" value="2"/>
<value name="A6XX_TEX_W" value="3"/>
<value name="A6XX_TEX_ZERO" value="4"/>
<value name="A6XX_TEX_ONE" value="5"/>
</enum>
<reg32 offset="0" name="0">
<bitfield name="TILE_MODE" low="0" high="1" type="a6xx_tile_mode"/>
<bitfield name="SRGB" pos="2" type="boolean"/>

View file

@ -320,14 +320,14 @@ to upconvert to 32b float internally?
16b float: 3
-->
<enum name="a6xx_2d_ifmt">
<value value="0x10" name="R2D_UNORM8"/>
<value value="0x7" name="R2D_INT32"/>
<value value="0x6" name="R2D_INT16"/>
<value value="0x5" name="R2D_INT8"/>
<value value="0x4" name="R2D_FLOAT32"/>
<value value="0x3" name="R2D_FLOAT16"/>
<value value="0x2" name="R2D_SNORM8"/>
<value value="0x1" name="R2D_UNORM8_SRGB"/>
<value value="0x0" name="R2D_RAW"/>
<value value="0x0" name="R2D_UNORM8"/>
</enum>
<enum name="a6xx_tex_type">
@ -380,4 +380,50 @@ to upconvert to 32b float internally?
<value value="0x3" name="TESS_CCW_TRIS"/>
</enum>
<enum name="a6xx_tex_filter"> <!-- same as a4xx? -->
<value name="A6XX_TEX_NEAREST" value="0"/>
<value name="A6XX_TEX_LINEAR" value="1"/>
<value name="A6XX_TEX_ANISO" value="2"/>
<value name="A6XX_TEX_CUBIC" value="3"/> <!-- a650 only -->
</enum>
<enum name="a6xx_tex_clamp"> <!-- same as a4xx? -->
<value name="A6XX_TEX_REPEAT" value="0"/>
<value name="A6XX_TEX_CLAMP_TO_EDGE" value="1"/>
<value name="A6XX_TEX_MIRROR_REPEAT" value="2"/>
<value name="A6XX_TEX_CLAMP_TO_BORDER" value="3"/>
<value name="A6XX_TEX_MIRROR_CLAMP" value="4"/>
</enum>
<enum name="a6xx_tex_aniso"> <!-- same as a4xx? -->
<value name="A6XX_TEX_ANISO_1" value="0"/>
<value name="A6XX_TEX_ANISO_2" value="1"/>
<value name="A6XX_TEX_ANISO_4" value="2"/>
<value name="A6XX_TEX_ANISO_8" value="3"/>
<value name="A6XX_TEX_ANISO_16" value="4"/>
</enum>
<enum name="a6xx_reduction_mode">
<value name="A6XX_REDUCTION_MODE_AVERAGE" value="0"/>
<value name="A6XX_REDUCTION_MODE_MIN" value="1"/>
<value name="A6XX_REDUCTION_MODE_MAX" value="2"/>
</enum>
<enum name="a6xx_fast_border_color">
<!-- R B G A -->
<value name="A6XX_BORDER_COLOR_0_0_0_0" value="0"/>
<value name="A6XX_BORDER_COLOR_0_0_0_1" value="1"/>
<value name="A6XX_BORDER_COLOR_1_1_1_0" value="2"/>
<value name="A6XX_BORDER_COLOR_1_1_1_1" value="3"/>
</enum>
<enum name="a6xx_tex_swiz"> <!-- same as a4xx? -->
<value name="A6XX_TEX_X" value="0"/>
<value name="A6XX_TEX_Y" value="1"/>
<value name="A6XX_TEX_Z" value="2"/>
<value name="A6XX_TEX_W" value="3"/>
<value name="A6XX_TEX_ZERO" value="4"/>
<value name="A6XX_TEX_ONE" value="5"/>
</enum>
</database>

View file

@ -99,6 +99,10 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<bitfield name="GX_HM_GDSC_POWER_OFF" pos="6" type="boolean"/>
<bitfield name="GX_HM_CLK_OFF" pos="7" type="boolean"/>
</reg32>
<reg32 offset="0x50d0" name="GMU_SPTPRAC_PWR_CLK_STATUS" variants="A7XX">
<bitfield name="GX_HM_GDSC_POWER_OFF" pos="0" type="boolean"/>
<bitfield name="GX_HM_CLK_OFF" pos="1" type="boolean"/>
</reg32>
<reg32 offset="0x50e4" name="GMU_GPU_NAP_CTRL">
<bitfield name="HW_NAP_ENABLE" pos="0"/>
<bitfield name="SID" low="4" high="8"/>
@ -127,6 +131,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x5088" name="GMU_ALWAYS_ON_COUNTER_L"/>
<reg32 offset="0x5089" name="GMU_ALWAYS_ON_COUNTER_H"/>
<reg32 offset="0x50c3" name="GMU_GMU_PWR_COL_KEEPALIVE"/>
<reg32 offset="0x50c4" name="GMU_PWR_COL_PREEMPT_KEEPALIVE"/>
<reg32 offset="0x5180" name="GMU_HFI_CTRL_STATUS"/>
<reg32 offset="0x5181" name="GMU_HFI_VERSION_INFO"/>
<reg32 offset="0x5182" name="GMU_HFI_SFR_ADDR"/>
@ -228,6 +233,12 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x03ee" name="RSCC_TCS1_DRV0_STATUS"/>
<reg32 offset="0x0496" name="RSCC_TCS2_DRV0_STATUS"/>
<reg32 offset="0x053e" name="RSCC_TCS3_DRV0_STATUS"/>
<reg32 offset="0x05e6" name="RSCC_TCS4_DRV0_STATUS" variants="A7XX"/>
<reg32 offset="0x068e" name="RSCC_TCS5_DRV0_STATUS" variants="A7XX"/>
<reg32 offset="0x0736" name="RSCC_TCS6_DRV0_STATUS" variants="A7XX"/>
<reg32 offset="0x07de" name="RSCC_TCS7_DRV0_STATUS" variants="A7XX"/>
<reg32 offset="0x0886" name="RSCC_TCS8_DRV0_STATUS" variants="A7XX"/>
<reg32 offset="0x092e" name="RSCC_TCS9_DRV0_STATUS" variants="A7XX"/>
</domain>
</database>

View file

@ -120,12 +120,12 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<value name="LRZ_FLUSH" value="38" variants="A5XX-"/>
<value name="BLIT_OP_FILL_2D" value="39" variants="A5XX-"/>
<value name="BLIT_OP_COPY_2D" value="40" variants="A5XX-A6XX"/>
<value name="UNK_40" value="40" variants="A7XX"/>
<value name="LRZ_CACHE_INVALIDATE" value="40" variants="A7XX"/>
<value name="LRZ_Q_CACHE_INVALIDATE" value="41" variants="A7XX"/>
<value name="BLIT_OP_SCALE_2D" value="42" variants="A5XX-"/>
<value name="CONTEXT_DONE_2D" value="43" variants="A5XX-"/>
<value name="UNK_2C" value="44" variants="A5XX-"/>
<value name="UNK_2D" value="45" variants="A5XX-"/>
<value name="VSC_BINNING_START" value="44" variants="A5XX-"/>
<value name="VSC_BINNING_END" value="45" variants="A5XX-"/>
<!-- a6xx events -->
<doc>
@ -523,7 +523,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<!--
Seems to set the mode flags which control which CP_SET_DRAW_STATE
packets are executed, based on their ENABLE_MASK values
CP_SET_MODE w/ payload of 0x1 seems to cause CP_SET_DRAW_STATE
packets w/ ENABLE_MASK & 0x6 to execute immediately
-->
@ -640,8 +640,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<value name="CP_BV_BR_COUNT_OPS" value="0x1b" variants="A7XX-"/>
<doc> Clears, adds to local, or adds to global timestamp </doc>
<value name="CP_MODIFY_TIMESTAMP" value="0x1c" variants="A7XX-"/>
<!-- similar to CP_CONTEXT_REG_BUNCH, but discards first two dwords?? -->
<value name="CP_CONTEXT_REG_BUNCH2" value="0x5d" variants="A7XX-"/>
<value name="CP_NON_CONTEXT_REG_BUNCH" value="0x5d" variants="A7XX-"/>
<doc>
Write to a scratch memory that is read by CP_REG_TEST with
SOURCE_SCRATCH_MEM set. It's not the same scratch as scratch registers.
@ -918,12 +917,6 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
</reg32>
<stripe varset="chip" variants="A5XX-">
<reg32 offset="4" name="4">
<bitfield name="INDX_BASE_LO" low="0" high="31"/>
</reg32>
<reg32 offset="5" name="5">
<bitfield name="INDX_BASE_HI" low="0" high="31"/>
</reg32>
<reg64 offset="4" name="INDX_BASE" type="address"/>
<reg32 offset="6" name="6">
<!-- max # of elements in index buffer -->
@ -1099,8 +1092,10 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<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"/>
<bitfield name="GROUP_ID" low="24" high="28" type="uint"/>
<!-- high bit is 28 until a750: -->
<bitfield name="GROUP_ID" low="24" high="29" type="uint"/>
</reg32>
<reg64 offset="1" name="ADDR" type="address"/>
<reg32 offset="1" name="1">
<bitfield name="ADDR_LO" low="0" high="31" type="hex"/>
</reg32>
@ -1166,26 +1161,11 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
</reg32>
<stripe varset="a7xx_abs_mask_mode" variants="NO_ABS_MASK">
<!-- BIN_DATA_ADDR -> VSC_PIPE[p].DATA_ADDRESS -->
<reg32 offset="1" name="1">
<bitfield name="BIN_DATA_ADDR_LO" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="BIN_DATA_ADDR_HI" low="0" high="31" type="hex"/>
</reg32>
<reg64 offset="1" name="BIN_DATA_ADDR" type="address"/>
<!-- BIN_SIZE_ADDRESS -> VSC_SIZE_ADDRESS + (p * 4)-->
<reg32 offset="3" name="3">
<bitfield name="BIN_SIZE_ADDRESS_LO" low="0" high="31"/>
</reg32>
<reg32 offset="4" name="4">
<bitfield name="BIN_SIZE_ADDRESS_HI" low="0" high="31"/>
</reg32>
<reg64 offset="3" name="BIN_SIZE_ADDR" type="address"/>
<!-- new on a6xx, where BIN_DATA_ADDR is the DRAW_STRM: -->
<reg32 offset="5" name="5">
<bitfield name="BIN_PRIM_STRM_LO" low="0" high="31"/>
</reg32>
<reg32 offset="6" name="6">
<bitfield name="BIN_PRIM_STRM_HI" low="0" high="31"/>
</reg32>
<reg64 offset="5" name="BIN_PRIM_STRM" type="address"/>
<!--
a7xx adds a few more addresses to the end of the pkt
-->
@ -1195,26 +1175,11 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<stripe varset="a7xx_abs_mask_mode" variants="ABS_MASK">
<reg32 offset="1" name="ABS_MASK"/>
<!-- BIN_DATA_ADDR -> VSC_PIPE[p].DATA_ADDRESS -->
<reg32 offset="2" name="2">
<bitfield name="BIN_DATA_ADDR_LO" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="3" name="3">
<bitfield name="BIN_DATA_ADDR_HI" low="0" high="31" type="hex"/>
</reg32>
<reg64 offset="2" name="BIN_DATA_ADDR" type="address"/>
<!-- BIN_SIZE_ADDRESS -> VSC_SIZE_ADDRESS + (p * 4)-->
<reg32 offset="4" name="4">
<bitfield name="BIN_SIZE_ADDRESS_LO" low="0" high="31"/>
</reg32>
<reg32 offset="5" name="5">
<bitfield name="BIN_SIZE_ADDRESS_HI" low="0" high="31"/>
</reg32>
<reg64 offset="4" name="BIN_SIZE_ADDR" type="address"/>
<!-- new on a6xx, where BIN_DATA_ADDR is the DRAW_STRM: -->
<reg32 offset="6" name="6">
<bitfield name="BIN_PRIM_STRM_LO" low="0" high="31"/>
</reg32>
<reg32 offset="7" name="7">
<bitfield name="BIN_PRIM_STRM_HI" low="0" high="31"/>
</reg32>
<reg64 offset="6" name="BIN_PRIM_STRM" type="address"/>
<!--
a7xx adds a few more addresses to the end of the pkt
-->
@ -1300,7 +1265,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
</reg32>
</domain>
<domain name="CP_REG_TO_MEM" width="32">
<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). -->
@ -1308,12 +1273,12 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<bitfield name="64B" pos="30" type="boolean"/>
<bitfield name="ACCUMULATE" pos="31" type="boolean"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="DEST" low="0" high="31"/>
</reg32>
<reg32 offset="2" name="2" varset="chip" variants="A5XX-">
<bitfield name="DEST_HI" low="0" high="31"/>
</reg32>
<stripe varset="chip" variants="A2XX-A4XX">
<reg32 offset="1" name="DEST" type="address"/>
</stripe>
<stripe varset="chip" variants="A5XX-">
<reg64 offset="1" name="DEST" type="address"/>
</stripe>
</domain>
<domain name="CP_REG_TO_MEM_OFFSET_REG" width="32">
@ -1329,12 +1294,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<bitfield name="64B" pos="30" type="boolean"/>
<bitfield name="ACCUMULATE" pos="31" type="boolean"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="DEST" low="0" high="31"/>
</reg32>
<reg32 offset="2" name="2" varset="chip" variants="A5XX-">
<bitfield name="DEST_HI" low="0" high="31"/>
</reg32>
<reg64 offset="1" name="DEST" type="waddress"/>
<reg32 offset="3" name="3">
<bitfield name="OFFSET0" low="0" high="17" type="hex"/>
<bitfield name="OFFSET0_SCRATCH" pos="19" type="boolean"/>
@ -1354,18 +1314,8 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<bitfield name="64B" pos="30" type="boolean"/>
<bitfield name="ACCUMULATE" pos="31" type="boolean"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="DEST" low="0" high="31"/>
</reg32>
<reg32 offset="2" name="2" varset="chip" variants="A5XX-">
<bitfield name="DEST_HI" low="0" high="31"/>
</reg32>
<reg32 offset="3" name="3">
<bitfield name="OFFSET_LO" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="4" name="4">
<bitfield name="OFFSET_HI" low="0" high="31" type="hex"/>
</reg32>
<reg64 offset="1" name="DEST" type="waddress"/>
<reg64 offset="3" name="OFFSET" type="waddress"/>
</domain>
<domain name="CP_MEM_TO_REG" width="32">
@ -1378,12 +1328,12 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<!-- does the same thing as CP_MEM_TO_MEM::UNK31 -->
<bitfield name="UNK31" pos="31" type="boolean"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="SRC" low="0" high="31"/>
</reg32>
<reg32 offset="2" name="2" varset="chip" variants="A5XX-">
<bitfield name="SRC_HI" low="0" high="31"/>
</reg32>
<stripe varset="chip" variants="A2XX-A4XX">
<reg32 offset="1" name="SRC" type="address"/>
</stripe>
<stripe varset="chip" variants="A5XX-">
<reg64 offset="1" name="SRC" type="address"/>
</stripe>
</domain>
<domain name="CP_MEM_TO_MEM" width="32">
@ -1403,6 +1353,10 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<!-- some other kind of wait -->
<bitfield name="UNK31" pos="31" type="boolean"/>
</reg32>
<reg64 offset="1" name="DST" type="waddress"/>
<reg64 offset="3" name="SRC_A" type="address"/>
<reg64 offset="5" name="SRC_B" type="address"/>
<reg64 offset="7" name="SRC_C" type="address"/>
<!--
followed by sequence of addresses.. the first is the
destination and the rest are N src addresses which are
@ -1461,12 +1415,12 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
</domain>
<domain name="CP_MEM_WRITE" width="32">
<reg32 offset="0" name="0">
<bitfield name="ADDR_LO" low="0" high="31"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="ADDR_HI" low="0" high="31"/>
</reg32>
<stripe varset="chip" variants="A2XX-A4XX">
<reg32 offset="0" name="ADDR" type="address"/>
</stripe>
<stripe varset="chip" variants="A5XX-">
<reg64 offset="0" name="ADDR" type="address"/>
</stripe>
<!-- followed by the DWORDs to write -->
</domain>
@ -1518,24 +1472,14 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<bitfield name="POLL" low="4" high="5" type="poll_memory_type"/>
<bitfield name="WRITE_MEMORY" pos="8" type="boolean"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="POLL_ADDR_LO" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="POLL_ADDR_HI" low="0" high="31" type="hex"/>
</reg32>
<reg64 offset="1" name="POLL_ADDR" type="address"/>
<reg32 offset="3" name="3">
<bitfield name="REF" low="0" high="31"/>
</reg32>
<reg32 offset="4" name="4">
<bitfield name="MASK" low="0" high="31"/>
</reg32>
<reg32 offset="5" name="5">
<bitfield name="WRITE_ADDR_LO" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="6" name="6">
<bitfield name="WRITE_ADDR_HI" low="0" high="31" type="hex"/>
</reg32>
<reg64 offset="5" name="WRITE_ADDR" type="waddress"/>
<reg32 offset="7" name="7">
<bitfield name="WRITE_DATA" low="0" high="31"/>
</reg32>
@ -1550,12 +1494,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<!-- Reserved for flags, presumably? Unused in FW -->
<bitfield name="RESERVED" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="POLL_ADDR_LO" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="POLL_ADDR_HI" low="0" high="31" type="hex"/>
</reg32>
<reg64 offset="1" name="POLL_ADDR" type="address"/>
<reg32 offset="3" name="3">
<bitfield name="REF" low="0" high="31"/>
</reg32>
@ -1573,12 +1512,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<bitfield name="POLL" low="4" high="5" type="poll_memory_type"/>
<bitfield name="WRITE_MEMORY" pos="8" type="boolean"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="POLL_ADDR_LO" low="0" high="31" type="hex"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="POLL_ADDR_HI" low="0" high="31" type="hex"/>
</reg32>
<reg64 offset="1" name="POLL_ADDR" type="address"/>
<reg32 offset="3" name="3">
<bitfield name="REF" low="0" high="31"/>
</reg32>
@ -1712,12 +1646,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
TODO what is gpuaddr for, seems to be all 0's.. maybe needed for
context switch?
-->
<reg32 offset="1" name="1">
<bitfield name="ADDR_0_LO" low="0" high="31"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="ADDR_0_HI" low="0" high="31"/>
</reg32>
<reg64 offset="1" name="ADDR" type="waddress"/>
<reg32 offset="3" name="3">
<!-- ??? -->
</reg32>
@ -1832,9 +1761,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
<reg32 offset="0" name="0">
</reg32>
<stripe varset="chip" variants="A4XX">
<reg32 offset="1" name="1">
<bitfield name="ADDR" low="0" high="31"/>
</reg32>
<reg32 offset="1" name="ADDR" type="address"/>
<reg32 offset="2" name="2">
<!-- localsize is value minus one: -->
<bitfield name="LOCALSIZEX" low="2" high="11" type="uint"/>
@ -1843,12 +1770,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
</reg32>
</stripe>
<stripe varset="chip" variants="A5XX-">
<reg32 offset="1" name="1">
<bitfield name="ADDR_LO" low="0" high="31"/>
</reg32>
<reg32 offset="2" name="2">
<bitfield name="ADDR_HI" low="0" high="31"/>
</reg32>
<reg64 offset="1" name="ADDR" type="address"/>
<reg32 offset="3" name="3">
<!-- localsize is value minus one: -->
<bitfield name="LOCALSIZEX" low="2" high="11" type="uint"/>
@ -2161,12 +2083,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
</doc>
</value>
</enum>
<reg32 offset="0" name="0">
<bitfield name="ADDR_LO" low="0" high="31"/>
</reg32>
<reg32 offset="1" name="1">
<bitfield name="ADDR_HI" low="0" high="31"/>
</reg32>
<reg64 offset="0" name="ADDR" type="address"/>
<reg32 offset="2" name="2">
<bitfield name="DWORDS" low="0" high="19" type="uint"/>
<bitfield name="TYPE" low="20" high="21" type="amble_type"/>

View file

@ -22,7 +22,16 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x00018" name="GLBL_CTRL"/>
<reg32 offset="0x0001c" name="RBUF_CTRL"/>
<reg32 offset="0x00020" name="VREG_CTRL_0"/>
<reg32 offset="0x00024" name="CTRL_0"/>
<reg32 offset="0x00024" name="CTRL_0">
<bitfield name="CLKSL_SHUTDOWNB" pos="7" type="boolean"/>
<bitfield name="DIGTOP_PWRDN_B" pos="6" type="boolean"/>
<bitfield name="PLL_SHUTDOWNB" pos="5" type="boolean"/>
<bitfield name="DLN3_SHUTDOWNB" pos="4" type="boolean"/>
<bitfield name="DLN2_SHUTDOWNB" pos="3" type="boolean"/>
<bitfield name="CLK_SHUTDOWNB" pos="2" type="boolean"/>
<bitfield name="DLN1_SHUTDOWNB" pos="1" type="boolean"/>
<bitfield name="DLN0_SHUTDOWNB" pos="0" type="boolean"/>
</reg32>
<reg32 offset="0x00028" name="CTRL_1"/>
<reg32 offset="0x0002c" name="CTRL_2"/>
<reg32 offset="0x00030" name="CTRL_3"/>

View file

@ -11,7 +11,6 @@ import collections
import argparse
import time
import datetime
import re
class Error(Exception):
def __init__(self, message):
@ -31,7 +30,7 @@ class Enum(object):
def names(self):
return [n for (n, value) in self.values]
def dump(self):
def dump(self, is_deprecated):
use_hex = False
for (name, value) in self.values:
if value > 0x1000:
@ -45,7 +44,7 @@ class Enum(object):
print("\t%s = %d," % (name, value))
print("};\n")
def dump_pack_struct(self):
def dump_pack_struct(self, is_deprecated):
pass
class Field(object):
@ -70,11 +69,11 @@ class Field(object):
raise parser.error("booleans should be 1 bit fields")
elif self.type == "float" and not (high - low == 31 or high - low == 15):
raise parser.error("floats should be 16 or 32 bit fields")
elif not self.type in builtin_types and not self.type in parser.enums:
elif self.type not in builtin_types and self.type not in parser.enums:
raise parser.error("unknown type '%s'" % self.type)
def ctype(self, var_name):
if self.type == None:
if self.type is None:
type = "uint32_t"
val = var_name
elif self.type == "boolean":
@ -124,7 +123,7 @@ def field_name(reg, f):
name = f.name.lower()
else:
# We hit this path when a reg is defined with no bitset fields, ie.
# <reg32 offset="0x88db" name="RB_BLIT_DST_ARRAY_PITCH" low="0" high="28" shr="6" type="uint"/>
# <reg32 offset="0x88db" name="RB_RESOLVE_SYSTEM_BUFFER_ARRAY_PITCH" low="0" high="28" shr="6" type="uint"/>
name = reg.name.lower()
if (name in [ "double", "float", "int" ]) or not (name[0].isalpha()):
@ -146,10 +145,23 @@ def indices_strides(indices):
"%s(i%d)" % (offset, idx)
for (idx, (ctype, stride, offset)) in enumerate(indices)])
def is_number(str):
try:
int(str)
return True
except ValueError:
return False
def sanitize_variant(variant):
if variant and "-" in variant:
return variant[:variant.index("-")]
return variant
class Bitset(object):
def __init__(self, name, template):
self.name = name
self.inline = False
self.reg = None
if template:
self.fields = template.fields[:]
else:
@ -175,11 +187,7 @@ class Bitset(object):
print("#endif\n")
print(" return (struct fd_reg_pair) {")
if reg.array:
print(" .reg = REG_%s(__i)," % reg.full_name)
else:
print(" .reg = REG_%s," % reg.full_name)
print(" .reg = (uint32_t)%s," % reg.reg_offset())
print(" .value =")
for f in self.fields:
if f.type in [ "address", "waddress" ]:
@ -204,7 +212,7 @@ class Bitset(object):
print(" };")
def dump_pack_struct(self, reg=None):
def dump_pack_struct(self, is_deprecated, reg=None):
if not reg:
return
@ -229,12 +237,15 @@ class Bitset(object):
tab_to(" uint32_t", "dword;")
print("};\n")
depcrstr = ""
if is_deprecated:
depcrstr = " FD_DEPRECATED"
if reg.array:
print("static inline struct fd_reg_pair\npack_%s(uint32_t __i, struct %s fields)\n{" %
(prefix, prefix))
print("static inline%s struct fd_reg_pair\npack_%s(uint32_t __i, struct %s fields)\n{" %
(depcrstr, prefix, prefix))
else:
print("static inline struct fd_reg_pair\npack_%s(struct %s fields)\n{" %
(prefix, prefix))
print("static inline%s struct fd_reg_pair\npack_%s(struct %s fields)\n{" %
(depcrstr, prefix, prefix))
self.dump_regpair_builder(reg)
@ -253,18 +264,23 @@ class Bitset(object):
(prefix, prefix, prefix, skip))
def dump(self, prefix=None):
if prefix == None:
def dump(self, is_deprecated, prefix=None):
if prefix is None:
prefix = self.name
if self.reg and self.reg.bit_size == 64:
print("static inline uint32_t %s_LO(uint32_t val)\n{" % prefix)
print("\treturn val;\n}")
print("static inline uint32_t %s_HI(uint32_t val)\n{" % prefix)
print("\treturn val;\n}")
for f in self.fields:
if f.name:
name = prefix + "_" + f.name
else:
name = prefix
if not f.name and f.low == 0 and f.shr == 0 and not f.type in ["float", "fixed", "ufixed"]:
if not f.name and f.low == 0 and f.shr == 0 and f.type not in ["float", "fixed", "ufixed"]:
pass
elif f.type == "boolean" or (f.type == None and f.low == f.high):
elif f.type == "boolean" or (f.type is None and f.low == f.high):
tab_to("#define %s" % name, "0x%08x" % (1 << f.low))
else:
tab_to("#define %s__MASK" % name, "0x%08x" % mask(f.low, f.high))
@ -286,6 +302,7 @@ class Array(object):
self.domain = domain
self.variant = variant
self.parent = parent
self.children = []
if self.parent:
self.name = self.parent.name + "_" + self.local_name
else:
@ -337,12 +354,15 @@ class Array(object):
offset += self.parent.total_offset()
return offset
def dump(self):
def dump(self, is_deprecated):
depcrstr = ""
if is_deprecated:
depcrstr = " FD_DEPRECATED"
proto = indices_varlist(self.indices())
strides = indices_strides(self.indices())
array_offset = self.total_offset()
if self.fixed_offsets:
print("static inline uint32_t __offset_%s(%s idx)" % (self.local_name, self.index_ctype()))
print("static inline%s uint32_t __offset_%s(%s idx)" % (depcrstr, self.local_name, self.index_ctype()))
print("{\n\tswitch (idx) {")
if self.index_type:
for val, offset in zip(self.index_type.names(), self.offsets):
@ -357,7 +377,7 @@ class Array(object):
else:
tab_to("#define REG_%s_%s(%s)" % (self.domain, self.name, proto), "(0x%08x + %s )\n" % (array_offset, strides))
def dump_pack_struct(self):
def dump_pack_struct(self, is_deprecated):
pass
def dump_regpair_builder(self):
@ -373,6 +393,7 @@ class Reg(object):
self.bit_size = bit_size
if array:
self.name = array.name + "_" + self.name
array.children.append(self)
self.full_name = self.domain + "_" + self.name
if "stride" in attrs:
self.stride = int(attrs["stride"], 0)
@ -397,25 +418,34 @@ class Reg(object):
else:
return self.offset
def dump(self):
def reg_offset(self):
if self.array:
offset = self.array.offset + self.offset
return "(0x%08x + 0x%x*__i)" % (offset, self.array.stride)
return "0x%08x" % self.offset
def dump(self, is_deprecated):
depcrstr = ""
if is_deprecated:
depcrstr = " FD_DEPRECATED "
proto = indices_prototype(self.indices())
strides = indices_strides(self.indices())
offset = self.total_offset()
if proto == '':
tab_to("#define REG_%s" % self.full_name, "0x%08x" % offset)
else:
print("static inline uint32_t REG_%s(%s) { return 0x%08x + %s; }" % (self.full_name, proto, offset, strides))
print("static inline%s uint32_t REG_%s(%s) { return 0x%08x + %s; }" % (depcrstr, self.full_name, proto, offset, strides))
if self.bitset.inline:
self.bitset.dump(self.full_name)
self.bitset.dump(is_deprecated, self.full_name)
print("")
def dump_pack_struct(self):
def dump_pack_struct(self, is_deprecated):
if self.bitset.inline:
self.bitset.dump_pack_struct(self)
self.bitset.dump_pack_struct(is_deprecated, self)
def dump_regpair_builder(self):
if self.bitset.inline:
self.bitset.dump_regpair_builder(self)
self.bitset.dump_regpair_builder(self)
def dump_py(self):
print("\tREG_%s = 0x%08x" % (self.full_name, self.offset))
@ -444,9 +474,6 @@ class Parser(object):
self.variants = set()
self.file = []
self.xml_files = []
self.copyright_year = None
self.authors = []
self.license = None
def error(self, message):
parser, filename = self.stack[-1]
@ -454,7 +481,7 @@ class Parser(object):
def prefix(self, variant=None):
if self.current_prefix_type == "variant" and variant:
return variant
return sanitize_variant(variant)
elif self.current_stripe:
return self.current_stripe + "_" + self.current_domain
elif self.current_prefix:
@ -500,15 +527,22 @@ class Parser(object):
return varset
def parse_variants(self, attrs):
if not "variants" in attrs:
if "variants" not in attrs:
return None
variant = attrs["variants"].split(",")[0]
if "-" in variant:
variant = variant[:variant.index("-")]
variant = attrs["variants"].split(",")[0]
varset = self.parse_varset(attrs)
assert varset.has_name(variant)
if "-" in variant:
# if we have a range, validate that both the start and end
# of the range are valid enums:
start = variant[:variant.index("-")]
end = variant[variant.index("-") + 1:]
assert varset.has_name(start)
if end != "":
assert varset.has_name(end)
else:
assert varset.has_name(variant)
return variant
@ -572,9 +606,6 @@ class Parser(object):
error_str = str(xmlschema.error_log.filter_from_errors()[0])
raise self.error("Schema validation failed for: " + filename + "\n" + error_str)
except ImportError as e:
if self.validate:
raise e
print("lxml not found, skipping validation", file=sys.stderr)
def do_parse(self, filename):
@ -620,6 +651,7 @@ class Parser(object):
self.current_reg = Reg(attrs, self.prefix(variant), self.current_array, bit_size)
self.current_reg.bitset = self.current_bitset
self.current_bitset.reg = self.current_reg
if len(self.stack) == 1:
self.file.append(self.current_reg)
@ -643,7 +675,7 @@ class Parser(object):
elif name == "domain":
self.current_domain = attrs["name"]
if "prefix" in attrs:
self.current_prefix = self.parse_variants(attrs)
self.current_prefix = sanitize_variant(self.parse_variants(attrs))
self.current_prefix_type = attrs["prefix"]
else:
self.current_prefix = None
@ -651,7 +683,7 @@ class Parser(object):
if "varset" in attrs:
self.current_varset = self.enums[attrs["varset"]]
elif name == "stripe":
self.current_stripe = self.parse_variants(attrs)
self.current_stripe = sanitize_variant(self.parse_variants(attrs))
elif name == "enum":
self.current_enum_value = 0
self.current_enum = Enum(attrs["name"])
@ -686,10 +718,6 @@ class Parser(object):
self.parse_field(attrs["name"], attrs)
elif name == "database":
self.do_validate(attrs["xsi:schemaLocation"])
elif name == "copyright":
self.copyright_year = attrs["year"]
elif name == "author":
self.authors.append(attrs["name"] + " <" + attrs["email"] + "> " + attrs["name"])
def end_element(self, name):
if name == "domain":
@ -703,11 +731,16 @@ class Parser(object):
elif name == "reg32":
self.current_reg = None
elif name == "array":
# if the array has no Reg children, push an implicit reg32:
if len(self.current_array.children) == 0:
attrs = {
"name": "REG",
"offset": "0",
}
self.parse_reg(attrs, 32)
self.current_array = self.current_array.parent
elif name == "enum":
self.current_enum = None
elif name == "license":
self.license = self.cdata
def character_data(self, data):
self.cdata += data
@ -720,10 +753,10 @@ class Parser(object):
if variants:
for variant, vreg in variants.items():
if reg == vreg:
d[(usage, variant)].append(reg)
d[(usage, sanitize_variant(variant))].append(reg)
else:
for variant in self.variants:
d[(usage, variant)].append(reg)
d[(usage, sanitize_variant(variant))].append(reg)
print("#ifdef __cplusplus")
@ -753,6 +786,9 @@ class Parser(object):
print("#endif")
def has_variants(self, reg):
return reg.name in self.variant_regs and not is_number(reg.name) and not is_number(reg.name[1:])
def dump(self):
enums = []
bitsets = []
@ -766,7 +802,7 @@ class Parser(object):
regs.append(e)
for e in enums + bitsets + regs:
e.dump()
e.dump(self.has_variants(e))
self.dump_reg_usages()
@ -782,8 +818,7 @@ class Parser(object):
def dump_reg_variants(self, regname, variants):
# Don't bother for things that only have a single variant:
if len(variants) == 1:
if is_number(regname) or is_number(regname[1:]):
return
print("#ifdef __cplusplus")
print("struct __%s {" % regname)
@ -834,11 +869,20 @@ class Parser(object):
xtravar = "__i, "
print("__%s(%sstruct __%s fields) {" % (regname, xtra, regname))
for variant in variants.keys():
print(" if (%s == %s) {" % (varenum.upper(), variant))
if "-" in variant:
start = variant[:variant.index("-")]
end = variant[variant.index("-") + 1:]
if end != "":
print(" if ((%s >= %s) && (%s <= %s)) {" % (varenum.upper(), start, varenum.upper(), end))
else:
print(" if (%s >= %s) {" % (varenum.upper(), start))
else:
print(" if (%s == %s) {" % (varenum.upper(), variant))
reg = variants[variant]
reg.dump_regpair_builder()
print(" } else")
print(" assert(!\"invalid variant\");")
print(" return (struct fd_reg_pair){};")
print("}")
if bit_size == 64:
@ -851,7 +895,7 @@ class Parser(object):
def dump_structs(self):
for e in self.file:
e.dump_pack_struct()
e.dump_pack_struct(self.has_variants(e))
for regname in self.variant_regs:
self.dump_reg_variants(regname, self.variant_regs[regname])
@ -868,33 +912,7 @@ def dump_c(args, guard, func):
print("#ifndef %s\n#define %s\n" % (guard, guard))
print("""/* Autogenerated file, DO NOT EDIT manually!
This file was generated by the rules-ng-ng gen_header.py tool in this git repository:
http://gitlab.freedesktop.org/mesa/mesa/
git clone https://gitlab.freedesktop.org/mesa/mesa.git
The rules-ng-ng source files this header was generated from are:
""")
maxlen = 0
for filepath in p.xml_files:
new_filepath = re.sub("^.+drivers","drivers",filepath)
maxlen = max(maxlen, len(new_filepath))
for filepath in p.xml_files:
pad = " " * (maxlen - len(new_filepath))
filesize = str(os.path.getsize(filepath))
filesize = " " * (7 - len(filesize)) + filesize
filetime = time.ctime(os.path.getmtime(filepath))
print("- " + new_filepath + pad + " (" + filesize + " bytes, from <stripped>)")
if p.copyright_year:
current_year = str(datetime.date.today().year)
print()
print("Copyright (C) %s-%s by the following authors:" % (p.copyright_year, current_year))
for author in p.authors:
print("- " + author)
if p.license:
print(p.license)
print("*/")
print("/* Autogenerated file, DO NOT EDIT manually! */")
print()
print("#ifdef __KERNEL__")
@ -912,9 +930,20 @@ The rules-ng-ng source files this header was generated from are:
print("#endif")
print()
print("#ifndef FD_NO_DEPRECATED_PACK")
print("#define FD_DEPRECATED __attribute__((deprecated))")
print("#else")
print("#define FD_DEPRECATED")
print("#endif")
print()
func(p)
print("\n#endif /* %s */" % guard)
print()
print("#undef FD_DEPRECATED")
print()
print("#endif /* %s */" % guard)
def dump_c_defines(args):
@ -931,7 +960,7 @@ def dump_py_defines(args):
p = Parser()
try:
p.parse(args.rnn, args.xml)
p.parse(args.rnn, args.xml, args.validate)
except Error as e:
print(e, file=sys.stderr)
exit(1)