diff options
419 files changed, 17120 insertions, 10980 deletions
diff --git a/Documentation/devicetree/bindings/display/connector/dvi-connector.txt b/Documentation/devicetree/bindings/display/connector/dvi-connector.txt index fc53f7c60bc6..207e42e9eba0 100644 --- a/Documentation/devicetree/bindings/display/connector/dvi-connector.txt +++ b/Documentation/devicetree/bindings/display/connector/dvi-connector.txt @@ -10,6 +10,7 @@ Optional properties: - analog: the connector has DVI analog pins - digital: the connector has DVI digital pins - dual-link: the connector has pins for DVI dual-link +- hpd-gpios: HPD GPIO number Required nodes: - Video port for DVI input diff --git a/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt index 05176f1ae108..8def11b16a24 100644 --- a/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt +++ b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt @@ -1,23 +1,3 @@ -Etnaviv DRM master device -========================= - -The Etnaviv DRM master device is a virtual device needed to list all -Vivante GPU cores that comprise the GPU subsystem. - -Required properties: -- compatible: Should be one of - "fsl,imx-gpu-subsystem" - "marvell,dove-gpu-subsystem" -- cores: Should contain a list of phandles pointing to Vivante GPU devices - -example: - -gpu-subsystem { - compatible = "fsl,imx-gpu-subsystem"; - cores = <&gpu_2d>, <&gpu_3d>; -}; - - Vivante GPU core devices ======================== @@ -32,7 +12,9 @@ Required properties: - clocks: should contain one clock for entry in clock-names see Documentation/devicetree/bindings/clock/clock-bindings.txt - clock-names: - - "bus": AXI/register clock + - "bus": AXI/master interface clock + - "reg": AHB/slave interface clock + (only required if GPU can gate slave interface independently) - "core": GPU core clock - "shader": Shader clock (only required if GPU has feature PIPE_3D) diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index a6671bd2c85a..518e9cdf0d4b 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -7,8 +7,6 @@ Required properties: - reg: Physical base address and length of the registers of controller - reg-names: The names of register regions. The following regions are required: * "dsi_ctrl" -- qcom,dsi-host-index: The ID of DSI controller hardware instance. This should - be 0 or 1, since we have 2 DSI controllers at most for now. - interrupts: The interrupt signal from the DSI block. - power-domains: Should be <&mmcc MDSS_GDSC>. - clocks: Phandles to device clocks. @@ -22,6 +20,8 @@ Required properties: * "core" For DSIv2, we need an additional clock: * "src" + For DSI6G v2.0 onwards, we need also need the clock: + * "byte_intf" - assigned-clocks: Parents of "byte" and "pixel" for the given platform. - assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided by a DSI PHY block. See [1] for details on clock bindings. @@ -88,21 +88,35 @@ Required properties: * "qcom,dsi-phy-28nm-lp" * "qcom,dsi-phy-20nm" * "qcom,dsi-phy-28nm-8960" -- reg: Physical base address and length of the registers of PLL, PHY and PHY - regulator + * "qcom,dsi-phy-14nm" + * "qcom,dsi-phy-10nm" +- reg: Physical base address and length of the registers of PLL, PHY. Some + revisions require the PHY regulator base address, whereas others require the + PHY lane base address. See below for each PHY revision. - reg-names: The names of register regions. The following regions are required: + For DSI 28nm HPM/LP/8960 PHYs and 20nm PHY: * "dsi_pll" * "dsi_phy" * "dsi_phy_regulator" + For DSI 14nm and 10nm PHYs: + * "dsi_pll" + * "dsi_phy" + * "dsi_phy_lane" - clock-cells: Must be 1. The DSI PHY block acts as a clock provider, creating 2 clocks: A byte clock (index 0), and a pixel clock (index 1). -- qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should - be 0 or 1, since we have 2 DSI PHYs at most for now. - power-domains: Should be <&mmcc MDSS_GDSC>. - clocks: Phandles to device clocks. See [1] for details on clock bindings. - clock-names: the following clocks are required: * "iface" + For 28nm HPM/LP, 28nm 8960 PHYs: +- vddio-supply: phandle to vdd-io regulator device node + For 20nm PHY: - vddio-supply: phandle to vdd-io regulator device node +- vcca-supply: phandle to vcca regulator device node + For 14nm PHY: +- vcca-supply: phandle to vcca regulator device node + For 10nm PHY: +- vdds-supply: phandle to vdds regulator device node Optional properties: - qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY diff --git a/Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt b/Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt new file mode 100644 index 000000000000..85626edf63e5 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt @@ -0,0 +1,12 @@ +AU Optronics Corporation 10.4" (800x600) color TFT LCD panel + +Required properties: +- compatible: should be "auo,g104sn02" +- power-supply: as specified in the base binding + +Optional properties: +- backlight: as specified in the base binding +- enable-gpios: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/display/panel/display-timing.txt b/Documentation/devicetree/bindings/display/panel/display-timing.txt index 58fa3e48481d..78222ced1874 100644 --- a/Documentation/devicetree/bindings/display/panel/display-timing.txt +++ b/Documentation/devicetree/bindings/display/panel/display-timing.txt @@ -80,6 +80,11 @@ The parameters are defined as: | | v | | | +----------+-------------------------------------+----------+-------+ +Note: In addition to being used as subnode(s) of display-timings, the timing + subnode may also be used on its own. This is appropriate if only one mode + need be conveyed. In this case, the node should be named 'panel-timing'. + + Example: display-timings { diff --git a/Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt b/Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt new file mode 100644 index 000000000000..6a036ede3e28 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt @@ -0,0 +1,25 @@ +Kaohsiung Opto-Electronics. TX31D200VM0BAA 12.3" HSXGA LVDS panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Required properties: +- compatible: should be "koe,tx31d200vm0baa" + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Optional nodes: +- Video port for LVDS panel input. + +Example: + panel { + compatible = "koe,tx31d200vm0baa"; + backlight = <&backlight_lvds>; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt index 6862028e7b2e..203b03eefb68 100644 --- a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt +++ b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt @@ -9,6 +9,7 @@ Required properties: Optional properties: - reset-gpios: a GPIO spec for the reset pin (active low). + - power-supply: phandle of the regulator that provides the supply voltage. Example: &dsi { @@ -17,5 +18,6 @@ Example: compatible = "orisetech,otm8009a"; reg = <0>; reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; + power-supply = <&v1v8>; }; }; diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt new file mode 100644 index 000000000000..cbb79ef3bfc9 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt @@ -0,0 +1,25 @@ +Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel + +The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD +panel connected using a MIPI-DSI video interface. + +Required properties: + - compatible: "raydium,rm68200" + - reg: the virtual channel number of a DSI peripheral + +Optional properties: + - reset-gpios: a GPIO spec for the reset pin (active low). + - power-supply: phandle of the regulator that provides the supply voltage. + - backlight: phandle of the backlight device attached to the panel. + +Example: +&dsi { + ... + panel@0 { + compatible = "raydium,rm68200"; + reg = <0>; + reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; + power-supply = <&v1v8>; + backlight = <&pwm_backlight>; + }; +}; diff --git a/Documentation/devicetree/bindings/display/panel/simple-panel.txt b/Documentation/devicetree/bindings/display/panel/simple-panel.txt index 16d8ff088b7d..45a457ad38f0 100644 --- a/Documentation/devicetree/bindings/display/panel/simple-panel.txt +++ b/Documentation/devicetree/bindings/display/panel/simple-panel.txt @@ -1,4 +1,8 @@ Simple display panel +==================== + +panel node +---------- Required properties: - power-supply: See panel-common.txt diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 8bdef4920edc..3346c1e2a7a0 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -146,13 +146,16 @@ Required properties: * allwinner,sun8i-a83t-tcon-lcd * allwinner,sun8i-a83t-tcon-tv * allwinner,sun8i-v3s-tcon + * allwinner,sun9i-a80-tcon-lcd + * allwinner,sun9i-a80-tcon-tv - reg: base address and size of memory-mapped region - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the TCON. - 'ahb': the interface clocks - - 'tcon-ch0': The clock driving the TCON channel 0, except for A83T TV TCON + - 'tcon-ch0': The clock driving the TCON channel 0, if supported - resets: phandles to the reset controllers driving the encoder - - "lcd": the reset line for the TCON channel 0 + - "lcd": the reset line for the TCON + - "edp": the reset line for the eDP block (A80 only) - clock-names: the clock names mentioned above - reset-names: the reset names mentioned above @@ -171,7 +174,9 @@ Required properties: channel the endpoint is associated to. If that property is not present, the endpoint number will be used as the channel number. -On SoCs other than the A33 and V3s, there is one more clock required: +For TCONs with channel 0, there is one more clock required: + - 'tcon-ch0': The clock driving the TCON channel 0 +For TCONs with channel 1, there is one more clock required: - 'tcon-ch1': The clock driving the TCON channel 1 When TCON support LVDS (all TCONs except TV TCON on A83T and those found @@ -186,7 +191,7 @@ DRC --- The DRC (Dynamic Range Controller), found in the latest Allwinner SoCs -(A31, A23, A33), allows to dynamically adjust pixel +(A31, A23, A33, A80), allows to dynamically adjust pixel brightness/contrast based on histogram measurements for LCD content adaptive backlight control. @@ -196,6 +201,7 @@ Required properties: * allwinner,sun6i-a31-drc * allwinner,sun6i-a31s-drc * allwinner,sun8i-a33-drc + * allwinner,sun9i-a80-drc - reg: base address and size of the memory-mapped region. - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the DRC @@ -222,6 +228,7 @@ Required properties: * allwinner,sun6i-a31-display-backend * allwinner,sun7i-a20-display-backend * allwinner,sun8i-a33-display-backend + * allwinner,sun9i-a80-display-backend - reg: base address and size of the memory-mapped region. - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the frontend and backend @@ -243,6 +250,28 @@ On the A33, some additional properties are required: - resets and reset-names need to have a phandle to the SAT bus resets, whose name will be "sat" +DEU +--- + +The DEU (Detail Enhancement Unit), found in the Allwinner A80 SoC, +can sharpen the display content in both luma and chroma channels. + +Required properties: + - compatible: value must be one of: + * allwinner,sun9i-a80-deu + - reg: base address and size of the memory-mapped region. + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the DEU + * ahb: the DEU interface clock + * mod: the DEU module clock + * ram: the DEU DRAM clock + - clock-names: the clock names mentioned above + - resets: phandles to the reset line driving the DEU + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoints, the second one the outputs + Display Engine Frontend ----------------------- @@ -256,6 +285,7 @@ Required properties: * allwinner,sun6i-a31-display-frontend * allwinner,sun7i-a20-display-frontend * allwinner,sun8i-a33-display-frontend + * allwinner,sun9i-a80-display-frontend - reg: base address and size of the memory-mapped region. - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the frontend and backend @@ -312,6 +342,7 @@ Required properties: * allwinner,sun8i-a83t-display-engine * allwinner,sun8i-h3-display-engine * allwinner,sun8i-v3s-display-engine + * allwinner,sun9i-a80-display-engine - allwinner,pipelines: list of phandle to the display engine frontends (DE 1.0) or mixers (DE 2.0) available. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ae850d6c0ad3..12e8b3e576b0 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -104,6 +104,7 @@ eeti eGalax_eMPIA Technology Inc elan Elan Microelectronic Corp. embest Shenzhen Embest Technology Co., Ltd. emmicro EM Microelectronic +emtrion emtrion GmbH energymicro Silicon Laboratories (formerly Energy Micro AS) engicam Engicam S.r.l. epcos EPCOS AG diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst new file mode 100644 index 000000000000..e8c84419a2a1 --- /dev/null +++ b/Documentation/gpu/drivers.rst @@ -0,0 +1,21 @@ +======================== +GPU Driver Documentation +======================== + +.. toctree:: + + i915 + meson + pl111 + tegra + tinydrm + tve200 + vc4 + bridge/dw-hdmi + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 56a3780e39b8..1dffd1ac4cd4 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -286,6 +286,9 @@ Atomic Mode Setting Function Reference .. kernel-doc:: drivers/gpu/drm/drm_atomic.c :export: +.. kernel-doc:: drivers/gpu/drm/drm_atomic.c + :internal: + CRTC Abstraction ================ diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index c36586dad29d..00288f34c5a6 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -10,16 +10,9 @@ Linux GPU Driver Developer's Guide drm-kms drm-kms-helpers drm-uapi - i915 - meson - pl111 - tegra - tinydrm - tve200 - vc4 + drivers vga-switcheroo vgaarbiter - bridge/dw-hdmi todo .. only:: subproject and html diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 8522c2ea1f3e..2ca2b5154d52 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -87,8 +87,7 @@ amdgpu-y += \ # add SMC block amdgpu-y += \ - amdgpu_dpm.o \ - amdgpu_powerplay.o + amdgpu_dpm.o # add DCE block amdgpu-y += \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index eba4abc8aac6..f44a83ab2bf4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -441,7 +441,7 @@ struct amdgpu_sa_bo { void amdgpu_gem_force_release(struct amdgpu_device *adev); int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size, int alignment, u32 initial_domain, - u64 flags, bool kernel, + u64 flags, enum ttm_bo_type type, struct reservation_object *resv, struct drm_gem_object **obj); @@ -1081,8 +1081,6 @@ struct amdgpu_wb { int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb); void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb); -void amdgpu_device_get_pcie_info(struct amdgpu_device *adev); - /* * SDMA */ @@ -1395,9 +1393,7 @@ enum amd_hw_ip_block_type { #define HWIP_MAX_INSTANCE 6 struct amd_powerplay { - struct cgs_device *cgs_device; void *pp_handle; - const struct amd_ip_funcs *ip_funcs; const struct amd_pm_funcs *pp_funcs; }; @@ -1632,6 +1628,9 @@ uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t acc_flags); void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags); +void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value); +uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset); + u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg); void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v); @@ -1655,6 +1654,9 @@ int emu_soc_asic_init(struct amdgpu_device *adev); #define RREG32_NO_KIQ(reg) amdgpu_mm_rreg(adev, (reg), AMDGPU_REGS_NO_KIQ) #define WREG32_NO_KIQ(reg, v) amdgpu_mm_wreg(adev, (reg), (v), AMDGPU_REGS_NO_KIQ) +#define RREG8(reg) amdgpu_mm_rreg8(adev, (reg)) +#define WREG8(reg, v) amdgpu_mm_wreg8(adev, (reg), (v)) + #define RREG32(reg) amdgpu_mm_rreg(adev, (reg), 0) #define RREG32_IDX(reg) amdgpu_mm_rreg(adev, (reg), AMDGPU_REGS_IDX) #define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", amdgpu_mm_rreg(adev, (reg), 0)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 8a23aa8f9c73..4d36203ffb11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -221,8 +221,9 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, uint64_t gpu_addr_tmp = 0; void *cpu_ptr_tmp = NULL; - r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_GTT, - AMDGPU_GEM_CREATE_CPU_GTT_USWC, NULL, NULL, &bo); + r = amdgpu_bo_create(adev, size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_CPU_GTT_USWC, ttm_bo_type_kernel, + NULL, &bo); if (r) { dev_err(adev->dev, "failed to allocate BO for amdkfd (%d)\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index e0371a9967b9..a12a1654e124 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -997,8 +997,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( pr_debug("\tcreate BO VA 0x%llx size 0x%llx domain %s\n", va, size, domain_string(alloc_domain)); - ret = amdgpu_bo_create(adev, size, byte_align, false, - alloc_domain, alloc_flags, NULL, NULL, &bo); + ret = amdgpu_bo_create(adev, size, byte_align, + alloc_domain, alloc_flags, ttm_bo_type_device, NULL, &bo); if (ret) { pr_debug("Failed to create BO on domain %s. ret %d\n", domain_string(alloc_domain), ret); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index ff8efd0f8fd5..a0f48cb9b8f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -114,6 +114,9 @@ union igp_info { struct atom_integrated_system_info_v1_11 v11; }; +union umc_info { + struct atom_umc_info_v3_1 v31; +}; /* * Return vram width from integrated system info table, if available, * or 0 if not. @@ -143,6 +146,94 @@ int amdgpu_atomfirmware_get_vram_width(struct amdgpu_device *adev) return 0; } +static int convert_atom_mem_type_to_vram_type (struct amdgpu_device *adev, + int atom_mem_type) +{ + int vram_type; + + if (adev->flags & AMD_IS_APU) { + switch (atom_mem_type) { + case Ddr2MemType: + case LpDdr2MemType: + vram_type = AMDGPU_VRAM_TYPE_DDR2; + break; + case Ddr3MemType: + case LpDdr3MemType: + vram_type = AMDGPU_VRAM_TYPE_DDR3; + break; + case Ddr4MemType: + case LpDdr4MemType: + vram_type = AMDGPU_VRAM_TYPE_DDR4; + break; + default: + vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; + break; + } + } else { + switch (atom_mem_type) { + case ATOM_DGPU_VRAM_TYPE_GDDR5: + vram_type = AMDGPU_VRAM_TYPE_GDDR5; + break; + case ATOM_DGPU_VRAM_TYPE_HBM: + vram_type = AMDGPU_VRAM_TYPE_HBM; + break; + default: + vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; + break; + } + } + + return vram_type; +} +/* + * Return vram type from either integrated system info table + * or umc info table, if available, or 0 (TYPE_UNKNOWN) if not + */ +int amdgpu_atomfirmware_get_vram_type(struct amdgpu_device *adev) +{ + struct amdgpu_mode_info *mode_info = &adev->mode_info; + int index; + u16 data_offset, size; + union igp_info *igp_info; + union umc_info *umc_info; + u8 frev, crev; + u8 mem_type; + + if (adev->flags & AMD_IS_APU) + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + integratedsysteminfo); + else + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + umc_info); + if (amdgpu_atom_parse_data_header(mode_info->atom_context, + index, &size, + &frev, &crev, &data_offset)) { + if (adev->flags & AMD_IS_APU) { + igp_info = (union igp_info *) + (mode_info->atom_context->bios + data_offset); + switch (crev) { + case 11: + mem_type = igp_info->v11.memorytype; + return convert_atom_mem_type_to_vram_type(adev, mem_type); + default: + return 0; + } + } else { + umc_info = (union umc_info *) + (mode_info->atom_context->bios + data_offset); + switch (crev) { + case 1: + mem_type = umc_info->v31.vram_type; + return convert_atom_mem_type_to_vram_type(adev, mem_type); + default: + return 0; + } + } + } + + return 0; +} + union firmware_info { struct atom_firmware_info_v3_1 v31; }; @@ -151,10 +242,6 @@ union smu_info { struct atom_smu_info_v3_1 v31; }; -union umc_info { - struct atom_umc_info_v3_1 v31; -}; - int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev) { struct amdgpu_mode_info *mode_info = &adev->mode_info; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h index 288b97e54347..7689c961c4ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h @@ -28,6 +28,7 @@ bool amdgpu_atomfirmware_gpu_supports_virtualization(struct amdgpu_device *adev) void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev); int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev); int amdgpu_atomfirmware_get_vram_width(struct amdgpu_device *adev); +int amdgpu_atomfirmware_get_vram_type(struct amdgpu_device *adev); int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c index 2fb299afc12b..02b849be083b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c @@ -80,8 +80,8 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, int time; n = AMDGPU_BENCHMARK_ITERATIONS; - r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, sdomain, 0, NULL, - NULL, &sobj); + r = amdgpu_bo_create(adev, size, PAGE_SIZE,sdomain, 0, + ttm_bo_type_kernel, NULL, &sobj); if (r) { goto out_cleanup; } @@ -93,8 +93,8 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, if (r) { goto out_cleanup; } - r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, ddomain, 0, NULL, - NULL, &dobj); + r = amdgpu_bo_create(adev, size, PAGE_SIZE, ddomain, 0, + ttm_bo_type_kernel, NULL, &dobj); if (r) { goto out_cleanup; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index f2dd98d3f5e6..37098c68a645 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -654,11 +654,6 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, else strcpy(fw_name, "amdgpu/vega10_smc.bin"); break; - case CHIP_CARRIZO: - case CHIP_STONEY: - case CHIP_RAVEN: - adev->pm.fw_version = info->version; - return 0; default: DRM_ERROR("SMC firmware not supported\n"); return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index ffc1f6f46913..9da8d5802980 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -69,25 +69,18 @@ void amdgpu_connector_hotplug(struct drm_connector *connector) /* don't do anything if sink is not display port, i.e., * passive dp->(dvi|hdmi) adaptor */ - if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { - int saved_dpms = connector->dpms; - /* Only turn off the display if it's physically disconnected */ - if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - } else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) { - /* Don't try to start link training before we - * have the dpcd */ - if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) - return; - - /* set it to OFF so that drm_helper_connector_dpms() - * won't return immediately since the current state - * is ON at this point. - */ - connector->dpms = DRM_MODE_DPMS_OFF; - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - } - connector->dpms = saved_dpms; + if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT && + amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd) && + amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) { + /* Don't start link training before we have the DPCD */ + if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) + return; + + /* Turn the connector off and back on immediately, which + * will trigger link training + */ + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 856378434ea2..690cf77b950e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -87,6 +87,8 @@ static const char *amdgpu_asic_name[] = { "LAST", }; +static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev); + bool amdgpu_device_is_px(struct drm_device *dev) { struct amdgpu_device *adev = dev->dev_private; @@ -121,6 +123,32 @@ uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg, return ret; } +/* + * MMIO register read with bytes helper functions + * @offset:bytes offset from MMIO start + * +*/ + +uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset) { + if (offset < adev->rmmio_size) + return (readb(adev->rmmio + offset)); + BUG(); +} + +/* + * MMIO register write with bytes helper functions + * @offset:bytes offset from MMIO start + * @value: the value want to be written to the register + * +*/ +void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value) { + if (offset < adev->rmmio_size) + writeb(value, adev->rmmio + offset); + else + BUG(); +} + + void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags) { @@ -830,6 +858,8 @@ static void amdgpu_device_check_arguments(struct amdgpu_device *adev) dev_warn(adev->dev, "lockup_timeout msut be > 0, adjusting to 10000\n"); amdgpu_lockup_timeout = 10000; } + + adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type); } /** @@ -1387,7 +1417,8 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) continue; /* skip CG for VCE/UVD, it's handled specially */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && - adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE) { + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && + adev->ip_blocks[i].version->funcs->set_clockgating_state) { /* enable clockgating to save power */ r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev, AMD_CG_STATE_GATE); @@ -1436,7 +1467,8 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.hw) continue; - if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) { + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC && + adev->ip_blocks[i].version->funcs->set_clockgating_state) { /* ungate blocks before hw fini so that we can shutdown the blocks safely */ r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev, AMD_CG_STATE_UNGATE); @@ -1545,7 +1577,8 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) if (!adev->ip_blocks[i].status.valid) continue; /* ungate blocks so that suspend can properly shut them down */ - if (i != AMD_IP_BLOCK_TYPE_SMC) { + if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_SMC && + adev->ip_blocks[i].version->funcs->set_clockgating_state) { r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev, AMD_CG_STATE_UNGATE); if (r) { @@ -1878,6 +1911,8 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (adev->rio_mem == NULL) DRM_INFO("PCI I/O BAR is not found.\n"); + amdgpu_device_get_pcie_info(adev); + /* early init functions */ r = amdgpu_device_ip_early_init(adev); if (r) @@ -2086,6 +2121,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_ib_pool_fini(adev); amdgpu_fence_driver_fini(adev); + amdgpu_pm_sysfs_fini(adev); amdgpu_fbdev_fini(adev); r = amdgpu_device_ip_fini(adev); if (adev->firmware.gpu_info_fw) { @@ -2114,7 +2150,6 @@ void amdgpu_device_fini(struct amdgpu_device *adev) iounmap(adev->rmmio); adev->rmmio = NULL; amdgpu_device_doorbell_fini(adev); - amdgpu_pm_sysfs_fini(adev); amdgpu_debugfs_regs_cleanup(adev); } @@ -2755,7 +2790,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, return r; } -void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) +static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) { u32 mask; int ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index e6709362994a..2337d4bfd85c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -738,7 +738,6 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(drm_dev); - vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); ret = amdgpu_device_suspend(drm_dev, false, false); pci_save_state(pdev); @@ -775,7 +774,6 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) ret = amdgpu_device_resume(drm_dev, false, false); drm_kms_helper_poll_enable(drm_dev); - vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 137145dd14a9..cf0f186c6092 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -113,11 +113,12 @@ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev) int r; if (adev->gart.robj == NULL) { - r = amdgpu_bo_create(adev, adev->gart.table_size, - PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, + r = amdgpu_bo_create(adev, adev->gart.table_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, &adev->gart.robj); + ttm_bo_type_kernel, NULL, + &adev->gart.robj); if (r) { return r; } @@ -315,7 +316,7 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, t = offset / AMDGPU_GPU_PAGE_SIZE; p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) - adev->gart.pages[p] = pagelist[i]; + adev->gart.pages[p] = pagelist ? pagelist[i] : NULL; #endif if (!adev->gart.ptr) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 55a840ae6d68..46b9ea4e6103 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -36,8 +36,6 @@ void amdgpu_gem_object_free(struct drm_gem_object *gobj) struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj); if (robj) { - if (robj->gem_base.import_attach) - drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg); amdgpu_mn_unregister(robj); amdgpu_bo_unref(&robj); } @@ -45,7 +43,7 @@ void amdgpu_gem_object_free(struct drm_gem_object *gobj) int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size, int alignment, u32 initial_domain, - u64 flags, bool kernel, + u64 flags, enum ttm_bo_type type, struct reservation_object *resv, struct drm_gem_object **obj) { @@ -59,8 +57,8 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size, } retry: - r = amdgpu_bo_create(adev, size, alignment, kernel, initial_domain, - flags, NULL, resv, &bo); + r = amdgpu_bo_create(adev, size, alignment, initial_domain, + flags, type, resv, &bo); if (r) { if (r != -ERESTARTSYS) { if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h index b8a7dba69595..0e01f115bbe5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h @@ -25,51 +25,12 @@ #define __AMDGPU_IH_H__ #include <linux/chash.h> +#include "soc15_ih_clientid.h" struct amdgpu_device; - /* - * vega10+ IH clients - */ -enum amdgpu_ih_clientid -{ - AMDGPU_IH_CLIENTID_IH = 0x00, - AMDGPU_IH_CLIENTID_ACP = 0x01, - AMDGPU_IH_CLIENTID_ATHUB = 0x02, - AMDGPU_IH_CLIENTID_BIF = 0x03, - AMDGPU_IH_CLIENTID_DCE = 0x04, - AMDGPU_IH_CLIENTID_ISP = 0x05, - AMDGPU_IH_CLIENTID_PCIE0 = 0x06, - AMDGPU_IH_CLIENTID_RLC = 0x07, - AMDGPU_IH_CLIENTID_SDMA0 = 0x08, - AMDGPU_IH_CLIENTID_SDMA1 = 0x09, - AMDGPU_IH_CLIENTID_SE0SH = 0x0a, - AMDGPU_IH_CLIENTID_SE1SH = 0x0b, - AMDGPU_IH_CLIENTID_SE2SH = 0x0c, - AMDGPU_IH_CLIENTID_SE3SH = 0x0d, - AMDGPU_IH_CLIENTID_SYSHUB = 0x0e, - AMDGPU_IH_CLIENTID_THM = 0x0f, - AMDGPU_IH_CLIENTID_UVD = 0x10, - AMDGPU_IH_CLIENTID_VCE0 = 0x11, - AMDGPU_IH_CLIENTID_VMC = 0x12, - AMDGPU_IH_CLIENTID_XDMA = 0x13, - AMDGPU_IH_CLIENTID_GRBM_CP = 0x14, - AMDGPU_IH_CLIENTID_ATS = 0x15, - AMDGPU_IH_CLIENTID_ROM_SMUIO = 0x16, - AMDGPU_IH_CLIENTID_DF = 0x17, - AMDGPU_IH_CLIENTID_VCE1 = 0x18, - AMDGPU_IH_CLIENTID_PWR = 0x19, - AMDGPU_IH_CLIENTID_UTCL2 = 0x1b, - AMDGPU_IH_CLIENTID_EA = 0x1c, - AMDGPU_IH_CLIENTID_UTCL2LOG = 0x1d, - AMDGPU_IH_CLIENTID_MP0 = 0x1e, - AMDGPU_IH_CLIENTID_MP1 = 0x1f, - - AMDGPU_IH_CLIENTID_MAX, - - AMDGPU_IH_CLIENTID_VCN = AMDGPU_IH_CLIENTID_UVD -}; #define AMDGPU_IH_CLIENTID_LEGACY 0 +#define AMDGPU_IH_CLIENTID_MAX SOC15_IH_CLIENTID_MAX #define AMDGPU_PAGEFAULT_HASH_BITS 8 struct amdgpu_retryfault_hashtable { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index d9533bbc467c..d6416ee52e32 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -350,6 +350,7 @@ struct amdgpu_mode_info { u16 firmware_flags; /* pointer to backlight encoder */ struct amdgpu_encoder *bl_encoder; + u8 bl_level; /* saved backlight level */ struct amdgpu_audio audio; /* audio stuff */ int num_crtc; /* number of crtcs */ int num_hpd; /* number of hpd pins */ @@ -550,14 +551,6 @@ struct amdgpu_connector { /* we need to mind the EDID between detect and get modes due to analog/digital/tvencoder */ struct edid *edid; - /* number of modes generated from EDID at 'dc_sink' */ - int num_modes; - /* The 'old' sink - before an HPD. - * The 'current' sink is in dc_link->sink. */ - struct dc_sink *dc_sink; - struct dc_link *dc_link; - struct dc_sink *dc_em_sink; - const struct dc_stream *stream; void *con_priv; bool dac_load_detect; bool detected_by_load; /* if the connection status was determined by load */ @@ -568,27 +561,6 @@ struct amdgpu_connector { enum amdgpu_connector_audio audio; enum amdgpu_connector_dither dither; unsigned pixelclock_for_modeset; - - struct drm_dp_mst_topology_mgr mst_mgr; - struct amdgpu_dm_dp_aux dm_dp_aux; - struct drm_dp_mst_port *port; - struct amdgpu_connector *mst_port; - struct amdgpu_encoder *mst_encoder; - struct semaphore mst_sem; - - /* TODO see if we can merge with ddc_bus or make a dm_connector */ - struct amdgpu_i2c_adapter *i2c; - - /* Monitor range limits */ - int min_vfreq ; - int max_vfreq ; - int pixel_clock_mhz; - - /*freesync caps*/ - struct mod_freesync_caps caps; - - struct mutex hpd_lock; - }; /* TODO: start to use this struct and remove same field from base one */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 9157745fce14..6d08cde8443c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -60,6 +60,8 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) amdgpu_bo_kunmap(bo); + if (bo->gem_base.import_attach) + drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg); drm_gem_object_release(&bo->gem_base); amdgpu_bo_unref(&bo->parent); if (!list_empty(&bo->shadow_list)) { @@ -173,13 +175,15 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) * @size: size for the new BO * @align: alignment for the new BO * @domain: where to place it - * @bo_ptr: resulting BO + * @bo_ptr: used to initialize BOs in structures * @gpu_addr: GPU addr of the pinned BO * @cpu_addr: optional CPU address mapping * * Allocates and pins a BO for kernel internal use, and returns it still * reserved. * + * Note: For bo_ptr new BO is only created if bo_ptr points to NULL. + * * Returns 0 on success, negative error code otherwise. */ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, @@ -191,10 +195,10 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, int r; if (!*bo_ptr) { - r = amdgpu_bo_create(adev, size, align, true, domain, + r = amdgpu_bo_create(adev, size, align, domain, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, bo_ptr); + ttm_bo_type_kernel, NULL, bo_ptr); if (r) { dev_err(adev->dev, "(%d) failed to allocate kernel bo\n", r); @@ -242,12 +246,14 @@ error_free: * @size: size for the new BO * @align: alignment for the new BO * @domain: where to place it - * @bo_ptr: resulting BO + * @bo_ptr: used to initialize BOs in structures * @gpu_addr: GPU addr of the pinned BO * @cpu_addr: optional CPU address mapping * * Allocates and pins a BO for kernel internal use. * + * Note: For bo_ptr new BO is only created if bo_ptr points to NULL. + * * Returns 0 on success, negative error code otherwise. */ int amdgpu_bo_create_kernel(struct amdgpu_device *adev, @@ -335,21 +341,19 @@ fail: return false; } -static int amdgpu_bo_do_create(struct amdgpu_device *adev, - unsigned long size, int byte_align, - bool kernel, u32 domain, u64 flags, - struct sg_table *sg, +static int amdgpu_bo_do_create(struct amdgpu_device *adev, unsigned long size, + int byte_align, u32 domain, + u64 flags, enum ttm_bo_type type, struct reservation_object *resv, struct amdgpu_bo **bo_ptr) { struct ttm_operation_ctx ctx = { - .interruptible = !kernel, + .interruptible = (type != ttm_bo_type_kernel), .no_wait_gpu = false, .resv = resv, .flags = TTM_OPT_FLAG_ALLOW_RES_EVICT }; struct amdgpu_bo *bo; - enum ttm_bo_type type; unsigned long page_align; size_t acc_size; int r; @@ -360,13 +364,6 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, if (!amdgpu_bo_validate_size(adev, size, domain)) return -ENOMEM; - if (kernel) { - type = ttm_bo_type_kernel; - } else if (sg) { - type = ttm_bo_type_sg; - } else { - type = ttm_bo_type_device; - } *bo_ptr = NULL; acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size, @@ -385,7 +382,8 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA); bo->allowed_domains = bo->preferred_domains; - if (!kernel && bo->allowed_domains == AMDGPU_GEM_DOMAIN_VRAM) + if (type != ttm_bo_type_kernel && + bo->allowed_domains == AMDGPU_GEM_DOMAIN_VRAM) bo->allowed_domains |= AMDGPU_GEM_DOMAIN_GTT; bo->flags = flags; @@ -423,7 +421,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, type, &bo->placement, page_align, &ctx, acc_size, - sg, resv, &amdgpu_ttm_bo_destroy); + NULL, resv, &amdgpu_ttm_bo_destroy); if (unlikely(r != 0)) return r; @@ -435,7 +433,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, else amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0); - if (kernel) + if (type == ttm_bo_type_kernel) bo->tbo.priority = 1; if (flags & AMDGPU_GEM_CREATE_VRAM_CLEARED && @@ -479,12 +477,11 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, if (bo->shadow) return 0; - r = amdgpu_bo_do_create(adev, size, byte_align, true, - AMDGPU_GEM_DOMAIN_GTT, + r = amdgpu_bo_do_create(adev, size, byte_align, AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_CREATE_CPU_GTT_USWC | AMDGPU_GEM_CREATE_SHADOW, - NULL, bo->tbo.resv, - &bo->shadow); + ttm_bo_type_kernel, + bo->tbo.resv, &bo->shadow); if (!r) { bo->shadow->parent = amdgpu_bo_ref(bo); mutex_lock(&adev->shadow_list_lock); @@ -495,18 +492,17 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, return r; } -int amdgpu_bo_create(struct amdgpu_device *adev, - unsigned long size, int byte_align, - bool kernel, u32 domain, u64 flags, - struct sg_table *sg, +int amdgpu_bo_create(struct amdgpu_device *adev, unsigned long size, + int byte_align, u32 domain, + u64 flags, enum ttm_bo_type type, struct reservation_object *resv, struct amdgpu_bo **bo_ptr) { uint64_t parent_flags = flags & ~AMDGPU_GEM_CREATE_SHADOW; int r; - r = amdgpu_bo_do_create(adev, size, byte_align, kernel, domain, - parent_flags, sg, resv, bo_ptr); + r = amdgpu_bo_do_create(adev, size, byte_align, domain, + parent_flags, type, resv, bo_ptr); if (r) return r; @@ -821,7 +817,8 @@ static const char *amdgpu_vram_names[] = { "GDDR4", "GDDR5", "HBM", - "DDR3" + "DDR3", + "DDR4", }; int amdgpu_bo_init(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index d4dbfe1f842e..546f77cb7882 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -203,12 +203,11 @@ static inline bool amdgpu_bo_explicit_sync(struct amdgpu_bo *bo) return bo->flags & AMDGPU_GEM_CREATE_EXPLICIT_SYNC; } -int amdgpu_bo_create(struct amdgpu_device *adev, - unsigned long size, int byte_align, - bool kernel, u32 domain, u64 flags, - struct sg_table *sg, - struct reservation_object *resv, - struct amdgpu_bo **bo_ptr); +int amdgpu_bo_create(struct amdgpu_device *adev, unsigned long size, + int byte_align, u32 domain, + u64 flags, enum ttm_bo_type type, + struct reservation_object *resv, + struct amdgpu_bo **bo_ptr); int amdgpu_bo_create_reserved(struct amdgpu_device *adev, unsigned long size, int align, u32 domain, struct amdgpu_bo **bo_ptr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 632b18670098..361975cf45a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -1154,7 +1154,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, umode_t effective_mode = attr->mode; /* handle non-powerplay limitations */ - if (!adev->powerplay.cgs_device) { + if (!adev->powerplay.pp_handle) { /* Skip fan attributes if fan is not present */ if (adev->pm.no_fan && (attr == &sensor_dev_attr_pwm1.dev_attr.attr || diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c deleted file mode 100644 index 5c2e2d5dc1ee..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#include "atom.h" -#include "amdgpu.h" -#include "amd_shared.h" -#include <linux/module.h> -#include <linux/moduleparam.h> -#include "amdgpu_pm.h" -#include <drm/amdgpu_drm.h> -#include "amdgpu_powerplay.h" -#include "si_dpm.h" -#include "cik_dpm.h" -#include "vi_dpm.h" - -static int amdgpu_pp_early_init(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - struct amd_powerplay *amd_pp; - int ret = 0; - - amd_pp = &(adev->powerplay); - amd_pp->pp_handle = (void *)adev; - - switch (adev->asic_type) { - case CHIP_POLARIS11: - case CHIP_POLARIS10: - case CHIP_POLARIS12: - case CHIP_TONGA: - case CHIP_FIJI: - case CHIP_TOPAZ: - case CHIP_CARRIZO: - case CHIP_STONEY: - case CHIP_VEGA10: - case CHIP_RAVEN: - amd_pp->cgs_device = amdgpu_cgs_create_device(adev); - amd_pp->ip_funcs = &pp_ip_funcs; - amd_pp->pp_funcs = &pp_dpm_funcs; - break; - /* These chips don't have powerplay implemenations */ -#ifdef CONFIG_DRM_AMDGPU_SI - case CHIP_TAHITI: - case CHIP_PITCAIRN: - case CHIP_VERDE: - case CHIP_OLAND: - case CHIP_HAINAN: - amd_pp->ip_funcs = &si_dpm_ip_funcs; - amd_pp->pp_funcs = &si_dpm_funcs; - break; -#endif -#ifdef CONFIG_DRM_AMDGPU_CIK - case CHIP_BONAIRE: - case CHIP_HAWAII: - if (amdgpu_dpm == -1) { - amd_pp->ip_funcs = &ci_dpm_ip_funcs; - amd_pp->pp_funcs = &ci_dpm_funcs; - } else { - amd_pp->cgs_device = amdgpu_cgs_create_device(adev); - amd_pp->ip_funcs = &pp_ip_funcs; - amd_pp->pp_funcs = &pp_dpm_funcs; - } - break; - case CHIP_KABINI: - case CHIP_MULLINS: - case CHIP_KAVERI: - amd_pp->ip_funcs = &kv_dpm_ip_funcs; - amd_pp->pp_funcs = &kv_dpm_funcs; - break; -#endif - default: - ret = -EINVAL; - break; - } - - if (adev->powerplay.ip_funcs->early_init) - ret = adev->powerplay.ip_funcs->early_init(adev); - - return ret; -} - - -static int amdgpu_pp_late_init(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->late_init) - ret = adev->powerplay.ip_funcs->late_init( - adev->powerplay.pp_handle); - - return ret; -} - -static int amdgpu_pp_sw_init(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->sw_init) - ret = adev->powerplay.ip_funcs->sw_init( - adev->powerplay.pp_handle); - - return ret; -} - -static int amdgpu_pp_sw_fini(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->sw_fini) - ret = adev->powerplay.ip_funcs->sw_fini( - adev->powerplay.pp_handle); - if (ret) - return ret; - - return ret; -} - -static int amdgpu_pp_hw_init(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) - amdgpu_ucode_init_bo(adev); - - if (adev->powerplay.ip_funcs->hw_init) - ret = adev->powerplay.ip_funcs->hw_init( - adev->powerplay.pp_handle); - - return ret; -} - -static int amdgpu_pp_hw_fini(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->hw_fini) - ret = adev->powerplay.ip_funcs->hw_fini( - adev->powerplay.pp_handle); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) - amdgpu_ucode_fini_bo(adev); - - return ret; -} - -static void amdgpu_pp_late_fini(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->late_fini) - adev->powerplay.ip_funcs->late_fini( - adev->powerplay.pp_handle); - - if (adev->powerplay.cgs_device) - amdgpu_cgs_destroy_device(adev->powerplay.cgs_device); -} - -static int amdgpu_pp_suspend(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->suspend) - ret = adev->powerplay.ip_funcs->suspend( - adev->powerplay.pp_handle); - return ret; -} - -static int amdgpu_pp_resume(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->resume) - ret = adev->powerplay.ip_funcs->resume( - adev->powerplay.pp_handle); - return ret; -} - -static int amdgpu_pp_set_clockgating_state(void *handle, - enum amd_clockgating_state state) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->set_clockgating_state) - ret = adev->powerplay.ip_funcs->set_clockgating_state( - adev->powerplay.pp_handle, state); - return ret; -} - -static int amdgpu_pp_set_powergating_state(void *handle, - enum amd_powergating_state state) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->set_powergating_state) - ret = adev->powerplay.ip_funcs->set_powergating_state( - adev->powerplay.pp_handle, state); - return ret; -} - - -static bool amdgpu_pp_is_idle(void *handle) -{ - bool ret = true; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->is_idle) - ret = adev->powerplay.ip_funcs->is_idle( - adev->powerplay.pp_handle); - return ret; -} - -static int amdgpu_pp_wait_for_idle(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->wait_for_idle) - ret = adev->powerplay.ip_funcs->wait_for_idle( - adev->powerplay.pp_handle); - return ret; -} - -static int amdgpu_pp_soft_reset(void *handle) -{ - int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->powerplay.ip_funcs->soft_reset) - ret = adev->powerplay.ip_funcs->soft_reset( - adev->powerplay.pp_handle); - return ret; -} - -static const struct amd_ip_funcs amdgpu_pp_ip_funcs = { - .name = "amdgpu_powerplay", - .early_init = amdgpu_pp_early_init, - .late_init = amdgpu_pp_late_init, - .sw_init = amdgpu_pp_sw_init, - .sw_fini = amdgpu_pp_sw_fini, - .hw_init = amdgpu_pp_hw_init, - .hw_fini = amdgpu_pp_hw_fini, - .late_fini = amdgpu_pp_late_fini, - .suspend = amdgpu_pp_suspend, - .resume = amdgpu_pp_resume, - .is_idle = amdgpu_pp_is_idle, - .wait_for_idle = amdgpu_pp_wait_for_idle, - .soft_reset = amdgpu_pp_soft_reset, - .set_clockgating_state = amdgpu_pp_set_clockgating_state, - .set_powergating_state = amdgpu_pp_set_powergating_state, -}; - -const struct amdgpu_ip_block_version amdgpu_pp_ip_block = -{ - .type = AMD_IP_BLOCK_TYPE_SMC, - .major = 1, - .minor = 0, - .rev = 0, - .funcs = &amdgpu_pp_ip_funcs, -}; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index fb66b45548d3..1c9991738477 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -105,11 +105,16 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, int ret; ww_mutex_lock(&resv->lock, NULL); - ret = amdgpu_bo_create(adev, attach->dmabuf->size, PAGE_SIZE, false, - AMDGPU_GEM_DOMAIN_GTT, 0, sg, resv, &bo); + ret = amdgpu_bo_create(adev, attach->dmabuf->size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_CPU, 0, ttm_bo_type_sg, + resv, &bo); if (ret) goto error; + bo->tbo.sg = sg; + bo->tbo.ttm->sg = sg; + bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; + bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; if (attach->dmabuf->ops != &amdgpu_dmabuf_ops) bo->prime_shared_count = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 6e712f12eecd..9a75410cd576 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -62,6 +62,9 @@ static int psp_sw_init(void *handle) psp->adev = adev; + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) + return 0; + ret = psp_init_microcode(psp); if (ret) { DRM_ERROR("Failed to load psp firmware!\n"); @@ -75,6 +78,9 @@ static int psp_sw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) + return 0; + release_firmware(adev->psp.sos_fw); adev->psp.sos_fw = NULL; release_firmware(adev->psp.asd_fw); @@ -453,6 +459,9 @@ static int psp_suspend(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct psp_context *psp = &adev->psp; + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) + return 0; + ret = psp_ring_stop(psp, PSP_RING_TYPE__KM); if (ret) { DRM_ERROR("PSP ring stop failed\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index f3d81b6fb499..2dbe87591f81 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -59,9 +59,8 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) goto out_cleanup; } - r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, - NULL, NULL, &vram_obj); + r = amdgpu_bo_create(adev, size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 0, + ttm_bo_type_kernel, NULL, &vram_obj); if (r) { DRM_ERROR("Failed to create VRAM object\n"); goto out_cleanup; @@ -80,9 +79,9 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) void **vram_start, **vram_end; struct dma_fence *fence = NULL; - r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_GTT, 0, NULL, - NULL, gtt_obj + i); + r = amdgpu_bo_create(adev, size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, 0, + ttm_bo_type_kernel, NULL, gtt_obj + i); if (r) { DRM_ERROR("Failed to create GTT object %d\n", i); goto out_lclean; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index c2fae04d769a..e28b73609fbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -204,6 +204,12 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM }; + if (bo->type == ttm_bo_type_sg) { + placement->num_placement = 0; + placement->num_busy_placement = 0; + return; + } + if (!amdgpu_ttm_bo_is_amdgpu_bo(bo)) { placement->placement = &placements; placement->busy_placement = &placements; @@ -982,20 +988,20 @@ static struct ttm_backend_func amdgpu_backend_func = { .destroy = &amdgpu_ttm_backend_destroy, }; -static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_buffer_object *bo, + uint32_t page_flags) { struct amdgpu_device *adev; struct amdgpu_ttm_tt *gtt; - adev = amdgpu_ttm_adev(bdev); + adev = amdgpu_ttm_adev(bo->bdev); gtt = kzalloc(sizeof(struct amdgpu_ttm_tt), GFP_KERNEL); if (gtt == NULL) { return NULL; } gtt->ttm.ttm.func = &amdgpu_backend_func; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { + if (ttm_sg_tt_init(>t->ttm, bo, page_flags)) { kfree(gtt); return NULL; } @@ -1021,7 +1027,8 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm, if (slave && ttm->sg) { drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, - gtt->ttm.dma_address, ttm->num_pages); + gtt->ttm.dma_address, + ttm->num_pages); ttm->state = tt_unbound; return 0; } @@ -1335,11 +1342,12 @@ static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev) if (adev->fw_vram_usage.size > 0 && adev->fw_vram_usage.size <= vram_size) { - r = amdgpu_bo_create(adev, adev->fw_vram_usage.size, - PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, - AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | - AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, NULL, NULL, - &adev->fw_vram_usage.reserved_bo); + r = amdgpu_bo_create(adev, adev->fw_vram_usage.size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | + AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, + ttm_bo_type_kernel, NULL, + &adev->fw_vram_usage.reserved_bo); if (r) goto error_create; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 0b237e027cab..24474294c92a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -413,9 +413,9 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, if (!entry->base.bo) { r = amdgpu_bo_create(adev, amdgpu_vm_bo_size(adev, level), - AMDGPU_GPU_PAGE_SIZE, true, + AMDGPU_GPU_PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, flags, - NULL, resv, &pt); + ttm_bo_type_kernel, resv, &pt); if (r) return r; @@ -2409,8 +2409,8 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, AMDGPU_GEM_CREATE_SHADOW); size = amdgpu_vm_bo_size(adev, adev->vm_manager.root_level); - r = amdgpu_bo_create(adev, size, align, true, AMDGPU_GEM_DOMAIN_VRAM, - flags, NULL, NULL, &vm->root.base.bo); + r = amdgpu_bo_create(adev, size, align, AMDGPU_GEM_DOMAIN_VRAM, flags, + ttm_bo_type_kernel, NULL, &vm->root.base.bo); if (r) goto error_free_sched_entity; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index 2af26d2da127..d702fb8e3427 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -34,7 +34,7 @@ #include <linux/backlight.h> #include "bif/bif_4_1_d.h" -static u8 +u8 amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev) { u8 backlight_level; @@ -48,7 +48,7 @@ amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev) return backlight_level; } -static void +void amdgpu_atombios_encoder_set_backlight_level_to_reg(struct amdgpu_device *adev, u8 backlight_level) { diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.h b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.h index 2bdec40515ce..f77cbdef679e 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.h +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.h @@ -25,6 +25,11 @@ #define __ATOMBIOS_ENCODER_H__ u8 +amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev); +void +amdgpu_atombios_encoder_set_backlight_level_to_reg(struct amdgpu_device *adev, + u8 backlight_level); +u8 amdgpu_atombios_encoder_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder); void amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder *amdgpu_encoder, diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index ddb814f7e952..98d1dd253596 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -65,6 +65,8 @@ MODULE_FIRMWARE("radeon/hawaii_k_smc.bin"); #define VOLTAGE_VID_OFFSET_SCALE1 625 #define VOLTAGE_VID_OFFSET_SCALE2 100 +static const struct amd_pm_funcs ci_dpm_funcs; + static const struct ci_pt_defaults defaults_hawaii_xt = { 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000, @@ -6241,6 +6243,7 @@ static int ci_dpm_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + adev->powerplay.pp_funcs = &ci_dpm_funcs; ci_dpm_set_irq_funcs(adev); return 0; @@ -6760,7 +6763,7 @@ static int ci_dpm_read_sensor(void *handle, int idx, } } -const struct amd_ip_funcs ci_dpm_ip_funcs = { +static const struct amd_ip_funcs ci_dpm_ip_funcs = { .name = "ci_dpm", .early_init = ci_dpm_early_init, .late_init = ci_dpm_late_init, @@ -6777,7 +6780,16 @@ const struct amd_ip_funcs ci_dpm_ip_funcs = { .set_powergating_state = ci_dpm_set_powergating_state, }; -const struct amd_pm_funcs ci_dpm_funcs = { +const struct amdgpu_ip_block_version ci_smu_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_SMC, + .major = 7, + .minor = 0, + .rev = 0, + .funcs = &ci_dpm_ip_funcs, +}; + +static const struct amd_pm_funcs ci_dpm_funcs = { .pre_set_power_state = &ci_dpm_pre_set_power_state, .set_power_state = &ci_dpm_set_power_state, .post_set_power_state = &ci_dpm_post_set_power_state, diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 4324184996a5..0df22030e713 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -67,7 +67,6 @@ #include "amdgpu_dm.h" #include "amdgpu_amdkfd.h" -#include "amdgpu_powerplay.h" #include "dce_virtual.h" /* @@ -1887,10 +1886,6 @@ static int cik_common_early_init(void *handle) return -EINVAL; } - adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type); - - amdgpu_device_get_pcie_info(adev); - return 0; } @@ -2000,7 +1995,10 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &cik_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + if (amdgpu_dpm == -1) + amdgpu_device_ip_block_add(adev, &ci_smu_ip_block); + else + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -2018,7 +2016,10 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &cik_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + if (amdgpu_dpm == -1) + amdgpu_device_ip_block_add(adev, &ci_smu_ip_block); + else + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -2036,7 +2037,7 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &cik_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &kv_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -2055,7 +2056,7 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &cik_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &kv_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) diff --git a/drivers/gpu/drm/amd/amdgpu/cik_dpm.h b/drivers/gpu/drm/amd/amdgpu/cik_dpm.h index c7b4349f6319..2a086610f74d 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/cik_dpm.h @@ -24,8 +24,7 @@ #ifndef __CIK_DPM_H__ #define __CIK_DPM_H__ -extern const struct amd_ip_funcs ci_dpm_ip_funcs; -extern const struct amd_ip_funcs kv_dpm_ip_funcs; -extern const struct amd_pm_funcs ci_dpm_funcs; -extern const struct amd_pm_funcs kv_dpm_funcs; +extern const struct amdgpu_ip_block_version ci_smu_ip_block; +extern const struct amdgpu_ip_block_version kv_smu_ip_block; + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 7ea900010702..452f88ea46a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2862,6 +2862,11 @@ static int dce_v10_0_hw_fini(void *handle) static int dce_v10_0_suspend(void *handle) { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + adev->mode_info.bl_level = + amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); + return dce_v10_0_hw_fini(handle); } @@ -2870,6 +2875,9 @@ static int dce_v10_0_resume(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int ret; + amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, + adev->mode_info.bl_level); + ret = dce_v10_0_hw_init(handle); /* turn on the BL */ diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 158b92ea435f..a7c1c584a191 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2988,6 +2988,11 @@ static int dce_v11_0_hw_fini(void *handle) static int dce_v11_0_suspend(void *handle) { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + adev->mode_info.bl_level = + amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); + return dce_v11_0_hw_fini(handle); } @@ -2996,6 +3001,9 @@ static int dce_v11_0_resume(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int ret; + amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, + adev->mode_info.bl_level); + ret = dce_v11_0_hw_init(handle); /* turn on the BL */ diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index ee2162e81da9..9f67b7fd3487 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -2730,6 +2730,11 @@ static int dce_v6_0_hw_fini(void *handle) static int dce_v6_0_suspend(void *handle) { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + adev->mode_info.bl_level = + amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); + return dce_v6_0_hw_fini(handle); } @@ -2738,6 +2743,9 @@ static int dce_v6_0_resume(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int ret; + amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, + adev->mode_info.bl_level); + ret = dce_v6_0_hw_init(handle); /* turn on the BL */ diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 8dbe97dff58c..f55422cbd77a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2760,6 +2760,11 @@ static int dce_v8_0_hw_fini(void *handle) static int dce_v8_0_suspend(void *handle) { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + adev->mode_info.bl_level = + amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); + return dce_v8_0_hw_fini(handle); } @@ -2768,6 +2773,9 @@ static int dce_v8_0_resume(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int ret; + amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, + adev->mode_info.bl_level); + ret = dce_v8_0_hw_init(handle); /* turn on the BL */ diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index d73bbb092202..d1d2c27156b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1261,23 +1261,23 @@ static int gfx_v9_0_sw_init(void *handle) adev->gfx.mec.num_queue_per_pipe = 8; /* KIQ event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_GRBM_CP, 178, &adev->gfx.kiq.irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 178, &adev->gfx.kiq.irq); if (r) return r; /* EOP Event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_GRBM_CP, 181, &adev->gfx.eop_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 181, &adev->gfx.eop_irq); if (r) return r; /* Privileged reg */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_GRBM_CP, 184, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 184, &adev->gfx.priv_reg_irq); if (r) return r; /* Privileged inst */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_GRBM_CP, 185, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 185, &adev->gfx.priv_inst_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 67cd1fe17649..a70cbc45c4c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -836,9 +836,9 @@ static int gmc_v9_0_sw_init(void *handle) spin_lock_init(&adev->gmc.invalidate_lock); + adev->gmc.vram_type = amdgpu_atomfirmware_get_vram_type(adev); switch (adev->asic_type) { case CHIP_RAVEN: - adev->gmc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; if (adev->rev_id == 0x0 || adev->rev_id == 0x1) { amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48); } else { @@ -849,8 +849,6 @@ static int gmc_v9_0_sw_init(void *handle) } break; case CHIP_VEGA10: - /* XXX Don't know how to get VRAM type yet. */ - adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM; /* * To fulfill 4-level page support, * vm size is 256TB (48bit), maximum size of Vega10, @@ -863,9 +861,9 @@ static int gmc_v9_0_sw_init(void *handle) } /* This interrupt is VMC page fault.*/ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_VMC, 0, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VMC, 0, &adev->gmc.vm_fault); - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_UTCL2, 0, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_UTCL2, 0, &adev->gmc.vm_fault); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 8766681cfd3f..81babe026529 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -42,6 +42,8 @@ #define KV_MINIMUM_ENGINE_CLOCK 800 #define SMC_RAM_END 0x40000 +static const struct amd_pm_funcs kv_dpm_funcs; + static void kv_dpm_set_irq_funcs(struct amdgpu_device *adev); static int kv_enable_nb_dpm(struct amdgpu_device *adev, bool enable); @@ -2960,6 +2962,7 @@ static int kv_dpm_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + adev->powerplay.pp_funcs = &kv_dpm_funcs; kv_dpm_set_irq_funcs(adev); return 0; @@ -3301,7 +3304,7 @@ static int kv_dpm_read_sensor(void *handle, int idx, } } -const struct amd_ip_funcs kv_dpm_ip_funcs = { +static const struct amd_ip_funcs kv_dpm_ip_funcs = { .name = "kv_dpm", .early_init = kv_dpm_early_init, .late_init = kv_dpm_late_init, @@ -3318,7 +3321,16 @@ const struct amd_ip_funcs kv_dpm_ip_funcs = { .set_powergating_state = kv_dpm_set_powergating_state, }; -const struct amd_pm_funcs kv_dpm_funcs = { +const struct amdgpu_ip_block_version kv_smu_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_SMC, + .major = 1, + .minor = 0, + .rev = 0, + .funcs = &kv_dpm_ip_funcs, +}; + +static const struct amd_pm_funcs kv_dpm_funcs = { .pre_set_power_state = &kv_dpm_pre_set_power_state, .set_power_state = &kv_dpm_set_power_state, .post_set_power_state = &kv_dpm_post_set_power_state, diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c index 271452d3999a..8fb933c62cf5 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -33,56 +33,34 @@ static void xgpu_ai_mailbox_send_ack(struct amdgpu_device *adev) { - u32 reg; - int timeout = AI_MAILBOX_TIMEDOUT; - u32 mask = REG_FIELD_MASK(BIF_BX_PF0_MAILBOX_CONTROL, RCV_MSG_VALID); - - reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL)); - reg = REG_SET_FIELD(reg, BIF_BX_PF0_MAILBOX_CONTROL, RCV_MSG_ACK, 1); - WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL), reg); - - /*Wait for RCV_MSG_VALID to be 0*/ - reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL)); - while (reg & mask) { - if (timeout <= 0) { - pr_err("RCV_MSG_VALID is not cleared\n"); - break; - } - mdelay(1); - timeout -=1; - - reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL)); - } + WREG8(AI_MAIBOX_CONTROL_RCV_OFFSET_BYTE, 2); } static void xgpu_ai_mailbox_set_valid(struct amdgpu_device *adev, bool val) { - u32 reg; + WREG8(AI_MAIBOX_CONTROL_TRN_OFFSET_BYTE, val ? 1 : 0); +} - reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL)); - reg = REG_SET_FIELD(reg, BIF_BX_PF0_MAILBOX_CONTROL, - TRN_MSG_VALID, val ? 1 : 0); - WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_CONTROL), - reg); +/* + * this peek_msg could *only* be called in IRQ routine becuase in IRQ routine + * RCV_MSG_VALID filed of BIF_BX_PF0_MAILBOX_CONTROL must already be set to 1 + * by host. + * + * if called no in IRQ routine, this peek_msg cannot guaranteed to return the + * correct value since it doesn't return the RCV_DW0 under the case that + * RCV_MSG_VALID is set by host. + */ +static enum idh_event xgpu_ai_mailbox_peek_msg(struct amdgpu_device *adev) +{ + return RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, + mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW0)); } + static int xgpu_ai_mailbox_rcv_msg(struct amdgpu_device *adev, enum idh_event event) { u32 reg; - u32 mask = REG_FIELD_MASK(BIF_BX_PF0_MAILBOX_CONTROL, RCV_MSG_VALID); - - if (event != IDH_FLR_NOTIFICATION_CMPL) { - reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL)); - if (!(reg & mask)) - return -ENOENT; - } reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW0)); @@ -94,54 +72,67 @@ static int xgpu_ai_mailbox_rcv_msg(struct amdgpu_device *adev, return 0; } +static uint8_t xgpu_ai_peek_ack(struct amdgpu_device *adev) { + return RREG8(AI_MAIBOX_CONTROL_TRN_OFFSET_BYTE) & 2; +} + static int xgpu_ai_poll_ack(struct amdgpu_device *adev) { - int r = 0, timeout = AI_MAILBOX_TIMEDOUT; - u32 mask = REG_FIELD_MASK(BIF_BX_PF0_MAILBOX_CONTROL, TRN_MSG_ACK); - u32 reg; + int timeout = AI_MAILBOX_POLL_ACK_TIMEDOUT; + u8 reg; + + do { + reg = RREG8(AI_MAIBOX_CONTROL_TRN_OFFSET_BYTE); + if (reg & 2) + return 0; - reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL)); - while (!(reg & mask)) { - if (timeout <= 0) { - pr_err("Doesn't get ack from pf.\n"); - r = -ETIME; - break; - } mdelay(5); timeout -= 5; + } while (timeout > 1); - reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_CONTROL)); - } + pr_err("Doesn't get TRN_MSG_ACK from pf in %d msec\n", AI_MAILBOX_POLL_ACK_TIMEDOUT); - return r; + return -ETIME; } static int xgpu_ai_poll_msg(struct amdgpu_device *adev, enum idh_event event) { - int r = 0, timeout = AI_MAILBOX_TIMEDOUT; - - r = xgpu_ai_mailbox_rcv_msg(adev, event); - while (r) { - if (timeout <= 0) { - pr_err("Doesn't get msg:%d from pf.\n", event); - r = -ETIME; - break; - } - mdelay(5); - timeout -= 5; + int r, timeout = AI_MAILBOX_POLL_MSG_TIMEDOUT; + do { r = xgpu_ai_mailbox_rcv_msg(adev, event); - } + if (!r) + return 0; - return r; + msleep(10); + timeout -= 10; + } while (timeout > 1); + + pr_err("Doesn't get msg:%d from pf, error=%d\n", event, r); + + return -ETIME; } static void xgpu_ai_mailbox_trans_msg (struct amdgpu_device *adev, enum idh_request req, u32 data1, u32 data2, u32 data3) { u32 reg; int r; + uint8_t trn; + + /* IMPORTANT: + * clear TRN_MSG_VALID valid to clear host's RCV_MSG_ACK + * and with host's RCV_MSG_ACK cleared hw automatically clear host's RCV_MSG_ACK + * which lead to VF's TRN_MSG_ACK cleared, otherwise below xgpu_ai_poll_ack() + * will return immediatly + */ + do { + xgpu_ai_mailbox_set_valid(adev, false); + trn = xgpu_ai_peek_ack(adev); + if (trn) { + pr_err("trn=%x ACK should not asssert! wait again !\n", trn); + msleep(1); + } + } while(trn); reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_TRN_DW0)); @@ -245,15 +236,36 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work) { struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, flr_work); struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt); - - /* wait until RCV_MSG become 3 */ - if (xgpu_ai_poll_msg(adev, IDH_FLR_NOTIFICATION_CMPL)) { - pr_err("failed to recieve FLR_CMPL\n"); - return; - } - - /* Trigger recovery due to world switch failure */ - amdgpu_device_gpu_recover(adev, NULL, false); + int timeout = AI_MAILBOX_POLL_FLR_TIMEDOUT; + int locked; + + /* block amdgpu_gpu_recover till msg FLR COMPLETE received, + * otherwise the mailbox msg will be ruined/reseted by + * the VF FLR. + * + * we can unlock the lock_reset to allow "amdgpu_job_timedout" + * to run gpu_recover() after FLR_NOTIFICATION_CMPL received + * which means host side had finished this VF's FLR. + */ + locked = mutex_trylock(&adev->lock_reset); + if (locked) + adev->in_gpu_reset = 1; + + do { + if (xgpu_ai_mailbox_peek_msg(adev) == IDH_FLR_NOTIFICATION_CMPL) + goto flr_done; + + msleep(10); + timeout -= 10; + } while (timeout > 1); + +flr_done: + if (locked) + mutex_unlock(&adev->lock_reset); + + /* Trigger recovery for world switch failure if no TDR */ + if (amdgpu_lockup_timeout == 0) + amdgpu_device_gpu_recover(adev, NULL, true); } static int xgpu_ai_set_mailbox_rcv_irq(struct amdgpu_device *adev, @@ -274,24 +286,22 @@ static int xgpu_ai_mailbox_rcv_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - int r; - - /* trigger gpu-reset by hypervisor only if TDR disbaled */ - if (!amdgpu_gpu_recovery) { - /* see what event we get */ - r = xgpu_ai_mailbox_rcv_msg(adev, IDH_FLR_NOTIFICATION); - - /* sometimes the interrupt is delayed to inject to VM, so under such case - * the IDH_FLR_NOTIFICATION is overwritten by VF FLR from GIM side, thus - * above recieve message could be failed, we should schedule the flr_work - * anyway + enum idh_event event = xgpu_ai_mailbox_peek_msg(adev); + + switch (event) { + case IDH_FLR_NOTIFICATION: + if (amdgpu_sriov_runtime(adev)) + schedule_work(&adev->virt.flr_work); + break; + /* READY_TO_ACCESS_GPU is fetched by kernel polling, IRQ can ignore + * it byfar since that polling thread will handle it, + * other msg like flr complete is not handled here. */ - if (r) { - DRM_ERROR("FLR_NOTIFICATION is missed\n"); - xgpu_ai_mailbox_send_ack(adev); - } - - schedule_work(&adev->virt.flr_work); + case IDH_CLR_MSG_BUF: + case IDH_FLR_NOTIFICATION_CMPL: + case IDH_READY_TO_ACCESS_GPU: + default: + break; } return 0; @@ -319,11 +329,11 @@ int xgpu_ai_mailbox_add_irq_id(struct amdgpu_device *adev) { int r; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_BIF, 135, &adev->virt.rcv_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_BIF, 135, &adev->virt.rcv_irq); if (r) return r; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_BIF, 138, &adev->virt.ack_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_BIF, 138, &adev->virt.ack_irq); if (r) { amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h index 67e78576a9eb..b4a9ceea334b 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h @@ -24,7 +24,9 @@ #ifndef __MXGPU_AI_H__ #define __MXGPU_AI_H__ -#define AI_MAILBOX_TIMEDOUT 12000 +#define AI_MAILBOX_POLL_ACK_TIMEDOUT 500 +#define AI_MAILBOX_POLL_MSG_TIMEDOUT 12000 +#define AI_MAILBOX_POLL_FLR_TIMEDOUT 500 enum idh_request { IDH_REQ_GPU_INIT_ACCESS = 1, @@ -51,4 +53,7 @@ int xgpu_ai_mailbox_add_irq_id(struct amdgpu_device *adev); int xgpu_ai_mailbox_get_irq(struct amdgpu_device *adev); void xgpu_ai_mailbox_put_irq(struct amdgpu_device *adev); +#define AI_MAIBOX_CONTROL_TRN_OFFSET_BYTE SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_CONTROL) * 4 +#define AI_MAIBOX_CONTROL_RCV_OFFSET_BYTE SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_CONTROL) * 4 + 1 + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 215743df0957..9448c45d1b60 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -31,8 +31,6 @@ #include "sdma0/sdma0_4_0_sh_mask.h" #include "sdma1/sdma1_4_0_offset.h" #include "sdma1/sdma1_4_0_sh_mask.h" -#include "mmhub/mmhub_1_0_offset.h" -#include "mmhub/mmhub_1_0_sh_mask.h" #include "hdp/hdp_4_0_offset.h" #include "sdma0/sdma0_4_1_default.h" @@ -1172,13 +1170,13 @@ static int sdma_v4_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_SDMA0, 224, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_SDMA0, 224, &adev->sdma.trap_irq); if (r) return r; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_SDMA1, 224, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_SDMA1, 224, &adev->sdma.trap_irq); if (r) return r; @@ -1333,7 +1331,7 @@ static int sdma_v4_0_process_trap_irq(struct amdgpu_device *adev, { DRM_DEBUG("IH: SDMA trap\n"); switch (entry->client_id) { - case AMDGPU_IH_CLIENTID_SDMA0: + case SOC15_IH_CLIENTID_SDMA0: switch (entry->ring_id) { case 0: amdgpu_fence_process(&adev->sdma.instance[0].ring); @@ -1349,7 +1347,7 @@ static int sdma_v4_0_process_trap_irq(struct amdgpu_device *adev, break; } break; - case AMDGPU_IH_CLIENTID_SDMA1: + case SOC15_IH_CLIENTID_SDMA1: switch (entry->ring_id) { case 0: amdgpu_fence_process(&adev->sdma.instance[1].ring); @@ -1399,7 +1397,7 @@ static void sdma_v4_0_update_medium_grain_clock_gating( if (def != data) WREG32(SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_CLK_CTRL), data); - if (adev->asic_type == CHIP_VEGA10) { + if (adev->sdma.num_instances > 1) { def = data = RREG32(SOC15_REG_OFFSET(SDMA1, 0, mmSDMA1_CLK_CTRL)); data &= ~(SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK | SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK | @@ -1427,7 +1425,7 @@ static void sdma_v4_0_update_medium_grain_clock_gating( if (def != data) WREG32(SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_CLK_CTRL), data); - if (adev->asic_type == CHIP_VEGA10) { + if (adev->sdma.num_instances > 1) { def = data = RREG32(SOC15_REG_OFFSET(SDMA1, 0, mmSDMA1_CLK_CTRL)); data |= (SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK | SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK | @@ -1458,7 +1456,7 @@ static void sdma_v4_0_update_medium_grain_light_sleep( WREG32(SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_POWER_CNTL), data); /* 1-not override: enable sdma1 mem light sleep */ - if (adev->asic_type == CHIP_VEGA10) { + if (adev->sdma.num_instances > 1) { def = data = RREG32(SOC15_REG_OFFSET(SDMA1, 0, mmSDMA1_POWER_CNTL)); data |= SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK; if (def != data) @@ -1472,7 +1470,7 @@ static void sdma_v4_0_update_medium_grain_light_sleep( WREG32(SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_POWER_CNTL), data); /* 0-override:disable sdma1 mem light sleep */ - if (adev->asic_type == CHIP_VEGA10) { + if (adev->sdma.num_instances > 1) { def = data = RREG32(SOC15_REG_OFFSET(SDMA1, 0, mmSDMA1_POWER_CNTL)); data &= ~SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK; if (def != data) diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 6e61b56bfbfc..b154667a8fd9 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -32,7 +32,7 @@ #include "amdgpu_vce.h" #include "atom.h" #include "amd_pcie.h" -#include "amdgpu_powerplay.h" +#include "si_dpm.h" #include "sid.h" #include "si_ih.h" #include "gfx_v6_0.h" @@ -1983,7 +1983,7 @@ int si_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &si_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v6_0_ip_block); amdgpu_device_ip_block_add(adev, &si_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &si_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); else @@ -1997,7 +1997,7 @@ int si_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &si_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v6_0_ip_block); amdgpu_device_ip_block_add(adev, &si_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &si_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); else @@ -2011,7 +2011,7 @@ int si_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &si_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v6_0_ip_block); amdgpu_device_ip_block_add(adev, &si_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &si_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); amdgpu_device_ip_block_add(adev, &gfx_v6_0_ip_block); diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 8137c02fd16a..3bfcf0d257ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -67,6 +67,8 @@ MODULE_FIRMWARE("radeon/hainan_smc.bin"); MODULE_FIRMWARE("radeon/hainan_k_smc.bin"); MODULE_FIRMWARE("radeon/banks_k_2_smc.bin"); +static const struct amd_pm_funcs si_dpm_funcs; + union power_info { struct _ATOM_POWERPLAY_INFO info; struct _ATOM_POWERPLAY_INFO_V2 info_2; @@ -7914,6 +7916,7 @@ static int si_dpm_early_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; + adev->powerplay.pp_funcs = &si_dpm_funcs; si_dpm_set_irq_funcs(adev); return 0; } @@ -8014,7 +8017,7 @@ static int si_dpm_read_sensor(void *handle, int idx, } } -const struct amd_ip_funcs si_dpm_ip_funcs = { +static const struct amd_ip_funcs si_dpm_ip_funcs = { .name = "si_dpm", .early_init = si_dpm_early_init, .late_init = si_dpm_late_init, @@ -8031,7 +8034,16 @@ const struct amd_ip_funcs si_dpm_ip_funcs = { .set_powergating_state = si_dpm_set_powergating_state, }; -const struct amd_pm_funcs si_dpm_funcs = { +const struct amdgpu_ip_block_version si_smu_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_SMC, + .major = 6, + .minor = 0, + .rev = 0, + .funcs = &si_dpm_ip_funcs, +}; + +static const struct amd_pm_funcs si_dpm_funcs = { .pre_set_power_state = &si_dpm_pre_set_power_state, .set_power_state = &si_dpm_set_power_state, .post_set_power_state = &si_dpm_post_set_power_state, diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.h b/drivers/gpu/drm/amd/amdgpu/si_dpm.h index 9fe343de3477..6b7d292b919f 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.h @@ -245,8 +245,7 @@ enum si_display_gap SI_PM_DISPLAY_GAP_IGNORE = 3, }; -extern const struct amd_ip_funcs si_dpm_ip_funcs; -extern const struct amd_pm_funcs si_dpm_funcs; +extern const struct amdgpu_ip_block_version si_smu_ip_block; struct ni_leakage_coeffients { diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 8dc8b72ed49b..c6e857325b58 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -57,7 +57,6 @@ #include "uvd_v7_0.h" #include "vce_v4_0.h" #include "vcn_v1_0.h" -#include "amdgpu_powerplay.h" #include "dce_virtual.h" #include "mxgpu_ai.h" @@ -531,10 +530,9 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block); amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); - if (amdgpu_fw_load_type == 2 || amdgpu_fw_load_type == -1) - amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block); + amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block); if (!amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -553,7 +551,7 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block); amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -692,10 +690,6 @@ static int soc15_common_early_init(void *handle) xgpu_ai_mailbox_set_irq_funcs(adev); } - adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type); - - amdgpu_device_get_pcie_info(adev); - return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index e54cc3ca2303..eddc57f3b72a 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -390,13 +390,13 @@ static int uvd_v7_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* UVD TRAP */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_UVD, 124, &adev->uvd.irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_UVD, 124, &adev->uvd.irq); if (r) return r; /* UVD ENC TRAP */ for (i = 0; i < adev->uvd.num_enc_rings; ++i) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_UVD, i + 119, &adev->uvd.irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_UVD, i + 119, &adev->uvd.irq); if (r) return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c index 2329b310ccf2..73fd48d6c756 100755 --- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c @@ -420,7 +420,7 @@ static int vce_v4_0_sw_init(void *handle) unsigned size; int r, i; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_VCE0, 167, &adev->vce.irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCE0, 167, &adev->vce.irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index fdf4ac9313cf..8c132673bc79 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -75,13 +75,13 @@ static int vcn_v1_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* VCN DEC TRAP */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_VCN, 124, &adev->vcn.irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, 124, &adev->vcn.irq); if (r) return r; /* VCN ENC TRAP */ for (i = 0; i < adev->vcn.num_enc_rings; ++i) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_VCN, i + 119, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, i + 119, &adev->vcn.irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c index cc8ce7e352a8..5ae5ed2e62d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c @@ -245,8 +245,8 @@ static bool vega10_ih_prescreen_iv(struct amdgpu_device *adev) * some faults get cleared. */ switch (dw0 & 0xff) { - case AMDGPU_IH_CLIENTID_VMC: - case AMDGPU_IH_CLIENTID_UTCL2: + case SOC15_IH_CLIENTID_VMC: + case SOC15_IH_CLIENTID_UTCL2: break; default: /* Not a VM fault */ diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 61360a1552d8..e7fb165cc9db 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -71,7 +71,6 @@ #include "uvd_v5_0.h" #include "uvd_v6_0.h" #include "vce_v3_0.h" -#include "amdgpu_powerplay.h" #if defined(CONFIG_DRM_AMD_ACP) #include "amdgpu_acp.h" #endif @@ -1097,11 +1096,6 @@ static int vi_common_early_init(void *handle) xgpu_vi_mailbox_set_irq_funcs(adev); } - /* vi use smc load by default */ - adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type); - - amdgpu_device_get_pcie_info(adev); - return 0; } @@ -1516,7 +1510,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vi_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v7_4_ip_block); amdgpu_device_ip_block_add(adev, &iceland_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); amdgpu_device_ip_block_add(adev, &gfx_v8_0_ip_block); @@ -1526,7 +1520,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vi_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v8_5_ip_block); amdgpu_device_ip_block_add(adev, &tonga_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -1546,7 +1540,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vi_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v8_0_ip_block); amdgpu_device_ip_block_add(adev, &tonga_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -1568,7 +1562,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vi_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v8_1_ip_block); amdgpu_device_ip_block_add(adev, &tonga_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -1586,7 +1580,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vi_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v8_0_ip_block); amdgpu_device_ip_block_add(adev, &cz_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -1607,7 +1601,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vi_common_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v8_0_ip_block); amdgpu_device_ip_block_add(adev, &cz_ih_ip_block); - amdgpu_device_ip_block_add(adev, &amdgpu_pp_ip_block); + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index ec3285f65517..5b124a67404c 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -11,7 +11,7 @@ config DRM_AMD_DC config DRM_AMD_DC_PRE_VEGA bool "DC support for Polaris and older ASICs" - default n + default y help Choose this option to enable the new DC support for older asics by default. This includes Polaris, Carrizo, Tonga, Bonaire, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7e5c5c9eeb4f..ae512ecb65ee 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1131,7 +1131,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) if (adev->asic_type == CHIP_VEGA10 || adev->asic_type == CHIP_RAVEN) - client_id = AMDGPU_IH_CLIENTID_DCE; + client_id = SOC15_IH_CLIENTID_DCE; int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; @@ -1231,7 +1231,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP; i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1; i++) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->crtc_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq); if (r) { DRM_ERROR("Failed to add crtc irq id!\n"); @@ -1255,7 +1255,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT; i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + adev->mode_info.num_crtc - 1; i++) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->pageflip_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq); if (r) { DRM_ERROR("Failed to add page flip irq id!\n"); return r; @@ -1276,7 +1276,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) } /* HPD */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, &adev->hpd_irq); if (r) { DRM_ERROR("Failed to add hpd irq id!\n"); @@ -1365,6 +1365,43 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) #endif +static int initialize_plane(struct amdgpu_display_manager *dm, + struct amdgpu_mode_info *mode_info, + int plane_id) +{ + struct amdgpu_plane *plane; + unsigned long possible_crtcs; + int ret = 0; + + plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL); + mode_info->planes[plane_id] = plane; + + if (!plane) { + DRM_ERROR("KMS: Failed to allocate plane\n"); + return -ENOMEM; + } + plane->base.type = mode_info->plane_type[plane_id]; + + /* + * HACK: IGT tests expect that each plane can only have one + * one possible CRTC. For now, set one CRTC for each + * plane that is not an underlay, but still allow multiple + * CRTCs for underlay planes. + */ + possible_crtcs = 1 << plane_id; + if (plane_id >= dm->dc->caps.max_streams) + possible_crtcs = 0xff; + + ret = amdgpu_dm_plane_init(dm, mode_info->planes[plane_id], possible_crtcs); + + if (ret) { + DRM_ERROR("KMS: Failed to initialize plane\n"); + return ret; + } + + return ret; +} + /* In this architecture, the association * connector -> encoder -> crtc * id not really requried. The crtc and connector will hold the @@ -1375,12 +1412,12 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) { struct amdgpu_display_manager *dm = &adev->dm; - uint32_t i; + int32_t i; struct amdgpu_dm_connector *aconnector = NULL; struct amdgpu_encoder *aencoder = NULL; struct amdgpu_mode_info *mode_info = &adev->mode_info; uint32_t link_cnt; - unsigned long possible_crtcs; + int32_t total_overlay_planes, total_primary_planes; link_cnt = dm->dc->caps.max_links; if (amdgpu_dm_mode_config_init(dm->adev)) { @@ -1388,30 +1425,22 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) return -1; } - for (i = 0; i < dm->dc->caps.max_planes; i++) { - struct amdgpu_plane *plane; + /* Identify the number of planes to be initialized */ + total_overlay_planes = dm->dc->caps.max_slave_planes; + total_primary_planes = dm->dc->caps.max_planes - dm->dc->caps.max_slave_planes; - plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL); - mode_info->planes[i] = plane; - - if (!plane) { - DRM_ERROR("KMS: Failed to allocate plane\n"); + /* First initialize overlay planes, index starting after primary planes */ + for (i = (total_overlay_planes - 1); i >= 0; i--) { + if (initialize_plane(dm, mode_info, (total_primary_planes + i))) { + DRM_ERROR("KMS: Failed to initialize overlay plane\n"); goto fail; } - plane->base.type = mode_info->plane_type[i]; - - /* - * HACK: IGT tests expect that each plane can only have one - * one possible CRTC. For now, set one CRTC for each - * plane that is not an underlay, but still allow multiple - * CRTCs for underlay planes. - */ - possible_crtcs = 1 << i; - if (i >= dm->dc->caps.max_streams) - possible_crtcs = 0xff; + } - if (amdgpu_dm_plane_init(dm, mode_info->planes[i], possible_crtcs)) { - DRM_ERROR("KMS: Failed to initialize plane\n"); + /* Initialize primary planes */ + for (i = (total_primary_planes - 1); i >= 0; i--) { + if (initialize_plane(dm, mode_info, i)) { + DRM_ERROR("KMS: Failed to initialize primary plane\n"); goto fail; } } @@ -1982,6 +2011,10 @@ static int fill_plane_attributes(struct amdgpu_device *adev, * every time. */ ret = amdgpu_dm_set_degamma_lut(crtc_state, dc_plane_state); + if (ret) { + dc_transfer_func_release(dc_plane_state->in_transfer_func); + dc_plane_state->in_transfer_func = NULL; + } return ret; } @@ -4691,8 +4724,8 @@ static int dm_update_planes_state(struct dc *dc, int ret = 0; - /* Add new planes */ - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { + /* Add new planes, in reverse order as DC expectation */ + for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { new_plane_crtc = new_plane_state->crtc; old_plane_crtc = old_plane_state->crtc; dm_new_plane_state = to_dm_plane_state(new_plane_state); @@ -4737,6 +4770,7 @@ static int dm_update_planes_state(struct dc *dc, *lock_and_validation_needed = true; } else { /* Add new planes */ + struct dc_plane_state *dc_new_plane_state; if (drm_atomic_plane_disabling(plane->state, new_plane_state)) continue; @@ -4755,34 +4789,42 @@ static int dm_update_planes_state(struct dc *dc, WARN_ON(dm_new_plane_state->dc_state); - dm_new_plane_state->dc_state = dc_create_plane_state(dc); + dc_new_plane_state = dc_create_plane_state(dc); + if (!dc_new_plane_state) + return -ENOMEM; DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", plane->base.id, new_plane_crtc->base.id); - if (!dm_new_plane_state->dc_state) { - ret = -EINVAL; - return ret; - } - ret = fill_plane_attributes( new_plane_crtc->dev->dev_private, - dm_new_plane_state->dc_state, + dc_new_plane_state, new_plane_state, new_crtc_state); - if (ret) + if (ret) { + dc_plane_state_release(dc_new_plane_state); return ret; + } + /* + * Any atomic check errors that occur after this will + * not need a release. The plane state will be attached + * to the stream, and therefore part of the atomic + * state. It'll be released when the atomic state is + * cleaned. + */ if (!dc_add_plane_to_context( dc, dm_new_crtc_state->stream, - dm_new_plane_state->dc_state, + dc_new_plane_state, dm_state->context)) { - ret = -EINVAL; - return ret; + dc_plane_state_release(dc_new_plane_state); + return -EINVAL; } + dm_new_plane_state->dc_state = dc_new_plane_state; + /* Tell DC to do a full surface update every time there * is a plane change. Inefficient, but works for now. */ @@ -4812,6 +4854,9 @@ static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, return -EDEADLK; crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + if (crtc->primary == plane && crtc_state->active) { if (!plane_state->fb) return -EINVAL; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index e845c511656e..f6cb502c303f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -193,6 +193,7 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) struct drm_property_blob *blob = crtc->base.ctm; struct dc_stream_state *stream = crtc->stream; struct drm_color_ctm *ctm; + int64_t val; int i; if (!blob) { @@ -206,7 +207,9 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) * DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating * with homogeneous coordinates, augment the matrix with 0's. * - * The format provided is S31.32, which is the same as our fixed31_32. + * The format provided is S31.32, using signed-magnitude representation. + * Our fixed31_32 is also S31.32, but is using 2's complement. We have + * to convert from signed-magnitude to 2's complement. */ for (i = 0; i < 12; i++) { /* Skip 4th element */ @@ -214,8 +217,14 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) stream->gamut_remap_matrix.matrix[i] = dal_fixed31_32_zero; continue; } - /* csc[i] = ctm[i - floor(i/4)] */ - stream->gamut_remap_matrix.matrix[i].value = ctm->matrix[i - (i/4)]; + + /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ + val = ctm->matrix[i - (i/4)]; + /* If negative, convert to 2's complement. */ + if (val & (1ULL << 63)) + val = -(val & ~(1ULL << 63)); + + stream->gamut_remap_matrix.matrix[i].value = val; } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 39cfe0fbf1b9..8291d74f26bc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -85,6 +85,9 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, enum ddc_result res; ssize_t read_bytes; + if (WARN_ON(msg->size > 16)) + return -E2BIG; + switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_READ: read_bytes = dal_ddc_service_read_dpcd_data( diff --git a/drivers/gpu/drm/amd/display/dc/basics/logger.c b/drivers/gpu/drm/amd/display/dc/basics/logger.c index 180a9d69d351..31bee054f43a 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/logger.c +++ b/drivers/gpu/drm/amd/display/dc/basics/logger.c @@ -60,7 +60,8 @@ static const struct dc_log_type_info log_type_info_tbl[] = { {LOG_EVENT_LINK_LOSS, "LinkLoss"}, {LOG_EVENT_UNDERFLOW, "Underflow"}, {LOG_IF_TRACE, "InterfaceTrace"}, - {LOG_DTN, "DTN"} + {LOG_DTN, "DTN"}, + {LOG_PROFILING, "Profiling"} }; diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 1689c670ca6f..e7680c41f117 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -44,7 +44,7 @@ #include "bios_parser_common.h" #define LAST_RECORD_TYPE 0xff - +#define SMU9_SYSPLL0_ID 0 struct i2c_id_config_access { uint8_t bfI2C_LineMux:4; @@ -1220,7 +1220,7 @@ static unsigned int bios_parser_get_smu_clock_info( if (!bp->cmd_tbl.get_smu_clock_info) return BP_RESULT_FAILURE; - return bp->cmd_tbl.get_smu_clock_info(bp); + return bp->cmd_tbl.get_smu_clock_info(bp, 0); } static enum bp_result bios_parser_program_crtc_timing( @@ -1376,7 +1376,7 @@ static enum bp_result get_firmware_info_v3_1( if (bp->cmd_tbl.get_smu_clock_info != NULL) { /* VBIOS gives in 10KHz */ info->smu_gpu_pll_output_freq = - bp->cmd_tbl.get_smu_clock_info(bp) * 10; + bp->cmd_tbl.get_smu_clock_info(bp, SMU9_SYSPLL0_ID) * 10; } return BP_RESULT_OK; diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index e362658aa3ce..3f63f712c8a4 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -796,7 +796,7 @@ static enum bp_result set_dce_clock_v2_1( ****************************************************************************** *****************************************************************************/ -static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp); +static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id); static void init_get_smu_clock_info(struct bios_parser *bp) { @@ -805,12 +805,13 @@ static void init_get_smu_clock_info(struct bios_parser *bp) } -static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp) +static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) { struct atom_get_smu_clock_info_parameters_v3_1 smu_input = {0}; struct atom_get_smu_clock_info_output_parameters_v3_1 smu_output; smu_input.command = GET_SMU_CLOCK_INFO_V3_1_GET_PLLVCO_FREQ; + smu_input.syspll_id = id; /* Get Specific Clock */ if (EXEC_BIOS_CMD_TABLE(getsmuclockinfo, smu_input)) { diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h index 59061b806df5..ec1c0c9f3f1d 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h @@ -96,7 +96,7 @@ struct cmd_tbl { struct bios_parser *bp, struct bp_set_dce_clock_parameters *bp_params); unsigned int (*get_smu_clock_info)( - struct bios_parser *bp); + struct bios_parser *bp, uint8_t id); }; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c index 6d38b8f43198..0cbab81ab304 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c @@ -85,7 +85,6 @@ static void calculate_bandwidth( const uint32_t s_mid5 = 5; const uint32_t s_mid6 = 6; const uint32_t s_high = 7; - const uint32_t bus_efficiency = 1; const uint32_t dmif_chunk_buff_margin = 1; uint32_t max_chunks_fbc_mode; @@ -592,7 +591,12 @@ static void calculate_bandwidth( /* 1 = use channel 0 and 1*/ /* 2 = use channel 0,1,2,3*/ if ((fbc_enabled == 1 && lpt_enabled == 1)) { - data->dram_efficiency = bw_int_to_fixed(1); + if (vbios->memory_type == bw_def_hbm) + data->dram_efficiency = bw_frc_to_fixed(5, 10); + else + data->dram_efficiency = bw_int_to_fixed(1); + + if (dceip->low_power_tiling_mode == 0) { data->number_of_dram_channels = 1; } @@ -607,7 +611,10 @@ static void calculate_bandwidth( } } else { - data->dram_efficiency = bw_frc_to_fixed(8, 10); + if (vbios->memory_type == bw_def_hbm) + data->dram_efficiency = bw_frc_to_fixed(5, 10); + else + data->dram_efficiency = bw_frc_to_fixed(8, 10); } /*memory request size and latency hiding:*/ /*request size is normally 64 byte, 2-line interleaved, with full latency hiding*/ @@ -1171,9 +1178,9 @@ static void calculate_bandwidth( } for (i = 0; i <= 2; i++) { for (j = 0; j <= 7; j++) { - data->dmif_burst_time[i][j] = bw_max3(data->dmif_total_page_close_open_time, bw_div(data->total_display_reads_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))), bw_div(data->total_display_reads_required_data, (bw_mul(bw_mul(sclk[j], vbios->data_return_bus_width), bw_int_to_fixed(bus_efficiency))))); + data->dmif_burst_time[i][j] = bw_max3(data->dmif_total_page_close_open_time, bw_div(data->total_display_reads_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))), bw_div(data->total_display_reads_required_data, (bw_mul(bw_mul(sclk[j], vbios->data_return_bus_width), bw_frc_to_fixed(dceip->percent_of_ideal_port_bw_received_after_urgent_latency, 100))))); if (data->d1_display_write_back_dwb_enable == 1) { - data->mcifwr_burst_time[i][j] = bw_max3(data->mcifwr_total_page_close_open_time, bw_div(data->total_display_writes_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_wrchannels)))), bw_div(data->total_display_writes_required_data, (bw_mul(bw_mul(sclk[j], vbios->data_return_bus_width), bw_int_to_fixed(bus_efficiency))))); + data->mcifwr_burst_time[i][j] = bw_max3(data->mcifwr_total_page_close_open_time, bw_div(data->total_display_writes_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_wrchannels)))), bw_div(data->total_display_writes_required_data, (bw_mul(sclk[j], vbios->data_return_bus_width)))); } } } @@ -1258,6 +1265,16 @@ static void calculate_bandwidth( /* / (dispclk - display bw)*/ /*the minimum latency hiding is the minimum for all pipes of one screen line time, plus one more line time if doing lb prefetch, plus the dmif data buffer size equivalent in time, minus the urgent latency.*/ /*the minimum latency hiding is further limited by the cursor. the cursor latency hiding is the number of lines of the cursor buffer, minus one if the downscaling is less than two, or minus three if it is more*/ + + /*initialize variables*/ + number_of_displays_enabled = 0; + number_of_displays_enabled_with_margin = 0; + for (k = 0; k <= maximum_number_of_surfaces - 1; k++) { + if (data->enable[k]) { + number_of_displays_enabled = number_of_displays_enabled + 1; + } + data->display_pstate_change_enable[k] = 0; + } for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { if ((bw_equ(dceip->stutter_and_dram_clock_state_change_gated_before_cursor, bw_int_to_fixed(0)) && bw_mtn(data->cursor_width_pixels[i], bw_int_to_fixed(0)))) { @@ -1276,7 +1293,10 @@ static void calculate_bandwidth( for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { if (dceip->graphics_lb_nodownscaling_multi_line_prefetching == 1 && (bw_equ(data->vsr[i], bw_int_to_fixed(1)) || (bw_leq(data->vsr[i], bw_frc_to_fixed(8, 10)) && bw_leq(data->v_taps[i], bw_int_to_fixed(2)) && data->lb_bpc[i] == 8)) && surface_type[i] == bw_def_graphics) { - data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_sub(data->lb_partitions[i], bw_int_to_fixed(1)), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); + if (number_of_displays_enabled > 2) + data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_sub(data->lb_partitions[i], bw_int_to_fixed(2)), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); + else + data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_sub(data->lb_partitions[i], bw_int_to_fixed(1)), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); } else { data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_int_to_fixed(1 + data->line_buffer_prefetch[i]), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); @@ -1338,24 +1358,15 @@ static void calculate_bandwidth( for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { if (dceip->graphics_lb_nodownscaling_multi_line_prefetching == 1) { - data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(8, 10), data->total_dmifmc_urgent_latency)); + data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(5, 10), data->total_dmifmc_urgent_latency)); } else { /*maximum_latency_hiding(i) = minimum_latency_hiding(i) + 1 / vsr(i) * h_total(i) / pixel_rate(i) + 0.5 * total_dmifmc_urgent_latency*/ - data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(8, 10), data->total_dmifmc_urgent_latency)); + data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(5, 10), data->total_dmifmc_urgent_latency)); } data->maximum_latency_hiding_with_cursor[i] = bw_min2(data->maximum_latency_hiding[i], data->cursor_latency_hiding[i]); } } - /*initialize variables*/ - number_of_displays_enabled = 0; - number_of_displays_enabled_with_margin = 0; - for (k = 0; k <= maximum_number_of_surfaces - 1; k++) { - if (data->enable[k]) { - number_of_displays_enabled = number_of_displays_enabled + 1; - } - data->display_pstate_change_enable[k] = 0; - } for (i = 0; i <= 2; i++) { for (j = 0; j <= 7; j++) { data->min_dram_speed_change_margin[i][j] = bw_int_to_fixed(9999); @@ -1370,10 +1381,11 @@ static void calculate_bandwidth( /*determine the minimum dram clock change margin for each set of clock frequencies*/ data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin); /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/ - data->dispclk_required_for_dram_speed_change[i][j] = bw_max3(data->dispclk_required_for_dram_speed_change[i][j], bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->active_time[k])))); - if ((bw_ltn(data->dispclk_required_for_dram_speed_change[i][j], vbios->high_voltage_max_dispclk))) { + data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->active_time[k])))); + if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) { data->display_pstate_change_enable[k] = 1; data->num_displays_with_margin[i][j] = data->num_displays_with_margin[i][j] + 1; + data->dispclk_required_for_dram_speed_change[i][j] = bw_max2(data->dispclk_required_for_dram_speed_change[i][j], data->dispclk_required_for_dram_speed_change_pipe[i][j]); } } } @@ -1383,10 +1395,11 @@ static void calculate_bandwidth( /*determine the minimum dram clock change margin for each display pipe*/ data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin); /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/ - data->dispclk_required_for_dram_speed_change[i][j] = bw_max3(data->dispclk_required_for_dram_speed_change[i][j], bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]), data->active_time[k])))); - if ((bw_ltn(data->dispclk_required_for_dram_speed_change[i][j], vbios->high_voltage_max_dispclk))) { + data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]), data->active_time[k])))); + if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) { data->display_pstate_change_enable[k] = 1; data->num_displays_with_margin[i][j] = data->num_displays_with_margin[i][j] + 1; + data->dispclk_required_for_dram_speed_change[i][j] = bw_max2(data->dispclk_required_for_dram_speed_change[i][j], data->dispclk_required_for_dram_speed_change_pipe[i][j]); } } } @@ -1420,7 +1433,7 @@ static void calculate_bandwidth( data->displays_with_same_mode[i] = bw_int_to_fixed(0); if (data->enable[i] == 1 && data->display_pstate_change_enable[i] == 0 && bw_mtn(data->v_blank_dram_speed_change_margin[i], bw_int_to_fixed(0))) { for (j = 0; j <= maximum_number_of_surfaces - 1; j++) { - if ((data->enable[j] == 1 && bw_equ(data->source_width_rounded_up_to_chunks[i], data->source_width_rounded_up_to_chunks[j]) && bw_equ(data->source_height_rounded_up_to_chunks[i], data->source_height_rounded_up_to_chunks[j]) && bw_equ(data->vsr[i], data->vsr[j]) && bw_equ(data->hsr[i], data->hsr[j]) && bw_equ(data->pixel_rate[i], data->pixel_rate[j]))) { + if ((i == j || data->display_synchronization_enabled) && (data->enable[j] == 1 && bw_equ(data->source_width_rounded_up_to_chunks[i], data->source_width_rounded_up_to_chunks[j]) && bw_equ(data->source_height_rounded_up_to_chunks[i], data->source_height_rounded_up_to_chunks[j]) && bw_equ(data->vsr[i], data->vsr[j]) && bw_equ(data->hsr[i], data->hsr[j]) && bw_equ(data->pixel_rate[i], data->pixel_rate[j]))) { data->displays_with_same_mode[i] = bw_add(data->displays_with_same_mode[i], bw_int_to_fixed(1)); } } @@ -1435,7 +1448,7 @@ static void calculate_bandwidth( /*aligned displays with the same timing.*/ /*the display(s) with the negative margin can be switched in the v_blank region while the other*/ /*displays are in v_blank or v_active.*/ - if ((number_of_displays_enabled_with_margin + number_of_aligned_displays_with_no_margin == number_of_displays_enabled && bw_mtn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(9999)) && bw_ltn(data->dispclk_required_for_dram_speed_change[high][s_high], vbios->high_voltage_max_dispclk))) { + if (number_of_displays_enabled_with_margin > 0 && (number_of_displays_enabled_with_margin + number_of_aligned_displays_with_no_margin) == number_of_displays_enabled && bw_mtn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(9999)) && bw_ltn(data->dispclk_required_for_dram_speed_change[high][s_high], vbios->high_voltage_max_dispclk)) { data->nbp_state_change_enable = bw_def_yes; } else { @@ -1448,6 +1461,25 @@ static void calculate_bandwidth( else { nbp_state_change_enable_blank = bw_def_no; } + + /*average bandwidth*/ + /*the average bandwidth with no compression is the vertical active time is the source width times the bytes per pixel divided by the line time, multiplied by the vertical scale ratio and the ratio of bytes per request divided by the useful bytes per request.*/ + /*the average bandwidth with compression is the same, divided by the compression ratio*/ + for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { + if (data->enable[i]) { + data->average_bandwidth_no_compression[i] = bw_div(bw_mul(bw_mul(bw_div(bw_mul(data->source_width_rounded_up_to_chunks[i], bw_int_to_fixed(data->bytes_per_pixel[i])), (bw_div(data->h_total[i], data->pixel_rate[i]))), data->vsr[i]), data->bytes_per_request[i]), data->useful_bytes_per_request[i]); + data->average_bandwidth[i] = bw_div(data->average_bandwidth_no_compression[i], data->compression_rate[i]); + } + } + data->total_average_bandwidth_no_compression = bw_int_to_fixed(0); + data->total_average_bandwidth = bw_int_to_fixed(0); + for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { + if (data->enable[i]) { + data->total_average_bandwidth_no_compression = bw_add(data->total_average_bandwidth_no_compression, data->average_bandwidth_no_compression[i]); + data->total_average_bandwidth = bw_add(data->total_average_bandwidth, data->average_bandwidth[i]); + } + } + /*required yclk(pclk)*/ /*yclk requirement only makes sense if the dmif and mcifwr data total page close-open time is less than the time for data transfer and the total pte requests fit in the scatter-gather saw queque size*/ /*if that is the case, the yclk requirement is the maximum of the ones required by dmif and mcifwr, and the high/low yclk(pclk) is chosen accordingly*/ @@ -1497,17 +1529,20 @@ static void calculate_bandwidth( } else { data->required_dram_bandwidth_gbyte_per_second = bw_div(bw_max2(data->dmif_required_dram_bandwidth, data->mcifwr_required_dram_bandwidth), bw_int_to_fixed(1000)); - if (bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[low]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[low][s_high], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[low][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[low][s_high] == number_of_displays_enabled_with_margin))) { + if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation, 100),yclk[low]),bw_div(bw_int_to_fixed(vbios->dram_channel_width_in_bits),bw_int_to_fixed(8))),bw_int_to_fixed(vbios->number_of_dram_channels))) + && bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[low]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[low][s_high], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[low][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[low][s_high] == number_of_displays_enabled_with_margin))) { yclk_message = bw_fixed_to_int(vbios->low_yclk); data->y_clk_level = low; data->dram_bandwidth = bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[low]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)); } - else if (bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[mid]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[mid][s_high], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[mid][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[mid][s_high] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation, 100),yclk[mid]),bw_div(bw_int_to_fixed(vbios->dram_channel_width_in_bits),bw_int_to_fixed(8))),bw_int_to_fixed(vbios->number_of_dram_channels))) + && bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[mid]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[mid][s_high], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[mid][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[mid][s_high] == number_of_displays_enabled_with_margin))) { yclk_message = bw_fixed_to_int(vbios->mid_yclk); data->y_clk_level = mid; data->dram_bandwidth = bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[mid]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)); } - else if (bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[high]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation, 100),yclk[high]),bw_div(bw_int_to_fixed(vbios->dram_channel_width_in_bits),bw_int_to_fixed(8))),bw_int_to_fixed(vbios->number_of_dram_channels))) + && bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[high]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))) { yclk_message = bw_fixed_to_int(vbios->high_yclk); data->y_clk_level = high; data->dram_bandwidth = bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[high]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)); @@ -1523,8 +1558,8 @@ static void calculate_bandwidth( /*if that is the case, the sclk requirement is the maximum of the ones required by dmif and mcifwr, and the high/mid/low sclk is chosen accordingly, unless that choice results in foresaking dram speed/nb p-state change.*/ /*the dmif and mcifwr sclk required is the one that allows the transfer of all pipe's data buffer size through the sclk bus in the time for data transfer*/ /*for dmif, pte and cursor requests have to be included.*/ - data->dmif_required_sclk = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer), (bw_mul(vbios->data_return_bus_width, bw_int_to_fixed(bus_efficiency)))); - data->mcifwr_required_sclk = bw_div(bw_div(data->total_display_writes_required_data, data->display_writes_time_for_data_transfer), (bw_mul(vbios->data_return_bus_width, bw_int_to_fixed(bus_efficiency)))); + data->dmif_required_sclk = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer), (bw_mul(vbios->data_return_bus_width, bw_frc_to_fixed(dceip->percent_of_ideal_port_bw_received_after_urgent_latency, 100)))); + data->mcifwr_required_sclk = bw_div(bw_div(data->total_display_writes_required_data, data->display_writes_time_for_data_transfer), vbios->data_return_bus_width); if (bw_mtn(data->scatter_gather_total_pte_requests, dceip->maximum_total_outstanding_pte_requests_allowed_by_saw)) { data->required_sclk = bw_int_to_fixed(9999); sclk_message = bw_def_exceeded_allowed_outstanding_pte_req_queue_size; @@ -1537,42 +1572,56 @@ static void calculate_bandwidth( } else { data->required_sclk = bw_max2(data->dmif_required_sclk, data->mcifwr_required_sclk); - if (bw_ltn(data->required_sclk, sclk[s_low]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_low], vbios->low_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_low] == number_of_displays_enabled_with_margin))) { + if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[low]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_low]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_low], vbios->low_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_low] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_low; data->sclk_level = s_low; data->required_sclk = vbios->low_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid1]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid1], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid1] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[mid]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid1]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid1], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid1] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid1; data->required_sclk = vbios->mid1_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid2]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid2], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid2] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid2]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid2]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid2], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid2] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid2; data->required_sclk = vbios->mid2_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid3]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid3], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid3] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid3]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid3]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid3], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid3] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid3; data->required_sclk = vbios->mid3_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid4]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid4], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid4] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid4]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid4]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid4], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid4] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid4; data->required_sclk = vbios->mid4_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid5]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid5], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid5] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid5]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid5]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid5], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid5] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid5; data->required_sclk = vbios->mid5_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid6]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid6] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid6]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid6]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid6] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid6; data->required_sclk = vbios->mid6_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_high])) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_high]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_high])) { + sclk_message = bw_def_high; + data->sclk_level = s_high; + data->required_sclk = vbios->high_sclk; + } + else if (bw_meq(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_high]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_high])) { sclk_message = bw_def_high; data->sclk_level = s_high; data->required_sclk = vbios->high_sclk; @@ -1681,7 +1730,7 @@ static void calculate_bandwidth( data->total_dispclk_required_with_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_with_ramping_with_request_bandwidth, data->dispclk_required_for_blackout_duration[data->y_clk_level][data->sclk_level]); data->total_dispclk_required_without_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_without_ramping_with_request_bandwidth, data->dispclk_required_for_blackout_duration[data->y_clk_level][data->sclk_level]); } - if (data->nbp_state_change_enable == bw_def_yes) { + if (data->nbp_state_change_enable == bw_def_yes && data->increase_voltage_to_support_mclk_switch) { data->total_dispclk_required_with_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_with_ramping_with_request_bandwidth, data->dispclk_required_for_dram_speed_change[data->y_clk_level][data->sclk_level]); data->total_dispclk_required_without_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_without_ramping_with_request_bandwidth, data->dispclk_required_for_dram_speed_change[data->y_clk_level][data->sclk_level]); } @@ -1861,23 +1910,6 @@ static void calculate_bandwidth( else { data->mcifwrdram_access_efficiency = bw_int_to_fixed(0); } - /*average bandwidth*/ - /*the average bandwidth with no compression is the vertical active time is the source width times the bytes per pixel divided by the line time, multiplied by the vertical scale ratio and the ratio of bytes per request divided by the useful bytes per request.*/ - /*the average bandwidth with compression is the same, divided by the compression ratio*/ - for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { - if (data->enable[i]) { - data->average_bandwidth_no_compression[i] = bw_div(bw_mul(bw_mul(bw_div(bw_mul(data->source_width_rounded_up_to_chunks[i], bw_int_to_fixed(data->bytes_per_pixel[i])), (bw_div(data->h_total[i], data->pixel_rate[i]))), data->vsr[i]), data->bytes_per_request[i]), data->useful_bytes_per_request[i]); - data->average_bandwidth[i] = bw_div(data->average_bandwidth_no_compression[i], data->compression_rate[i]); - } - } - data->total_average_bandwidth_no_compression = bw_int_to_fixed(0); - data->total_average_bandwidth = bw_int_to_fixed(0); - for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { - if (data->enable[i]) { - data->total_average_bandwidth_no_compression = bw_add(data->total_average_bandwidth_no_compression, data->average_bandwidth_no_compression[i]); - data->total_average_bandwidth = bw_add(data->total_average_bandwidth, data->average_bandwidth[i]); - } - } /*stutter efficiency*/ /*the stutter efficiency is the frame-average time in self-refresh divided by the frame-average stutter cycle duration. only applies if the display write-back is not enabled.*/ /*the frame-average stutter cycle used is the minimum for all pipes of the frame-average data buffer size in time, times the compression rate*/ @@ -1905,7 +1937,7 @@ static void calculate_bandwidth( data->total_stutter_dmif_buffer_size = bw_fixed_to_int(bw_add(data->stutter_dmif_buffer_size[i], bw_int_to_fixed(data->total_stutter_dmif_buffer_size))); } } - data->stutter_burst_time = bw_div(bw_int_to_fixed(data->total_stutter_dmif_buffer_size), bw_min2(bw_mul(data->dram_bandwidth, data->dmifdram_access_efficiency), bw_mul(sclk[data->sclk_level], bw_int_to_fixed(32)))); + data->stutter_burst_time = bw_div(bw_int_to_fixed(data->total_stutter_dmif_buffer_size), bw_mul(sclk[data->sclk_level], vbios->data_return_bus_width)); data->num_stutter_bursts = data->total_bytes_requested / data->min_stutter_dmif_buffer_size; data->total_stutter_cycle_duration = bw_add(bw_add(data->min_stutter_refresh_duration, vbios->stutter_self_refresh_exit_latency), data->stutter_burst_time); data->time_in_self_refresh = data->min_stutter_refresh_duration; @@ -1957,7 +1989,7 @@ static void calculate_bandwidth( for (i = 1; i <= 5; i++) { data->display_reads_time_for_data_transfer_and_urgent_latency = bw_sub(data->min_read_buffer_size_in_time, bw_mul(data->total_dmifmc_urgent_trips, bw_int_to_fixed(i))); if (pipe_check == bw_def_ok && (bw_mtn(data->display_reads_time_for_data_transfer_and_urgent_latency, data->dmif_total_page_close_open_time))) { - data->dmif_required_sclk_for_urgent_latency[i] = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer_and_urgent_latency), (bw_mul(vbios->data_return_bus_width, bw_int_to_fixed(bus_efficiency)))); + data->dmif_required_sclk_for_urgent_latency[i] = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer_and_urgent_latency), (bw_mul(vbios->data_return_bus_width, bw_frc_to_fixed(dceip->percent_of_ideal_port_bw_received_after_urgent_latency, 100)))); } else { data->dmif_required_sclk_for_urgent_latency[i] = bw_int_to_fixed(bw_def_na); @@ -2036,6 +2068,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2146,6 +2181,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2259,6 +2297,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2369,6 +2410,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2479,6 +2523,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(2304); dceip.dmif_pipe_en_fbc_chunk_tracker = true; @@ -2597,6 +2644,7 @@ static void populate_initial_data( data->graphics_tiling_mode = bw_def_tiled; data->underlay_micro_tile_mode = bw_def_display_micro_tiling; data->graphics_micro_tile_mode = bw_def_display_micro_tiling; + data->increase_voltage_to_support_mclk_switch = true; /* Pipes with underlay first */ for (i = 0; i < pipe_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 8020bc7742c1..4bb43a371292 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -983,8 +983,6 @@ bool dcn_validate_bandwidth( context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); } - context->bw.dcn.calc_clk.dram_ccm_us = (int)(v->dram_clock_change_margin); - context->bw.dcn.calc_clk.min_active_dram_ccm_us = (int)(v->min_active_dram_clock_change_margin); context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); context->bw.dcn.calc_clk.dcfclk_khz = (int)(v->dcfclk * 1000); @@ -998,7 +996,26 @@ bool dcn_validate_bandwidth( dc->debug.min_disp_clk_khz; } - context->bw.dcn.calc_clk.max_dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; + context->bw.dcn.calc_clk.dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; + + switch (v->voltage_level) { + case 0: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vmin0p65 * 1000); + break; + case 1: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vmid0p72 * 1000); + break; + case 2: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vnom0p8 * 1000); + break; + default: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vmax0p9 * 1000); + break; + } for (i = 0, input_idx = 0; i < pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 8394d69b963f..63a3d468939a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -42,6 +42,7 @@ #include "dmcu.h" #include "dpp.h" #include "timing_generator.h" +#include "abm.h" #include "virtual/virtual_link_encoder.h" #include "link_hwss.h" @@ -802,6 +803,8 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c if (!dcb->funcs->is_accelerated_mode(dcb)) dc->hwss.enable_accelerated_mode(dc, context); + dc->hwss.set_bandwidth(dc, context, false); + /* re-program planes for existing stream, in case we need to * free up plane resource for later use */ @@ -870,6 +873,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c dc_enable_stereo(dc, context, dc_streams, context->stream_count); + /* pplib is notified if disp_num changed */ + dc->hwss.set_bandwidth(dc, context, true); + dc_release_state(dc->current_state); dc->current_state = context; @@ -1104,9 +1110,6 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa if (u->plane_info->input_tf != u->surface->input_tf) update_flags->bits.input_tf_change = 1; - if (u->plane_info->sdr_white_level != u->surface->sdr_white_level) - update_flags->bits.output_tf_change = 1; - if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) update_flags->bits.horizontal_mirror_change = 1; @@ -1361,6 +1364,17 @@ static void commit_planes_for_stream(struct dc *dc, dc->hwss.apply_ctx_for_surface( dc, pipe_ctx->stream, stream_status->plane_count, context); + + if (stream_update && stream_update->abm_level && pipe_ctx->stream_res.abm) { + if (pipe_ctx->stream_res.tg->funcs->is_blanked) { + // if otg funcs defined check if blanked before programming + if (!pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) + pipe_ctx->stream_res.abm->funcs->set_abm_level( + pipe_ctx->stream_res.abm, stream->abm_level); + } else + pipe_ctx->stream_res.abm->funcs->set_abm_level( + pipe_ctx->stream_res.abm, stream->abm_level); + } } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index c15565092ca8..5a552cb3f8a7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -36,26 +36,22 @@ #include "hw_sequencer.h" #include "resource.h" +#define DC_LOGGER \ + logger #define SURFACE_TRACE(...) do {\ if (dc->debug.surface_trace) \ - dm_logger_write(logger, \ - LOG_IF_TRACE, \ - ##__VA_ARGS__); \ + DC_LOG_IF_TRACE(__VA_ARGS__); \ } while (0) #define TIMING_TRACE(...) do {\ if (dc->debug.timing_trace) \ - dm_logger_write(logger, \ - LOG_SYNC, \ - ##__VA_ARGS__); \ + DC_LOG_SYNC(__VA_ARGS__); \ } while (0) #define CLOCK_TRACE(...) do {\ if (dc->debug.clock_trace) \ - dm_logger_write(logger, \ - LOG_BANDWIDTH_CALCS, \ - ##__VA_ARGS__); \ + DC_LOG_BANDWIDTH_CALCS(__VA_ARGS__); \ } while (0) void pre_surface_trace( @@ -362,25 +358,19 @@ void context_clock_trace( struct dal_logger *logger = core_dc->ctx->logger; CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n" - "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.max_dppclk_khz, + context->bw.dcn.calc_clk.dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz, - context->bw.dcn.calc_clk.dram_ccm_us, - context->bw.dcn.calc_clk.min_active_dram_ccm_us); + context->bw.dcn.calc_clk.socclk_khz); CLOCK_TRACE("Calculated: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n" - "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.max_dppclk_khz, + context->bw.dcn.calc_clk.dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.dram_ccm_us, - context->bw.dcn.calc_clk.min_active_dram_ccm_us); + context->bw.dcn.calc_clk.fclk_khz); #endif } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index f8c09273e0f1..eeb04471b2f5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1960,6 +1960,13 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, (abm->funcs->set_backlight_level == NULL)) return false; + if (stream) { + if (stream->bl_pwm_level == 0) + frame_ramp = 0; + + ((struct dc_stream_state *)stream)->bl_pwm_level = level; + } + use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", level, level); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index b9fc6d842931..ba3487e97361 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1124,6 +1124,7 @@ bool dc_add_plane_to_context( ASSERT(tail_pipe); free_pipe->stream_res.tg = tail_pipe->stream_res.tg; + free_pipe->stream_res.abm = tail_pipe->stream_res.abm; free_pipe->stream_res.opp = tail_pipe->stream_res.opp; free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; free_pipe->stream_res.audio = tail_pipe->stream_res.audio; @@ -1736,6 +1737,10 @@ enum dc_status resource_map_pool_resources( pipe_ctx->stream_res.audio, true); } + /* Add ABM to the resource if on EDP */ + if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.abm = pool->abm; + for (i = 0; i < context->stream_count; i++) if (context->streams[i] == stream) { context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index cd5819789d76..ce0747ed0f00 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -198,8 +198,7 @@ bool dc_stream_set_cursor_attributes( for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && - !pipe_ctx->plane_res.dpp) || !pipe_ctx->plane_res.ipp) + if (pipe_ctx->stream != stream) continue; if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) continue; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2cd97342bf0f..fa4b3c8b3bb7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.37" +#define DC_VER "3.1.38" #define MAX_SURFACES 3 #define MAX_STREAMS 6 @@ -186,13 +186,12 @@ enum wm_report_mode { struct dc_clocks { int dispclk_khz; - int max_dppclk_khz; + int max_supported_dppclk_khz; + int dppclk_khz; int dcfclk_khz; int socclk_khz; int dcfclk_deep_sleep_khz; int fclk_khz; - int dram_ccm_us; - int min_active_dram_ccm_us; }; struct dc_debug { @@ -447,6 +446,7 @@ union surface_update_flags { struct dc_plane_state { struct dc_plane_address address; + struct dc_plane_flip_time time; struct scaling_taps scaling_quality; struct rect src_rect; struct rect dst_rect; @@ -557,6 +557,7 @@ struct dc_transfer_func *dc_create_transfer_func(void); */ struct dc_flip_addrs { struct dc_plane_address address; + unsigned int flip_timestamp_in_us; bool flip_immediate; /* TODO: add flip duration for FreeSync */ }; diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index e91ac6811990..b83a7dc2f5a9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -692,8 +692,18 @@ struct crtc_trigger_info { enum trigger_delay delay; }; -struct dc_crtc_timing { +enum vrr_state { + VRR_STATE_OFF = 0, + VRR_STATE_VARIABLE, + VRR_STATE_FIXED, +}; +struct dc_crtc_timing_adjust { + uint32_t v_total_min; + uint32_t v_total_max; +}; + +struct dc_crtc_timing { uint32_t h_total; uint32_t h_border_left; uint32_t h_addressable; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index f44cd4d87b79..d017df56b2ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -48,6 +48,8 @@ struct dc_stream_status { struct dc_stream_state { struct dc_sink *sink; struct dc_crtc_timing timing; + struct dc_crtc_timing_adjust timing_adjust; + struct vrr_params vrr_params; struct rect src; /* composition area */ struct rect dst; /* stream addressable area */ @@ -74,6 +76,10 @@ struct dc_stream_state { unsigned char psr_version; /* TODO: CEA VIC */ + /* DMCU info */ + unsigned int abm_level; + unsigned int bl_pwm_level; + /* from core_stream struct */ struct dc_context *ctx; @@ -106,6 +112,7 @@ struct dc_stream_update { struct dc_transfer_func *out_transfer_func; struct dc_hdr_static_metadata *hdr_static_metadata; enum color_transfer_func color_output_tf; + unsigned int *abm_level; }; bool dc_is_stream_unchanged( diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 8811b6f86bff..9441305d3ab5 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -521,6 +521,24 @@ struct audio_info { struct audio_mode modes[DC_MAX_AUDIO_DESC_COUNT]; }; +struct vrr_params { + enum vrr_state state; + uint32_t window_min; + uint32_t window_max; + uint32_t inserted_frame_duration_in_us; + uint32_t frames_to_insert; + uint32_t frame_counter; +}; + +#define DC_PLANE_UPDATE_TIMES_MAX 10 + +struct dc_plane_flip_time { + unsigned int time_elapsed_in_us[DC_PLANE_UPDATE_TIMES_MAX]; + unsigned int index; + unsigned int prev_update_time_in_us; +}; + +// Will combine with vrr_params at some point. struct freesync_context { bool supported; bool enabled; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h index 1d4546f23135..c24c0e5ea44e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h @@ -46,6 +46,23 @@ SR(SMU_INTERRUPT_CONTROL), \ SR(DC_DMCU_SCRATCH) +#define DMCU_DCE80_REG_LIST() \ + SR(DMCU_CTRL), \ + SR(DMCU_STATUS), \ + SR(DMCU_RAM_ACCESS_CTRL), \ + SR(DMCU_IRAM_WR_CTRL), \ + SR(DMCU_IRAM_WR_DATA), \ + SR(MASTER_COMM_DATA_REG1), \ + SR(MASTER_COMM_DATA_REG2), \ + SR(MASTER_COMM_DATA_REG3), \ + SR(MASTER_COMM_CMD_REG), \ + SR(MASTER_COMM_CNTL_REG), \ + SR(DMCU_IRAM_RD_CTRL), \ + SR(DMCU_IRAM_RD_DATA), \ + SR(DMCU_INTERRUPT_TO_UC_EN_MASK), \ + SR(SMU_INTERRUPT_CONTROL), \ + SR(DC_DMCU_SCRATCH) + #define DMCU_DCE110_COMMON_REG_LIST() \ DMCU_COMMON_REG_LIST_DCE_BASE(), \ SR(DCI_MEM_PWR_STATUS) @@ -83,6 +100,24 @@ STATIC_SCREEN4_INT_TO_UC_EN, mask_sh), \ DMCU_SF(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, mask_sh) +#define DMCU_MASK_SH_LIST_DCE80(mask_sh) \ + DMCU_SF(DMCU_CTRL, \ + DMCU_ENABLE, mask_sh), \ + DMCU_SF(DMCU_STATUS, \ + UC_IN_STOP_MODE, mask_sh), \ + DMCU_SF(DMCU_STATUS, \ + UC_IN_RESET, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_HOST_ACCESS_EN, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_WR_ADDR_AUTO_INC, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_RD_ADDR_AUTO_INC, mask_sh), \ + DMCU_SF(MASTER_COMM_CMD_REG, \ + MASTER_COMM_CMD_REG_BYTE0, mask_sh), \ + DMCU_SF(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, mask_sh), \ + DMCU_SF(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, mask_sh) + #define DMCU_MASK_SH_LIST_DCE110(mask_sh) \ DMCU_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh), \ DMCU_SF(DCI_MEM_PWR_STATUS, \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c index 4b8e7ce2de8c..487724345d9d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c @@ -56,7 +56,7 @@ void dce_pipe_control_lock(struct dc *dc, if (lock && pipe->stream_res.tg->funcs->is_blanked(pipe->stream_res.tg)) return; - val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->pipe_idx], + val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], BLND_DCP_GRPH_V_UPDATE_LOCK, &dcp_grph, BLND_SCL_V_UPDATE_LOCK, &scl, BLND_BLND_V_UPDATE_LOCK, &blnd, @@ -67,19 +67,19 @@ void dce_pipe_control_lock(struct dc *dc, blnd = lock_val; update_lock_mode = lock_val; - REG_SET_2(BLND_V_UPDATE_LOCK[pipe->pipe_idx], val, + REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, BLND_DCP_GRPH_V_UPDATE_LOCK, dcp_grph, BLND_SCL_V_UPDATE_LOCK, scl); if (hws->masks->BLND_BLND_V_UPDATE_LOCK != 0) - REG_SET_2(BLND_V_UPDATE_LOCK[pipe->pipe_idx], val, + REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, BLND_BLND_V_UPDATE_LOCK, blnd, BLND_V_UPDATE_LOCK_MODE, update_lock_mode); if (hws->wa.blnd_crtc_trigger) { if (!lock) { - uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->pipe_idx]); - REG_WRITE(CRTC_H_BLANK_START_END[pipe->pipe_idx], value); + uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst]); + REG_WRITE(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst], value); } } } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 3336428b1fed..057b8afd74bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -190,6 +190,7 @@ SR(D2VGA_CONTROL), \ SR(D3VGA_CONTROL), \ SR(D4VGA_CONTROL), \ + SR(VGA_TEST_CONTROL), \ SR(DC_IP_REQUEST_CNTL), \ BL_REG_LIST() @@ -261,6 +262,7 @@ struct dce_hwseq_registers { uint32_t D2VGA_CONTROL; uint32_t D3VGA_CONTROL; uint32_t D4VGA_CONTROL; + uint32_t VGA_TEST_CONTROL; /* MMHUB registers. read only. temporary hack */ uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32; uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; @@ -327,6 +329,8 @@ struct dce_hwseq_registers { HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, mask_sh),\ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh),\ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) @@ -403,7 +407,15 @@ struct dce_hwseq_registers { HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D2VGA_CONTROL, D2VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D3VGA_CONTROL, D3VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D4VGA_CONTROL, D4VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ + HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh), \ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) #define HWSEQ_REG_FIELD_LIST(type) \ @@ -436,7 +448,9 @@ struct dce_hwseq_registers { type ENABLE_L1_TLB;\ type SYSTEM_ACCESS_MODE;\ type LVTMA_BLON;\ - type LVTMA_PWRSEQ_TARGET_STATE_R; + type LVTMA_PWRSEQ_TARGET_STATE_R;\ + type LVTMA_DIGON;\ + type LVTMA_DIGON_OVRD; #define HWSEQ_DCN_REG_FIELD_LIST(type) \ type HUBP_VTG_SEL; \ @@ -483,7 +497,13 @@ struct dce_hwseq_registers { type DCFCLK_GATE_DIS; \ type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ type DENTIST_DPPCLK_WDIVIDER; \ - type DENTIST_DISPCLK_WDIVIDER; + type DENTIST_DISPCLK_WDIVIDER; \ + type VGA_TEST_ENABLE; \ + type VGA_TEST_RENDER_START; \ + type D1VGA_MODE_ENABLE; \ + type D2VGA_MODE_ENABLE; \ + type D3VGA_MODE_ENABLE; \ + type D4VGA_MODE_ENABLE; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 81776e4797ed..8167cad7bcf7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -767,8 +767,7 @@ void dce110_link_encoder_construct( bp_cap_info.DP_HBR3_EN; enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; } else { - dm_logger_write(enc110->base.ctx->logger, LOG_WARNING, - "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", + DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", __func__, result); } diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 3bdbed80f7f8..3092f76bdb75 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -51,6 +51,9 @@ #include "dce/dce_10_0_d.h" #include "dce/dce_10_0_sh_mask.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_abm.h" + #ifndef mmMC_HUB_RDREQ_DMIF_LIMIT #include "gmc/gmc_8_2_d.h" #include "gmc/gmc_8_2_sh_mask.h" @@ -320,7 +323,29 @@ static const struct dce110_clk_src_mask cs_mask = { CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; #define DCFE_MEM_PWR_CTRL_REG_BASE 0x1b03 @@ -622,6 +647,12 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.display_clock != NULL) dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + if (pool->base.irqs != NULL) dal_irq_service_destroy(&pool->base.irqs); } @@ -829,6 +860,25 @@ static bool construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } /* get static clock information for PPLIB or firmware, save * max_clock_state diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index c2041a63cccd..30dd62f0f5fa 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -737,10 +737,14 @@ static bool is_panel_backlight_on(struct dce_hwseq *hws) static bool is_panel_powered_on(struct dce_hwseq *hws) { - uint32_t value; + uint32_t pwr_seq_state, dig_on, dig_on_ovrd; + + + REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &pwr_seq_state); + + REG_GET_2(LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, &dig_on, LVTMA_DIGON_OVRD, &dig_on_ovrd); - REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &value); - return value == 1; + return (pwr_seq_state == 1) || (dig_on == 1 && dig_on_ovrd == 1); } static enum bp_result link_transmitter_control( @@ -1002,8 +1006,10 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, if (dc_is_dp_signal(pipe_ctx->stream->signal)) pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { link->dc->hwss.edp_backlight_control(link, true); + stream->bl_pwm_level = 0; + } } void dce110_blank_stream(struct pipe_ctx *pipe_ctx) { @@ -1128,7 +1134,7 @@ static void build_audio_output( static void get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx, struct tg_color *color) { - uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->pipe_idx) / 4; + uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->stream_res.tg->inst) / 4; switch (pipe_ctx->plane_res.scl_data.format) { case PIXEL_FORMAT_ARGB8888: @@ -2106,9 +2112,6 @@ enum dc_status dce110_apply_ctx_to_hw( return status; } - /* pplib is notified if disp_num changed */ - dc->hwss.set_bandwidth(dc, context, true); - /* to save power */ apply_min_clocks(dc, context, &clocks_state, false); @@ -2936,15 +2939,18 @@ void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) { struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; - if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) + if (pipe_ctx->plane_res.ipp && + pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( pipe_ctx->plane_res.ipp, attributes); - if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) + if (pipe_ctx->plane_res.mi && + pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( pipe_ctx->plane_res.mi, attributes); - if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) + if (pipe_ctx->plane_res.xfm && + pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( pipe_ctx->plane_res.xfm, attributes); } diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index a36c14d3d9a8..5d854a37a978 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -53,6 +53,8 @@ #include "reg_helper.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_abm.h" /* TODO remove this include */ #ifndef mmMC_HUB_RDREQ_DMIF_LIMIT @@ -364,6 +366,29 @@ static const struct resource_caps res_cap_83 = { .num_pll = 2, }; +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE80_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE80(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE80(_MASK) +}; +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + #define CTX ctx #define REG(reg) mm ## reg @@ -643,6 +668,12 @@ static void destruct(struct dce110_resource_pool *pool) } } + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + if (pool->base.dp_clock_source != NULL) dce80_clock_source_destroy(&pool->base.dp_clock_source); @@ -850,7 +881,25 @@ static bool dce80_construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) pool->base.display_clock->max_clks_state = static_clk_info.max_clocks_state; @@ -1016,6 +1065,25 @@ static bool dce81_construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) pool->base.display_clock->max_clks_state = @@ -1178,6 +1246,25 @@ static bool dce83_construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) pool->base.display_clock->max_clks_state = diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index f0b798930b51..e305c28c98de 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -464,6 +464,7 @@ static const struct dpp_funcs dcn10_dpp_funcs = { .set_cursor_attributes = dpp1_set_cursor_attributes, .set_cursor_position = dpp1_set_cursor_position, .dpp_dppclk_control = dpp1_dppclk_control, + .dpp_set_hdr_multiplier = dpp1_set_hdr_multiplier, }; static struct dpp_caps dcn10_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index 07003d9c6bba..17b062a8f88a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -113,7 +113,8 @@ SRI(CURSOR0_CONTROL, CNVC_CUR, id), \ SRI(CURSOR0_COLOR0, CNVC_CUR, id), \ SRI(CURSOR0_COLOR1, CNVC_CUR, id), \ - SRI(DPP_CONTROL, DPP_TOP, id) + SRI(DPP_CONTROL, DPP_TOP, id), \ + SRI(CM_HDR_MULT_COEF, CM, id) @@ -308,7 +309,8 @@ TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh), \ - TF_SF(DPP_TOP0_DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh) + TF_SF(DPP_TOP0_DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh), \ + TF_SF(CM0_CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, mask_sh) #define TF_REG_LIST_SH_MASK_DCN10(mask_sh)\ TF_REG_LIST_SH_MASK_DCN(mask_sh),\ @@ -1012,7 +1014,8 @@ type CUR0_COLOR0; \ type CUR0_COLOR1; \ type DPPCLK_RATE_CONTROL; \ - type DPP_CLOCK_ENABLE; + type DPP_CLOCK_ENABLE; \ + type CM_HDR_MULT_COEF; struct dcn_dpp_shift { TF_REG_FIELD_LIST(uint8_t) @@ -1258,7 +1261,8 @@ struct dcn_dpp_mask { uint32_t CURSOR0_CONTROL; \ uint32_t CURSOR0_COLOR0; \ uint32_t CURSOR0_COLOR1; \ - uint32_t DPP_CONTROL; + uint32_t DPP_CONTROL; \ + uint32_t CM_HDR_MULT_COEF; struct dcn_dpp_registers { DPP_COMMON_REG_VARIABLE_LIST @@ -1414,6 +1418,10 @@ void dpp1_dppclk_control( bool dppclk_div, bool enable); +void dpp1_set_hdr_multiplier( + struct dpp *dpp_base, + uint32_t multiplier); + void dpp1_construct(struct dcn10_dpp *dpp1, struct dc_context *ctx, uint32_t inst, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index bd3fcdfb79c5..fb32975e4b67 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -804,3 +804,12 @@ void dpp1_program_input_lut( REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, rama_occupied ? 3 : 2); REG_GET(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, &ram_num); } + +void dpp1_set_hdr_multiplier( + struct dpp *dpp_base, + uint32_t multiplier) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_UPDATE(CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, multiplier); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 1907ade1574a..8b0f6b8a5627 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -220,10 +220,34 @@ static void enable_power_gating_plane( static void disable_vga( struct dce_hwseq *hws) { + unsigned int in_vga1_mode = 0; + unsigned int in_vga2_mode = 0; + unsigned int in_vga3_mode = 0; + unsigned int in_vga4_mode = 0; + + REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); + REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); + REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); + REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); + + if (in_vga1_mode == 0 && in_vga2_mode == 0 && + in_vga3_mode == 0 && in_vga4_mode == 0) + return; + REG_WRITE(D1VGA_CONTROL, 0); REG_WRITE(D2VGA_CONTROL, 0); REG_WRITE(D3VGA_CONTROL, 0); REG_WRITE(D4VGA_CONTROL, 0); + + /* HW Engineer's Notes: + * During switch from vga->extended, if we set the VGA_TEST_ENABLE and + * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. + * + * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset + * VGA_TEST_ENABLE, to leave it in the same state as before. + */ + REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); + REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); } static void dpp_pg_control( @@ -1685,16 +1709,22 @@ static void update_dchubp_dpp( union plane_size size = plane_state->plane_size; /* depends on DML calculation, DPP clock value may change dynamically */ + /* If request max dpp clk is lower than current dispclk, no need to + * divided by 2 + */ if (plane_state->update_flags.bits.full_update) { + bool should_divided_by_2 = context->bw.dcn.calc_clk.dppclk_khz <= + context->bw.dcn.cur_clk.dispclk_khz / 2; + dpp->funcs->dpp_dppclk_control( dpp, - context->bw.dcn.calc_clk.max_dppclk_khz < - context->bw.dcn.calc_clk.dispclk_khz, + should_divided_by_2, true); - dc->current_state->bw.dcn.cur_clk.max_dppclk_khz = - context->bw.dcn.calc_clk.max_dppclk_khz; - context->bw.dcn.cur_clk.max_dppclk_khz = context->bw.dcn.calc_clk.max_dppclk_khz; + dc->current_state->bw.dcn.cur_clk.dppclk_khz = + should_divided_by_2 ? + context->bw.dcn.cur_clk.dispclk_khz / 2 : + context->bw.dcn.cur_clk.dispclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG @@ -1780,14 +1810,62 @@ static void update_dchubp_dpp( hubp->funcs->set_blank(hubp, false); } +static void dcn10_otg_blank( + struct dc *dc, + struct stream_resource stream_res, + struct dc_stream_state *stream, + bool blank) +{ + enum dc_color_space color_space; + struct tg_color black_color = {0}; + + /* program otg blank color */ + color_space = stream->output_color_space; + color_space_to_black_color(dc, color_space, &black_color); + + if (stream_res.tg->funcs->set_blank_color) + stream_res.tg->funcs->set_blank_color( + stream_res.tg, + &black_color); + + if (!blank) { + if (stream_res.tg->funcs->set_blank) + stream_res.tg->funcs->set_blank(stream_res.tg, blank); + if (stream_res.abm) + stream_res.abm->funcs->set_abm_level(stream_res.abm, stream->abm_level); + } else if (blank) { + if (stream_res.abm) + stream_res.abm->funcs->set_abm_immediate_disable(stream_res.abm); + if (stream_res.tg->funcs->set_blank) + stream_res.tg->funcs->set_blank(stream_res.tg, blank); + } +} + +static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) +{ + struct fixed31_32 multiplier = dal_fixed31_32_from_fraction( + pipe_ctx->plane_state->sdr_white_level, 80); + uint32_t hw_mult = 0x1f000; // 1.0 default multiplier + struct custom_float_format fmt; + + fmt.exponenta_bits = 6; + fmt.mantissa_bits = 12; + fmt.sign = true; + + if (pipe_ctx->plane_state->sdr_white_level > 80) + convert_to_custom_float_format(multiplier, &fmt, &hw_mult); + + pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( + pipe_ctx->plane_res.dpp, hw_mult); +} static void program_all_pipe_in_tree( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { - if (pipe_ctx->top_pipe == NULL) { + bool blank = !is_pipe_tree_visible(pipe_ctx); pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; @@ -1798,10 +1876,8 @@ static void program_all_pipe_in_tree( pipe_ctx->stream_res.tg->funcs->program_global_sync( pipe_ctx->stream_res.tg); - if (pipe_ctx->stream_res.tg->funcs->set_blank) - pipe_ctx->stream_res.tg->funcs->set_blank( - pipe_ctx->stream_res.tg, - !is_pipe_tree_visible(pipe_ctx)); + dcn10_otg_blank(dc, pipe_ctx->stream_res, + pipe_ctx->stream, blank); } if (pipe_ctx->plane_state != NULL) { @@ -1810,6 +1886,8 @@ static void program_all_pipe_in_tree( update_dchubp_dpp(dc, pipe_ctx, context); + set_hdr_multiplier(pipe_ctx); + if (pipe_ctx->plane_state->update_flags.bits.full_update || pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || pipe_ctx->plane_state->update_flags.bits.gamma_change) @@ -1836,16 +1914,10 @@ static void dcn10_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->all_displays_in_sync = false;/*todo*/ - pp_display_cfg->nb_pstate_switch_disable = false; pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz; pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz; pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->avail_mclk_switch_time_us = - context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0; - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = - context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0; pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz; pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); @@ -1908,29 +1980,23 @@ static void dcn10_apply_ctx_for_surface( { int i; struct timing_generator *tg; - struct output_pixel_processor *opp; bool removed_pipe[4] = { false }; unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; bool program_water_mark = false; struct dc_context *ctx = dc->ctx; - struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); if (!top_pipe_to_program) return; - opp = top_pipe_to_program->stream_res.opp; - tg = top_pipe_to_program->stream_res.tg; dcn10_pipe_control_lock(dc, top_pipe_to_program, true); if (num_planes == 0) { - /* OTG blank before remove all front end */ - if (tg->funcs->set_blank) - tg->funcs->set_blank(tg, true); + dcn10_otg_blank(dc, top_pipe_to_program->stream_res, top_pipe_to_program->stream, true); } /* Disconnect unused mpcc */ @@ -2056,6 +2122,101 @@ static void dcn10_apply_ctx_for_surface( */ } +static inline bool should_set_clock(bool decrease_allowed, int calc_clk, int cur_clk) +{ + return ((decrease_allowed && calc_clk < cur_clk) || calc_clk > cur_clk); +} + +static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) +{ + bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.calc_clk.dppclk_khz; + bool dispclk_increase = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.cur_clk.dispclk_khz; + int disp_clk_threshold = context->bw.dcn.calc_clk.max_supported_dppclk_khz; + bool cur_dpp_div = context->bw.dcn.cur_clk.dispclk_khz > + context->bw.dcn.cur_clk.dppclk_khz; + + /* increase clock, looking for div is 0 for current, request div is 1*/ + if (dispclk_increase) { + /* already divided by 2, no need to reach target clk with 2 steps*/ + if (cur_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* request disp clk is lower than maximum supported dpp clk, + * no need to reach target clk with two steps. + */ + if (context->bw.dcn.calc_clk.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* target dpp clk not request divided by 2, still within threshold */ + if (!request_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + } else { + /* decrease clock, looking for current dppclk divided by 2, + * request dppclk not divided by 2. + */ + + /* current dpp clk not divided by 2, no need to ramp*/ + if (!cur_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* current disp clk is lower than current maximum dpp clk, + * no need to ramp + */ + if (context->bw.dcn.cur_clk.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* request dpp clk need to be divided by 2 */ + if (request_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + } + + return disp_clk_threshold; +} + +static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) +{ + int i; + bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.calc_clk.dppclk_khz; + + int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); + + /* set disp clk to dpp clk threshold */ + dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock, + dispclk_to_dpp_threshold); + + /* update request dpp clk division option */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->plane_state) + continue; + + pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( + pipe_ctx->plane_res.dpp, + request_dpp_div, + true); + } + + /* If target clk not same as dppclk threshold, set to target clock */ + if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { + dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock, + context->bw.dcn.calc_clk.dispclk_khz); + } + + context->bw.dcn.cur_clk.dispclk_khz = + context->bw.dcn.calc_clk.dispclk_khz; + context->bw.dcn.cur_clk.dppclk_khz = + context->bw.dcn.calc_clk.dppclk_khz; + context->bw.dcn.cur_clk.max_supported_dppclk_khz = + context->bw.dcn.calc_clk.max_supported_dppclk_khz; +} + static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, @@ -2073,32 +2234,32 @@ static void dcn10_set_bandwidth( if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) return; - if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz - > dc->current_state->bw.dcn.cur_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - } - if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dcfclk_khz, + dc->current_state->bw.dcn.cur_clk.dcfclk_khz)) { context->bw.dcn.cur_clk.dcfclk_khz = context->bw.dcn.calc_clk.dcfclk_khz; smu_req.hard_min_dcefclk_khz = context->bw.dcn.calc_clk.dcfclk_khz; } - if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz - > dc->current_state->bw.dcn.cur_clk.fclk_khz) { + + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, + dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz)) { + context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = + context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; + } + + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.fclk_khz, + dc->current_state->bw.dcn.cur_clk.fclk_khz)) { context->bw.dcn.cur_clk.fclk_khz = context->bw.dcn.calc_clk.fclk_khz; smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; } - if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) { - context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; - } smu_req.display_count = context->stream_count; @@ -2107,17 +2268,17 @@ static void dcn10_set_bandwidth( *smu_req_cur = smu_req; - /* Decrease in freq is increase in period so opposite comparison for dram_ccm */ - if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us - < dc->current_state->bw.dcn.cur_clk.dram_ccm_us) { - context->bw.dcn.cur_clk.dram_ccm_us = - context->bw.dcn.calc_clk.dram_ccm_us; - } - if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us - < dc->current_state->bw.dcn.cur_clk.min_active_dram_ccm_us) { - context->bw.dcn.cur_clk.min_active_dram_ccm_us = - context->bw.dcn.calc_clk.min_active_dram_ccm_us; + /* make sure dcf clk is before dpp clk to + * make sure we have enough voltage to run dpp clk + */ + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dispclk_khz, + dc->current_state->bw.dcn.cur_clk.dispclk_khz)) { + + ramp_up_dispclk_with_dpp(dc, context); } + dcn10_pplib_apply_display_requirements(dc, context); if (dc->debug.sanity_checks) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index c4a564cb56b9..02bd664aed3e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -440,7 +440,11 @@ static const struct dc_debug debug_defaults_drv = { .timing_trace = false, .clock_trace = true, - .min_disp_clk_khz = 300000, + /* raven smu dones't allow 0 disp clk, + * smu min disp clk limit is 50Mhz + * keep min disp clk 100Mhz avoid smu hang + */ + .min_disp_clk_khz = 100000, .disable_pplib_clock_request = true, .disable_pplib_wm_range = false, @@ -963,6 +967,7 @@ static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer( idle_pipe->stream = head_pipe->stream; idle_pipe->stream_res.tg = head_pipe->stream_res.tg; + idle_pipe->stream_res.abm = head_pipe->stream_res.abm; idle_pipe->stream_res.opp = head_pipe->stream_res.opp; idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c index 189052e911fc..48400d642610 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c @@ -24,6 +24,7 @@ */ #include "display_rq_dlg_helpers.h" +#include "dml_logger.h" void print__rq_params_st(struct display_mode_lib *mode_lib, display_rq_params_st rq_param) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h b/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h index b2847bc469fe..f78cbae9db88 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h @@ -31,8 +31,6 @@ #include "display_mode_structs.h" #include "display_mode_enums.h" -#define dml_print(str, ...) {dm_logger_write(mode_lib->logger, LOG_DML, str, ##__VA_ARGS__); } -#define DTRACE(str, ...) {dm_logger_write(mode_lib->logger, LOG_DML, str, ##__VA_ARGS__); } double dml_round(double a); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h b/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h index e68086b8a22f..f9cf08357989 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h @@ -28,6 +28,7 @@ #include "dml_common_defs.h" #include "../calcs/dcn_calc_math.h" +#include "dml_logger.h" static inline double dml_min(double a, double b) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h b/drivers/gpu/drm/amd/display/dc/dml/dml_logger.h index c0c4bfdcdb14..465859b77248 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_logger.h @@ -1,5 +1,5 @@ /* - * Copyright 2015 Advanced Micro Devices, Inc. + * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,11 +23,16 @@ * */ -#ifndef __AMDGPU_POWERPLAY_H__ -#define __AMDGPU_POWERPLAY_H__ -#include "amd_shared.h" +#ifndef __DML_LOGGER_H_ +#define __DML_LOGGER_H_ + +#define DC_LOGGER \ + mode_lib->logger + +#define dml_print(str, ...) {DC_LOG_DML(str, ##__VA_ARGS__); } +#define DTRACE(str, ...) {DC_LOG_DML(str, ##__VA_ARGS__); } + +#endif -extern const struct amdgpu_ip_block_version amdgpu_pp_ip_block; -#endif /* __AMDGPU_POWERPLAY_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index b8f05384a897..8c51ad70cace 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -194,6 +194,8 @@ struct stream_resource { struct pixel_clk_params pix_clk_params; struct encoder_info_frame encoder_info_frame; + + struct abm *abm; }; struct plane_resource { diff --git a/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h index ae2399f16d1c..a9bfe9ff8ce6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h @@ -130,6 +130,9 @@ enum bw_defines { struct bw_calcs_dceip { enum bw_calcs_version version; + uint32_t percent_of_ideal_port_bw_received_after_urgent_latency; + uint32_t max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation; + uint32_t max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation; bool large_cursor; uint32_t cursor_max_outstanding_group_num; bool dmif_pipe_en_fbc_chunk_tracker; @@ -230,6 +233,7 @@ struct bw_calcs_vbios { struct bw_calcs_data { /* data for all displays */ + bool display_synchronization_enabled; uint32_t number_of_displays; enum bw_defines underlay_surface_type; enum bw_defines panning_and_bezel_adjustment; @@ -241,6 +245,7 @@ struct bw_calcs_data { bool d1_display_write_back_dwb_enable; enum bw_defines d1_underlay_mode; + bool increase_voltage_to_support_mclk_switch; bool cpup_state_change_enable; bool cpuc_state_change_enable; bool nbp_state_change_enable; @@ -449,6 +454,7 @@ struct bw_calcs_data { struct bw_fixed dram_speed_change_line_source_transfer_time[maximum_number_of_surfaces][3][8]; struct bw_fixed min_dram_speed_change_margin[3][8]; struct bw_fixed dispclk_required_for_dram_speed_change[3][8]; + struct bw_fixed dispclk_required_for_dram_speed_change_pipe[3][8]; struct bw_fixed blackout_duration_margin[3][8]; struct bw_fixed dispclk_required_for_blackout_duration[3][8]; struct bw_fixed dispclk_required_for_blackout_recovery[3][8]; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index c5aae2daf442..99995608b620 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -132,6 +132,9 @@ struct dpp_funcs { const struct dc_cursor_mi_param *param, uint32_t width ); + void (*dpp_set_hdr_multiplier)( + struct dpp *dpp_base, + uint32_t multiplier); void (*dpp_dppclk_control)( struct dpp *dpp_base, diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index b727f5eeb3a9..427796bdc14a 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -98,6 +98,7 @@ enum dc_log_type { LOG_EVENT_UNDERFLOW, LOG_IF_TRACE, LOG_PERF_TRACE, + LOG_PROFILING, LOG_SECTION_TOTAL_COUNT }; diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 57d5c2575de1..e7e374f56864 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1267,7 +1267,8 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, bool ret = false; struct pwl_float_data_ex *rgb_regamma = NULL; - if (trans == TRANSFER_FUNCTION_UNITY) { + if (trans == TRANSFER_FUNCTION_UNITY || + trans == TRANSFER_FUNCTION_LINEAR) { points->end_exponent = 0; points->x_point_at_y1_red = 1; points->x_point_at_y1_green = 1; @@ -1337,7 +1338,8 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, bool ret = false; struct pwl_float_data_ex *rgb_degamma = NULL; - if (trans == TRANSFER_FUNCTION_UNITY) { + if (trans == TRANSFER_FUNCTION_UNITY || + trans == TRANSFER_FUNCTION_LINEAR) { for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = coordinates_x[i].x; diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index b4723af368a5..27d4003aa2c7 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -33,7 +33,7 @@ /* Refresh rate ramp at a fixed rate of 65 Hz/second */ #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) /* Number of elements in the render times cache array */ -#define RENDER_TIMES_MAX_COUNT 20 +#define RENDER_TIMES_MAX_COUNT 10 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ #define BTR_EXIT_MARGIN 2000 /* Number of consecutive frames to check before entering/exiting fixed refresh*/ @@ -46,13 +46,15 @@ #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal" +#define FREESYNC_DEFAULT_REGKEY "LCDFreeSyncDefault" + struct gradual_static_ramp { bool ramp_is_active; bool ramp_direction_is_up; unsigned int ramp_current_frame_duration_in_ns; }; -struct time_cache { +struct freesync_time { /* video (48Hz feature) related */ unsigned int update_duration_in_ns; @@ -64,6 +66,9 @@ struct time_cache { unsigned int render_times_index; unsigned int render_times[RENDER_TIMES_MAX_COUNT]; + + unsigned int min_window; + unsigned int max_window; }; struct below_the_range { @@ -98,11 +103,14 @@ struct freesync_state { bool static_screen; bool video; + unsigned int vmin; + unsigned int vmax; + + struct freesync_time time; + unsigned int nominal_refresh_rate_in_micro_hz; bool windowed_fullscreen; - struct time_cache time; - struct gradual_static_ramp static_ramp; struct below_the_range btr; struct fixed_refresh fixed_refresh; @@ -119,14 +127,16 @@ struct freesync_entity { struct freesync_registry_options { bool drr_external_supported; bool drr_internal_supported; + bool lcd_freesync_default_set; + int lcd_freesync_default_value; }; struct core_freesync { struct mod_freesync public; struct dc *dc; + struct freesync_registry_options opts; struct freesync_entity *map; int num_entities; - struct freesync_registry_options opts; }; #define MOD_FREESYNC_TO_CORE(mod_freesync)\ @@ -146,7 +156,7 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) goto fail_alloc_context; core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, - GFP_KERNEL); + GFP_KERNEL); if (core_freesync->map == NULL) goto fail_alloc_map; @@ -183,6 +193,16 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) (data & 1) ? false : true; } + if (dm_read_persistent_data(dc->ctx, NULL, NULL, + FREESYNC_DEFAULT_REGKEY, + &data, sizeof(data), &flag)) { + core_freesync->opts.lcd_freesync_default_set = true; + core_freesync->opts.lcd_freesync_default_value = data; + } else { + core_freesync->opts.lcd_freesync_default_set = false; + core_freesync->opts.lcd_freesync_default_value = 0; + } + return &core_freesync->public; fail_construct: @@ -288,6 +308,18 @@ bool mod_freesync_add_stream(struct mod_freesync *mod_freesync, core_freesync->map[core_freesync->num_entities].user_enable. enable_for_video = (persistent_freesync_enable & 4) ? true : false; + /* If FreeSync display and LCDFreeSyncDefault is set, use as default values write back to userenable */ + } else if (caps->supported && (core_freesync->opts.lcd_freesync_default_set)) { + core_freesync->map[core_freesync->num_entities].user_enable.enable_for_gaming = + (core_freesync->opts.lcd_freesync_default_value & 1) ? true : false; + core_freesync->map[core_freesync->num_entities].user_enable.enable_for_static = + (core_freesync->opts.lcd_freesync_default_value & 2) ? true : false; + core_freesync->map[core_freesync->num_entities].user_enable.enable_for_video = + (core_freesync->opts.lcd_freesync_default_value & 4) ? true : false; + dm_write_persistent_data(dc->ctx, stream->sink, + FREESYNC_REGISTRY_NAME, + "userenable", &core_freesync->opts.lcd_freesync_default_value, + sizeof(int), &flag); } else { core_freesync->map[core_freesync->num_entities].user_enable. enable_for_gaming = false; @@ -330,6 +362,25 @@ bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync, return true; } +static void adjust_vmin_vmax(struct core_freesync *core_freesync, + struct dc_stream_state **streams, + int num_streams, + int map_index, + unsigned int v_total_min, + unsigned int v_total_max) +{ + if (num_streams == 0 || streams == NULL || num_streams > 1) + return; + + core_freesync->map[map_index].state.vmin = v_total_min; + core_freesync->map[map_index].state.vmax = v_total_max; + + dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, + num_streams, v_total_min, + v_total_max); +} + + static void update_stream_freesync_context(struct core_freesync *core_freesync, struct dc_stream_state *stream) { @@ -588,9 +639,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, update_stream_freesync_context(core_freesync, streams[stream_idx]); - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total_min, - v_total_max); + adjust_vmin_vmax(core_freesync, streams, + num_streams, map_index, + v_total_min, + v_total_max); return true; @@ -613,9 +665,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, core_freesync, streams[stream_idx]); - dc_stream_adjust_vmin_vmax( - core_freesync->dc, streams, - num_streams, v_total_nominal, + adjust_vmin_vmax( + core_freesync, streams, + num_streams, map_index, + v_total_nominal, v_total_nominal); } return true; @@ -632,9 +685,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, core_freesync, streams[stream_idx]); - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total_nominal, - v_total_nominal); + adjust_vmin_vmax(core_freesync, streams, + num_streams, map_index, + v_total_nominal, + v_total_nominal); /* Reset the cached variables */ reset_freesync_state_variables(state); @@ -650,9 +704,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, * not support freesync because a former stream has * be programmed */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total_nominal, - v_total_nominal); + adjust_vmin_vmax(core_freesync, streams, + num_streams, map_index, + v_total_nominal, + v_total_nominal); /* Reset the cached variables */ reset_freesync_state_variables(state); } @@ -769,8 +824,9 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, vmin = inserted_frame_v_total; /* Program V_TOTAL */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, vmin, vmax); + adjust_vmin_vmax(core_freesync, streams, + num_streams, index, + vmin, vmax); } if (state->btr.frame_counter > 0) @@ -804,9 +860,10 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, update_stream_freesync_context(core_freesync, streams[0]); /* Program static screen ramp values */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total, - v_total); + adjust_vmin_vmax(core_freesync, streams, + num_streams, index, + v_total, + v_total); triggers.overlay_update = true; triggers.surface_update = true; @@ -1063,9 +1120,9 @@ bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync, max_refresh); /* Program vtotal min/max */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, &streams, 1, - state->freesync_range.vmin, - state->freesync_range.vmax); + adjust_vmin_vmax(core_freesync, &streams, 1, index, + state->freesync_range.vmin, + state->freesync_range.vmax); } if (min_refresh != 0 && @@ -1399,11 +1456,9 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, } else { vmin = state->freesync_range.vmin; - vmax = vmin; - - dc_stream_adjust_vmin_vmax(core_freesync->dc, &stream, - 1, vmin, vmax); + adjust_vmin_vmax(core_freesync, &stream, map_index, + 1, vmin, vmax); } } @@ -1457,3 +1512,43 @@ void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, } } + +void mod_freesync_get_settings(struct mod_freesync *mod_freesync, + struct dc_stream_state **streams, int num_streams, + unsigned int *v_total_min, unsigned int *v_total_max, + unsigned int *event_triggers, + unsigned int *window_min, unsigned int *window_max, + unsigned int *lfc_mid_point_in_us, + unsigned int *inserted_frames, + unsigned int *inserted_duration_in_us) +{ + unsigned int stream_index, map_index; + struct core_freesync *core_freesync = NULL; + + if (mod_freesync == NULL) + return; + + core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); + + for (stream_index = 0; stream_index < num_streams; stream_index++) { + + map_index = map_index_from_stream(core_freesync, + streams[stream_index]); + + if (core_freesync->map[map_index].caps->supported) { + struct freesync_state state = + core_freesync->map[map_index].state; + *v_total_min = state.vmin; + *v_total_max = state.vmax; + *event_triggers = 0; + *window_min = state.time.min_window; + *window_max = state.time.max_window; + *lfc_mid_point_in_us = state.btr.mid_point_in_us; + *inserted_frames = state.btr.frames_to_insert; + *inserted_duration_in_us = + state.btr.inserted_frame_duration_in_us; + } + + } +} + diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index 84b53425f2c8..f083e1619dbe 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -164,4 +164,13 @@ void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, struct dc_stream_state **streams, int num_streams, unsigned int curr_time_stamp); +void mod_freesync_get_settings(struct mod_freesync *mod_freesync, + struct dc_stream_state **streams, int num_streams, + unsigned int *v_total_min, unsigned int *v_total_max, + unsigned int *event_triggers, + unsigned int *window_min, unsigned int *window_max, + unsigned int *lfc_mid_point_in_us, + unsigned int *inserted_frames, + unsigned int *inserted_duration_in_us); + #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h index 0c1593e53654..3230e2adb870 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h @@ -1,5 +1,5 @@ /* - * Copyright 2015 Advanced Micro Devices, Inc. + * Copyright 2016 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -19,29 +19,47 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * + * Authors: AMD + * */ -#ifndef PP_ASICBLOCKS_H -#define PP_ASICBLOCKS_H +#ifndef MODULES_INC_MOD_STATS_H_ +#define MODULES_INC_MOD_STATS_H_ -enum PHM_AsicBlock { - PHM_AsicBlock_GFX, - PHM_AsicBlock_UVD_MVC, - PHM_AsicBlock_UVD, - PHM_AsicBlock_UVD_HD, - PHM_AsicBlock_UVD_SD, - PHM_AsicBlock_Count -}; +#include "dm_services.h" -enum PHM_ClockGateSetting { - PHM_ClockGateSetting_StaticOn, - PHM_ClockGateSetting_StaticOff, - PHM_ClockGateSetting_Dynamic +struct mod_stats { + int dummy; }; -struct phm_asic_blocks { - bool gfx : 1; - bool uvd : 1; +struct mod_stats_caps { + bool dummy; }; -#endif +struct mod_stats *mod_stats_create(struct dc *dc); + +void mod_stats_destroy(struct mod_stats *mod_stats); + +bool mod_stats_init(struct mod_stats *mod_stats); + +void mod_stats_dump(struct mod_stats *mod_stats); + +void mod_stats_reset_data(struct mod_stats *mod_stats); + +void mod_stats_update_flip(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns); + +void mod_stats_update_vupdate(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns); + +void mod_stats_update_freesync(struct mod_stats *mod_stats, + unsigned int v_total_min, + unsigned int v_total_max, + unsigned int event_triggers, + unsigned int window_min, + unsigned int window_max, + unsigned int lfc_mid_point_in_us, + unsigned int inserted_frames, + unsigned int inserted_frame_duration_in_us); + +#endif /* MODULES_INC_MOD_STATS_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/stats/stats.c b/drivers/gpu/drm/amd/display/modules/stats/stats.c new file mode 100644 index 000000000000..041f87b73d5f --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/stats/stats.c @@ -0,0 +1,334 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "mod_stats.h" +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" + +#define DAL_STATS_ENABLE_REGKEY "DalStatsEnable" +#define DAL_STATS_ENABLE_REGKEY_DEFAULT 0x00000001 +#define DAL_STATS_ENABLE_REGKEY_ENABLED 0x00000001 + +#define DAL_STATS_ENTRIES_REGKEY "DalStatsEntries" +#define DAL_STATS_ENTRIES_REGKEY_DEFAULT 0x00350000 +#define DAL_STATS_ENTRIES_REGKEY_MAX 0x01000000 + +#define MOD_STATS_NUM_VSYNCS 5 + +struct stats_time_cache { + unsigned long flip_timestamp_in_ns; + unsigned long vupdate_timestamp_in_ns; + + unsigned int render_time_in_us; + unsigned int avg_render_time_in_us_last_ten; + unsigned int v_sync_time_in_us[MOD_STATS_NUM_VSYNCS]; + unsigned int num_vsync_between_flips; + + unsigned int flip_to_vsync_time_in_us; + unsigned int vsync_to_flip_time_in_us; + + unsigned int min_window; + unsigned int max_window; + unsigned int v_total_min; + unsigned int v_total_max; + unsigned int event_triggers; + + unsigned int lfc_mid_point_in_us; + unsigned int num_frames_inserted; + unsigned int inserted_duration_in_us; + + unsigned int flags; +}; + +struct core_stats { + struct mod_stats public; + struct dc *dc; + + struct stats_time_cache *time; + unsigned int index; + + bool enabled; + unsigned int entries; +}; + +#define MOD_STATS_TO_CORE(mod_stats)\ + container_of(mod_stats, struct core_stats, public) + +bool mod_stats_init(struct mod_stats *mod_stats) +{ + bool result = false; + struct core_stats *core_stats = NULL; + struct dc *dc = NULL; + + if (mod_stats == NULL) + return false; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + dc = core_stats->dc; + + return result; +} + +struct mod_stats *mod_stats_create(struct dc *dc) +{ + struct core_stats *core_stats = NULL; + struct persistent_data_flag flag; + unsigned int reg_data; + int i = 0; + + core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL); + + if (core_stats == NULL) + goto fail_alloc_context; + + if (dc == NULL) + goto fail_construct; + + core_stats->dc = dc; + + core_stats->enabled = DAL_STATS_ENABLE_REGKEY_DEFAULT; + if (dm_read_persistent_data(dc->ctx, NULL, NULL, + DAL_STATS_ENABLE_REGKEY, + ®_data, sizeof(unsigned int), &flag)) + core_stats->enabled = reg_data; + + core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT; + if (dm_read_persistent_data(dc->ctx, NULL, NULL, + DAL_STATS_ENTRIES_REGKEY, + ®_data, sizeof(unsigned int), &flag)) { + if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX) + core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX; + else + core_stats->entries = reg_data; + } + + core_stats->time = kzalloc(sizeof(struct stats_time_cache) * core_stats->entries, + GFP_KERNEL); + + if (core_stats->time == NULL) + goto fail_construct; + + /* Purposely leave index 0 unused so we don't need special logic to + * handle calculation cases that depend on previous flip data. + */ + core_stats->index = 1; + + return &core_stats->public; + +fail_construct: + kfree(core_stats); + +fail_alloc_context: + return NULL; +} + +void mod_stats_destroy(struct mod_stats *mod_stats) +{ + if (mod_stats != NULL) { + struct core_stats *core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->time != NULL) + kfree(core_stats->time); + + kfree(core_stats); + } +} + +void mod_stats_dump(struct mod_stats *mod_stats) +{ + struct dc *dc = NULL; + struct dal_logger *logger = NULL; + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + dc = core_stats->dc; + logger = dc->ctx->logger; + time = core_stats->time; + + //LogEntry* pLog = GetLog()->Open(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); + + //if (!pLog->IsDummyEntry()) + { + dm_logger_write(logger, LOG_PROFILING, "==Display Caps==\n"); + dm_logger_write(logger, LOG_PROFILING, "\n"); + dm_logger_write(logger, LOG_PROFILING, "\n"); + + dm_logger_write(logger, LOG_PROFILING, "==Stats==\n"); + dm_logger_write(logger, LOG_PROFILING, + "render avgRender minWindow midPoint maxWindow vsyncToFlip flipToVsync #vsyncBetweenFlip #frame insertDuration vTotalMin vTotalMax eventTrigs vSyncTime1 vSyncTime2 vSyncTime3 vSyncTime4 vSyncTime5 flags\n"); + + for (int i = 0; i < core_stats->index && i < core_stats->entries; i++) { + dm_logger_write(logger, LOG_PROFILING, + "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n", + time[i].render_time_in_us, + time[i].avg_render_time_in_us_last_ten, + time[i].min_window, + time[i].lfc_mid_point_in_us, + time[i].max_window, + time[i].vsync_to_flip_time_in_us, + time[i].flip_to_vsync_time_in_us, + time[i].num_vsync_between_flips, + time[i].num_frames_inserted, + time[i].inserted_duration_in_us, + time[i].v_total_min, + time[i].v_total_max, + time[i].event_triggers, + time[i].v_sync_time_in_us[0], + time[i].v_sync_time_in_us[1], + time[i].v_sync_time_in_us[2], + time[i].v_sync_time_in_us[3], + time[i].v_sync_time_in_us[4], + time[i].flags); + } + } + //GetLog()->Close(pLog); + //GetLog()->UnSetLogMask(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); +} + +void mod_stats_reset_data(struct mod_stats *mod_stats) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + memset(core_stats->time, 0, + sizeof(struct stats_time_cache) * core_stats->entries); + + core_stats->index = 0; +} + +void mod_stats_update_flip(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->index >= core_stats->entries) + return; + + time = core_stats->time; + index = core_stats->index; + + time[index].flip_timestamp_in_ns = timestamp_in_ns; + time[index].render_time_in_us = + timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; + + if (index >= 10) { + for (unsigned int i = 0; i < 10; i++) + time[index].avg_render_time_in_us_last_ten += + time[index - i].render_time_in_us; + time[index].avg_render_time_in_us_last_ten /= 10; + } + + if (time[index].num_vsync_between_flips > 0) + time[index].vsync_to_flip_time_in_us = + timestamp_in_ns - time[index].vupdate_timestamp_in_ns; + else + time[index].vsync_to_flip_time_in_us = + timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; + + core_stats->index++; +} + +void mod_stats_update_vupdate(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->index >= core_stats->entries) + return; + + time = core_stats->time; + index = core_stats->index; + + time[index].vupdate_timestamp_in_ns = timestamp_in_ns; + if (time[index].num_vsync_between_flips < MOD_STATS_NUM_VSYNCS) + time[index].v_sync_time_in_us[time[index].num_vsync_between_flips] = + timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; + time[index].flip_to_vsync_time_in_us = + timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; + + time[index].num_vsync_between_flips++; +} + +void mod_stats_update_freesync(struct mod_stats *mod_stats, + unsigned int v_total_min, + unsigned int v_total_max, + unsigned int event_triggers, + unsigned int window_min, + unsigned int window_max, + unsigned int lfc_mid_point_in_us, + unsigned int inserted_frames, + unsigned int inserted_duration_in_us) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->index >= core_stats->entries) + return; + + time = core_stats->time; + index = core_stats->index; + + time[index].v_total_min = v_total_min; + time[index].v_total_max = v_total_max; + time[index].event_triggers = event_triggers; + time[index].min_window = window_min; + time[index].max_window = window_max; + time[index].lfc_mid_point_in_us = lfc_mid_point_in_us; + time[index].num_frames_inserted = inserted_frames; + time[index].inserted_duration_in_us = inserted_duration_in_us; +} + diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 15bd0f9acf73..5c840c022b52 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -24,8 +24,7 @@ #ifndef __KGD_PP_INTERFACE_H__ #define __KGD_PP_INTERFACE_H__ -extern const struct amd_ip_funcs pp_ip_funcs; -extern const struct amd_pm_funcs pp_dpm_funcs; +extern const struct amdgpu_ip_block_version pp_smu_ip_block; struct amd_vce_state { /* vce clocks */ diff --git a/drivers/gpu/drm/amd/include/soc15_ih_clientid.h b/drivers/gpu/drm/amd/include/soc15_ih_clientid.h new file mode 100644 index 000000000000..a12d4f27cfa4 --- /dev/null +++ b/drivers/gpu/drm/amd/include/soc15_ih_clientid.h @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __SOC15_IH_CLIENTID_H__ +#define __SOC15_IH_CLIENTID_H__ + + /* + * vega10+ IH clients + */ +enum soc15_ih_clientid { + SOC15_IH_CLIENTID_IH = 0x00, + SOC15_IH_CLIENTID_ACP = 0x01, + SOC15_IH_CLIENTID_ATHUB = 0x02, + SOC15_IH_CLIENTID_BIF = 0x03, + SOC15_IH_CLIENTID_DCE = 0x04, + SOC15_IH_CLIENTID_ISP = 0x05, + SOC15_IH_CLIENTID_PCIE0 = 0x06, + SOC15_IH_CLIENTID_RLC = 0x07, + SOC15_IH_CLIENTID_SDMA0 = 0x08, + SOC15_IH_CLIENTID_SDMA1 = 0x09, + SOC15_IH_CLIENTID_SE0SH = 0x0a, + SOC15_IH_CLIENTID_SE1SH = 0x0b, + SOC15_IH_CLIENTID_SE2SH = 0x0c, + SOC15_IH_CLIENTID_SE3SH = 0x0d, + SOC15_IH_CLIENTID_SYSHUB = 0x0e, + SOC15_IH_CLIENTID_THM = 0x0f, + SOC15_IH_CLIENTID_UVD = 0x10, + SOC15_IH_CLIENTID_VCE0 = 0x11, + SOC15_IH_CLIENTID_VMC = 0x12, + SOC15_IH_CLIENTID_XDMA = 0x13, + SOC15_IH_CLIENTID_GRBM_CP = 0x14, + SOC15_IH_CLIENTID_ATS = 0x15, + SOC15_IH_CLIENTID_ROM_SMUIO = 0x16, + SOC15_IH_CLIENTID_DF = 0x17, + SOC15_IH_CLIENTID_VCE1 = 0x18, + SOC15_IH_CLIENTID_PWR = 0x19, + SOC15_IH_CLIENTID_UTCL2 = 0x1b, + SOC15_IH_CLIENTID_EA = 0x1c, + SOC15_IH_CLIENTID_UTCL2LOG = 0x1d, + SOC15_IH_CLIENTID_MP0 = 0x1e, + SOC15_IH_CLIENTID_MP1 = 0x1f, + + SOC15_IH_CLIENTID_MAX, + + SOC15_IH_CLIENTID_VCN = SOC15_IH_CLIENTID_UVD +}; + +#endif + + diff --git a/drivers/gpu/drm/amd/include/vega10_ip_offset.h b/drivers/gpu/drm/amd/include/vega10_ip_offset.h index 4c78dba5cf25..976dd2d565ba 100644 --- a/drivers/gpu/drm/amd/include/vega10_ip_offset.h +++ b/drivers/gpu/drm/amd/include/vega10_ip_offset.h @@ -24,191 +24,191 @@ #define MAX_INSTANCE 5 #define MAX_SEGMENT 5 -struct IP_BASE_INSTANCE +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; - -struct IP_BASE + +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; }; -static const struct IP_BASE NBIF_BASE = { { { { 0x00000000, 0x00000014, 0x00000D20, 0x00010400, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE NBIF_BASE = { { { { 0x00000000, 0x00000014, 0x00000D20, 0x00010400, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE NBIO_BASE = { { { { 0x00000000, 0x00000014, 0x00000D20, 0x00010400, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE NBIO_BASE = { { { { 0x00000000, 0x00000014, 0x00000D20, 0x00010400, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE DCE_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DCE_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE MP1_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE MP1_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE MP2_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE MP2_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE DF_BASE = { { { { 0x00007000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DF_BASE = { { { { 0x00007000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE UVD_BASE = { { { { 0x00007800, 0x00007E00, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE UVD_BASE = { { { { 0x00007800, 0x00007E00, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; //note: GLN does not use the first segment -static const struct IP_BASE VCN_BASE = { { { { 0x00007800, 0x00007E00, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE VCN_BASE = { { { { 0x00007800, 0x00007E00, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; //note: GLN does not use the first segment -static const struct IP_BASE DBGU_BASE = { { { { 0x00000180, 0x000001A0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DBGU_BASE = { { { { 0x00000180, 0x000001A0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; // not exist -static const struct IP_BASE DBGU_NBIO_BASE = { { { { 0x000001C0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DBGU_NBIO_BASE = { { { { 0x000001C0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; // not exist -static const struct IP_BASE DBGU_IO_BASE = { { { { 0x000001E0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DBGU_IO_BASE = { { { { 0x000001E0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; // not exist -static const struct IP_BASE DFX_DAP_BASE = { { { { 0x000005A0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DFX_DAP_BASE = { { { { 0x000005A0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; // not exist -static const struct IP_BASE DFX_BASE = { { { { 0x00000580, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE DFX_BASE = { { { { 0x00000580, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; // this file does not contain registers -static const struct IP_BASE ISP_BASE = { { { { 0x00018000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE ISP_BASE = { { { { 0x00018000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; // not exist -static const struct IP_BASE SYSTEMHUB_BASE = { { { { 0x00000EA0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE SYSTEMHUB_BASE = { { { { 0x00000EA0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; // not exist -static const struct IP_BASE L2IMU_BASE = { { { { 0x00007DC0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE L2IMU_BASE = { { { { 0x00007DC0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE IOHC_BASE = { { { { 0x00010000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE IOHC_BASE = { { { { 0x00010000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE ATHUB_BASE = { { { { 0x00000C20, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE ATHUB_BASE = { { { { 0x00000C20, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE VCE_BASE = { { { { 0x00007E00, 0x00048800, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE VCE_BASE = { { { { 0x00007E00, 0x00048800, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE GC_BASE = { { { { 0x00002000, 0x0000A000, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE GC_BASE = { { { { 0x00002000, 0x0000A000, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE MMHUB_BASE = { { { { 0x0001A000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE MMHUB_BASE = { { { { 0x0001A000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE RSMU_BASE = { { { { 0x00012000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE RSMU_BASE = { { { { 0x00012000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE HDP_BASE = { { { { 0x00000F20, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE HDP_BASE = { { { { 0x00000F20, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE OSSSYS_BASE = { { { { 0x000010A0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE OSSSYS_BASE = { { { { 0x000010A0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE SDMA0_BASE = { { { { 0x00001260, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE SDMA0_BASE = { { { { 0x00001260, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE SDMA1_BASE = { { { { 0x00001460, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE SDMA1_BASE = { { { { 0x00001460, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE XDMA_BASE = { { { { 0x00003400, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE XDMA_BASE = { { { { 0x00003400, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE UMC_BASE = { { { { 0x00014000, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE UMC_BASE = { { { { 0x00014000, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE THM_BASE = { { { { 0x00016600, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE THM_BASE = { { { { 0x00016600, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE SMUIO_BASE = { { { { 0x00016800, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE SMUIO_BASE = { { { { 0x00016800, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE PWR_BASE = { { { { 0x00016A00, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, +static const struct IP_BASE PWR_BASE = { { { { 0x00016A00, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0, 0, 0, 0 } }, - { { 0x00016E00, 0, 0, 0, 0 } }, - { { 0x00017000, 0, 0, 0, 0 } }, - { { 0x00017200, 0, 0, 0, 0 } }, - { { 0x00017E00, 0, 0, 0, 0 } } } }; -static const struct IP_BASE FUSE_BASE = { { { { 0x00017400, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0 } }, + { { 0x00016E00, 0, 0, 0, 0 } }, + { { 0x00017000, 0, 0, 0, 0 } }, + { { 0x00017200, 0, 0, 0, 0 } }, + { { 0x00017E00, 0, 0, 0, 0 } } } }; +static const struct IP_BASE FUSE_BASE = { { { { 0x00017400, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0 } } } }; diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index b989bf3542d6..3da3dccd13e2 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -27,7 +27,6 @@ #include <linux/slab.h> #include "amd_shared.h" #include "amd_powerplay.h" -#include "pp_instance.h" #include "power_state.h" #include "amdgpu.h" #include "hwmgr.h" @@ -37,18 +36,14 @@ static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id, enum amd_pm_state_type *user_state); -static inline int pp_check(struct pp_instance *handle) -{ - if (handle == NULL) - return -EINVAL; +static const struct amd_pm_funcs pp_dpm_funcs; - if (handle->hwmgr == NULL || handle->hwmgr->smumgr_funcs == NULL) +static inline int pp_check(struct pp_hwmgr *hwmgr) +{ + if (hwmgr == NULL || hwmgr->smumgr_funcs == NULL) return -EINVAL; - if (handle->pm_en == 0) - return PP_DPM_DISABLED; - - if (handle->hwmgr->hwmgr_func == NULL) + if (hwmgr->pm_en == 0 || hwmgr->hwmgr_func == NULL) return PP_DPM_DISABLED; return 0; @@ -56,54 +51,52 @@ static inline int pp_check(struct pp_instance *handle) static int amd_powerplay_create(struct amdgpu_device *adev) { - struct pp_instance *instance; + struct pp_hwmgr *hwmgr; if (adev == NULL) return -EINVAL; - instance = kzalloc(sizeof(struct pp_instance), GFP_KERNEL); - if (instance == NULL) + hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL); + if (hwmgr == NULL) return -ENOMEM; - instance->parent = adev; - instance->pm_en = (amdgpu_dpm != 0 && !amdgpu_sriov_vf(adev)) ? true : false; - instance->device = adev->powerplay.cgs_device; - mutex_init(&instance->pp_lock); - adev->powerplay.pp_handle = instance; - + hwmgr->adev = adev; + hwmgr->pm_en = (amdgpu_dpm != 0 && !amdgpu_sriov_vf(adev)) ? true : false; + hwmgr->device = amdgpu_cgs_create_device(adev); + mutex_init(&hwmgr->smu_lock); + hwmgr->chip_family = adev->family; + hwmgr->chip_id = adev->asic_type; + hwmgr->feature_mask = amdgpu_pp_feature_mask; + adev->powerplay.pp_handle = hwmgr; + adev->powerplay.pp_funcs = &pp_dpm_funcs; return 0; } -static int amd_powerplay_destroy(void *handle) +static int amd_powerplay_destroy(struct amdgpu_device *adev) { - struct pp_instance *instance = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - kfree(instance->hwmgr->hardcode_pp_table); - instance->hwmgr->hardcode_pp_table = NULL; + kfree(hwmgr->hardcode_pp_table); + hwmgr->hardcode_pp_table = NULL; - kfree(instance->hwmgr); - instance->hwmgr = NULL; + kfree(hwmgr); + hwmgr = NULL; - kfree(instance); - instance = NULL; return 0; } static int pp_early_init(void *handle) { int ret; - struct pp_instance *pp_handle = NULL; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = handle; ret = amd_powerplay_create(adev); if (ret != 0) return ret; - pp_handle = adev->powerplay.pp_handle; - - ret = hwmgr_early_init(pp_handle); + ret = hwmgr_early_init(adev->powerplay.pp_handle); if (ret) return -EINVAL; @@ -112,15 +105,13 @@ static int pp_early_init(void *handle) static int pp_sw_init(void *handle) { - struct pp_hwmgr *hwmgr; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret = 0; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret >= 0) { - hwmgr = pp_handle->hwmgr; - if (hwmgr->smumgr_funcs->smu_init == NULL) return -EINVAL; @@ -128,55 +119,57 @@ static int pp_sw_init(void *handle) pr_debug("amdgpu: powerplay sw initialized\n"); } + return ret; } static int pp_sw_fini(void *handle) { - struct pp_hwmgr *hwmgr; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret = 0; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret >= 0) { - hwmgr = pp_handle->hwmgr; + if (hwmgr->smumgr_funcs->smu_fini != NULL) + hwmgr->smumgr_funcs->smu_fini(hwmgr); + } - if (hwmgr->smumgr_funcs->smu_fini == NULL) - return -EINVAL; + if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) + amdgpu_ucode_fini_bo(adev); - ret = hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr); - } - return ret; + return 0; } static int pp_hw_init(void *handle) { int ret = 0; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - struct pp_hwmgr *hwmgr; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - ret = pp_check(pp_handle); + if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) + amdgpu_ucode_init_bo(adev); - if (ret >= 0) { - hwmgr = pp_handle->hwmgr; + ret = pp_check(hwmgr); + if (ret >= 0) { if (hwmgr->smumgr_funcs->start_smu == NULL) return -EINVAL; - if(hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr)) { + if (hwmgr->smumgr_funcs->start_smu(hwmgr)) { pr_err("smc start failed\n"); - hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr); + hwmgr->smumgr_funcs->smu_fini(hwmgr); return -EINVAL; } if (ret == PP_DPM_DISABLED) goto exit; - ret = hwmgr_hw_init(pp_handle); + ret = hwmgr_hw_init(hwmgr); if (ret) goto exit; } return ret; exit: - pp_handle->pm_en = 0; + hwmgr->pm_en = 0; cgs_notify_dpm_enabled(hwmgr->device, false); return 0; @@ -184,24 +177,27 @@ exit: static int pp_hw_fini(void *handle) { - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret == 0) - hwmgr_hw_fini(pp_handle); + hwmgr_hw_fini(hwmgr); return 0; } static int pp_late_init(void *handle) { - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); + if (ret == 0) - pp_dpm_dispatch_tasks(pp_handle, + pp_dpm_dispatch_tasks(hwmgr, AMD_PP_TASK_COMPLETE_INIT, NULL); return 0; @@ -209,7 +205,9 @@ static int pp_late_init(void *handle) static void pp_late_fini(void *handle) { - amd_powerplay_destroy(handle); + struct amdgpu_device *adev = handle; + + amd_powerplay_destroy(adev); } @@ -231,17 +229,15 @@ static int pp_sw_reset(void *handle) static int pp_set_powergating_state(void *handle, enum amd_powergating_state state) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; @@ -254,44 +250,43 @@ static int pp_set_powergating_state(void *handle, static int pp_suspend(void *handle) { - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret == 0) - hwmgr_hw_suspend(pp_handle); + hwmgr_hw_suspend(hwmgr); return 0; } static int pp_resume(void *handle) { - struct pp_hwmgr *hwmgr; + struct amdgpu_device *adev = handle; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret < 0) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->smumgr_funcs->start_smu == NULL) return -EINVAL; - if (hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr)) { + if (hwmgr->smumgr_funcs->start_smu(hwmgr)) { pr_err("smc start failed\n"); - hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr); + hwmgr->smumgr_funcs->smu_fini(hwmgr); return -EINVAL; } if (ret == PP_DPM_DISABLED) return 0; - return hwmgr_hw_resume(pp_handle); + return hwmgr_hw_resume(hwmgr); } -const struct amd_ip_funcs pp_ip_funcs = { +static const struct amd_ip_funcs pp_ip_funcs = { .name = "powerplay", .early_init = pp_early_init, .late_init = pp_late_init, @@ -309,6 +304,15 @@ const struct amd_ip_funcs pp_ip_funcs = { .set_powergating_state = pp_set_powergating_state, }; +const struct amdgpu_ip_block_version pp_smu_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_SMC, + .major = 1, + .minor = 0, + .rev = 0, + .funcs = &pp_ip_funcs, +}; + static int pp_dpm_load_fw(void *handle) { return 0; @@ -321,17 +325,14 @@ static int pp_dpm_fw_loading_complete(void *handle) static int pp_set_clockgating_by_smu(void *handle, uint32_t msg_id) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->update_clock_gatings == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; @@ -379,25 +380,22 @@ static void pp_dpm_en_umd_pstate(struct pp_hwmgr *hwmgr, static int pp_dpm_force_performance_level(void *handle, enum amd_dpm_forced_level level) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (level == hwmgr->dpm_level) return 0; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); pp_dpm_en_umd_pstate(hwmgr, &level); hwmgr->request_dpm_level = level; - hwmgr_handle_task(pp_handle, AMD_PP_TASK_READJUST_POWER_STATE, NULL); - mutex_unlock(&pp_handle->pp_lock); + hwmgr_handle_task(hwmgr, AMD_PP_TASK_READJUST_POWER_STATE, NULL); + mutex_unlock(&hwmgr->smu_lock); return 0; } @@ -405,152 +403,135 @@ static int pp_dpm_force_performance_level(void *handle, static enum amd_dpm_forced_level pp_dpm_get_performance_level( void *handle) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; enum amd_dpm_forced_level level; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); level = hwmgr->dpm_level; - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return level; } static uint32_t pp_dpm_get_sclk(void *handle, bool low) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; uint32_t clk = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_sclk == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); clk = hwmgr->hwmgr_func->get_sclk(hwmgr, low); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return clk; } static uint32_t pp_dpm_get_mclk(void *handle, bool low) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; uint32_t clk = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_mclk == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); clk = hwmgr->hwmgr_func->get_mclk(hwmgr, low); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return clk; } static void pp_dpm_powergate_vce(void *handle, bool gate) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->powergate_vce == NULL) { pr_info("%s was not implemented.\n", __func__); return; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); hwmgr->hwmgr_func->powergate_vce(hwmgr, gate); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); } static void pp_dpm_powergate_uvd(void *handle, bool gate) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->powergate_uvd == NULL) { pr_info("%s was not implemented.\n", __func__); return; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); } static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id, enum amd_pm_state_type *user_state) { int ret = 0; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - mutex_lock(&pp_handle->pp_lock); - ret = hwmgr_handle_task(pp_handle, task_id, user_state); - mutex_unlock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); + ret = hwmgr_handle_task(hwmgr, task_id, user_state); + mutex_unlock(&hwmgr->smu_lock); return ret; } static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle) { - struct pp_hwmgr *hwmgr; + struct pp_hwmgr *hwmgr = handle; struct pp_power_state *state; - struct pp_instance *pp_handle = (struct pp_instance *)handle; int ret = 0; enum amd_pm_state_type pm_type; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->current_ps == NULL) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); state = hwmgr->current_ps; @@ -571,147 +552,129 @@ static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle) pm_type = POWER_STATE_TYPE_DEFAULT; break; } - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return pm_type; } static void pp_dpm_set_fan_control_mode(void *handle, uint32_t mode) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) { pr_info("%s was not implemented.\n", __func__); return; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); } static uint32_t pp_dpm_get_fan_control_mode(void *handle) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; uint32_t mode = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); mode = hwmgr->hwmgr_func->get_fan_control_mode(hwmgr); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return mode; } static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_fan_speed_rpm == NULL) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->get_fan_speed_rpm(hwmgr, rpm); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_get_pp_num_states(void *handle, struct pp_states_info *data) { - struct pp_hwmgr *hwmgr; + struct pp_hwmgr *hwmgr = handle; int i; - struct pp_instance *pp_handle = (struct pp_instance *)handle; int ret = 0; memset(data, 0, sizeof(*data)); - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->ps == NULL) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); data->nums = hwmgr->num_ps; @@ -735,73 +698,68 @@ static int pp_dpm_get_pp_num_states(void *handle, data->states[i] = POWER_STATE_TYPE_DEFAULT; } } - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return 0; } static int pp_dpm_get_pp_table(void *handle, char **table) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; int size = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (!hwmgr->soft_pp_table) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); *table = (char *)hwmgr->soft_pp_table; size = hwmgr->soft_pp_table_size; - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return size; } static int amd_powerplay_reset(void *handle) { - struct pp_instance *instance = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret; - ret = pp_check(instance); + ret = pp_check(hwmgr); if (ret) return ret; - ret = pp_hw_fini(instance); + ret = pp_hw_fini(hwmgr); if (ret) return ret; - ret = hwmgr_hw_init(instance); + ret = hwmgr_hw_init(hwmgr); if (ret) return ret; - return hwmgr_handle_task(instance, AMD_PP_TASK_COMPLETE_INIT, NULL); + return hwmgr_handle_task(hwmgr, AMD_PP_TASK_COMPLETE_INIT, NULL); } static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); if (!hwmgr->hardcode_pp_table) { hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table, hwmgr->soft_pp_table_size, GFP_KERNEL); if (!hwmgr->hardcode_pp_table) { - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return -ENOMEM; } } @@ -809,7 +767,7 @@ static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) memcpy(hwmgr->hardcode_pp_table, buf, size); hwmgr->soft_pp_table = hwmgr->hardcode_pp_table; - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); ret = amd_powerplay_reset(handle); if (ret) @@ -827,163 +785,142 @@ static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) static int pp_dpm_force_clock_level(void *handle, enum pp_clock_type type, uint32_t mask) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->force_clock_level == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) ret = hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask); else ret = -EINVAL; - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_print_clock_levels(void *handle, enum pp_clock_type type, char *buf) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->print_clock_levels == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_get_sclk_od(void *handle) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_sclk_od == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->get_sclk_od(hwmgr); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_set_sclk_od(void *handle, uint32_t value) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_sclk_od == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->set_sclk_od(hwmgr, value); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_get_mclk_od(void *handle) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_mclk_od == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->get_mclk_od(hwmgr); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_set_mclk_od(void *handle, uint32_t value) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_mclk_od == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->set_mclk_od(hwmgr, value); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_dpm_read_sensor(void *handle, int idx, void *value, int *size) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; if (value == NULL) return -EINVAL; - hwmgr = pp_handle->hwmgr; - switch (idx) { case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK: *((uint32_t *)value) = hwmgr->pstate_sclk; @@ -992,9 +929,9 @@ static int pp_dpm_read_sensor(void *handle, int idx, *((uint32_t *)value) = hwmgr->pstate_mclk; return 0; default: - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } } @@ -1002,17 +939,14 @@ static int pp_dpm_read_sensor(void *handle, int idx, static struct amd_vce_state* pp_dpm_get_vce_clock_state(void *handle, unsigned idx) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return NULL; - hwmgr = pp_handle->hwmgr; - if (hwmgr && idx < hwmgr->num_vce_state_tables) return &hwmgr->vce_states[idx]; return NULL; @@ -1020,14 +954,11 @@ pp_dpm_get_vce_clock_state(void *handle, unsigned idx) static int pp_get_power_profile_mode(void *handle, char *buf) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; - if (!buf || pp_check(pp_handle)) + if (!buf || pp_check(hwmgr)) return -EINVAL; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->get_power_profile_mode == NULL) { pr_info("%s was not implemented.\n", __func__); return snprintf(buf, PAGE_SIZE, "\n"); @@ -1038,36 +969,30 @@ static int pp_get_power_profile_mode(void *handle, char *buf) static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = -EINVAL; - if (pp_check(pp_handle)) + if (pp_check(hwmgr)) return -EINVAL; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) { pr_info("%s was not implemented.\n", __func__); return -EINVAL; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) ret = hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, input, size); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; - if (pp_check(pp_handle)) + if (pp_check(hwmgr)) return -EINVAL; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) { pr_info("%s was not implemented.\n", __func__); return -EINVAL; @@ -1079,16 +1004,13 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3 static int pp_dpm_switch_power_profile(void *handle, enum PP_SMC_POWER_PROFILE type, bool en) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; long workload; uint32_t index; - if (pp_check(pp_handle)) + if (pp_check(hwmgr)) return -EINVAL; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) { pr_info("%s was not implemented.\n", __func__); return -EINVAL; @@ -1097,7 +1019,7 @@ static int pp_dpm_switch_power_profile(void *handle, if (!(type < PP_SMC_POWER_PROFILE_CUSTOM)) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); if (!en) { hwmgr->workload_mask &= ~(1 << hwmgr->workload_prority[type]); @@ -1113,7 +1035,7 @@ static int pp_dpm_switch_power_profile(void *handle, if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return 0; } @@ -1125,46 +1047,40 @@ static int pp_dpm_notify_smu_memory_info(void *handle, uint32_t mc_addr_hi, uint32_t size) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->notify_cac_buffer_info == NULL) { pr_info("%s was not implemented.\n", __func__); return -EINVAL; } - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = hwmgr->hwmgr_func->notify_cac_buffer_info(hwmgr, virtual_addr_low, virtual_addr_hi, mc_addr_low, mc_addr_hi, size); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_set_power_limit(void *handle, uint32_t limit) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_power_limit == NULL) { pr_info("%s was not implemented.\n", __func__); return -EINVAL; @@ -1176,20 +1092,19 @@ static int pp_set_power_limit(void *handle, uint32_t limit) if (limit > hwmgr->default_power_limit) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); hwmgr->hwmgr_func->set_power_limit(hwmgr, limit); hwmgr->power_limit = limit; - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_get_power_limit(void *handle, uint32_t *limit, bool default_limit) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; @@ -1197,16 +1112,14 @@ static int pp_get_power_limit(void *handle, uint32_t *limit, bool default_limit) if (limit == NULL) return -EINVAL; - hwmgr = pp_handle->hwmgr; - - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); if (default_limit) *limit = hwmgr->default_power_limit; else *limit = hwmgr->power_limit; - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } @@ -1214,42 +1127,37 @@ static int pp_get_power_limit(void *handle, uint32_t *limit, bool default_limit) static int pp_display_configuration_change(void *handle, const struct amd_pp_display_configuration *display_config) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); phm_store_dal_configuration_data(hwmgr, display_config); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return 0; } static int pp_get_display_power_level(void *handle, struct amd_pp_simple_clock_info *output) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (output == NULL) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = phm_get_dal_power_level(hwmgr, output); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } @@ -1258,18 +1166,15 @@ static int pp_get_current_clocks(void *handle, { struct amd_pp_simple_clock_info simple_clocks; struct pp_clock_info hw_clocks; - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); phm_get_dal_power_level(hwmgr, &simple_clocks); @@ -1283,7 +1188,7 @@ static int pp_get_current_clocks(void *handle, if (ret) { pr_info("Error in phm_get_clock_info \n"); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return -EINVAL; } @@ -1303,29 +1208,26 @@ static int pp_get_current_clocks(void *handle, clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; } - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return 0; } static int pp_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (clocks == NULL) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = phm_get_clock_by_type(hwmgr, type, clocks); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } @@ -1333,21 +1235,19 @@ static int pp_get_clock_by_type_with_latency(void *handle, enum amd_pp_clock_type type, struct pp_clock_levels_with_latency *clocks) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; if (!clocks) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); - hwmgr = ((struct pp_instance *)handle)->hwmgr; + mutex_lock(&hwmgr->smu_lock); ret = phm_get_clock_by_type_with_latency(hwmgr, type, clocks); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } @@ -1355,47 +1255,41 @@ static int pp_get_clock_by_type_with_voltage(void *handle, enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; if (!clocks) return -EINVAL; - hwmgr = ((struct pp_instance *)handle)->hwmgr; - - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = phm_get_clock_by_type_with_voltage(hwmgr, type, clocks); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_set_watermarks_for_clocks_ranges(void *handle, struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; if (!wm_with_clock_ranges) return -EINVAL; - hwmgr = ((struct pp_instance *)handle)->hwmgr; - - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = phm_set_watermarks_for_clocks_ranges(hwmgr, wm_with_clock_ranges); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } @@ -1403,22 +1297,19 @@ static int pp_set_watermarks_for_clocks_ranges(void *handle, static int pp_display_clock_voltage_request(void *handle, struct pp_display_clock_request *clock) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; if (!clock) return -EINVAL; - hwmgr = ((struct pp_instance *)handle)->hwmgr; - - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); ret = phm_display_clock_voltage_request(hwmgr, clock); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } @@ -1426,42 +1317,36 @@ static int pp_display_clock_voltage_request(void *handle, static int pp_get_display_mode_validation_clocks(void *handle, struct amd_pp_simple_clock_info *clocks) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (clocks == NULL) return -EINVAL; - mutex_lock(&pp_handle->pp_lock); + mutex_lock(&hwmgr->smu_lock); if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState)) ret = phm_get_max_high_clocks(hwmgr, clocks); - mutex_unlock(&pp_handle->pp_lock); + mutex_unlock(&hwmgr->smu_lock); return ret; } static int pp_set_mmhub_powergating_by_smu(void *handle) { - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; + struct pp_hwmgr *hwmgr = handle; int ret = 0; - ret = pp_check(pp_handle); + ret = pp_check(hwmgr); if (ret) return ret; - hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->set_mmhub_powergating_by_smu == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; @@ -1470,7 +1355,7 @@ static int pp_set_mmhub_powergating_by_smu(void *handle) return hwmgr->hwmgr_func->set_mmhub_powergating_by_smu(hwmgr); } -const struct amd_pm_funcs pp_dpm_funcs = { +static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, .force_performance_level = pp_dpm_force_performance_level, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index e8c5a4f84324..f868b955da92 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile @@ -24,14 +24,14 @@ # It provides the hardware management services for the driver. HARDWARE_MGR = hwmgr.o processpptables.o \ - hardwaremanager.o cz_hwmgr.o \ - cz_clockpowergating.o pppcielanes.o\ + hardwaremanager.o smu8_hwmgr.o \ + pppcielanes.o\ process_pptables_v1_0.o ppatomctrl.o ppatomfwctrl.o \ smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \ smu7_clockpowergating.o \ vega10_processpptables.o vega10_hwmgr.o vega10_powertune.o \ - vega10_thermal.o rv_hwmgr.o pp_psm.o\ - pp_overdriver.o + vega10_thermal.o smu10_hwmgr.o pp_psm.o\ + pp_overdriver.o smu_helper.o AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c deleted file mode 100644 index 416abebb8b86..000000000000 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "hwmgr.h" -#include "cz_clockpowergating.h" -#include "cz_ppsmc.h" - -/* PhyID -> Status Mapping in DDI_PHY_GEN_STATUS - 0 GFX0L (3:0), (27:24), - 1 GFX0H (7:4), (31:28), - 2 GFX1L (3:0), (19:16), - 3 GFX1H (7:4), (23:20), - 4 DDIL (3:0), (11: 8), - 5 DDIH (7:4), (15:12), - 6 DDI2L (3:0), ( 3: 0), - 7 DDI2H (7:4), ( 7: 4), -*/ -#define DDI_PHY_GEN_STATUS_VAL(phyID) (1 << ((3 - ((phyID & 0x07)/2))*8 + (phyID & 0x01)*4)) -#define IS_PHY_ID_USED_BY_PLL(PhyID) (((0xF3 & (1 << PhyID)) & 0xFF) ? true : false) - - -int cz_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating) -{ - int ret = 0; - - switch (block) { - case PHM_AsicBlock_UVD_MVC: - case PHM_AsicBlock_UVD: - case PHM_AsicBlock_UVD_HD: - case PHM_AsicBlock_UVD_SD: - if (gating == PHM_ClockGateSetting_StaticOff) - ret = cz_dpm_powerdown_uvd(hwmgr); - else - ret = cz_dpm_powerup_uvd(hwmgr); - break; - case PHM_AsicBlock_GFX: - default: - break; - } - - return ret; -} - - -bool cz_phm_is_safe_for_asic_block(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, enum PHM_AsicBlock block) -{ - return true; -} - - -int cz_phm_enable_disable_gfx_power_gating(struct pp_hwmgr *hwmgr, bool enable) -{ - return 0; -} - -int cz_phm_smu_power_up_down_pcie(struct pp_hwmgr *hwmgr, uint32_t target, bool up, uint32_t args) -{ - /* TODO */ - return 0; -} - -int cz_phm_initialize_display_phy_access(struct pp_hwmgr *hwmgr, bool initialize, bool accesshw) -{ - /* TODO */ - return 0; -} - -int cz_phm_get_display_phy_access_info(struct pp_hwmgr *hwmgr) -{ - /* TODO */ - return 0; -} - -int cz_phm_gate_unused_display_phys(struct pp_hwmgr *hwmgr) -{ - /* TODO */ - return 0; -} - -int cz_phm_ungate_all_display_phys(struct pp_hwmgr *hwmgr) -{ - /* TODO */ - return 0; -} - -int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) -{ - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - uint32_t dpm_features = 0; - - if (enable && - phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_UVDDPM)) { - cz_hwmgr->dpm_flags |= DPMFlags_UVD_Enabled; - dpm_features |= UVD_DPM_MASK; - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_EnableAllSmuFeatures, dpm_features); - } else { - dpm_features |= UVD_DPM_MASK; - cz_hwmgr->dpm_flags &= ~DPMFlags_UVD_Enabled; - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_DisableAllSmuFeatures, dpm_features); - } - return 0; -} - -int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) -{ - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - uint32_t dpm_features = 0; - - if (enable && phm_cap_enabled( - hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_VCEDPM)) { - cz_hwmgr->dpm_flags |= DPMFlags_VCE_Enabled; - dpm_features |= VCE_DPM_MASK; - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_EnableAllSmuFeatures, dpm_features); - } else { - dpm_features |= VCE_DPM_MASK; - cz_hwmgr->dpm_flags &= ~DPMFlags_VCE_Enabled; - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_DisableAllSmuFeatures, dpm_features); - } - - return 0; -} - - -void cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate) -{ - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - - cz_hwmgr->uvd_power_gated = bgate; - - if (bgate) { - cgs_set_powergating_state(hwmgr->device, - AMD_IP_BLOCK_TYPE_UVD, - AMD_PG_STATE_GATE); - cgs_set_clockgating_state(hwmgr->device, - AMD_IP_BLOCK_TYPE_UVD, - AMD_CG_STATE_GATE); - cz_dpm_update_uvd_dpm(hwmgr, true); - cz_dpm_powerdown_uvd(hwmgr); - } else { - cz_dpm_powerup_uvd(hwmgr); - cgs_set_clockgating_state(hwmgr->device, - AMD_IP_BLOCK_TYPE_UVD, - AMD_CG_STATE_UNGATE); - cgs_set_powergating_state(hwmgr->device, - AMD_IP_BLOCK_TYPE_UVD, - AMD_PG_STATE_UNGATE); - cz_dpm_update_uvd_dpm(hwmgr, false); - } - -} - -void cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) -{ - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - - if (bgate) { - cgs_set_powergating_state( - hwmgr->device, - AMD_IP_BLOCK_TYPE_VCE, - AMD_PG_STATE_GATE); - cgs_set_clockgating_state( - hwmgr->device, - AMD_IP_BLOCK_TYPE_VCE, - AMD_CG_STATE_GATE); - cz_enable_disable_vce_dpm(hwmgr, false); - cz_dpm_powerdown_vce(hwmgr); - cz_hwmgr->vce_power_gated = true; - } else { - cz_dpm_powerup_vce(hwmgr); - cz_hwmgr->vce_power_gated = false; - cgs_set_clockgating_state( - hwmgr->device, - AMD_IP_BLOCK_TYPE_VCE, - AMD_CG_STATE_UNGATE); - cgs_set_powergating_state( - hwmgr->device, - AMD_IP_BLOCK_TYPE_VCE, - AMD_PG_STATE_UNGATE); - cz_dpm_update_vce_dpm(hwmgr); - cz_enable_disable_vce_dpm(hwmgr, true); - } -} - diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h deleted file mode 100644 index 92f707bc46e7..000000000000 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _CZ_CLOCK_POWER_GATING_H_ -#define _CZ_CLOCK_POWER_GATING_H_ - -#include "cz_hwmgr.h" -#include "pp_asicblocks.h" - -extern int cz_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating); -extern const struct phm_master_table_header cz_phm_enable_clock_power_gatings_master; -extern void cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate); -extern void cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate); -extern int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable); -extern int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable); -#endif /* _CZ_CLOCK_POWER_GATING_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index af1b22d964fd..229030027f3e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -30,22 +30,24 @@ #include <drm/amdgpu_drm.h> #include "power_state.h" #include "hwmgr.h" -#include "pppcielanes.h" -#include "ppatomctrl.h" #include "ppsmc.h" #include "amd_acpi.h" #include "pp_psm.h" extern const struct pp_smumgr_func ci_smu_funcs; -extern const struct pp_smumgr_func cz_smu_funcs; +extern const struct pp_smumgr_func smu8_smu_funcs; extern const struct pp_smumgr_func iceland_smu_funcs; extern const struct pp_smumgr_func tonga_smu_funcs; extern const struct pp_smumgr_func fiji_smu_funcs; extern const struct pp_smumgr_func polaris10_smu_funcs; extern const struct pp_smumgr_func vega10_smu_funcs; -extern const struct pp_smumgr_func rv_smu_funcs; +extern const struct pp_smumgr_func smu10_smu_funcs; + +extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); +extern int smu8_init_function_pointers(struct pp_hwmgr *hwmgr); +extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr); +extern int smu10_init_function_pointers(struct pp_hwmgr *hwmgr); -extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr); static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr); static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr); static int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr); @@ -54,32 +56,6 @@ static int tonga_set_asic_special_caps(struct pp_hwmgr *hwmgr); static int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr); static int ci_set_asic_special_caps(struct pp_hwmgr *hwmgr); -uint8_t convert_to_vid(uint16_t vddc) -{ - return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25); -} - -uint16_t convert_to_vddc(uint8_t vid) -{ - return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); -} - -uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size) -{ - u32 mask = 0; - u32 shift = 0; - - shift = (offset % 4) << 3; - if (size == sizeof(uint8_t)) - mask = 0xFF << shift; - else if (size == sizeof(uint16_t)) - mask = 0xFFFF << shift; - - original_data &= ~mask; - original_data |= (field << shift); - return original_data; -} - static int phm_thermal_l2h_irq(void *private_data, unsigned src_id, const uint32_t *iv_entry) { @@ -140,23 +116,11 @@ static void hwmgr_init_workload_prority(struct pp_hwmgr *hwmgr) hwmgr->workload_setting[4] = PP_SMC_POWER_PROFILE_COMPUTE; } -int hwmgr_early_init(struct pp_instance *handle) +int hwmgr_early_init(struct pp_hwmgr *hwmgr) { - struct pp_hwmgr *hwmgr; - - if (handle == NULL) + if (hwmgr == NULL) return -EINVAL; - hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL); - if (hwmgr == NULL) - return -ENOMEM; - - handle->hwmgr = hwmgr; - hwmgr->adev = handle->parent; - hwmgr->device = handle->device; - hwmgr->chip_family = ((struct amdgpu_device *)handle->parent)->family; - hwmgr->chip_id = ((struct amdgpu_device *)handle->parent)->asic_type; - hwmgr->feature_mask = amdgpu_pp_feature_mask; hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT; hwmgr->power_source = PP_PowerSource_AC; hwmgr->pp_table_version = PP_TABLE_V1; @@ -180,8 +144,8 @@ int hwmgr_early_init(struct pp_instance *handle) break; case AMDGPU_FAMILY_CZ: hwmgr->od_enabled = false; - hwmgr->smumgr_funcs = &cz_smu_funcs; - cz_init_function_pointers(hwmgr); + hwmgr->smumgr_funcs = &smu8_smu_funcs; + smu8_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_VI: switch (hwmgr->chip_id) { @@ -230,8 +194,8 @@ int hwmgr_early_init(struct pp_instance *handle) switch (hwmgr->chip_id) { case CHIP_RAVEN: hwmgr->od_enabled = false; - hwmgr->smumgr_funcs = &rv_smu_funcs; - rv_init_function_pointers(hwmgr); + hwmgr->smumgr_funcs = &smu10_smu_funcs; + smu10_init_function_pointers(hwmgr); break; default: return -EINVAL; @@ -244,16 +208,13 @@ int hwmgr_early_init(struct pp_instance *handle) return 0; } -int hwmgr_hw_init(struct pp_instance *handle) +int hwmgr_hw_init(struct pp_hwmgr *hwmgr) { - struct pp_hwmgr *hwmgr; int ret = 0; - if (handle == NULL) + if (hwmgr == NULL) return -EINVAL; - hwmgr = handle->hwmgr; - if (hwmgr->pptable_func == NULL || hwmgr->pptable_func->pptable_init == NULL || hwmgr->hwmgr_func->backend_init == NULL) @@ -299,15 +260,11 @@ err: return ret; } -int hwmgr_hw_fini(struct pp_instance *handle) +int hwmgr_hw_fini(struct pp_hwmgr *hwmgr) { - struct pp_hwmgr *hwmgr; - - if (handle == NULL || handle->hwmgr == NULL) + if (hwmgr == NULL) return -EINVAL; - hwmgr = handle->hwmgr; - phm_stop_thermal_controller(hwmgr); psm_set_boot_states(hwmgr); psm_adjust_power_state_dynamic(hwmgr, false, NULL); @@ -321,15 +278,13 @@ int hwmgr_hw_fini(struct pp_instance *handle) return psm_fini_power_state_table(hwmgr); } -int hwmgr_hw_suspend(struct pp_instance *handle) +int hwmgr_hw_suspend(struct pp_hwmgr *hwmgr) { - struct pp_hwmgr *hwmgr; int ret = 0; - if (handle == NULL || handle->hwmgr == NULL) + if (hwmgr == NULL) return -EINVAL; - hwmgr = handle->hwmgr; phm_disable_smc_firmware_ctf(hwmgr); ret = psm_set_boot_states(hwmgr); if (ret) @@ -342,15 +297,13 @@ int hwmgr_hw_suspend(struct pp_instance *handle) return ret; } -int hwmgr_hw_resume(struct pp_instance *handle) +int hwmgr_hw_resume(struct pp_hwmgr *hwmgr) { - struct pp_hwmgr *hwmgr; int ret = 0; - if (handle == NULL || handle->hwmgr == NULL) + if (hwmgr == NULL) return -EINVAL; - hwmgr = handle->hwmgr; ret = phm_setup_asic(hwmgr); if (ret) return ret; @@ -385,17 +338,14 @@ static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type state) } } -int hwmgr_handle_task(struct pp_instance *handle, enum amd_pp_task task_id, +int hwmgr_handle_task(struct pp_hwmgr *hwmgr, enum amd_pp_task task_id, enum amd_pm_state_type *user_state) { int ret = 0; - struct pp_hwmgr *hwmgr; - if (handle == NULL || handle->hwmgr == NULL) + if (hwmgr == NULL) return -EINVAL; - hwmgr = handle->hwmgr; - switch (task_id) { case AMD_PP_TASK_DISPLAY_CONFIG_CHANGE: ret = phm_set_cpu_power_state(hwmgr); @@ -432,468 +382,6 @@ int hwmgr_handle_task(struct pp_instance *handle, enum amd_pp_task task_id, } return ret; } -/** - * Returns once the part of the register indicated by the mask has - * reached the given value. - */ -int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, - uint32_t value, uint32_t mask) -{ - uint32_t i; - uint32_t cur_value; - - if (hwmgr == NULL || hwmgr->device == NULL) { - pr_err("Invalid Hardware Manager!"); - return -EINVAL; - } - - for (i = 0; i < hwmgr->usec_timeout; i++) { - cur_value = cgs_read_register(hwmgr->device, index); - if ((cur_value & mask) == (value & mask)) - break; - udelay(1); - } - - /* timeout means wrong logic*/ - if (i == hwmgr->usec_timeout) - return -1; - return 0; -} - - -/** - * Returns once the part of the register indicated by the mask has - * reached the given value.The indirect space is described by giving - * the memory-mapped index of the indirect index register. - */ -int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, - uint32_t indirect_port, - uint32_t index, - uint32_t value, - uint32_t mask) -{ - if (hwmgr == NULL || hwmgr->device == NULL) { - pr_err("Invalid Hardware Manager!"); - return -EINVAL; - } - - cgs_write_register(hwmgr->device, indirect_port, index); - return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); -} - -int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, - uint32_t index, - uint32_t value, uint32_t mask) -{ - uint32_t i; - uint32_t cur_value; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - for (i = 0; i < hwmgr->usec_timeout; i++) { - cur_value = cgs_read_register(hwmgr->device, - index); - if ((cur_value & mask) != (value & mask)) - break; - udelay(1); - } - - /* timeout means wrong logic */ - if (i == hwmgr->usec_timeout) - return -ETIME; - return 0; -} - -int phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr, - uint32_t indirect_port, - uint32_t index, - uint32_t value, - uint32_t mask) -{ - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cgs_write_register(hwmgr->device, indirect_port, index); - return phm_wait_for_register_unequal(hwmgr, indirect_port + 1, - value, mask); -} - -bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr) -{ - return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating); -} - -bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr) -{ - return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating); -} - - -int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table) -{ - uint32_t i, j; - uint16_t vvalue; - bool found = false; - struct pp_atomctrl_voltage_table *table; - - PP_ASSERT_WITH_CODE((NULL != vol_table), - "Voltage Table empty.", return -EINVAL); - - table = kzalloc(sizeof(struct pp_atomctrl_voltage_table), - GFP_KERNEL); - - if (NULL == table) - return -EINVAL; - - table->mask_low = vol_table->mask_low; - table->phase_delay = vol_table->phase_delay; - - for (i = 0; i < vol_table->count; i++) { - vvalue = vol_table->entries[i].value; - found = false; - - for (j = 0; j < table->count; j++) { - if (vvalue == table->entries[j].value) { - found = true; - break; - } - } - - if (!found) { - table->entries[table->count].value = vvalue; - table->entries[table->count].smio_low = - vol_table->entries[i].smio_low; - table->count++; - } - } - - memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table)); - kfree(table); - table = NULL; - return 0; -} - -int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, - phm_ppt_v1_clock_voltage_dependency_table *dep_table) -{ - uint32_t i; - int result; - - PP_ASSERT_WITH_CODE((0 != dep_table->count), - "Voltage Dependency Table empty.", return -EINVAL); - - PP_ASSERT_WITH_CODE((NULL != vol_table), - "vol_table empty.", return -EINVAL); - - vol_table->mask_low = 0; - vol_table->phase_delay = 0; - vol_table->count = dep_table->count; - - for (i = 0; i < dep_table->count; i++) { - vol_table->entries[i].value = dep_table->entries[i].mvdd; - vol_table->entries[i].smio_low = 0; - } - - result = phm_trim_voltage_table(vol_table); - PP_ASSERT_WITH_CODE((0 == result), - "Failed to trim MVDD table.", return result); - - return 0; -} - -int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, - phm_ppt_v1_clock_voltage_dependency_table *dep_table) -{ - uint32_t i; - int result; - - PP_ASSERT_WITH_CODE((0 != dep_table->count), - "Voltage Dependency Table empty.", return -EINVAL); - - PP_ASSERT_WITH_CODE((NULL != vol_table), - "vol_table empty.", return -EINVAL); - - vol_table->mask_low = 0; - vol_table->phase_delay = 0; - vol_table->count = dep_table->count; - - for (i = 0; i < dep_table->count; i++) { - vol_table->entries[i].value = dep_table->entries[i].vddci; - vol_table->entries[i].smio_low = 0; - } - - result = phm_trim_voltage_table(vol_table); - PP_ASSERT_WITH_CODE((0 == result), - "Failed to trim VDDCI table.", return result); - - return 0; -} - -int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, - phm_ppt_v1_voltage_lookup_table *lookup_table) -{ - int i = 0; - - PP_ASSERT_WITH_CODE((0 != lookup_table->count), - "Voltage Lookup Table empty.", return -EINVAL); - - PP_ASSERT_WITH_CODE((NULL != vol_table), - "vol_table empty.", return -EINVAL); - - vol_table->mask_low = 0; - vol_table->phase_delay = 0; - - vol_table->count = lookup_table->count; - - for (i = 0; i < vol_table->count; i++) { - vol_table->entries[i].value = lookup_table->entries[i].us_vdd; - vol_table->entries[i].smio_low = 0; - } - - return 0; -} - -void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, - struct pp_atomctrl_voltage_table *vol_table) -{ - unsigned int i, diff; - - if (vol_table->count <= max_vol_steps) - return; - - diff = vol_table->count - max_vol_steps; - - for (i = 0; i < max_vol_steps; i++) - vol_table->entries[i] = vol_table->entries[i + diff]; - - vol_table->count = max_vol_steps; - - return; -} - -int phm_reset_single_dpm_table(void *table, - uint32_t count, int max) -{ - int i; - - struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; - - dpm_table->count = count > max ? max : count; - - for (i = 0; i < dpm_table->count; i++) - dpm_table->dpm_level[i].enabled = false; - - return 0; -} - -void phm_setup_pcie_table_entry( - void *table, - uint32_t index, uint32_t pcie_gen, - uint32_t pcie_lanes) -{ - struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; - dpm_table->dpm_level[index].value = pcie_gen; - dpm_table->dpm_level[index].param1 = pcie_lanes; - dpm_table->dpm_level[index].enabled = 1; -} - -int32_t phm_get_dpm_level_enable_mask_value(void *table) -{ - int32_t i; - int32_t mask = 0; - struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; - - for (i = dpm_table->count; i > 0; i--) { - mask = mask << 1; - if (dpm_table->dpm_level[i - 1].enabled) - mask |= 0x1; - else - mask &= 0xFFFFFFFE; - } - - return mask; -} - -uint8_t phm_get_voltage_index( - struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage) -{ - uint8_t count = (uint8_t) (lookup_table->count); - uint8_t i; - - PP_ASSERT_WITH_CODE((NULL != lookup_table), - "Lookup Table empty.", return 0); - PP_ASSERT_WITH_CODE((0 != count), - "Lookup Table empty.", return 0); - - for (i = 0; i < lookup_table->count; i++) { - /* find first voltage equal or bigger than requested */ - if (lookup_table->entries[i].us_vdd >= voltage) - return i; - } - /* voltage is bigger than max voltage in the table */ - return i - 1; -} - -uint8_t phm_get_voltage_id(pp_atomctrl_voltage_table *voltage_table, - uint32_t voltage) -{ - uint8_t count = (uint8_t) (voltage_table->count); - uint8_t i = 0; - - PP_ASSERT_WITH_CODE((NULL != voltage_table), - "Voltage Table empty.", return 0;); - PP_ASSERT_WITH_CODE((0 != count), - "Voltage Table empty.", return 0;); - - for (i = 0; i < count; i++) { - /* find first voltage bigger than requested */ - if (voltage_table->entries[i].value >= voltage) - return i; - } - - /* voltage is bigger than max voltage in the table */ - return i - 1; -} - -uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci) -{ - uint32_t i; - - for (i = 0; i < vddci_table->count; i++) { - if (vddci_table->entries[i].value >= vddci) - return vddci_table->entries[i].value; - } - - pr_debug("vddci is larger than max value in vddci_table\n"); - return vddci_table->entries[i-1].value; -} - -int phm_find_boot_level(void *table, - uint32_t value, uint32_t *boot_level) -{ - int result = -EINVAL; - uint32_t i; - struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; - - for (i = 0; i < dpm_table->count; i++) { - if (value == dpm_table->dpm_level[i].value) { - *boot_level = i; - result = 0; - } - } - - return result; -} - -int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, - phm_ppt_v1_voltage_lookup_table *lookup_table, - uint16_t virtual_voltage_id, int32_t *sclk) -{ - uint8_t entry_id; - uint8_t voltage_id; - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - - PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL); - - /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */ - for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) { - voltage_id = table_info->vdd_dep_on_sclk->entries[entry_id].vddInd; - if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id) - break; - } - - if (entry_id >= table_info->vdd_dep_on_sclk->count) { - pr_debug("Can't find requested voltage id in vdd_dep_on_sclk table\n"); - return -EINVAL; - } - - *sclk = table_info->vdd_dep_on_sclk->entries[entry_id].clk; - - return 0; -} - -/** - * Initialize Dynamic State Adjustment Rule Settings - * - * @param hwmgr the address of the powerplay hardware manager. - */ -int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) -{ - uint32_t table_size; - struct phm_clock_voltage_dependency_table *table_clk_vlt; - struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); - - /* initialize vddc_dep_on_dal_pwrl table */ - table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record); - table_clk_vlt = kzalloc(table_size, GFP_KERNEL); - - if (NULL == table_clk_vlt) { - pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n"); - return -ENOMEM; - } else { - table_clk_vlt->count = 4; - table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; - table_clk_vlt->entries[0].v = 0; - table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; - table_clk_vlt->entries[1].v = 720; - table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; - table_clk_vlt->entries[2].v = 810; - table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; - table_clk_vlt->entries[3].v = 900; - if (pptable_info != NULL) - pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt; - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; - } - - return 0; -} - -uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) -{ - uint32_t level = 0; - - while (0 == (mask & (1 << level))) - level++; - - return level; -} - -void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr) -{ - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)hwmgr->pptable; - struct phm_clock_voltage_dependency_table *table = - table_info->vddc_dep_on_dal_pwrl; - struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table; - enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level; - uint32_t req_vddc = 0, req_volt, i; - - if (!table || table->count <= 0 - || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW - || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE) - return; - - for (i = 0; i < table->count; i++) { - if (dal_power_level == table->entries[i].clk) { - req_vddc = table->entries[i].v; - break; - } - } - - vddc_table = table_info->vdd_dep_on_sclk; - for (i = 0; i < vddc_table->count; i++) { - if (req_vddc <= vddc_table->entries[i].vddc) { - req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE); - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_VddC_Request, req_volt); - return; - } - } - pr_err("DAL requested level can not" - " found a available voltage in VDDC DPM Table \n"); -} void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr) { @@ -954,25 +442,6 @@ int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr) return 0; } -int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, - uint32_t sclk, uint16_t id, uint16_t *voltage) -{ - uint32_t vol; - int ret = 0; - - if (hwmgr->chip_id < CHIP_TONGA) { - ret = atomctrl_get_voltage_evv(hwmgr, id, voltage); - } else if (hwmgr->chip_id < CHIP_POLARIS10) { - ret = atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage); - if (*voltage >= 2000 || *voltage == 0) - *voltage = 1150; - } else { - ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol); - *voltage = (uint16_t)(vol/100); - } - return ret; -} - int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr) { phm_cap_set(hwmgr->platform_descriptor.platformCaps, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 8ddfb78f28cc..10253b89b3d8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -32,53 +32,52 @@ #include "hwmgr.h" #include "hardwaremanager.h" #include "rv_ppsmc.h" -#include "rv_hwmgr.h" +#include "smu10_hwmgr.h" #include "power_state.h" -#include "rv_smumgr.h" #include "pp_soc15.h" -#define RAVEN_MAX_DEEPSLEEP_DIVIDER_ID 5 -#define RAVEN_MINIMUM_ENGINE_CLOCK 800 /* 8Mhz, the low boundary of engine clock allowed on this chip */ +#define SMU10_MAX_DEEPSLEEP_DIVIDER_ID 5 +#define SMU10_MINIMUM_ENGINE_CLOCK 800 /* 8Mhz, the low boundary of engine clock allowed on this chip */ #define SCLK_MIN_DIV_INTV_SHIFT 12 -#define RAVEN_DISPCLK_BYPASS_THRESHOLD 10000 /* 100Mhz */ +#define SMU10_DISPCLK_BYPASS_THRESHOLD 10000 /* 100Mhz */ #define SMC_RAM_END 0x40000 -static const unsigned long PhwRaven_Magic = (unsigned long) PHM_Rv_Magic; +static const unsigned long SMU10_Magic = (unsigned long) PHM_Rv_Magic; -int rv_display_clock_voltage_request(struct pp_hwmgr *hwmgr, +static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock_req); -static struct rv_power_state *cast_rv_ps(struct pp_hw_power_state *hw_ps) +static struct smu10_power_state *cast_smu10_ps(struct pp_hw_power_state *hw_ps) { - if (PhwRaven_Magic != hw_ps->magic) + if (SMU10_Magic != hw_ps->magic) return NULL; - return (struct rv_power_state *)hw_ps; + return (struct smu10_power_state *)hw_ps; } -static const struct rv_power_state *cast_const_rv_ps( +static const struct smu10_power_state *cast_const_smu10_ps( const struct pp_hw_power_state *hw_ps) { - if (PhwRaven_Magic != hw_ps->magic) + if (SMU10_Magic != hw_ps->magic) return NULL; - return (struct rv_power_state *)hw_ps; + return (struct smu10_power_state *)hw_ps; } -static int rv_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) +static int smu10_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) { - struct rv_hwmgr *rv_hwmgr = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - rv_hwmgr->dce_slow_sclk_threshold = 30000; - rv_hwmgr->thermal_auto_throttling_treshold = 0; - rv_hwmgr->is_nb_dpm_enabled = 1; - rv_hwmgr->dpm_flags = 1; - rv_hwmgr->gfx_off_controled_by_driver = false; - rv_hwmgr->need_min_deep_sleep_dcefclk = true; - rv_hwmgr->num_active_display = 0; - rv_hwmgr->deep_sleep_dcefclk = 0; + smu10_data->dce_slow_sclk_threshold = 30000; + smu10_data->thermal_auto_throttling_treshold = 0; + smu10_data->is_nb_dpm_enabled = 1; + smu10_data->dpm_flags = 1; + smu10_data->gfx_off_controled_by_driver = false; + smu10_data->need_min_deep_sleep_dcefclk = true; + smu10_data->num_active_display = 0; + smu10_data->deep_sleep_dcefclk = 0; phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep); @@ -91,13 +90,13 @@ static int rv_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) return 0; } -static int rv_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, +static int smu10_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, struct phm_clock_and_voltage_limits *table) { return 0; } -static int rv_init_dynamic_state_adjustment_rule_settings( +static int smu10_init_dynamic_state_adjustment_rule_settings( struct pp_hwmgr *hwmgr) { uint32_t table_size = @@ -134,30 +133,30 @@ static int rv_init_dynamic_state_adjustment_rule_settings( return 0; } -static int rv_get_system_info_data(struct pp_hwmgr *hwmgr) +static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)hwmgr->backend; + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)hwmgr->backend; - rv_data->sys_info.htc_hyst_lmt = 5; - rv_data->sys_info.htc_tmp_lmt = 203; + smu10_data->sys_info.htc_hyst_lmt = 5; + smu10_data->sys_info.htc_tmp_lmt = 203; - if (rv_data->thermal_auto_throttling_treshold == 0) - rv_data->thermal_auto_throttling_treshold = 203; + if (smu10_data->thermal_auto_throttling_treshold == 0) + smu10_data->thermal_auto_throttling_treshold = 203; - rv_construct_max_power_limits_table (hwmgr, + smu10_construct_max_power_limits_table (hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_ac); - rv_init_dynamic_state_adjustment_rule_settings(hwmgr); + smu10_init_dynamic_state_adjustment_rule_settings(hwmgr); return 0; } -static int rv_construct_boot_state(struct pp_hwmgr *hwmgr) +static int smu10_construct_boot_state(struct pp_hwmgr *hwmgr) { return 0; } -static int rv_set_clock_limit(struct pp_hwmgr *hwmgr, const void *input) +static int smu10_set_clock_limit(struct pp_hwmgr *hwmgr, const void *input) { struct PP_Clocks clocks = {0}; struct pp_display_clock_request clock_req; @@ -166,111 +165,109 @@ static int rv_set_clock_limit(struct pp_hwmgr *hwmgr, const void *input) clock_req.clock_type = amd_pp_dcf_clock; clock_req.clock_freq_in_khz = clocks.dcefClock * 10; - PP_ASSERT_WITH_CODE(!rv_display_clock_voltage_request(hwmgr, &clock_req), + PP_ASSERT_WITH_CODE(!smu10_display_clock_voltage_request(hwmgr, &clock_req), "Attempt to set DCF Clock Failed!", return -EINVAL); return 0; } -static int rv_set_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock) +static int smu10_set_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - if (rv_data->need_min_deep_sleep_dcefclk && rv_data->deep_sleep_dcefclk != clock/100) { - rv_data->deep_sleep_dcefclk = clock/100; + if (smu10_data->need_min_deep_sleep_dcefclk && smu10_data->deep_sleep_dcefclk != clock/100) { + smu10_data->deep_sleep_dcefclk = clock/100; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk, - rv_data->deep_sleep_dcefclk); + smu10_data->deep_sleep_dcefclk); } return 0; } -static int rv_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count) +static int smu10_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - if (rv_data->num_active_display != count) { - rv_data->num_active_display = count; + if (smu10_data->num_active_display != count) { + smu10_data->num_active_display = count; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDisplayCount, - rv_data->num_active_display); + smu10_data->num_active_display); } return 0; } -static int rv_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) +static int smu10_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) { - return rv_set_clock_limit(hwmgr, input); + return smu10_set_clock_limit(hwmgr, input); } -static int rv_init_power_gate_state(struct pp_hwmgr *hwmgr) +static int smu10_init_power_gate_state(struct pp_hwmgr *hwmgr) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - rv_data->vcn_power_gated = true; - rv_data->isp_tileA_power_gated = true; - rv_data->isp_tileB_power_gated = true; + smu10_data->vcn_power_gated = true; + smu10_data->isp_tileA_power_gated = true; + smu10_data->isp_tileB_power_gated = true; return 0; } -static int rv_setup_asic_task(struct pp_hwmgr *hwmgr) +static int smu10_setup_asic_task(struct pp_hwmgr *hwmgr) { - return rv_init_power_gate_state(hwmgr); + return smu10_init_power_gate_state(hwmgr); } -static int rv_reset_cc6_data(struct pp_hwmgr *hwmgr) +static int smu10_reset_cc6_data(struct pp_hwmgr *hwmgr) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - rv_data->separation_time = 0; - rv_data->cc6_disable = false; - rv_data->pstate_disable = false; - rv_data->cc6_setting_changed = false; + smu10_data->separation_time = 0; + smu10_data->cc6_disable = false; + smu10_data->pstate_disable = false; + smu10_data->cc6_setting_changed = false; return 0; } -static int rv_power_off_asic(struct pp_hwmgr *hwmgr) +static int smu10_power_off_asic(struct pp_hwmgr *hwmgr) { - return rv_reset_cc6_data(hwmgr); + return smu10_reset_cc6_data(hwmgr); } -static int rv_disable_gfx_off(struct pp_hwmgr *hwmgr) +static int smu10_disable_gfx_off(struct pp_hwmgr *hwmgr) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - if (rv_data->gfx_off_controled_by_driver) - smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_DisableGfxOff); + if (smu10_data->gfx_off_controled_by_driver) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableGfxOff); return 0; } -static int rv_disable_dpm_tasks(struct pp_hwmgr *hwmgr) +static int smu10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { - return rv_disable_gfx_off(hwmgr); + return smu10_disable_gfx_off(hwmgr); } -static int rv_enable_gfx_off(struct pp_hwmgr *hwmgr) +static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - if (rv_data->gfx_off_controled_by_driver) - smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_EnableGfxOff); + if (smu10_data->gfx_off_controled_by_driver) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableGfxOff); return 0; } -static int rv_enable_dpm_tasks(struct pp_hwmgr *hwmgr) +static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { - return rv_enable_gfx_off(hwmgr); + return smu10_enable_gfx_off(hwmgr); } -static int rv_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, +static int smu10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, struct pp_power_state *prequest_ps, const struct pp_power_state *pcurrent_ps) { @@ -314,14 +311,14 @@ static const DpmClock_t VddPhyClk[]= { { 810, 3600}, }; -static int rv_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, - struct rv_voltage_dependency_table **pptable, +static int smu10_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, + struct smu10_voltage_dependency_table **pptable, uint32_t num_entry, const DpmClock_t *pclk_dependency_table) { uint32_t table_size, i; - struct rv_voltage_dependency_table *ptable; + struct smu10_voltage_dependency_table *ptable; - table_size = sizeof(uint32_t) + sizeof(struct rv_voltage_dependency_table) * num_entry; + table_size = sizeof(uint32_t) + sizeof(struct smu10_voltage_dependency_table) * num_entry; ptable = kzalloc(table_size, GFP_KERNEL); if (NULL == ptable) @@ -341,107 +338,95 @@ static int rv_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, } -static int rv_populate_clock_table(struct pp_hwmgr *hwmgr) +static int smu10_populate_clock_table(struct pp_hwmgr *hwmgr) { int result; - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); - DpmClocks_t *table = &(rv_data->clock_table); - struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); + DpmClocks_t *table = &(smu10_data->clock_table); + struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); - result = rv_copy_table_from_smc(hwmgr, (uint8_t *)table, CLOCKTABLE); + result = smum_smc_table_manager(hwmgr, (uint8_t *)table, SMU10_CLOCKTABLE, true); PP_ASSERT_WITH_CODE((0 == result), "Attempt to copy clock table from smc failed", return result); if (0 == result && table->DcefClocks[0].Freq != 0) { - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, NUM_DCEFCLK_DPM_LEVELS, - &rv_data->clock_table.DcefClocks[0]); - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, + &smu10_data->clock_table.DcefClocks[0]); + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, NUM_SOCCLK_DPM_LEVELS, - &rv_data->clock_table.SocClocks[0]); - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, + &smu10_data->clock_table.SocClocks[0]); + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, NUM_FCLK_DPM_LEVELS, - &rv_data->clock_table.FClocks[0]); - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_mclk, + &smu10_data->clock_table.FClocks[0]); + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_mclk, NUM_MEMCLK_DPM_LEVELS, - &rv_data->clock_table.MemClocks[0]); + &smu10_data->clock_table.MemClocks[0]); } else { - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, ARRAY_SIZE(VddDcfClk), &VddDcfClk[0]); - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, ARRAY_SIZE(VddSocClk), &VddSocClk[0]); - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, ARRAY_SIZE(VddFClk), &VddFClk[0]); } - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dispclk, + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dispclk, ARRAY_SIZE(VddDispClk), &VddDispClk[0]); - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dppclk, + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dppclk, ARRAY_SIZE(VddDppClk), &VddDppClk[0]); - rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_phyclk, + smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_phyclk, ARRAY_SIZE(VddPhyClk), &VddPhyClk[0]); - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetMinGfxclkFrequency), - "Attempt to get min GFXCLK Failed!", - return -1); - PP_ASSERT_WITH_CODE(!rv_read_arg_from_smc(hwmgr, - &result), - "Attempt to get min GFXCLK Failed!", - return -1); - rv_data->gfx_min_freq_limit = result * 100; - - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetMaxGfxclkFrequency), - "Attempt to get max GFXCLK Failed!", - return -1); - PP_ASSERT_WITH_CODE(!rv_read_arg_from_smc(hwmgr, - &result), - "Attempt to get max GFXCLK Failed!", - return -1); - rv_data->gfx_max_freq_limit = result * 100; + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency); + result = smum_get_argument(hwmgr); + smu10_data->gfx_min_freq_limit = result * 100; + + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency); + result = smum_get_argument(hwmgr); + smu10_data->gfx_max_freq_limit = result * 100; return 0; } -static int rv_hwmgr_backend_init(struct pp_hwmgr *hwmgr) +static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) { int result = 0; - struct rv_hwmgr *data; + struct smu10_hwmgr *data; - data = kzalloc(sizeof(struct rv_hwmgr), GFP_KERNEL); + data = kzalloc(sizeof(struct smu10_hwmgr), GFP_KERNEL); if (data == NULL) return -ENOMEM; hwmgr->backend = data; - result = rv_initialize_dpm_defaults(hwmgr); + result = smu10_initialize_dpm_defaults(hwmgr); if (result != 0) { - pr_err("rv_initialize_dpm_defaults failed\n"); + pr_err("smu10_initialize_dpm_defaults failed\n"); return result; } - rv_populate_clock_table(hwmgr); + smu10_populate_clock_table(hwmgr); - result = rv_get_system_info_data(hwmgr); + result = smu10_get_system_info_data(hwmgr); if (result != 0) { - pr_err("rv_get_system_info_data failed\n"); + pr_err("smu10_get_system_info_data failed\n"); return result; } - rv_construct_boot_state(hwmgr); + smu10_construct_boot_state(hwmgr); hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = - RAVEN_MAX_HARDWARE_POWERLEVELS; + SMU10_MAX_HARDWARE_POWERLEVELS; hwmgr->platform_descriptor.hardwarePerformanceLevels = - RAVEN_MAX_HARDWARE_POWERLEVELS; + SMU10_MAX_HARDWARE_POWERLEVELS; hwmgr->platform_descriptor.vbiosInterruptId = 0; @@ -451,16 +436,16 @@ static int rv_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; - hwmgr->pstate_sclk = RAVEN_UMD_PSTATE_GFXCLK; - hwmgr->pstate_mclk = RAVEN_UMD_PSTATE_FCLK; + hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK; + hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK; return result; } -static int rv_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) +static int smu10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) { - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); - struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); + struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); kfree(pinfo->vdd_dep_on_dcefclk); pinfo->vdd_dep_on_dcefclk = NULL; @@ -484,7 +469,7 @@ static int rv_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) return 0; } -static int rv_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, +static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level) { if (hwmgr->smu_version < 0x1E3700) { @@ -497,113 +482,113 @@ static int rv_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinGfxClk, - RAVEN_UMD_PSTATE_PEAK_GFXCLK); + SMU10_UMD_PSTATE_PEAK_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinFclkByFreq, - RAVEN_UMD_PSTATE_PEAK_FCLK); + SMU10_UMD_PSTATE_PEAK_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinSocclkByFreq, - RAVEN_UMD_PSTATE_PEAK_SOCCLK); + SMU10_UMD_PSTATE_PEAK_SOCCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinVcn, - RAVEN_UMD_PSTATE_VCE); + SMU10_UMD_PSTATE_VCE); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxGfxClk, - RAVEN_UMD_PSTATE_PEAK_GFXCLK); + SMU10_UMD_PSTATE_PEAK_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxFclkByFreq, - RAVEN_UMD_PSTATE_PEAK_FCLK); + SMU10_UMD_PSTATE_PEAK_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxSocclkByFreq, - RAVEN_UMD_PSTATE_PEAK_SOCCLK); + SMU10_UMD_PSTATE_PEAK_SOCCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxVcn, - RAVEN_UMD_PSTATE_VCE); + SMU10_UMD_PSTATE_VCE); break; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinGfxClk, - RAVEN_UMD_PSTATE_MIN_GFXCLK); + SMU10_UMD_PSTATE_MIN_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxGfxClk, - RAVEN_UMD_PSTATE_MIN_GFXCLK); + SMU10_UMD_PSTATE_MIN_GFXCLK); break; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinFclkByFreq, - RAVEN_UMD_PSTATE_MIN_FCLK); + SMU10_UMD_PSTATE_MIN_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxFclkByFreq, - RAVEN_UMD_PSTATE_MIN_FCLK); + SMU10_UMD_PSTATE_MIN_FCLK); break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinGfxClk, - RAVEN_UMD_PSTATE_GFXCLK); + SMU10_UMD_PSTATE_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinFclkByFreq, - RAVEN_UMD_PSTATE_FCLK); + SMU10_UMD_PSTATE_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinSocclkByFreq, - RAVEN_UMD_PSTATE_SOCCLK); + SMU10_UMD_PSTATE_SOCCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinVcn, - RAVEN_UMD_PSTATE_VCE); + SMU10_UMD_PSTATE_VCE); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxGfxClk, - RAVEN_UMD_PSTATE_GFXCLK); + SMU10_UMD_PSTATE_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxFclkByFreq, - RAVEN_UMD_PSTATE_FCLK); + SMU10_UMD_PSTATE_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxSocclkByFreq, - RAVEN_UMD_PSTATE_SOCCLK); + SMU10_UMD_PSTATE_SOCCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxVcn, - RAVEN_UMD_PSTATE_VCE); + SMU10_UMD_PSTATE_VCE); break; case AMD_DPM_FORCED_LEVEL_AUTO: smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinGfxClk, - RAVEN_UMD_PSTATE_MIN_GFXCLK); + SMU10_UMD_PSTATE_MIN_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinFclkByFreq, - RAVEN_UMD_PSTATE_MIN_FCLK); + SMU10_UMD_PSTATE_MIN_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinSocclkByFreq, - RAVEN_UMD_PSTATE_MIN_SOCCLK); + SMU10_UMD_PSTATE_MIN_SOCCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinVcn, - RAVEN_UMD_PSTATE_MIN_VCE); + SMU10_UMD_PSTATE_MIN_VCE); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxGfxClk, - RAVEN_UMD_PSTATE_PEAK_GFXCLK); + SMU10_UMD_PSTATE_PEAK_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxFclkByFreq, - RAVEN_UMD_PSTATE_PEAK_FCLK); + SMU10_UMD_PSTATE_PEAK_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxSocclkByFreq, - RAVEN_UMD_PSTATE_PEAK_SOCCLK); + SMU10_UMD_PSTATE_PEAK_SOCCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxVcn, - RAVEN_UMD_PSTATE_VCE); + SMU10_UMD_PSTATE_VCE); break; case AMD_DPM_FORCED_LEVEL_LOW: smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinGfxClk, - RAVEN_UMD_PSTATE_MIN_GFXCLK); + SMU10_UMD_PSTATE_MIN_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxGfxClk, - RAVEN_UMD_PSTATE_MIN_GFXCLK); + SMU10_UMD_PSTATE_MIN_GFXCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinFclkByFreq, - RAVEN_UMD_PSTATE_MIN_FCLK); + SMU10_UMD_PSTATE_MIN_FCLK); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxFclkByFreq, - RAVEN_UMD_PSTATE_MIN_FCLK); + SMU10_UMD_PSTATE_MIN_FCLK); break; case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: @@ -613,14 +598,14 @@ static int rv_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, return 0; } -static uint32_t rv_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) +static uint32_t smu10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) { - struct rv_hwmgr *data; + struct smu10_hwmgr *data; if (hwmgr == NULL) return -EINVAL; - data = (struct rv_hwmgr *)(hwmgr->backend); + data = (struct smu10_hwmgr *)(hwmgr->backend); if (low) return data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk; @@ -629,14 +614,14 @@ static uint32_t rv_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) data->clock_vol_info.vdd_dep_on_fclk->count - 1].clk; } -static uint32_t rv_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) +static uint32_t smu10_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) { - struct rv_hwmgr *data; + struct smu10_hwmgr *data; if (hwmgr == NULL) return -EINVAL; - data = (struct rv_hwmgr *)(hwmgr->backend); + data = (struct smu10_hwmgr *)(hwmgr->backend); if (low) return data->gfx_min_freq_limit; @@ -644,34 +629,34 @@ static uint32_t rv_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) return data->gfx_max_freq_limit; } -static int rv_dpm_patch_boot_state(struct pp_hwmgr *hwmgr, +static int smu10_dpm_patch_boot_state(struct pp_hwmgr *hwmgr, struct pp_hw_power_state *hw_ps) { return 0; } -static int rv_dpm_get_pp_table_entry_callback( +static int smu10_dpm_get_pp_table_entry_callback( struct pp_hwmgr *hwmgr, struct pp_hw_power_state *hw_ps, unsigned int index, const void *clock_info) { - struct rv_power_state *rv_ps = cast_rv_ps(hw_ps); + struct smu10_power_state *smu10_ps = cast_smu10_ps(hw_ps); - rv_ps->levels[index].engine_clock = 0; + smu10_ps->levels[index].engine_clock = 0; - rv_ps->levels[index].vddc_index = 0; - rv_ps->level = index + 1; + smu10_ps->levels[index].vddc_index = 0; + smu10_ps->level = index + 1; if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) { - rv_ps->levels[index].ds_divider_index = 5; - rv_ps->levels[index].ss_divider_index = 5; + smu10_ps->levels[index].ds_divider_index = 5; + smu10_ps->levels[index].ss_divider_index = 5; } return 0; } -static int rv_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) +static int smu10_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) { int result; unsigned long ret = 0; @@ -681,72 +666,66 @@ static int rv_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) return result ? 0 : ret; } -static int rv_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr, +static int smu10_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr, unsigned long entry, struct pp_power_state *ps) { int result; - struct rv_power_state *rv_ps; + struct smu10_power_state *smu10_ps; - ps->hardware.magic = PhwRaven_Magic; + ps->hardware.magic = SMU10_Magic; - rv_ps = cast_rv_ps(&(ps->hardware)); + smu10_ps = cast_smu10_ps(&(ps->hardware)); result = pp_tables_get_entry(hwmgr, entry, ps, - rv_dpm_get_pp_table_entry_callback); + smu10_dpm_get_pp_table_entry_callback); - rv_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK; - rv_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK; + smu10_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK; + smu10_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK; return result; } -static int rv_get_power_state_size(struct pp_hwmgr *hwmgr) +static int smu10_get_power_state_size(struct pp_hwmgr *hwmgr) { - return sizeof(struct rv_power_state); + return sizeof(struct smu10_power_state); } -static int rv_set_cpu_power_state(struct pp_hwmgr *hwmgr) +static int smu10_set_cpu_power_state(struct pp_hwmgr *hwmgr) { return 0; } -static int rv_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, +static int smu10_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, bool cc6_disable, bool pstate_disable, bool pstate_switch_disable) { return 0; } -static int rv_get_dal_power_level(struct pp_hwmgr *hwmgr, +static int smu10_get_dal_power_level(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *info) { return -EINVAL; } -static int rv_force_clock_level(struct pp_hwmgr *hwmgr, +static int smu10_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { return 0; } -static int rv_print_clock_levels(struct pp_hwmgr *hwmgr, +static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf) { - struct rv_hwmgr *data = (struct rv_hwmgr *)(hwmgr->backend); - struct rv_voltage_dependency_table *mclk_table = + struct smu10_hwmgr *data = (struct smu10_hwmgr *)(hwmgr->backend); + struct smu10_voltage_dependency_table *mclk_table = data->clock_vol_info.vdd_dep_on_fclk; int i, now, size = 0; switch (type) { case PP_SCLK: - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetGfxclkFrequency), - "Attempt to get current GFXCLK Failed!", - return -1); - PP_ASSERT_WITH_CODE(!rv_read_arg_from_smc(hwmgr, - &now), - "Attempt to get current GFXCLK Failed!", - return -1); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency); + now = smum_get_argument(hwmgr); size += sprintf(buf + size, "0: %uMhz %s\n", data->gfx_min_freq_limit / 100, @@ -758,14 +737,8 @@ static int rv_print_clock_levels(struct pp_hwmgr *hwmgr, == now) ? "*" : ""); break; case PP_MCLK: - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetFclkFrequency), - "Attempt to get current MEMCLK Failed!", - return -1); - PP_ASSERT_WITH_CODE(!rv_read_arg_from_smc(hwmgr, - &now), - "Attempt to get current MEMCLK Failed!", - return -1); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency); + now = smum_get_argument(hwmgr); for (i = 0; i < mclk_table->count; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", @@ -781,16 +754,16 @@ static int rv_print_clock_levels(struct pp_hwmgr *hwmgr, return size; } -static int rv_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, +static int smu10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, PHM_PerformanceLevelDesignation designation, uint32_t index, PHM_PerformanceLevel *level) { - struct rv_hwmgr *data; + struct smu10_hwmgr *data; if (level == NULL || hwmgr == NULL || state == NULL) return -EINVAL; - data = (struct rv_hwmgr *)(hwmgr->backend); + data = (struct smu10_hwmgr *)(hwmgr->backend); if (index == 0) { level->memory_clock = data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk; @@ -807,10 +780,10 @@ static int rv_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_p return 0; } -static int rv_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, +static int smu10_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *clock_info) { - const struct rv_power_state *ps = cast_const_rv_ps(state); + const struct smu10_power_state *ps = cast_const_smu10_ps(state); clock_info->min_eng_clk = ps->levels[0].engine_clock / (1 << (ps->levels[0].ss_divider_index)); clock_info->max_eng_clk = ps->levels[ps->level - 1].engine_clock / (1 << (ps->levels[ps->level - 1].ss_divider_index)); @@ -825,7 +798,7 @@ static int rv_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, #define MEM_LATENCY_ERR 0xFFFF -static uint32_t rv_get_mem_latency(struct pp_hwmgr *hwmgr, +static uint32_t smu10_get_mem_latency(struct pp_hwmgr *hwmgr, uint32_t clock) { if (clock >= MEM_FREQ_LOW_LATENCY && @@ -837,14 +810,14 @@ static uint32_t rv_get_mem_latency(struct pp_hwmgr *hwmgr, return MEM_LATENCY_ERR; } -static int rv_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, +static int smu10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct pp_clock_levels_with_latency *clocks) { uint32_t i; - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); - struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); - struct rv_voltage_dependency_table *pclk_vol_table; + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); + struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); + struct smu10_voltage_dependency_table *pclk_vol_table; bool latency_required = false; if (pinfo == NULL) @@ -881,7 +854,7 @@ static int rv_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, for (i = 0; i < pclk_vol_table->count; i++) { clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; clocks->data[i].latency_in_us = latency_required ? - rv_get_mem_latency(hwmgr, + smu10_get_mem_latency(hwmgr, pclk_vol_table->entries[i].clk) : 0; clocks->num_levels++; @@ -890,14 +863,14 @@ static int rv_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, return 0; } -static int rv_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, +static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks) { uint32_t i; - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); - struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); - struct rv_voltage_dependency_table *pclk_vol_table = NULL; + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); + struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); + struct smu10_voltage_dependency_table *pclk_vol_table = NULL; if (pinfo == NULL) return -EINVAL; @@ -932,29 +905,28 @@ static int rv_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, return 0; } -int rv_display_clock_voltage_request(struct pp_hwmgr *hwmgr, +static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock_req) { - int result = 0; - struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); enum amd_pp_clock_type clk_type = clock_req->clock_type; uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; PPSMC_Msg msg; switch (clk_type) { case amd_pp_dcf_clock: - if (clk_freq == rv_data->dcf_actual_hard_min_freq) + if (clk_freq == smu10_data->dcf_actual_hard_min_freq) return 0; msg = PPSMC_MSG_SetHardMinDcefclkByFreq; - rv_data->dcf_actual_hard_min_freq = clk_freq; + smu10_data->dcf_actual_hard_min_freq = clk_freq; break; case amd_pp_soc_clock: msg = PPSMC_MSG_SetHardMinSocclkByFreq; break; case amd_pp_f_clock: - if (clk_freq == rv_data->f_actual_hard_min_freq) + if (clk_freq == smu10_data->f_actual_hard_min_freq) return 0; - rv_data->f_actual_hard_min_freq = clk_freq; + smu10_data->f_actual_hard_min_freq = clk_freq; msg = PPSMC_MSG_SetHardMinFclkByFreq; break; default: @@ -962,19 +934,18 @@ int rv_display_clock_voltage_request(struct pp_hwmgr *hwmgr, return -EINVAL; } - result = smum_send_msg_to_smc_with_parameter(hwmgr, msg, - clk_freq); + smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq); - return result; + return 0; } -static int rv_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) +static int smu10_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) { clocks->engine_max_clock = 80000; /* driver can't get engine clock, temp hard code to 800MHz */ return 0; } -static int rv_thermal_get_temperature(struct pp_hwmgr *hwmgr) +static int smu10_thermal_get_temperature(struct pp_hwmgr *hwmgr) { uint32_t reg_offset = soc15_get_register_offset(THM_HWID, 0, mmTHM_TCON_CUR_TMP_BASE_IDX, mmTHM_TCON_CUR_TMP); @@ -990,7 +961,7 @@ static int rv_thermal_get_temperature(struct pp_hwmgr *hwmgr) return cur_temp; } -static int rv_read_sensor(struct pp_hwmgr *hwmgr, int idx, +static int smu10_read_sensor(struct pp_hwmgr *hwmgr, int idx, void *value, int *size) { uint32_t sclk, mclk; @@ -998,25 +969,21 @@ static int rv_read_sensor(struct pp_hwmgr *hwmgr, int idx, switch (idx) { case AMDGPU_PP_SENSOR_GFX_SCLK: - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency); - if (!ret) { - rv_read_arg_from_smc(hwmgr, &sclk); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency); + sclk = smum_get_argument(hwmgr); /* in units of 10KHZ */ - *((uint32_t *)value) = sclk * 100; - *size = 4; - } + *((uint32_t *)value) = sclk * 100; + *size = 4; break; case AMDGPU_PP_SENSOR_GFX_MCLK: - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency); - if (!ret) { - rv_read_arg_from_smc(hwmgr, &mclk); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency); + mclk = smum_get_argument(hwmgr); /* in units of 10KHZ */ - *((uint32_t *)value) = mclk * 100; - *size = 4; - } + *((uint32_t *)value) = mclk * 100; + *size = 4; break; case AMDGPU_PP_SENSOR_GPU_TEMP: - *((uint32_t *)value) = rv_thermal_get_temperature(hwmgr); + *((uint32_t *)value) = smu10_thermal_get_temperature(hwmgr); break; default: ret = -EINVAL; @@ -1026,50 +993,50 @@ static int rv_read_sensor(struct pp_hwmgr *hwmgr, int idx, return ret; } -static int rv_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr) +static int smu10_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr) { return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PowerGateMmHub); } -static const struct pp_hwmgr_func rv_hwmgr_funcs = { - .backend_init = rv_hwmgr_backend_init, - .backend_fini = rv_hwmgr_backend_fini, +static const struct pp_hwmgr_func smu10_hwmgr_funcs = { + .backend_init = smu10_hwmgr_backend_init, + .backend_fini = smu10_hwmgr_backend_fini, .asic_setup = NULL, - .apply_state_adjust_rules = rv_apply_state_adjust_rules, - .force_dpm_level = rv_dpm_force_dpm_level, - .get_power_state_size = rv_get_power_state_size, + .apply_state_adjust_rules = smu10_apply_state_adjust_rules, + .force_dpm_level = smu10_dpm_force_dpm_level, + .get_power_state_size = smu10_get_power_state_size, .powerdown_uvd = NULL, .powergate_uvd = NULL, .powergate_vce = NULL, - .get_mclk = rv_dpm_get_mclk, - .get_sclk = rv_dpm_get_sclk, - .patch_boot_state = rv_dpm_patch_boot_state, - .get_pp_table_entry = rv_dpm_get_pp_table_entry, - .get_num_of_pp_table_entries = rv_dpm_get_num_of_pp_table_entries, - .set_cpu_power_state = rv_set_cpu_power_state, - .store_cc6_data = rv_store_cc6_data, - .force_clock_level = rv_force_clock_level, - .print_clock_levels = rv_print_clock_levels, - .get_dal_power_level = rv_get_dal_power_level, - .get_performance_level = rv_get_performance_level, - .get_current_shallow_sleep_clocks = rv_get_current_shallow_sleep_clocks, - .get_clock_by_type_with_latency = rv_get_clock_by_type_with_latency, - .get_clock_by_type_with_voltage = rv_get_clock_by_type_with_voltage, - .get_max_high_clocks = rv_get_max_high_clocks, - .read_sensor = rv_read_sensor, - .set_active_display_count = rv_set_active_display_count, - .set_deep_sleep_dcefclk = rv_set_deep_sleep_dcefclk, - .dynamic_state_management_enable = rv_enable_dpm_tasks, - .power_off_asic = rv_power_off_asic, - .asic_setup = rv_setup_asic_task, - .power_state_set = rv_set_power_state_tasks, - .dynamic_state_management_disable = rv_disable_dpm_tasks, - .set_mmhub_powergating_by_smu = rv_set_mmhub_powergating_by_smu, + .get_mclk = smu10_dpm_get_mclk, + .get_sclk = smu10_dpm_get_sclk, + .patch_boot_state = smu10_dpm_patch_boot_state, + .get_pp_table_entry = smu10_dpm_get_pp_table_entry, + .get_num_of_pp_table_entries = smu10_dpm_get_num_of_pp_table_entries, + .set_cpu_power_state = smu10_set_cpu_power_state, + .store_cc6_data = smu10_store_cc6_data, + .force_clock_level = smu10_force_clock_level, + .print_clock_levels = smu10_print_clock_levels, + .get_dal_power_level = smu10_get_dal_power_level, + .get_performance_level = smu10_get_performance_level, + .get_current_shallow_sleep_clocks = smu10_get_current_shallow_sleep_clocks, + .get_clock_by_type_with_latency = smu10_get_clock_by_type_with_latency, + .get_clock_by_type_with_voltage = smu10_get_clock_by_type_with_voltage, + .get_max_high_clocks = smu10_get_max_high_clocks, + .read_sensor = smu10_read_sensor, + .set_active_display_count = smu10_set_active_display_count, + .set_deep_sleep_dcefclk = smu10_set_deep_sleep_dcefclk, + .dynamic_state_management_enable = smu10_enable_dpm_tasks, + .power_off_asic = smu10_power_off_asic, + .asic_setup = smu10_setup_asic_task, + .power_state_set = smu10_set_power_state_tasks, + .dynamic_state_management_disable = smu10_disable_dpm_tasks, + .set_mmhub_powergating_by_smu = smu10_set_mmhub_powergating_by_smu, }; -int rv_init_function_pointers(struct pp_hwmgr *hwmgr) +int smu10_init_function_pointers(struct pp_hwmgr *hwmgr) { - hwmgr->hwmgr_func = &rv_hwmgr_funcs; + hwmgr->hwmgr_func = &smu10_hwmgr_funcs; hwmgr->pptable_func = &pptable_funcs; return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h index c3bc311dc59f..175c3a592b6c 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h @@ -21,17 +21,17 @@ * */ -#ifndef RAVEN_HWMGR_H -#define RAVEN_HWMGR_H +#ifndef SMU10_HWMGR_H +#define SMU10_HWMGR_H #include "hwmgr.h" -#include "rv_inc.h" +#include "smu10_inc.h" #include "smu10_driver_if.h" #include "rv_ppsmc.h" -#define RAVEN_MAX_HARDWARE_POWERLEVELS 8 -#define PHMRAVEN_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15 +#define SMU10_MAX_HARDWARE_POWERLEVELS 8 +#define SMU10_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15 #define DPMFlags_SCLK_Enabled 0x00000001 #define DPMFlags_UVD_Enabled 0x00000002 @@ -47,10 +47,10 @@ #define SMU_PHYID_SHIFT 8 -#define RAVEN_PCIE_POWERGATING_TARGET_GFX 0 -#define RAVEN_PCIE_POWERGATING_TARGET_DDI 1 -#define RAVEN_PCIE_POWERGATING_TARGET_PLLCASCADE 2 -#define RAVEN_PCIE_POWERGATING_TARGET_PHY 3 +#define SMU10_PCIE_POWERGATING_TARGET_GFX 0 +#define SMU10_PCIE_POWERGATING_TARGET_DDI 1 +#define SMU10_PCIE_POWERGATING_TARGET_PLLCASCADE 2 +#define SMU10_PCIE_POWERGATING_TARGET_PHY 3 enum VQ_TYPE { CLOCK_TYPE_DCLK = 0L, @@ -65,14 +65,14 @@ enum VQ_TYPE { #define SUSTAINABLE_CU_MASK 0xff000000 #define SUSTAINABLE_CU_SHIFT 24 -struct rv_dpm_entry { +struct smu10_dpm_entry { uint32_t soft_min_clk; uint32_t hard_min_clk; uint32_t soft_max_clk; uint32_t hard_max_clk; }; -struct rv_power_level { +struct smu10_power_level { uint32_t engine_clock; uint8_t vddc_index; uint8_t ds_divider_index; @@ -86,14 +86,14 @@ struct rv_power_level { uint8_t rsv[3]; }; -/*used for the nbpsFlags field in rv_power state*/ -#define RAVEN_POWERSTATE_FLAGS_NBPS_FORCEHIGH (1<<0) -#define RAVEN_POWERSTATE_FLAGS_NBPS_LOCKTOHIGH (1<<1) -#define RAVEN_POWERSTATE_FLAGS_NBPS_LOCKTOLOW (1<<2) +/*used for the nbpsFlags field in smu10_power state*/ +#define SMU10_POWERSTATE_FLAGS_NBPS_FORCEHIGH (1<<0) +#define SMU10_POWERSTATE_FLAGS_NBPS_LOCKTOHIGH (1<<1) +#define SMU10_POWERSTATE_FLAGS_NBPS_LOCKTOLOW (1<<2) -#define RAVEN_POWERSTATE_FLAGS_BAPM_DISABLE (1<<0) +#define SMU10_POWERSTATE_FLAGS_BAPM_DISABLE (1<<0) -struct rv_uvd_clocks { +struct smu10_uvd_clocks { uint32_t vclk; uint32_t dclk; uint32_t vclk_low_divider; @@ -118,16 +118,16 @@ struct pp_disable_nbpslo_flags { }; -enum rv_pstate_previous_action { +enum smu10_pstate_previous_action { DO_NOTHING = 1, FORCE_HIGH, CANCEL_FORCE_HIGH }; -struct rv_power_state { +struct smu10_power_state { unsigned int magic; uint32_t level; - struct rv_uvd_clocks uvd_clocks; + struct smu10_uvd_clocks uvd_clocks; uint32_t evclk; uint32_t ecclk; uint32_t samclk; @@ -141,79 +141,79 @@ struct rv_power_state { uint8_t dpm_x_nbps_low; uint8_t dpm_x_nbps_high; - enum rv_pstate_previous_action action; + enum smu10_pstate_previous_action action; - struct rv_power_level levels[RAVEN_MAX_HARDWARE_POWERLEVELS]; + struct smu10_power_level levels[SMU10_MAX_HARDWARE_POWERLEVELS]; struct pp_disable_nbpslo_flags nbpslo_flags; }; -#define RAVEN_NUM_NBPSTATES 4 -#define RAVEN_NUM_NBPMEMORYCLOCK 2 +#define SMU10_NUM_NBPSTATES 4 +#define SMU10_NUM_NBPMEMORYCLOCK 2 -struct rv_display_phy_info_entry { +struct smu10_display_phy_info_entry { uint8_t phy_present; uint8_t active_lane_mapping; uint8_t display_config_type; uint8_t active_num_of_lanes; }; -#define RAVEN_MAX_DISPLAYPHY_IDS 10 +#define SMU10_MAX_DISPLAYPHY_IDS 10 -struct rv_display_phy_info { +struct smu10_display_phy_info { bool display_phy_access_initialized; - struct rv_display_phy_info_entry entries[RAVEN_MAX_DISPLAYPHY_IDS]; + struct smu10_display_phy_info_entry entries[SMU10_MAX_DISPLAYPHY_IDS]; }; #define MAX_DISPLAY_CLOCK_LEVEL 8 -struct rv_system_info{ +struct smu10_system_info{ uint8_t htc_tmp_lmt; uint8_t htc_hyst_lmt; }; #define MAX_REGULAR_DPM_NUMBER 8 -struct rv_mclk_latency_entries { +struct smu10_mclk_latency_entries { uint32_t frequency; uint32_t latency; }; -struct rv_mclk_latency_table { +struct smu10_mclk_latency_table { uint32_t count; - struct rv_mclk_latency_entries entries[MAX_REGULAR_DPM_NUMBER]; + struct smu10_mclk_latency_entries entries[MAX_REGULAR_DPM_NUMBER]; }; -struct rv_clock_voltage_dependency_record { +struct smu10_clock_voltage_dependency_record { uint32_t clk; uint32_t vol; }; -struct rv_voltage_dependency_table { +struct smu10_voltage_dependency_table { uint32_t count; - struct rv_clock_voltage_dependency_record entries[1]; + struct smu10_clock_voltage_dependency_record entries[1]; }; -struct rv_clock_voltage_information { - struct rv_voltage_dependency_table *vdd_dep_on_dcefclk; - struct rv_voltage_dependency_table *vdd_dep_on_socclk; - struct rv_voltage_dependency_table *vdd_dep_on_fclk; - struct rv_voltage_dependency_table *vdd_dep_on_mclk; - struct rv_voltage_dependency_table *vdd_dep_on_dispclk; - struct rv_voltage_dependency_table *vdd_dep_on_dppclk; - struct rv_voltage_dependency_table *vdd_dep_on_phyclk; +struct smu10_clock_voltage_information { + struct smu10_voltage_dependency_table *vdd_dep_on_dcefclk; + struct smu10_voltage_dependency_table *vdd_dep_on_socclk; + struct smu10_voltage_dependency_table *vdd_dep_on_fclk; + struct smu10_voltage_dependency_table *vdd_dep_on_mclk; + struct smu10_voltage_dependency_table *vdd_dep_on_dispclk; + struct smu10_voltage_dependency_table *vdd_dep_on_dppclk; + struct smu10_voltage_dependency_table *vdd_dep_on_phyclk; }; -struct rv_hwmgr { +struct smu10_hwmgr { uint32_t disable_driver_thermal_policy; uint32_t thermal_auto_throttling_treshold; - struct rv_system_info sys_info; - struct rv_mclk_latency_table mclk_latency_table; + struct smu10_system_info sys_info; + struct smu10_mclk_latency_table mclk_latency_table; uint32_t ddi_power_gating_disabled; - struct rv_display_phy_info_entry display_phy_info; + struct smu10_display_phy_info_entry display_phy_info; uint32_t dce_slow_sclk_threshold; bool disp_clk_bypass; @@ -255,10 +255,10 @@ struct rv_hwmgr { uint32_t fps_low_threshold; uint32_t dpm_flags; - struct rv_dpm_entry sclk_dpm; - struct rv_dpm_entry uvd_dpm; - struct rv_dpm_entry vce_dpm; - struct rv_dpm_entry acp_dpm; + struct smu10_dpm_entry sclk_dpm; + struct smu10_dpm_entry uvd_dpm; + struct smu10_dpm_entry vce_dpm; + struct smu10_dpm_entry acp_dpm; bool acp_power_up_no_dsp; uint32_t max_sclk_level; @@ -291,7 +291,7 @@ struct rv_hwmgr { bool gfx_off_controled_by_driver; Watermarks_t water_marks_table; - struct rv_clock_voltage_information clock_vol_info; + struct smu10_clock_voltage_information clock_vol_info; DpmClocks_t clock_table; uint32_t active_process_mask; @@ -302,21 +302,21 @@ struct rv_hwmgr { struct pp_hwmgr; -int rv_init_function_pointers(struct pp_hwmgr *hwmgr); +int smu10_init_function_pointers(struct pp_hwmgr *hwmgr); -/* UMD PState Raven Msg Parameters in MHz */ -#define RAVEN_UMD_PSTATE_GFXCLK 700 -#define RAVEN_UMD_PSTATE_SOCCLK 626 -#define RAVEN_UMD_PSTATE_FCLK 933 -#define RAVEN_UMD_PSTATE_VCE 0x03C00320 +/* UMD PState SMU10 Msg Parameters in MHz */ +#define SMU10_UMD_PSTATE_GFXCLK 700 +#define SMU10_UMD_PSTATE_SOCCLK 626 +#define SMU10_UMD_PSTATE_FCLK 933 +#define SMU10_UMD_PSTATE_VCE 0x03C00320 -#define RAVEN_UMD_PSTATE_PEAK_GFXCLK 1100 -#define RAVEN_UMD_PSTATE_PEAK_SOCCLK 757 -#define RAVEN_UMD_PSTATE_PEAK_FCLK 1200 +#define SMU10_UMD_PSTATE_PEAK_GFXCLK 1100 +#define SMU10_UMD_PSTATE_PEAK_SOCCLK 757 +#define SMU10_UMD_PSTATE_PEAK_FCLK 1200 -#define RAVEN_UMD_PSTATE_MIN_GFXCLK 200 -#define RAVEN_UMD_PSTATE_MIN_FCLK 400 -#define RAVEN_UMD_PSTATE_MIN_SOCCLK 200 -#define RAVEN_UMD_PSTATE_MIN_VCE 0x0190012C +#define SMU10_UMD_PSTATE_MIN_GFXCLK 200 +#define SMU10_UMD_PSTATE_MIN_FCLK 400 +#define SMU10_UMD_PSTATE_MIN_SOCCLK 200 +#define SMU10_UMD_PSTATE_MIN_VCE 0x0190012C #endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_inc.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h index ae59a3fdea8a..edb68e302f6f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_inc.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h @@ -21,8 +21,8 @@ * */ -#ifndef RAVEN_INC_H -#define RAVEN_INC_H +#ifndef SMU10_INC_H +#define SMU10_INC_H #include "asic_reg/mp/mp_10_0_default.h" diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h index 7b54d48b2ce2..1ddce023218a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h @@ -25,7 +25,6 @@ #define _SMU7_CLOCK_POWER_GATING_H_ #include "smu7_hwmgr.h" -#include "pp_asicblocks.h" void smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate); void smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index df2a312ca6c9..7a87209f7258 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -40,7 +40,6 @@ #include "hwmgr.h" #include "smu7_hwmgr.h" -#include "smu7_smumgr.h" #include "smu_ucode_xfer_vi.h" #include "smu7_powertune.h" #include "smu7_dyn_defaults.h" @@ -1353,12 +1352,7 @@ static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr) static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable) { - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - - if (smu_data == NULL) - return -EINVAL; - - if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) + if (!hwmgr->avfs_supported) return 0; if (enable) { @@ -1382,13 +1376,9 @@ static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable) static int smu7_update_avfs(struct pp_hwmgr *hwmgr) { - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - if (smu_data == NULL) - return -EINVAL; - - if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) + if (!hwmgr->avfs_supported) return 0; if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_VDDC) { diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c index 8c1f884ae555..75a465f771f0 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c @@ -35,9 +35,8 @@ #include "hwmgr.h" #include "hardwaremanager.h" #include "cz_ppsmc.h" -#include "cz_hwmgr.h" +#include "smu8_hwmgr.h" #include "power_state.h" -#include "cz_clockpowergating.h" #include "pp_thermal.h" #define ixSMUSVI_NB_CURRENTVID 0xD8230044 @@ -47,26 +46,26 @@ #define CURRENT_GFX_VID_MASK 0xff000000 #define CURRENT_GFX_VID__SHIFT 24 -static const unsigned long PhwCz_Magic = (unsigned long) PHM_Cz_Magic; +static const unsigned long smu8_magic = (unsigned long) PHM_Cz_Magic; -static struct cz_power_state *cast_PhwCzPowerState(struct pp_hw_power_state *hw_ps) +static struct smu8_power_state *cast_smu8_power_state(struct pp_hw_power_state *hw_ps) { - if (PhwCz_Magic != hw_ps->magic) + if (smu8_magic != hw_ps->magic) return NULL; - return (struct cz_power_state *)hw_ps; + return (struct smu8_power_state *)hw_ps; } -static const struct cz_power_state *cast_const_PhwCzPowerState( +static const struct smu8_power_state *cast_const_smu8_power_state( const struct pp_hw_power_state *hw_ps) { - if (PhwCz_Magic != hw_ps->magic) + if (smu8_magic != hw_ps->magic) return NULL; - return (struct cz_power_state *)hw_ps; + return (struct smu8_power_state *)hw_ps; } -static uint32_t cz_get_eclk_level(struct pp_hwmgr *hwmgr, +static uint32_t smu8_get_eclk_level(struct pp_hwmgr *hwmgr, uint32_t clock, uint32_t msg) { int i = 0; @@ -97,7 +96,7 @@ static uint32_t cz_get_eclk_level(struct pp_hwmgr *hwmgr, return i; } -static uint32_t cz_get_sclk_level(struct pp_hwmgr *hwmgr, +static uint32_t smu8_get_sclk_level(struct pp_hwmgr *hwmgr, uint32_t clock, uint32_t msg) { int i = 0; @@ -127,7 +126,7 @@ static uint32_t cz_get_sclk_level(struct pp_hwmgr *hwmgr, return i; } -static uint32_t cz_get_uvd_level(struct pp_hwmgr *hwmgr, +static uint32_t smu8_get_uvd_level(struct pp_hwmgr *hwmgr, uint32_t clock, uint32_t msg) { int i = 0; @@ -158,42 +157,42 @@ static uint32_t cz_get_uvd_level(struct pp_hwmgr *hwmgr, return i; } -static uint32_t cz_get_max_sclk_level(struct pp_hwmgr *hwmgr) +static uint32_t smu8_get_max_sclk_level(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - if (cz_hwmgr->max_sclk_level == 0) { + if (data->max_sclk_level == 0) { smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxSclkLevel); - cz_hwmgr->max_sclk_level = smum_get_argument(hwmgr) + 1; + data->max_sclk_level = smum_get_argument(hwmgr) + 1; } - return cz_hwmgr->max_sclk_level; + return data->max_sclk_level; } -static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) +static int smu8_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct amdgpu_device *adev = hwmgr->adev; - cz_hwmgr->gfx_ramp_step = 256*25/100; - cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */ - - cz_hwmgr->mgcg_cgtt_local0 = 0x00000000; - cz_hwmgr->mgcg_cgtt_local1 = 0x00000000; - cz_hwmgr->clock_slow_down_freq = 25000; - cz_hwmgr->skip_clock_slow_down = 1; - cz_hwmgr->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */ - cz_hwmgr->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */ - cz_hwmgr->voting_rights_clients = 0x00C00033; - cz_hwmgr->static_screen_threshold = 8; - cz_hwmgr->ddi_power_gating_disabled = 0; - cz_hwmgr->bapm_enabled = 1; - cz_hwmgr->voltage_drop_threshold = 0; - cz_hwmgr->gfx_power_gating_threshold = 500; - cz_hwmgr->vce_slow_sclk_threshold = 20000; - cz_hwmgr->dce_slow_sclk_threshold = 30000; - cz_hwmgr->disable_driver_thermal_policy = 1; - cz_hwmgr->disable_nb_ps3_in_battery = 0; + data->gfx_ramp_step = 256*25/100; + data->gfx_ramp_delay = 1; /* by default, we delay 1us */ + + data->mgcg_cgtt_local0 = 0x00000000; + data->mgcg_cgtt_local1 = 0x00000000; + data->clock_slow_down_freq = 25000; + data->skip_clock_slow_down = 1; + data->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */ + data->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */ + data->voting_rights_clients = 0x00C00033; + data->static_screen_threshold = 8; + data->ddi_power_gating_disabled = 0; + data->bapm_enabled = 1; + data->voltage_drop_threshold = 0; + data->gfx_power_gating_threshold = 500; + data->vce_slow_sclk_threshold = 20000; + data->dce_slow_sclk_threshold = 30000; + data->disable_driver_thermal_policy = 1; + data->disable_nb_ps3_in_battery = 0; phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ABM); @@ -204,14 +203,14 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicM3Arbiter); - cz_hwmgr->override_dynamic_mgpg = 1; + data->override_dynamic_mgpg = 1; phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState); - cz_hwmgr->thermal_auto_throttling_treshold = 0; - cz_hwmgr->tdr_clock = 0; - cz_hwmgr->disable_gfx_power_gating_in_uvd = 0; + data->thermal_auto_throttling_treshold = 0; + data->tdr_clock = 0; + data->disable_gfx_power_gating_in_uvd = 0; phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicUVDState); @@ -221,10 +220,10 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEDPM); - cz_hwmgr->cc6_settings.cpu_cc6_disable = false; - cz_hwmgr->cc6_settings.cpu_pstate_disable = false; - cz_hwmgr->cc6_settings.nb_pstate_switch_disable = false; - cz_hwmgr->cc6_settings.cpu_pstate_separation_time = 0; + data->cc6_settings.cpu_cc6_disable = false; + data->cc6_settings.cpu_pstate_disable = false; + data->cc6_settings.nb_pstate_switch_disable = false; + data->cc6_settings.cpu_pstate_separation_time = 0; phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableVoltageIsland); @@ -245,30 +244,30 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) return 0; } -static uint32_t cz_convert_8Bit_index_to_voltage( +static uint32_t smu8_convert_8Bit_index_to_voltage( struct pp_hwmgr *hwmgr, uint16_t voltage) { return 6200 - (voltage * 25); } -static int cz_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, +static int smu8_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, struct phm_clock_and_voltage_limits *table) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend; - struct cz_sys_info *sys_info = &cz_hwmgr->sys_info; + struct smu8_hwmgr *data = hwmgr->backend; + struct smu8_sys_info *sys_info = &data->sys_info; struct phm_clock_voltage_dependency_table *dep_table = hwmgr->dyn_state.vddc_dependency_on_sclk; if (dep_table->count > 0) { table->sclk = dep_table->entries[dep_table->count-1].clk; - table->vddc = cz_convert_8Bit_index_to_voltage(hwmgr, + table->vddc = smu8_convert_8Bit_index_to_voltage(hwmgr, (uint16_t)dep_table->entries[dep_table->count-1].v); } table->mclk = sys_info->nbp_memory_clock[0]; return 0; } -static int cz_init_dynamic_state_adjustment_rule_settings( +static int smu8_init_dynamic_state_adjustment_rule_settings( struct pp_hwmgr *hwmgr, ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table) { @@ -306,9 +305,9 @@ static int cz_init_dynamic_state_adjustment_rule_settings( return 0; } -static int cz_get_system_info_data(struct pp_hwmgr *hwmgr) +static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend; + struct smu8_hwmgr *data = hwmgr->backend; ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info = NULL; uint32_t i; int result = 0; @@ -330,67 +329,67 @@ static int cz_get_system_info_data(struct pp_hwmgr *hwmgr) return -EINVAL; } - cz_hwmgr->sys_info.bootup_uma_clock = + data->sys_info.bootup_uma_clock = le32_to_cpu(info->ulBootUpUMAClock); - cz_hwmgr->sys_info.bootup_engine_clock = + data->sys_info.bootup_engine_clock = le32_to_cpu(info->ulBootUpEngineClock); - cz_hwmgr->sys_info.dentist_vco_freq = + data->sys_info.dentist_vco_freq = le32_to_cpu(info->ulDentistVCOFreq); - cz_hwmgr->sys_info.system_config = + data->sys_info.system_config = le32_to_cpu(info->ulSystemConfig); - cz_hwmgr->sys_info.bootup_nb_voltage_index = + data->sys_info.bootup_nb_voltage_index = le16_to_cpu(info->usBootUpNBVoltage); - cz_hwmgr->sys_info.htc_hyst_lmt = + data->sys_info.htc_hyst_lmt = (info->ucHtcHystLmt == 0) ? 5 : info->ucHtcHystLmt; - cz_hwmgr->sys_info.htc_tmp_lmt = + data->sys_info.htc_tmp_lmt = (info->ucHtcTmpLmt == 0) ? 203 : info->ucHtcTmpLmt; - if (cz_hwmgr->sys_info.htc_tmp_lmt <= - cz_hwmgr->sys_info.htc_hyst_lmt) { + if (data->sys_info.htc_tmp_lmt <= + data->sys_info.htc_hyst_lmt) { pr_err("The htcTmpLmt should be larger than htcHystLmt.\n"); return -EINVAL; } - cz_hwmgr->sys_info.nb_dpm_enable = - cz_hwmgr->enable_nb_ps_policy && + data->sys_info.nb_dpm_enable = + data->enable_nb_ps_policy && (le32_to_cpu(info->ulSystemConfig) >> 3 & 0x1); - for (i = 0; i < CZ_NUM_NBPSTATES; i++) { - if (i < CZ_NUM_NBPMEMORYCLOCK) { - cz_hwmgr->sys_info.nbp_memory_clock[i] = + for (i = 0; i < SMU8_NUM_NBPSTATES; i++) { + if (i < SMU8_NUM_NBPMEMORYCLOCK) { + data->sys_info.nbp_memory_clock[i] = le32_to_cpu(info->ulNbpStateMemclkFreq[i]); } - cz_hwmgr->sys_info.nbp_n_clock[i] = + data->sys_info.nbp_n_clock[i] = le32_to_cpu(info->ulNbpStateNClkFreq[i]); } for (i = 0; i < MAX_DISPLAY_CLOCK_LEVEL; i++) { - cz_hwmgr->sys_info.display_clock[i] = + data->sys_info.display_clock[i] = le32_to_cpu(info->sDispClkVoltageMapping[i].ulMaximumSupportedCLK); } /* Here use 4 levels, make sure not exceed */ - for (i = 0; i < CZ_NUM_NBPSTATES; i++) { - cz_hwmgr->sys_info.nbp_voltage_index[i] = + for (i = 0; i < SMU8_NUM_NBPSTATES; i++) { + data->sys_info.nbp_voltage_index[i] = le16_to_cpu(info->usNBPStateVoltage[i]); } - if (!cz_hwmgr->sys_info.nb_dpm_enable) { - for (i = 1; i < CZ_NUM_NBPSTATES; i++) { - if (i < CZ_NUM_NBPMEMORYCLOCK) { - cz_hwmgr->sys_info.nbp_memory_clock[i] = - cz_hwmgr->sys_info.nbp_memory_clock[0]; + if (!data->sys_info.nb_dpm_enable) { + for (i = 1; i < SMU8_NUM_NBPSTATES; i++) { + if (i < SMU8_NUM_NBPMEMORYCLOCK) { + data->sys_info.nbp_memory_clock[i] = + data->sys_info.nbp_memory_clock[0]; } - cz_hwmgr->sys_info.nbp_n_clock[i] = - cz_hwmgr->sys_info.nbp_n_clock[0]; - cz_hwmgr->sys_info.nbp_voltage_index[i] = - cz_hwmgr->sys_info.nbp_voltage_index[0]; + data->sys_info.nbp_n_clock[i] = + data->sys_info.nbp_n_clock[0]; + data->sys_info.nbp_voltage_index[i] = + data->sys_info.nbp_voltage_index[0]; } } @@ -400,40 +399,40 @@ static int cz_get_system_info_data(struct pp_hwmgr *hwmgr) PHM_PlatformCaps_EnableDFSBypass); } - cz_hwmgr->sys_info.uma_channel_number = info->ucUMAChannelNumber; + data->sys_info.uma_channel_number = info->ucUMAChannelNumber; - cz_construct_max_power_limits_table (hwmgr, + smu8_construct_max_power_limits_table (hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_ac); - cz_init_dynamic_state_adjustment_rule_settings(hwmgr, + smu8_init_dynamic_state_adjustment_rule_settings(hwmgr, &info->sDISPCLK_Voltage[0]); return result; } -static int cz_construct_boot_state(struct pp_hwmgr *hwmgr) +static int smu8_construct_boot_state(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - cz_hwmgr->boot_power_level.engineClock = - cz_hwmgr->sys_info.bootup_engine_clock; + data->boot_power_level.engineClock = + data->sys_info.bootup_engine_clock; - cz_hwmgr->boot_power_level.vddcIndex = - (uint8_t)cz_hwmgr->sys_info.bootup_nb_voltage_index; + data->boot_power_level.vddcIndex = + (uint8_t)data->sys_info.bootup_nb_voltage_index; - cz_hwmgr->boot_power_level.dsDividerIndex = 0; - cz_hwmgr->boot_power_level.ssDividerIndex = 0; - cz_hwmgr->boot_power_level.allowGnbSlow = 1; - cz_hwmgr->boot_power_level.forceNBPstate = 0; - cz_hwmgr->boot_power_level.hysteresis_up = 0; - cz_hwmgr->boot_power_level.numSIMDToPowerDown = 0; - cz_hwmgr->boot_power_level.display_wm = 0; - cz_hwmgr->boot_power_level.vce_wm = 0; + data->boot_power_level.dsDividerIndex = 0; + data->boot_power_level.ssDividerIndex = 0; + data->boot_power_level.allowGnbSlow = 1; + data->boot_power_level.forceNBPstate = 0; + data->boot_power_level.hysteresis_up = 0; + data->boot_power_level.numSIMDToPowerDown = 0; + data->boot_power_level.display_wm = 0; + data->boot_power_level.vce_wm = 0; return 0; } -static int cz_upload_pptable_to_smu(struct pp_hwmgr *hwmgr) +static int smu8_upload_pptable_to_smu(struct pp_hwmgr *hwmgr) { struct SMU8_Fusion_ClkTable *clock_table; int ret; @@ -463,18 +462,18 @@ static int cz_upload_pptable_to_smu(struct pp_hwmgr *hwmgr) clock_table = (struct SMU8_Fusion_ClkTable *)table; /* patch clock table */ - PP_ASSERT_WITH_CODE((vddc_table->count <= CZ_MAX_HARDWARE_POWERLEVELS), + PP_ASSERT_WITH_CODE((vddc_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS), "Dependency table entry exceeds max limit!", return -EINVAL;); - PP_ASSERT_WITH_CODE((vdd_gfx_table->count <= CZ_MAX_HARDWARE_POWERLEVELS), + PP_ASSERT_WITH_CODE((vdd_gfx_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS), "Dependency table entry exceeds max limit!", return -EINVAL;); - PP_ASSERT_WITH_CODE((acp_table->count <= CZ_MAX_HARDWARE_POWERLEVELS), + PP_ASSERT_WITH_CODE((acp_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS), "Dependency table entry exceeds max limit!", return -EINVAL;); - PP_ASSERT_WITH_CODE((uvd_table->count <= CZ_MAX_HARDWARE_POWERLEVELS), + PP_ASSERT_WITH_CODE((uvd_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS), "Dependency table entry exceeds max limit!", return -EINVAL;); - PP_ASSERT_WITH_CODE((vce_table->count <= CZ_MAX_HARDWARE_POWERLEVELS), + PP_ASSERT_WITH_CODE((vce_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS), "Dependency table entry exceeds max limit!", return -EINVAL;); - for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++) { + for (i = 0; i < SMU8_MAX_HARDWARE_POWERLEVELS; i++) { /* vddc_sclk */ clock_table->SclkBreakdownTable.ClkLevel[i].GnbVid = @@ -552,9 +551,9 @@ static int cz_upload_pptable_to_smu(struct pp_hwmgr *hwmgr) return ret; } -static int cz_init_sclk_limit(struct pp_hwmgr *hwmgr) +static int smu8_init_sclk_limit(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_clock_voltage_dependency_table *table = hwmgr->dyn_state.vddc_dependency_on_sclk; unsigned long clock = 0, level; @@ -562,25 +561,25 @@ static int cz_init_sclk_limit(struct pp_hwmgr *hwmgr) if (NULL == table || table->count <= 0) return -EINVAL; - cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk; - cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk; + data->sclk_dpm.soft_min_clk = table->entries[0].clk; + data->sclk_dpm.hard_min_clk = table->entries[0].clk; - level = cz_get_max_sclk_level(hwmgr) - 1; + level = smu8_get_max_sclk_level(hwmgr) - 1; if (level < table->count) clock = table->entries[level].clk; else clock = table->entries[table->count - 1].clk; - cz_hwmgr->sclk_dpm.soft_max_clk = clock; - cz_hwmgr->sclk_dpm.hard_max_clk = clock; + data->sclk_dpm.soft_max_clk = clock; + data->sclk_dpm.hard_max_clk = clock; return 0; } -static int cz_init_uvd_limit(struct pp_hwmgr *hwmgr) +static int smu8_init_uvd_limit(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_uvd_clock_voltage_dependency_table *table = hwmgr->dyn_state.uvd_clock_voltage_dependency_table; unsigned long clock = 0, level; @@ -588,8 +587,8 @@ static int cz_init_uvd_limit(struct pp_hwmgr *hwmgr) if (NULL == table || table->count <= 0) return -EINVAL; - cz_hwmgr->uvd_dpm.soft_min_clk = 0; - cz_hwmgr->uvd_dpm.hard_min_clk = 0; + data->uvd_dpm.soft_min_clk = 0; + data->uvd_dpm.hard_min_clk = 0; smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxUvdLevel); level = smum_get_argument(hwmgr); @@ -599,15 +598,15 @@ static int cz_init_uvd_limit(struct pp_hwmgr *hwmgr) else clock = table->entries[table->count - 1].vclk; - cz_hwmgr->uvd_dpm.soft_max_clk = clock; - cz_hwmgr->uvd_dpm.hard_max_clk = clock; + data->uvd_dpm.soft_max_clk = clock; + data->uvd_dpm.hard_max_clk = clock; return 0; } -static int cz_init_vce_limit(struct pp_hwmgr *hwmgr) +static int smu8_init_vce_limit(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_vce_clock_voltage_dependency_table *table = hwmgr->dyn_state.vce_clock_voltage_dependency_table; unsigned long clock = 0, level; @@ -615,8 +614,8 @@ static int cz_init_vce_limit(struct pp_hwmgr *hwmgr) if (NULL == table || table->count <= 0) return -EINVAL; - cz_hwmgr->vce_dpm.soft_min_clk = 0; - cz_hwmgr->vce_dpm.hard_min_clk = 0; + data->vce_dpm.soft_min_clk = 0; + data->vce_dpm.hard_min_clk = 0; smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxEclkLevel); level = smum_get_argument(hwmgr); @@ -626,15 +625,15 @@ static int cz_init_vce_limit(struct pp_hwmgr *hwmgr) else clock = table->entries[table->count - 1].ecclk; - cz_hwmgr->vce_dpm.soft_max_clk = clock; - cz_hwmgr->vce_dpm.hard_max_clk = clock; + data->vce_dpm.soft_max_clk = clock; + data->vce_dpm.hard_max_clk = clock; return 0; } -static int cz_init_acp_limit(struct pp_hwmgr *hwmgr) +static int smu8_init_acp_limit(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_acp_clock_voltage_dependency_table *table = hwmgr->dyn_state.acp_clock_voltage_dependency_table; unsigned long clock = 0, level; @@ -642,8 +641,8 @@ static int cz_init_acp_limit(struct pp_hwmgr *hwmgr) if (NULL == table || table->count <= 0) return -EINVAL; - cz_hwmgr->acp_dpm.soft_min_clk = 0; - cz_hwmgr->acp_dpm.hard_min_clk = 0; + data->acp_dpm.soft_min_clk = 0; + data->acp_dpm.hard_min_clk = 0; smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxAclkLevel); level = smum_get_argument(hwmgr); @@ -653,32 +652,32 @@ static int cz_init_acp_limit(struct pp_hwmgr *hwmgr) else clock = table->entries[table->count - 1].acpclk; - cz_hwmgr->acp_dpm.soft_max_clk = clock; - cz_hwmgr->acp_dpm.hard_max_clk = clock; + data->acp_dpm.soft_max_clk = clock; + data->acp_dpm.hard_max_clk = clock; return 0; } -static void cz_init_power_gate_state(struct pp_hwmgr *hwmgr) +static void smu8_init_power_gate_state(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - cz_hwmgr->uvd_power_gated = false; - cz_hwmgr->vce_power_gated = false; - cz_hwmgr->samu_power_gated = false; - cz_hwmgr->acp_power_gated = false; - cz_hwmgr->pgacpinit = true; + data->uvd_power_gated = false; + data->vce_power_gated = false; + data->samu_power_gated = false; + data->acp_power_gated = false; + data->pgacpinit = true; } -static void cz_init_sclk_threshold(struct pp_hwmgr *hwmgr) +static void smu8_init_sclk_threshold(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - cz_hwmgr->low_sclk_interrupt_threshold = 0; + data->low_sclk_interrupt_threshold = 0; } -static int cz_update_sclk_limit(struct pp_hwmgr *hwmgr) +static int smu8_update_sclk_limit(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_clock_voltage_dependency_table *table = hwmgr->dyn_state.vddc_dependency_on_sclk; @@ -687,29 +686,29 @@ static int cz_update_sclk_limit(struct pp_hwmgr *hwmgr) unsigned long stable_pstate_sclk; unsigned long percentage; - cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk; - level = cz_get_max_sclk_level(hwmgr) - 1; + data->sclk_dpm.soft_min_clk = table->entries[0].clk; + level = smu8_get_max_sclk_level(hwmgr) - 1; if (level < table->count) - cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[level].clk; + data->sclk_dpm.soft_max_clk = table->entries[level].clk; else - cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[table->count - 1].clk; + data->sclk_dpm.soft_max_clk = table->entries[table->count - 1].clk; clock = hwmgr->display_config.min_core_set_clock; if (clock == 0) pr_debug("min_core_set_clock not set\n"); - if (cz_hwmgr->sclk_dpm.hard_min_clk != clock) { - cz_hwmgr->sclk_dpm.hard_min_clk = clock; + if (data->sclk_dpm.hard_min_clk != clock) { + data->sclk_dpm.hard_min_clk = clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkHardMin, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.hard_min_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.hard_min_clk, PPSMC_MSG_SetSclkHardMin)); } - clock = cz_hwmgr->sclk_dpm.soft_min_clk; + clock = data->sclk_dpm.soft_min_clk; /* update minimum clocks for Stable P-State feature */ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, @@ -723,36 +722,36 @@ static int cz_update_sclk_limit(struct pp_hwmgr *hwmgr) clock = stable_pstate_sclk; } - if (cz_hwmgr->sclk_dpm.soft_min_clk != clock) { - cz_hwmgr->sclk_dpm.soft_min_clk = clock; + if (data->sclk_dpm.soft_min_clk != clock) { + data->sclk_dpm.soft_min_clk = clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMin, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_min_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_min_clk, PPSMC_MSG_SetSclkSoftMin)); } if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState) && - cz_hwmgr->sclk_dpm.soft_max_clk != clock) { - cz_hwmgr->sclk_dpm.soft_max_clk = clock; + data->sclk_dpm.soft_max_clk != clock) { + data->sclk_dpm.soft_max_clk = clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMax, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_max_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_max_clk, PPSMC_MSG_SetSclkSoftMax)); } return 0; } -static int cz_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr) +static int smu8_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr) { if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) { uint32_t clks = hwmgr->display_config.min_core_set_clock_in_sr; if (clks == 0) - clks = CZ_MIN_DEEP_SLEEP_SCLK; + clks = SMU8_MIN_DEEP_SLEEP_SCLK; PP_DBG_LOG("Setting Deep Sleep Clock: %d\n", clks); @@ -764,21 +763,21 @@ static int cz_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr) return 0; } -static int cz_set_watermark_threshold(struct pp_hwmgr *hwmgr) +static int smu8_set_watermark_threshold(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = - (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = + hwmgr->backend; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWatermarkFrequency, - cz_hwmgr->sclk_dpm.soft_max_clk); + data->sclk_dpm.soft_max_clk); return 0; } -static int cz_nbdpm_pstate_enable_disable(struct pp_hwmgr *hwmgr, bool enable, bool lock) +static int smu8_nbdpm_pstate_enable_disable(struct pp_hwmgr *hwmgr, bool enable, bool lock) { - struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *hw_data = hwmgr->backend; if (hw_data->is_nb_dpm_enabled) { if (enable) { @@ -799,35 +798,35 @@ static int cz_nbdpm_pstate_enable_disable(struct pp_hwmgr *hwmgr, bool enable, b return 0; } -static int cz_disable_nb_dpm(struct pp_hwmgr *hwmgr) +static int smu8_disable_nb_dpm(struct pp_hwmgr *hwmgr) { int ret = 0; - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; unsigned long dpm_features = 0; - if (cz_hwmgr->is_nb_dpm_enabled) { - cz_nbdpm_pstate_enable_disable(hwmgr, true, true); + if (data->is_nb_dpm_enabled) { + smu8_nbdpm_pstate_enable_disable(hwmgr, true, true); dpm_features |= NB_DPM_MASK; ret = smum_send_msg_to_smc_with_parameter( hwmgr, PPSMC_MSG_DisableAllSmuFeatures, dpm_features); if (ret == 0) - cz_hwmgr->is_nb_dpm_enabled = false; + data->is_nb_dpm_enabled = false; } return ret; } -static int cz_enable_nb_dpm(struct pp_hwmgr *hwmgr) +static int smu8_enable_nb_dpm(struct pp_hwmgr *hwmgr) { int ret = 0; - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; unsigned long dpm_features = 0; - if (!cz_hwmgr->is_nb_dpm_enabled) { + if (!data->is_nb_dpm_enabled) { PP_DBG_LOG("enabling ALL SMU features.\n"); dpm_features |= NB_DPM_MASK; ret = smum_send_msg_to_smc_with_parameter( @@ -835,94 +834,94 @@ static int cz_enable_nb_dpm(struct pp_hwmgr *hwmgr) PPSMC_MSG_EnableAllSmuFeatures, dpm_features); if (ret == 0) - cz_hwmgr->is_nb_dpm_enabled = true; + data->is_nb_dpm_enabled = true; } return ret; } -static int cz_update_low_mem_pstate(struct pp_hwmgr *hwmgr, const void *input) +static int smu8_update_low_mem_pstate(struct pp_hwmgr *hwmgr, const void *input) { bool disable_switch; bool enable_low_mem_state; - struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *hw_data = hwmgr->backend; const struct phm_set_power_state_input *states = (struct phm_set_power_state_input *)input; - const struct cz_power_state *pnew_state = cast_const_PhwCzPowerState(states->pnew_state); + const struct smu8_power_state *pnew_state = cast_const_smu8_power_state(states->pnew_state); if (hw_data->sys_info.nb_dpm_enable) { disable_switch = hw_data->cc6_settings.nb_pstate_switch_disable ? true : false; enable_low_mem_state = hw_data->cc6_settings.nb_pstate_switch_disable ? false : true; if (pnew_state->action == FORCE_HIGH) - cz_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch); + smu8_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch); else if (pnew_state->action == CANCEL_FORCE_HIGH) - cz_nbdpm_pstate_enable_disable(hwmgr, true, disable_switch); + smu8_nbdpm_pstate_enable_disable(hwmgr, true, disable_switch); else - cz_nbdpm_pstate_enable_disable(hwmgr, enable_low_mem_state, disable_switch); + smu8_nbdpm_pstate_enable_disable(hwmgr, enable_low_mem_state, disable_switch); } return 0; } -static int cz_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) +static int smu8_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) { int ret = 0; - cz_update_sclk_limit(hwmgr); - cz_set_deep_sleep_sclk_threshold(hwmgr); - cz_set_watermark_threshold(hwmgr); - ret = cz_enable_nb_dpm(hwmgr); + smu8_update_sclk_limit(hwmgr); + smu8_set_deep_sleep_sclk_threshold(hwmgr); + smu8_set_watermark_threshold(hwmgr); + ret = smu8_enable_nb_dpm(hwmgr); if (ret) return ret; - cz_update_low_mem_pstate(hwmgr, input); + smu8_update_low_mem_pstate(hwmgr, input); return 0; }; -static int cz_setup_asic_task(struct pp_hwmgr *hwmgr) +static int smu8_setup_asic_task(struct pp_hwmgr *hwmgr) { int ret; - ret = cz_upload_pptable_to_smu(hwmgr); + ret = smu8_upload_pptable_to_smu(hwmgr); if (ret) return ret; - ret = cz_init_sclk_limit(hwmgr); + ret = smu8_init_sclk_limit(hwmgr); if (ret) return ret; - ret = cz_init_uvd_limit(hwmgr); + ret = smu8_init_uvd_limit(hwmgr); if (ret) return ret; - ret = cz_init_vce_limit(hwmgr); + ret = smu8_init_vce_limit(hwmgr); if (ret) return ret; - ret = cz_init_acp_limit(hwmgr); + ret = smu8_init_acp_limit(hwmgr); if (ret) return ret; - cz_init_power_gate_state(hwmgr); - cz_init_sclk_threshold(hwmgr); + smu8_init_power_gate_state(hwmgr); + smu8_init_sclk_threshold(hwmgr); return 0; } -static void cz_power_up_display_clock_sys_pll(struct pp_hwmgr *hwmgr) +static void smu8_power_up_display_clock_sys_pll(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *hw_data = hwmgr->backend; hw_data->disp_clk_bypass_pending = false; hw_data->disp_clk_bypass = false; } -static void cz_clear_nb_dpm_flag(struct pp_hwmgr *hwmgr) +static void smu8_clear_nb_dpm_flag(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *hw_data = hwmgr->backend; hw_data->is_nb_dpm_enabled = false; } -static void cz_reset_cc6_data(struct pp_hwmgr *hwmgr) +static void smu8_reset_cc6_data(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *hw_data = hwmgr->backend; hw_data->cc6_settings.cc6_setting_changed = false; hw_data->cc6_settings.cpu_pstate_separation_time = 0; @@ -930,45 +929,47 @@ static void cz_reset_cc6_data(struct pp_hwmgr *hwmgr) hw_data->cc6_settings.cpu_pstate_disable = false; } -static int cz_power_off_asic(struct pp_hwmgr *hwmgr) +static int smu8_power_off_asic(struct pp_hwmgr *hwmgr) { - cz_power_up_display_clock_sys_pll(hwmgr); - cz_clear_nb_dpm_flag(hwmgr); - cz_reset_cc6_data(hwmgr); + smu8_power_up_display_clock_sys_pll(hwmgr); + smu8_clear_nb_dpm_flag(hwmgr); + smu8_reset_cc6_data(hwmgr); return 0; }; -static void cz_program_voting_clients(struct pp_hwmgr *hwmgr) +static void smu8_program_voting_clients(struct pp_hwmgr *hwmgr) { - PHMCZ_WRITE_SMC_REGISTER(hwmgr->device, CG_FREQ_TRAN_VOTING_0, - PPCZ_VOTINGRIGHTSCLIENTS_DFLT0); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, + ixCG_FREQ_TRAN_VOTING_0, + SMU8_VOTINGRIGHTSCLIENTS_DFLT0); } -static void cz_clear_voting_clients(struct pp_hwmgr *hwmgr) +static void smu8_clear_voting_clients(struct pp_hwmgr *hwmgr) { - PHMCZ_WRITE_SMC_REGISTER(hwmgr->device, CG_FREQ_TRAN_VOTING_0, 0); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, + ixCG_FREQ_TRAN_VOTING_0, 0); } -static int cz_start_dpm(struct pp_hwmgr *hwmgr) +static int smu8_start_dpm(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - cz_hwmgr->dpm_flags |= DPMFlags_SCLK_Enabled; + data->dpm_flags |= DPMFlags_SCLK_Enabled; return smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnableAllSmuFeatures, SCLK_DPM_MASK); } -static int cz_stop_dpm(struct pp_hwmgr *hwmgr) +static int smu8_stop_dpm(struct pp_hwmgr *hwmgr) { int ret = 0; - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; unsigned long dpm_features = 0; - if (cz_hwmgr->dpm_flags & DPMFlags_SCLK_Enabled) { + if (data->dpm_flags & DPMFlags_SCLK_Enabled) { dpm_features |= SCLK_DPM_MASK; - cz_hwmgr->dpm_flags &= ~DPMFlags_SCLK_Enabled; + data->dpm_flags &= ~DPMFlags_SCLK_Enabled; ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DisableAllSmuFeatures, dpm_features); @@ -976,80 +977,80 @@ static int cz_stop_dpm(struct pp_hwmgr *hwmgr) return ret; } -static int cz_program_bootup_state(struct pp_hwmgr *hwmgr) +static int smu8_program_bootup_state(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - cz_hwmgr->sclk_dpm.soft_min_clk = cz_hwmgr->sys_info.bootup_engine_clock; - cz_hwmgr->sclk_dpm.soft_max_clk = cz_hwmgr->sys_info.bootup_engine_clock; + data->sclk_dpm.soft_min_clk = data->sys_info.bootup_engine_clock; + data->sclk_dpm.soft_max_clk = data->sys_info.bootup_engine_clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMin, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_min_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_min_clk, PPSMC_MSG_SetSclkSoftMin)); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMax, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_max_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_max_clk, PPSMC_MSG_SetSclkSoftMax)); return 0; } -static void cz_reset_acp_boot_level(struct pp_hwmgr *hwmgr) +static void smu8_reset_acp_boot_level(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - cz_hwmgr->acp_boot_level = 0xff; + data->acp_boot_level = 0xff; } -static int cz_disable_dpm_tasks(struct pp_hwmgr *hwmgr) +static int smu8_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { - cz_disable_nb_dpm(hwmgr); + smu8_disable_nb_dpm(hwmgr); - cz_clear_voting_clients(hwmgr); - if (cz_stop_dpm(hwmgr)) + smu8_clear_voting_clients(hwmgr); + if (smu8_stop_dpm(hwmgr)) return -EINVAL; return 0; }; -static int cz_enable_dpm_tasks(struct pp_hwmgr *hwmgr) +static int smu8_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { - cz_program_voting_clients(hwmgr); - if (cz_start_dpm(hwmgr)) + smu8_program_voting_clients(hwmgr); + if (smu8_start_dpm(hwmgr)) return -EINVAL; - cz_program_bootup_state(hwmgr); - cz_reset_acp_boot_level(hwmgr); + smu8_program_bootup_state(hwmgr); + smu8_reset_acp_boot_level(hwmgr); return 0; }; -static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, +static int smu8_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, struct pp_power_state *prequest_ps, const struct pp_power_state *pcurrent_ps) { - struct cz_power_state *cz_ps = - cast_PhwCzPowerState(&prequest_ps->hardware); + struct smu8_power_state *smu8_ps = + cast_smu8_power_state(&prequest_ps->hardware); - const struct cz_power_state *cz_current_ps = - cast_const_PhwCzPowerState(&pcurrent_ps->hardware); + const struct smu8_power_state *smu8_current_ps = + cast_const_smu8_power_state(&pcurrent_ps->hardware); - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct PP_Clocks clocks = {0, 0, 0, 0}; bool force_high; uint32_t num_of_active_displays = 0; struct cgs_display_info info = {0}; - cz_ps->need_dfs_bypass = true; + smu8_ps->need_dfs_bypass = true; - cz_hwmgr->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label); + data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label); clocks.memoryClock = hwmgr->display_config.min_mem_set_clock != 0 ? hwmgr->display_config.min_mem_set_clock : - cz_hwmgr->sys_info.nbp_memory_clock[1]; + data->sys_info.nbp_memory_clock[1]; cgs_get_active_displays_info(hwmgr->device, &info); num_of_active_displays = info.display_count; @@ -1057,56 +1058,56 @@ static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) clocks.memoryClock = hwmgr->dyn_state.max_clock_voltage_on_ac.mclk; - force_high = (clocks.memoryClock > cz_hwmgr->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK - 1]) + force_high = (clocks.memoryClock > data->sys_info.nbp_memory_clock[SMU8_NUM_NBPMEMORYCLOCK - 1]) || (num_of_active_displays >= 3); - cz_ps->action = cz_current_ps->action; + smu8_ps->action = smu8_current_ps->action; if (hwmgr->request_dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) - cz_nbdpm_pstate_enable_disable(hwmgr, false, false); + smu8_nbdpm_pstate_enable_disable(hwmgr, false, false); else if (hwmgr->request_dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD) - cz_nbdpm_pstate_enable_disable(hwmgr, false, true); - else if (!force_high && (cz_ps->action == FORCE_HIGH)) - cz_ps->action = CANCEL_FORCE_HIGH; - else if (force_high && (cz_ps->action != FORCE_HIGH)) - cz_ps->action = FORCE_HIGH; + smu8_nbdpm_pstate_enable_disable(hwmgr, false, true); + else if (!force_high && (smu8_ps->action == FORCE_HIGH)) + smu8_ps->action = CANCEL_FORCE_HIGH; + else if (force_high && (smu8_ps->action != FORCE_HIGH)) + smu8_ps->action = FORCE_HIGH; else - cz_ps->action = DO_NOTHING; + smu8_ps->action = DO_NOTHING; return 0; } -static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr) +static int smu8_hwmgr_backend_init(struct pp_hwmgr *hwmgr) { int result = 0; - struct cz_hwmgr *data; + struct smu8_hwmgr *data; - data = kzalloc(sizeof(struct cz_hwmgr), GFP_KERNEL); + data = kzalloc(sizeof(struct smu8_hwmgr), GFP_KERNEL); if (data == NULL) return -ENOMEM; hwmgr->backend = data; - result = cz_initialize_dpm_defaults(hwmgr); + result = smu8_initialize_dpm_defaults(hwmgr); if (result != 0) { - pr_err("cz_initialize_dpm_defaults failed\n"); + pr_err("smu8_initialize_dpm_defaults failed\n"); return result; } - result = cz_get_system_info_data(hwmgr); + result = smu8_get_system_info_data(hwmgr); if (result != 0) { - pr_err("cz_get_system_info_data failed\n"); + pr_err("smu8_get_system_info_data failed\n"); return result; } - cz_construct_boot_state(hwmgr); + smu8_construct_boot_state(hwmgr); - hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = CZ_MAX_HARDWARE_POWERLEVELS; + hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = SMU8_MAX_HARDWARE_POWERLEVELS; return result; } -static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) +static int smu8_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) { if (hwmgr != NULL) { kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); @@ -1118,28 +1119,28 @@ static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) return 0; } -static int cz_phm_force_dpm_highest(struct pp_hwmgr *hwmgr) +static int smu8_phm_force_dpm_highest(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMin, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_max_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_max_clk, PPSMC_MSG_SetSclkSoftMin)); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMax, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_max_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_max_clk, PPSMC_MSG_SetSclkSoftMax)); return 0; } -static int cz_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr) +static int smu8_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_clock_voltage_dependency_table *table = hwmgr->dyn_state.vddc_dependency_on_sclk; unsigned long clock = 0, level; @@ -1147,56 +1148,56 @@ static int cz_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr) if (NULL == table || table->count <= 0) return -EINVAL; - cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk; - cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk; + data->sclk_dpm.soft_min_clk = table->entries[0].clk; + data->sclk_dpm.hard_min_clk = table->entries[0].clk; hwmgr->pstate_sclk = table->entries[0].clk; hwmgr->pstate_mclk = 0; - level = cz_get_max_sclk_level(hwmgr) - 1; + level = smu8_get_max_sclk_level(hwmgr) - 1; if (level < table->count) clock = table->entries[level].clk; else clock = table->entries[table->count - 1].clk; - cz_hwmgr->sclk_dpm.soft_max_clk = clock; - cz_hwmgr->sclk_dpm.hard_max_clk = clock; + data->sclk_dpm.soft_max_clk = clock; + data->sclk_dpm.hard_max_clk = clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMin, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_min_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_min_clk, PPSMC_MSG_SetSclkSoftMin)); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMax, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_max_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_max_clk, PPSMC_MSG_SetSclkSoftMax)); return 0; } -static int cz_phm_force_dpm_lowest(struct pp_hwmgr *hwmgr) +static int smu8_phm_force_dpm_lowest(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMax, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_min_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_min_clk, PPSMC_MSG_SetSclkSoftMax)); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSclkSoftMin, - cz_get_sclk_level(hwmgr, - cz_hwmgr->sclk_dpm.soft_min_clk, + smu8_get_sclk_level(hwmgr, + data->sclk_dpm.soft_min_clk, PPSMC_MSG_SetSclkSoftMin)); return 0; } -static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, +static int smu8_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level) { int ret = 0; @@ -1204,15 +1205,15 @@ static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: - ret = cz_phm_force_dpm_highest(hwmgr); + ret = smu8_phm_force_dpm_highest(hwmgr); break; case AMD_DPM_FORCED_LEVEL_LOW: case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: - ret = cz_phm_force_dpm_lowest(hwmgr); + ret = smu8_phm_force_dpm_lowest(hwmgr); break; case AMD_DPM_FORCED_LEVEL_AUTO: - ret = cz_phm_unforce_dpm_levels(hwmgr); + ret = smu8_phm_unforce_dpm_levels(hwmgr); break; case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: @@ -1223,14 +1224,14 @@ static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, return ret; } -int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr) +static int smu8_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr) { if (PP_CAP(PHM_PlatformCaps_UVDPowerGating)) return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_UVDPowerOFF); return 0; } -int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr) +static int smu8_dpm_powerup_uvd(struct pp_hwmgr *hwmgr) { if (PP_CAP(PHM_PlatformCaps_UVDPowerGating)) { return smum_send_msg_to_smc_with_parameter( @@ -1242,52 +1243,22 @@ int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr) return 0; } -int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate) +static int smu8_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - struct phm_uvd_clock_voltage_dependency_table *ptable = - hwmgr->dyn_state.uvd_clock_voltage_dependency_table; - - if (!bgate) { - /* Stable Pstate is enabled and we need to set the UVD DPM to highest level */ - if (PP_CAP(PHM_PlatformCaps_StablePState) || - hwmgr->en_umd_pstate) { - cz_hwmgr->uvd_dpm.hard_min_clk = - ptable->entries[ptable->count - 1].vclk; - - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetUvdHardMin, - cz_get_uvd_level(hwmgr, - cz_hwmgr->uvd_dpm.hard_min_clk, - PPSMC_MSG_SetUvdHardMin)); - - cz_enable_disable_uvd_dpm(hwmgr, true); - } else { - cz_enable_disable_uvd_dpm(hwmgr, true); - } - } else { - cz_enable_disable_uvd_dpm(hwmgr, false); - } - - return 0; -} - -int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr) -{ - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_vce_clock_voltage_dependency_table *ptable = hwmgr->dyn_state.vce_clock_voltage_dependency_table; /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */ if (PP_CAP(PHM_PlatformCaps_StablePState) || hwmgr->en_umd_pstate) { - cz_hwmgr->vce_dpm.hard_min_clk = + data->vce_dpm.hard_min_clk = ptable->entries[ptable->count - 1].ecclk; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetEclkHardMin, - cz_get_eclk_level(hwmgr, - cz_hwmgr->vce_dpm.hard_min_clk, + smu8_get_eclk_level(hwmgr, + data->vce_dpm.hard_min_clk, PPSMC_MSG_SetEclkHardMin)); } else { @@ -1301,7 +1272,7 @@ int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr) return 0; } -int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr) +static int smu8_dpm_powerdown_vce(struct pp_hwmgr *hwmgr) { if (PP_CAP(PHM_PlatformCaps_VCEPowerGating)) return smum_send_msg_to_smc(hwmgr, @@ -1309,7 +1280,7 @@ int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr) return 0; } -int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr) +static int smu8_dpm_powerup_vce(struct pp_hwmgr *hwmgr) { if (PP_CAP(PHM_PlatformCaps_VCEPowerGating)) return smum_send_msg_to_smc(hwmgr, @@ -1317,17 +1288,17 @@ int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr) return 0; } -static uint32_t cz_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) +static uint32_t smu8_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; - return cz_hwmgr->sys_info.bootup_uma_clock; + return data->sys_info.bootup_uma_clock; } -static uint32_t cz_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) +static uint32_t smu8_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) { struct pp_power_state *ps; - struct cz_power_state *cz_ps; + struct smu8_power_state *smu8_ps; if (hwmgr == NULL) return -EINVAL; @@ -1337,59 +1308,59 @@ static uint32_t cz_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) if (ps == NULL) return -EINVAL; - cz_ps = cast_PhwCzPowerState(&ps->hardware); + smu8_ps = cast_smu8_power_state(&ps->hardware); if (low) - return cz_ps->levels[0].engineClock; + return smu8_ps->levels[0].engineClock; else - return cz_ps->levels[cz_ps->level-1].engineClock; + return smu8_ps->levels[smu8_ps->level-1].engineClock; } -static int cz_dpm_patch_boot_state(struct pp_hwmgr *hwmgr, +static int smu8_dpm_patch_boot_state(struct pp_hwmgr *hwmgr, struct pp_hw_power_state *hw_ps) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps); + struct smu8_hwmgr *data = hwmgr->backend; + struct smu8_power_state *smu8_ps = cast_smu8_power_state(hw_ps); - cz_ps->level = 1; - cz_ps->nbps_flags = 0; - cz_ps->bapm_flags = 0; - cz_ps->levels[0] = cz_hwmgr->boot_power_level; + smu8_ps->level = 1; + smu8_ps->nbps_flags = 0; + smu8_ps->bapm_flags = 0; + smu8_ps->levels[0] = data->boot_power_level; return 0; } -static int cz_dpm_get_pp_table_entry_callback( +static int smu8_dpm_get_pp_table_entry_callback( struct pp_hwmgr *hwmgr, struct pp_hw_power_state *hw_ps, unsigned int index, const void *clock_info) { - struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps); + struct smu8_power_state *smu8_ps = cast_smu8_power_state(hw_ps); - const ATOM_PPLIB_CZ_CLOCK_INFO *cz_clock_info = clock_info; + const ATOM_PPLIB_CZ_CLOCK_INFO *smu8_clock_info = clock_info; struct phm_clock_voltage_dependency_table *table = hwmgr->dyn_state.vddc_dependency_on_sclk; - uint8_t clock_info_index = cz_clock_info->index; + uint8_t clock_info_index = smu8_clock_info->index; if (clock_info_index > (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1)) clock_info_index = (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1); - cz_ps->levels[index].engineClock = table->entries[clock_info_index].clk; - cz_ps->levels[index].vddcIndex = (uint8_t)table->entries[clock_info_index].v; + smu8_ps->levels[index].engineClock = table->entries[clock_info_index].clk; + smu8_ps->levels[index].vddcIndex = (uint8_t)table->entries[clock_info_index].v; - cz_ps->level = index + 1; + smu8_ps->level = index + 1; if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) { - cz_ps->levels[index].dsDividerIndex = 5; - cz_ps->levels[index].ssDividerIndex = 5; + smu8_ps->levels[index].dsDividerIndex = 5; + smu8_ps->levels[index].ssDividerIndex = 5; } return 0; } -static int cz_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) +static int smu8_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) { int result; unsigned long ret = 0; @@ -1399,31 +1370,31 @@ static int cz_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) return result ? 0 : ret; } -static int cz_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr, +static int smu8_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr, unsigned long entry, struct pp_power_state *ps) { int result; - struct cz_power_state *cz_ps; + struct smu8_power_state *smu8_ps; - ps->hardware.magic = PhwCz_Magic; + ps->hardware.magic = smu8_magic; - cz_ps = cast_PhwCzPowerState(&(ps->hardware)); + smu8_ps = cast_smu8_power_state(&(ps->hardware)); result = pp_tables_get_entry(hwmgr, entry, ps, - cz_dpm_get_pp_table_entry_callback); + smu8_dpm_get_pp_table_entry_callback); - cz_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK; - cz_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK; + smu8_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK; + smu8_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK; return result; } -static int cz_get_power_state_size(struct pp_hwmgr *hwmgr) +static int smu8_get_power_state_size(struct pp_hwmgr *hwmgr) { - return sizeof(struct cz_power_state); + return sizeof(struct smu8_power_state); } -static void cz_hw_print_display_cfg( +static void smu8_hw_print_display_cfg( const struct cc6_settings *cc6_settings) { PP_DBG_LOG("New Display Configuration:\n"); @@ -1438,16 +1409,16 @@ static void cz_hw_print_display_cfg( cc6_settings->cpu_pstate_separation_time); } - static int cz_set_cpu_power_state(struct pp_hwmgr *hwmgr) + static int smu8_set_cpu_power_state(struct pp_hwmgr *hwmgr) { - struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *hw_data = hwmgr->backend; uint32_t data = 0; if (hw_data->cc6_settings.cc6_setting_changed) { hw_data->cc6_settings.cc6_setting_changed = false; - cz_hw_print_display_cfg(&hw_data->cc6_settings); + smu8_hw_print_display_cfg(&hw_data->cc6_settings); data |= (hw_data->cc6_settings.cpu_pstate_separation_time & PWRMGT_SEPARATION_TIME_MASK) @@ -1471,10 +1442,10 @@ static void cz_hw_print_display_cfg( } -static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, +static int smu8_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, bool cc6_disable, bool pstate_disable, bool pstate_switch_disable) { - struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *hw_data = hwmgr->backend; if (separation_time != hw_data->cc6_settings.cpu_pstate_separation_time || @@ -1498,7 +1469,7 @@ static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, return 0; } -static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr, +static int smu8_get_dal_power_level(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *info) { uint32_t i; @@ -1519,7 +1490,7 @@ static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr, return -EINVAL; } -static int cz_force_clock_level(struct pp_hwmgr *hwmgr, +static int smu8_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { switch (type) { @@ -1538,10 +1509,10 @@ static int cz_force_clock_level(struct pp_hwmgr *hwmgr, return 0; } -static int cz_print_clock_levels(struct pp_hwmgr *hwmgr, +static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf) { - struct cz_hwmgr *data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_clock_voltage_dependency_table *sclk_table = hwmgr->dyn_state.vddc_dependency_on_sclk; int i, now, size = 0; @@ -1566,10 +1537,10 @@ static int cz_print_clock_levels(struct pp_hwmgr *hwmgr, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX); - for (i = CZ_NUM_NBPMEMORYCLOCK; i > 0; i--) + for (i = SMU8_NUM_NBPMEMORYCLOCK; i > 0; i--) size += sprintf(buf + size, "%d: %uMhz %s\n", - CZ_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100, - (CZ_NUM_NBPMEMORYCLOCK-i == now) ? "*" : ""); + SMU8_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100, + (SMU8_NUM_NBPMEMORYCLOCK-i == now) ? "*" : ""); break; default: break; @@ -1577,20 +1548,20 @@ static int cz_print_clock_levels(struct pp_hwmgr *hwmgr, return size; } -static int cz_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, +static int smu8_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, PHM_PerformanceLevelDesignation designation, uint32_t index, PHM_PerformanceLevel *level) { - const struct cz_power_state *ps; - struct cz_hwmgr *data; + const struct smu8_power_state *ps; + struct smu8_hwmgr *data; uint32_t level_index; uint32_t i; if (level == NULL || hwmgr == NULL || state == NULL) return -EINVAL; - data = (struct cz_hwmgr *)(hwmgr->backend); - ps = cast_const_PhwCzPowerState(state); + data = hwmgr->backend; + ps = cast_const_smu8_power_state(state); level_index = index > ps->level - 1 ? ps->level - 1 : index; level->coreClock = ps->levels[level_index].engineClock; @@ -1605,21 +1576,21 @@ static int cz_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_p } if (level_index == 0) - level->memory_clock = data->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK - 1]; + level->memory_clock = data->sys_info.nbp_memory_clock[SMU8_NUM_NBPMEMORYCLOCK - 1]; else level->memory_clock = data->sys_info.nbp_memory_clock[0]; - level->vddc = (cz_convert_8Bit_index_to_voltage(hwmgr, ps->levels[level_index].vddcIndex) + 2) / 4; + level->vddc = (smu8_convert_8Bit_index_to_voltage(hwmgr, ps->levels[level_index].vddcIndex) + 2) / 4; level->nonLocalMemoryFreq = 0; level->nonLocalMemoryWidth = 0; return 0; } -static int cz_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, +static int smu8_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *clock_info) { - const struct cz_power_state *ps = cast_const_PhwCzPowerState(state); + const struct smu8_power_state *ps = cast_const_smu8_power_state(state); clock_info->min_eng_clk = ps->levels[0].engineClock / (1 << (ps->levels[0].ssDividerIndex)); clock_info->max_eng_clk = ps->levels[ps->level - 1].engineClock / (1 << (ps->levels[ps->level - 1].ssDividerIndex)); @@ -1627,14 +1598,14 @@ static int cz_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, return 0; } -static int cz_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, +static int smu8_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks) { - struct cz_hwmgr *data = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; int i; struct phm_clock_voltage_dependency_table *table; - clocks->count = cz_get_max_sclk_level(hwmgr); + clocks->count = smu8_get_max_sclk_level(hwmgr); switch (type) { case amd_pp_disp_clock: for (i = 0; i < clocks->count; i++) @@ -1646,7 +1617,7 @@ static int cz_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type t clocks->clock[i] = table->entries[i].clk; break; case amd_pp_mem_clock: - clocks->count = CZ_NUM_NBPMEMORYCLOCK; + clocks->count = SMU8_NUM_NBPMEMORYCLOCK; for (i = 0; i < clocks->count; i++) clocks->clock[i] = data->sys_info.nbp_memory_clock[clocks->count - 1 - i]; break; @@ -1657,7 +1628,7 @@ static int cz_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type t return 0; } -static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) +static int smu8_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) { struct phm_clock_voltage_dependency_table *table = hwmgr->dyn_state.vddc_dependency_on_sclk; @@ -1668,7 +1639,7 @@ static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_c if ((NULL == table) || (table->count <= 0) || (clocks == NULL)) return -EINVAL; - level = cz_get_max_sclk_level(hwmgr) - 1; + level = smu8_get_max_sclk_level(hwmgr) - 1; if (level < table->count) clocks->engine_max_clock = table->entries[level].clk; @@ -1680,7 +1651,7 @@ static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_c return 0; } -static int cz_thermal_get_temperature(struct pp_hwmgr *hwmgr) +static int smu8_thermal_get_temperature(struct pp_hwmgr *hwmgr) { int actual_temp = 0; uint32_t val = cgs_read_ind_register(hwmgr->device, @@ -1695,10 +1666,10 @@ static int cz_thermal_get_temperature(struct pp_hwmgr *hwmgr) return actual_temp; } -static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, +static int smu8_read_sensor(struct pp_hwmgr *hwmgr, int idx, void *value, int *size) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; struct phm_clock_voltage_dependency_table *table = hwmgr->dyn_state.vddc_dependency_on_sclk; @@ -1736,18 +1707,18 @@ static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, case AMDGPU_PP_SENSOR_VDDNB: tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) & CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT; - vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp); + vddnb = smu8_convert_8Bit_index_to_voltage(hwmgr, tmp); *((uint32_t *)value) = vddnb; return 0; case AMDGPU_PP_SENSOR_VDDGFX: tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) & CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT; - vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp); + vddgfx = smu8_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp); *((uint32_t *)value) = vddgfx; return 0; case AMDGPU_PP_SENSOR_UVD_VCLK: - if (!cz_hwmgr->uvd_power_gated) { - if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) { + if (!data->uvd_power_gated) { + if (uvd_index >= SMU8_MAX_HARDWARE_POWERLEVELS) { return -EINVAL; } else { vclk = uvd_table->entries[uvd_index].vclk; @@ -1758,8 +1729,8 @@ static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = 0; return 0; case AMDGPU_PP_SENSOR_UVD_DCLK: - if (!cz_hwmgr->uvd_power_gated) { - if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) { + if (!data->uvd_power_gated) { + if (uvd_index >= SMU8_MAX_HARDWARE_POWERLEVELS) { return -EINVAL; } else { dclk = uvd_table->entries[uvd_index].dclk; @@ -1770,8 +1741,8 @@ static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = 0; return 0; case AMDGPU_PP_SENSOR_VCE_ECCLK: - if (!cz_hwmgr->vce_power_gated) { - if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) { + if (!data->vce_power_gated) { + if (vce_index >= SMU8_MAX_HARDWARE_POWERLEVELS) { return -EINVAL; } else { ecclk = vce_table->entries[vce_index].ecclk; @@ -1792,20 +1763,20 @@ static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = activity_percent; return 0; case AMDGPU_PP_SENSOR_UVD_POWER: - *((uint32_t *)value) = cz_hwmgr->uvd_power_gated ? 0 : 1; + *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1; return 0; case AMDGPU_PP_SENSOR_VCE_POWER: - *((uint32_t *)value) = cz_hwmgr->vce_power_gated ? 0 : 1; + *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; return 0; case AMDGPU_PP_SENSOR_GPU_TEMP: - *((uint32_t *)value) = cz_thermal_get_temperature(hwmgr); + *((uint32_t *)value) = smu8_thermal_get_temperature(hwmgr); return 0; default: return -EINVAL; } } -static int cz_notify_cac_buffer_info(struct pp_hwmgr *hwmgr, +static int smu8_notify_cac_buffer_info(struct pp_hwmgr *hwmgr, uint32_t virtual_addr_low, uint32_t virtual_addr_hi, uint32_t mc_addr_low, @@ -1831,56 +1802,190 @@ static int cz_notify_cac_buffer_info(struct pp_hwmgr *hwmgr, return 0; } -static int cz_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, +static int smu8_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *thermal_data) { - struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + struct smu8_hwmgr *data = hwmgr->backend; memcpy(thermal_data, &SMU7ThermalPolicy[0], sizeof(struct PP_TemperatureRange)); - thermal_data->max = (cz_hwmgr->thermal_auto_throttling_treshold + - cz_hwmgr->sys_info.htc_hyst_lmt) * + thermal_data->max = (data->thermal_auto_throttling_treshold + + data->sys_info.htc_hyst_lmt) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; return 0; } -static const struct pp_hwmgr_func cz_hwmgr_funcs = { - .backend_init = cz_hwmgr_backend_init, - .backend_fini = cz_hwmgr_backend_fini, - .apply_state_adjust_rules = cz_apply_state_adjust_rules, - .force_dpm_level = cz_dpm_force_dpm_level, - .get_power_state_size = cz_get_power_state_size, - .powerdown_uvd = cz_dpm_powerdown_uvd, - .powergate_uvd = cz_dpm_powergate_uvd, - .powergate_vce = cz_dpm_powergate_vce, - .get_mclk = cz_dpm_get_mclk, - .get_sclk = cz_dpm_get_sclk, - .patch_boot_state = cz_dpm_patch_boot_state, - .get_pp_table_entry = cz_dpm_get_pp_table_entry, - .get_num_of_pp_table_entries = cz_dpm_get_num_of_pp_table_entries, - .set_cpu_power_state = cz_set_cpu_power_state, - .store_cc6_data = cz_store_cc6_data, - .force_clock_level = cz_force_clock_level, - .print_clock_levels = cz_print_clock_levels, - .get_dal_power_level = cz_get_dal_power_level, - .get_performance_level = cz_get_performance_level, - .get_current_shallow_sleep_clocks = cz_get_current_shallow_sleep_clocks, - .get_clock_by_type = cz_get_clock_by_type, - .get_max_high_clocks = cz_get_max_high_clocks, - .read_sensor = cz_read_sensor, - .power_off_asic = cz_power_off_asic, - .asic_setup = cz_setup_asic_task, - .dynamic_state_management_enable = cz_enable_dpm_tasks, - .power_state_set = cz_set_power_state_tasks, - .dynamic_state_management_disable = cz_disable_dpm_tasks, - .notify_cac_buffer_info = cz_notify_cac_buffer_info, - .get_thermal_temperature_range = cz_get_thermal_temperature_range, +static int smu8_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) +{ + struct smu8_hwmgr *data = hwmgr->backend; + uint32_t dpm_features = 0; + + if (enable && + phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_UVDDPM)) { + data->dpm_flags |= DPMFlags_UVD_Enabled; + dpm_features |= UVD_DPM_MASK; + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_EnableAllSmuFeatures, dpm_features); + } else { + dpm_features |= UVD_DPM_MASK; + data->dpm_flags &= ~DPMFlags_UVD_Enabled; + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DisableAllSmuFeatures, dpm_features); + } + return 0; +} + +int smu8_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate) +{ + struct smu8_hwmgr *data = hwmgr->backend; + struct phm_uvd_clock_voltage_dependency_table *ptable = + hwmgr->dyn_state.uvd_clock_voltage_dependency_table; + + if (!bgate) { + /* Stable Pstate is enabled and we need to set the UVD DPM to highest level */ + if (PP_CAP(PHM_PlatformCaps_StablePState) || + hwmgr->en_umd_pstate) { + data->uvd_dpm.hard_min_clk = + ptable->entries[ptable->count - 1].vclk; + + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetUvdHardMin, + smu8_get_uvd_level(hwmgr, + data->uvd_dpm.hard_min_clk, + PPSMC_MSG_SetUvdHardMin)); + + smu8_enable_disable_uvd_dpm(hwmgr, true); + } else { + smu8_enable_disable_uvd_dpm(hwmgr, true); + } + } else { + smu8_enable_disable_uvd_dpm(hwmgr, false); + } + + return 0; +} + +static int smu8_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) +{ + struct smu8_hwmgr *data = hwmgr->backend; + uint32_t dpm_features = 0; + + if (enable && phm_cap_enabled( + hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_VCEDPM)) { + data->dpm_flags |= DPMFlags_VCE_Enabled; + dpm_features |= VCE_DPM_MASK; + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_EnableAllSmuFeatures, dpm_features); + } else { + dpm_features |= VCE_DPM_MASK; + data->dpm_flags &= ~DPMFlags_VCE_Enabled; + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DisableAllSmuFeatures, dpm_features); + } + + return 0; +} + + +static void smu8_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate) +{ + struct smu8_hwmgr *data = hwmgr->backend; + + data->uvd_power_gated = bgate; + + if (bgate) { + cgs_set_powergating_state(hwmgr->device, + AMD_IP_BLOCK_TYPE_UVD, + AMD_PG_STATE_GATE); + cgs_set_clockgating_state(hwmgr->device, + AMD_IP_BLOCK_TYPE_UVD, + AMD_CG_STATE_GATE); + smu8_dpm_update_uvd_dpm(hwmgr, true); + smu8_dpm_powerdown_uvd(hwmgr); + } else { + smu8_dpm_powerup_uvd(hwmgr); + cgs_set_clockgating_state(hwmgr->device, + AMD_IP_BLOCK_TYPE_UVD, + AMD_CG_STATE_UNGATE); + cgs_set_powergating_state(hwmgr->device, + AMD_IP_BLOCK_TYPE_UVD, + AMD_PG_STATE_UNGATE); + smu8_dpm_update_uvd_dpm(hwmgr, false); + } + +} + +static void smu8_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) +{ + struct smu8_hwmgr *data = hwmgr->backend; + + if (bgate) { + cgs_set_powergating_state( + hwmgr->device, + AMD_IP_BLOCK_TYPE_VCE, + AMD_PG_STATE_GATE); + cgs_set_clockgating_state( + hwmgr->device, + AMD_IP_BLOCK_TYPE_VCE, + AMD_CG_STATE_GATE); + smu8_enable_disable_vce_dpm(hwmgr, false); + smu8_dpm_powerdown_vce(hwmgr); + data->vce_power_gated = true; + } else { + smu8_dpm_powerup_vce(hwmgr); + data->vce_power_gated = false; + cgs_set_clockgating_state( + hwmgr->device, + AMD_IP_BLOCK_TYPE_VCE, + AMD_CG_STATE_UNGATE); + cgs_set_powergating_state( + hwmgr->device, + AMD_IP_BLOCK_TYPE_VCE, + AMD_PG_STATE_UNGATE); + smu8_dpm_update_vce_dpm(hwmgr); + smu8_enable_disable_vce_dpm(hwmgr, true); + } +} + +static const struct pp_hwmgr_func smu8_hwmgr_funcs = { + .backend_init = smu8_hwmgr_backend_init, + .backend_fini = smu8_hwmgr_backend_fini, + .apply_state_adjust_rules = smu8_apply_state_adjust_rules, + .force_dpm_level = smu8_dpm_force_dpm_level, + .get_power_state_size = smu8_get_power_state_size, + .powerdown_uvd = smu8_dpm_powerdown_uvd, + .powergate_uvd = smu8_dpm_powergate_uvd, + .powergate_vce = smu8_dpm_powergate_vce, + .get_mclk = smu8_dpm_get_mclk, + .get_sclk = smu8_dpm_get_sclk, + .patch_boot_state = smu8_dpm_patch_boot_state, + .get_pp_table_entry = smu8_dpm_get_pp_table_entry, + .get_num_of_pp_table_entries = smu8_dpm_get_num_of_pp_table_entries, + .set_cpu_power_state = smu8_set_cpu_power_state, + .store_cc6_data = smu8_store_cc6_data, + .force_clock_level = smu8_force_clock_level, + .print_clock_levels = smu8_print_clock_levels, + .get_dal_power_level = smu8_get_dal_power_level, + .get_performance_level = smu8_get_performance_level, + .get_current_shallow_sleep_clocks = smu8_get_current_shallow_sleep_clocks, + .get_clock_by_type = smu8_get_clock_by_type, + .get_max_high_clocks = smu8_get_max_high_clocks, + .read_sensor = smu8_read_sensor, + .power_off_asic = smu8_power_off_asic, + .asic_setup = smu8_setup_asic_task, + .dynamic_state_management_enable = smu8_enable_dpm_tasks, + .power_state_set = smu8_set_power_state_tasks, + .dynamic_state_management_disable = smu8_disable_dpm_tasks, + .notify_cac_buffer_info = smu8_notify_cac_buffer_info, + .get_thermal_temperature_range = smu8_get_thermal_temperature_range, }; -int cz_init_function_pointers(struct pp_hwmgr *hwmgr) +int smu8_init_function_pointers(struct pp_hwmgr *hwmgr) { - hwmgr->hwmgr_func = &cz_hwmgr_funcs; + hwmgr->hwmgr_func = &smu8_hwmgr_funcs; hwmgr->pptable_func = &pptable_funcs; return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.h index b56720a3fc88..05a06083e1b8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.h @@ -21,18 +21,18 @@ * */ -#ifndef _CZ_HWMGR_H_ -#define _CZ_HWMGR_H_ +#ifndef _SMU8_HWMGR_H_ +#define _SMU8_HWMGR_H_ #include "cgs_common.h" #include "ppatomctrl.h" -#define CZ_NUM_NBPSTATES 4 -#define CZ_NUM_NBPMEMORYCLOCK 2 +#define SMU8_NUM_NBPSTATES 4 +#define SMU8_NUM_NBPMEMORYCLOCK 2 #define MAX_DISPLAY_CLOCK_LEVEL 8 -#define CZ_MAX_HARDWARE_POWERLEVELS 8 -#define PPCZ_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 -#define CZ_MIN_DEEP_SLEEP_SCLK 800 +#define SMU8_MAX_HARDWARE_POWERLEVELS 8 +#define SMU8_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 +#define SMU8_MIN_DEEP_SLEEP_SCLK 800 /* Carrizo device IDs */ #define DEVICE_ID_CZ_9870 0x9870 @@ -41,24 +41,21 @@ #define DEVICE_ID_CZ_9876 0x9876 #define DEVICE_ID_CZ_9877 0x9877 -#define PHMCZ_WRITE_SMC_REGISTER(device, reg, value) \ - cgs_write_ind_register(device, CGS_IND_REG__SMC, ix##reg, value) - -struct cz_dpm_entry { +struct smu8_dpm_entry { uint32_t soft_min_clk; uint32_t hard_min_clk; uint32_t soft_max_clk; uint32_t hard_max_clk; }; -struct cz_sys_info { +struct smu8_sys_info { uint32_t bootup_uma_clock; uint32_t bootup_engine_clock; uint32_t dentist_vco_freq; uint32_t nb_dpm_enable; - uint32_t nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK]; - uint32_t nbp_n_clock[CZ_NUM_NBPSTATES]; - uint16_t nbp_voltage_index[CZ_NUM_NBPSTATES]; + uint32_t nbp_memory_clock[SMU8_NUM_NBPMEMORYCLOCK]; + uint32_t nbp_n_clock[SMU8_NUM_NBPSTATES]; + uint16_t nbp_voltage_index[SMU8_NUM_NBPSTATES]; uint32_t display_clock[MAX_DISPLAY_CLOCK_LEVEL]; uint16_t bootup_nb_voltage_index; uint8_t htc_tmp_lmt; @@ -85,21 +82,21 @@ struct cz_sys_info { ((tx) ? DISPLAYPHY_TX_SELECT : 0) | \ ((core) ? DISPLAYPHY_CORE_SELECT : 0)) -struct cz_display_phy_info_entry { +struct smu8_display_phy_info_entry { uint8_t phy_present; uint8_t active_lane_mapping; uint8_t display_config_type; uint8_t active_number_of_lanes; }; -#define CZ_MAX_DISPLAYPHY_IDS 10 +#define SMU8_MAX_DISPLAYPHY_IDS 10 -struct cz_display_phy_info { +struct smu8_display_phy_info { bool display_phy_access_initialized; - struct cz_display_phy_info_entry entries[CZ_MAX_DISPLAYPHY_IDS]; + struct smu8_display_phy_info_entry entries[SMU8_MAX_DISPLAYPHY_IDS]; }; -struct cz_power_level { +struct smu8_power_level { uint32_t engineClock; uint8_t vddcIndex; uint8_t dsDividerIndex; @@ -113,7 +110,7 @@ struct cz_power_level { uint8_t rsv[3]; }; -struct cz_uvd_clocks { +struct smu8_uvd_clocks { uint32_t vclk; uint32_t dclk; uint32_t vclk_low_divider; @@ -122,7 +119,7 @@ struct cz_uvd_clocks { uint32_t dclk_high_divider; }; -enum cz_pstate_previous_action { +enum smu8_pstate_previous_action { DO_NOTHING = 1, FORCE_HIGH, CANCEL_FORCE_HIGH @@ -143,10 +140,10 @@ struct pp_disable_nb_ps_flags { }; }; -struct cz_power_state { +struct smu8_power_state { unsigned int magic; uint32_t level; - struct cz_uvd_clocks uvd_clocks; + struct smu8_uvd_clocks uvd_clocks; uint32_t evclk; uint32_t ecclk; uint32_t samclk; @@ -158,8 +155,8 @@ struct cz_power_state { uint8_t dpm_0_pg_nb_ps_high; uint8_t dpm_x_nb_ps_low; uint8_t dpm_x_nb_ps_high; - enum cz_pstate_previous_action action; - struct cz_power_level levels[CZ_MAX_HARDWARE_POWERLEVELS]; + enum smu8_pstate_previous_action action; + struct smu8_power_level levels[SMU8_MAX_HARDWARE_POWERLEVELS]; struct pp_disable_nb_ps_flags disable_nb_ps_flag; }; @@ -182,7 +179,7 @@ struct cc6_settings { uint32_t cpu_pstate_separation_time; }; -struct cz_hwmgr { +struct smu8_hwmgr { uint32_t dpm_interval; uint32_t voltage_drop_threshold; @@ -202,11 +199,11 @@ struct cz_hwmgr { uint32_t thermal_auto_throttling_treshold; - struct cz_sys_info sys_info; + struct smu8_sys_info sys_info; - struct cz_power_level boot_power_level; - struct cz_power_state *cz_current_ps; - struct cz_power_state *cz_requested_ps; + struct smu8_power_level boot_power_level; + struct smu8_power_state *smu8_current_ps; + struct smu8_power_state *smu8_requested_ps; uint32_t mgcg_cgtt_local0; uint32_t mgcg_cgtt_local1; @@ -219,7 +216,7 @@ struct cz_hwmgr { uint32_t lock_nb_ps_in_uvd_play_back; - struct cz_display_phy_info display_phy_info; + struct smu8_display_phy_info display_phy_info; uint32_t vce_slow_sclk_threshold; /* default 200mhz */ uint32_t dce_slow_sclk_threshold; /* default 300mhz */ uint32_t min_sclk_did; /* minimum sclk divider */ @@ -270,10 +267,10 @@ struct cz_hwmgr { uint32_t fps_low_threshold; uint32_t dpm_flags; - struct cz_dpm_entry sclk_dpm; - struct cz_dpm_entry uvd_dpm; - struct cz_dpm_entry vce_dpm; - struct cz_dpm_entry acp_dpm; + struct smu8_dpm_entry sclk_dpm; + struct smu8_dpm_entry uvd_dpm; + struct smu8_dpm_entry vce_dpm; + struct smu8_dpm_entry acp_dpm; uint8_t uvd_boot_level; uint8_t vce_boot_level; @@ -311,12 +308,4 @@ struct cz_hwmgr { uint32_t num_of_clk_entries; }; -struct pp_hwmgr; - -int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr); -int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr); -int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr); -int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr); -int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate); -int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr); -#endif /* _CZ_HWMGR_H_ */ +#endif /* _SMU8_HWMGR_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c new file mode 100644 index 000000000000..e11daf5cbf80 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c @@ -0,0 +1,536 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include "hwmgr.h" +#include "pp_debug.h" +#include "ppatomctrl.h" +#include "ppsmc.h" + +uint8_t convert_to_vid(uint16_t vddc) +{ + return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25); +} + +uint16_t convert_to_vddc(uint8_t vid) +{ + return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); +} + +uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size) +{ + u32 mask = 0; + u32 shift = 0; + + shift = (offset % 4) << 3; + if (size == sizeof(uint8_t)) + mask = 0xFF << shift; + else if (size == sizeof(uint16_t)) + mask = 0xFFFF << shift; + + original_data &= ~mask; + original_data |= (field << shift); + return original_data; +} + +/** + * Returns once the part of the register indicated by the mask has + * reached the given value. + */ +int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, + uint32_t value, uint32_t mask) +{ + uint32_t i; + uint32_t cur_value; + + if (hwmgr == NULL || hwmgr->device == NULL) { + pr_err("Invalid Hardware Manager!"); + return -EINVAL; + } + + for (i = 0; i < hwmgr->usec_timeout; i++) { + cur_value = cgs_read_register(hwmgr->device, index); + if ((cur_value & mask) == (value & mask)) + break; + udelay(1); + } + + /* timeout means wrong logic*/ + if (i == hwmgr->usec_timeout) + return -1; + return 0; +} + + +/** + * Returns once the part of the register indicated by the mask has + * reached the given value.The indirect space is described by giving + * the memory-mapped index of the indirect index register. + */ +int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, + uint32_t indirect_port, + uint32_t index, + uint32_t value, + uint32_t mask) +{ + if (hwmgr == NULL || hwmgr->device == NULL) { + pr_err("Invalid Hardware Manager!"); + return -EINVAL; + } + + cgs_write_register(hwmgr->device, indirect_port, index); + return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); +} + +int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, + uint32_t index, + uint32_t value, uint32_t mask) +{ + uint32_t i; + uint32_t cur_value; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + for (i = 0; i < hwmgr->usec_timeout; i++) { + cur_value = cgs_read_register(hwmgr->device, + index); + if ((cur_value & mask) != (value & mask)) + break; + udelay(1); + } + + /* timeout means wrong logic */ + if (i == hwmgr->usec_timeout) + return -ETIME; + return 0; +} + +int phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr, + uint32_t indirect_port, + uint32_t index, + uint32_t value, + uint32_t mask) +{ + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + cgs_write_register(hwmgr->device, indirect_port, index); + return phm_wait_for_register_unequal(hwmgr, indirect_port + 1, + value, mask); +} + +bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr) +{ + return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating); +} + +bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr) +{ + return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating); +} + + +int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table) +{ + uint32_t i, j; + uint16_t vvalue; + bool found = false; + struct pp_atomctrl_voltage_table *table; + + PP_ASSERT_WITH_CODE((NULL != vol_table), + "Voltage Table empty.", return -EINVAL); + + table = kzalloc(sizeof(struct pp_atomctrl_voltage_table), + GFP_KERNEL); + + if (NULL == table) + return -EINVAL; + + table->mask_low = vol_table->mask_low; + table->phase_delay = vol_table->phase_delay; + + for (i = 0; i < vol_table->count; i++) { + vvalue = vol_table->entries[i].value; + found = false; + + for (j = 0; j < table->count; j++) { + if (vvalue == table->entries[j].value) { + found = true; + break; + } + } + + if (!found) { + table->entries[table->count].value = vvalue; + table->entries[table->count].smio_low = + vol_table->entries[i].smio_low; + table->count++; + } + } + + memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table)); + kfree(table); + table = NULL; + return 0; +} + +int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, + phm_ppt_v1_clock_voltage_dependency_table *dep_table) +{ + uint32_t i; + int result; + + PP_ASSERT_WITH_CODE((0 != dep_table->count), + "Voltage Dependency Table empty.", return -EINVAL); + + PP_ASSERT_WITH_CODE((NULL != vol_table), + "vol_table empty.", return -EINVAL); + + vol_table->mask_low = 0; + vol_table->phase_delay = 0; + vol_table->count = dep_table->count; + + for (i = 0; i < dep_table->count; i++) { + vol_table->entries[i].value = dep_table->entries[i].mvdd; + vol_table->entries[i].smio_low = 0; + } + + result = phm_trim_voltage_table(vol_table); + PP_ASSERT_WITH_CODE((0 == result), + "Failed to trim MVDD table.", return result); + + return 0; +} + +int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, + phm_ppt_v1_clock_voltage_dependency_table *dep_table) +{ + uint32_t i; + int result; + + PP_ASSERT_WITH_CODE((0 != dep_table->count), + "Voltage Dependency Table empty.", return -EINVAL); + + PP_ASSERT_WITH_CODE((NULL != vol_table), + "vol_table empty.", return -EINVAL); + + vol_table->mask_low = 0; + vol_table->phase_delay = 0; + vol_table->count = dep_table->count; + + for (i = 0; i < dep_table->count; i++) { + vol_table->entries[i].value = dep_table->entries[i].vddci; + vol_table->entries[i].smio_low = 0; + } + + result = phm_trim_voltage_table(vol_table); + PP_ASSERT_WITH_CODE((0 == result), + "Failed to trim VDDCI table.", return result); + + return 0; +} + +int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, + phm_ppt_v1_voltage_lookup_table *lookup_table) +{ + int i = 0; + + PP_ASSERT_WITH_CODE((0 != lookup_table->count), + "Voltage Lookup Table empty.", return -EINVAL); + + PP_ASSERT_WITH_CODE((NULL != vol_table), + "vol_table empty.", return -EINVAL); + + vol_table->mask_low = 0; + vol_table->phase_delay = 0; + + vol_table->count = lookup_table->count; + + for (i = 0; i < vol_table->count; i++) { + vol_table->entries[i].value = lookup_table->entries[i].us_vdd; + vol_table->entries[i].smio_low = 0; + } + + return 0; +} + +void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, + struct pp_atomctrl_voltage_table *vol_table) +{ + unsigned int i, diff; + + if (vol_table->count <= max_vol_steps) + return; + + diff = vol_table->count - max_vol_steps; + + for (i = 0; i < max_vol_steps; i++) + vol_table->entries[i] = vol_table->entries[i + diff]; + + vol_table->count = max_vol_steps; + + return; +} + +int phm_reset_single_dpm_table(void *table, + uint32_t count, int max) +{ + int i; + + struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; + + dpm_table->count = count > max ? max : count; + + for (i = 0; i < dpm_table->count; i++) + dpm_table->dpm_level[i].enabled = false; + + return 0; +} + +void phm_setup_pcie_table_entry( + void *table, + uint32_t index, uint32_t pcie_gen, + uint32_t pcie_lanes) +{ + struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; + dpm_table->dpm_level[index].value = pcie_gen; + dpm_table->dpm_level[index].param1 = pcie_lanes; + dpm_table->dpm_level[index].enabled = 1; +} + +int32_t phm_get_dpm_level_enable_mask_value(void *table) +{ + int32_t i; + int32_t mask = 0; + struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; + + for (i = dpm_table->count; i > 0; i--) { + mask = mask << 1; + if (dpm_table->dpm_level[i - 1].enabled) + mask |= 0x1; + else + mask &= 0xFFFFFFFE; + } + + return mask; +} + +uint8_t phm_get_voltage_index( + struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage) +{ + uint8_t count = (uint8_t) (lookup_table->count); + uint8_t i; + + PP_ASSERT_WITH_CODE((NULL != lookup_table), + "Lookup Table empty.", return 0); + PP_ASSERT_WITH_CODE((0 != count), + "Lookup Table empty.", return 0); + + for (i = 0; i < lookup_table->count; i++) { + /* find first voltage equal or bigger than requested */ + if (lookup_table->entries[i].us_vdd >= voltage) + return i; + } + /* voltage is bigger than max voltage in the table */ + return i - 1; +} + +uint8_t phm_get_voltage_id(pp_atomctrl_voltage_table *voltage_table, + uint32_t voltage) +{ + uint8_t count = (uint8_t) (voltage_table->count); + uint8_t i = 0; + + PP_ASSERT_WITH_CODE((NULL != voltage_table), + "Voltage Table empty.", return 0;); + PP_ASSERT_WITH_CODE((0 != count), + "Voltage Table empty.", return 0;); + + for (i = 0; i < count; i++) { + /* find first voltage bigger than requested */ + if (voltage_table->entries[i].value >= voltage) + return i; + } + + /* voltage is bigger than max voltage in the table */ + return i - 1; +} + +uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci) +{ + uint32_t i; + + for (i = 0; i < vddci_table->count; i++) { + if (vddci_table->entries[i].value >= vddci) + return vddci_table->entries[i].value; + } + + pr_debug("vddci is larger than max value in vddci_table\n"); + return vddci_table->entries[i-1].value; +} + +int phm_find_boot_level(void *table, + uint32_t value, uint32_t *boot_level) +{ + int result = -EINVAL; + uint32_t i; + struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; + + for (i = 0; i < dpm_table->count; i++) { + if (value == dpm_table->dpm_level[i].value) { + *boot_level = i; + result = 0; + } + } + + return result; +} + +int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, + phm_ppt_v1_voltage_lookup_table *lookup_table, + uint16_t virtual_voltage_id, int32_t *sclk) +{ + uint8_t entry_id; + uint8_t voltage_id; + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)(hwmgr->pptable); + + PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL); + + /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */ + for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) { + voltage_id = table_info->vdd_dep_on_sclk->entries[entry_id].vddInd; + if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id) + break; + } + + if (entry_id >= table_info->vdd_dep_on_sclk->count) { + pr_debug("Can't find requested voltage id in vdd_dep_on_sclk table\n"); + return -EINVAL; + } + + *sclk = table_info->vdd_dep_on_sclk->entries[entry_id].clk; + + return 0; +} + +/** + * Initialize Dynamic State Adjustment Rule Settings + * + * @param hwmgr the address of the powerplay hardware manager. + */ +int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) +{ + uint32_t table_size; + struct phm_clock_voltage_dependency_table *table_clk_vlt; + struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); + + /* initialize vddc_dep_on_dal_pwrl table */ + table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record); + table_clk_vlt = kzalloc(table_size, GFP_KERNEL); + + if (NULL == table_clk_vlt) { + pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n"); + return -ENOMEM; + } else { + table_clk_vlt->count = 4; + table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; + table_clk_vlt->entries[0].v = 0; + table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; + table_clk_vlt->entries[1].v = 720; + table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; + table_clk_vlt->entries[2].v = 810; + table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; + table_clk_vlt->entries[3].v = 900; + if (pptable_info != NULL) + pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt; + hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; + } + + return 0; +} + +uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) +{ + uint32_t level = 0; + + while (0 == (mask & (1 << level))) + level++; + + return level; +} + +void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr) +{ + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)hwmgr->pptable; + struct phm_clock_voltage_dependency_table *table = + table_info->vddc_dep_on_dal_pwrl; + struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table; + enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level; + uint32_t req_vddc = 0, req_volt, i; + + if (!table || table->count <= 0 + || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW + || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE) + return; + + for (i = 0; i < table->count; i++) { + if (dal_power_level == table->entries[i].clk) { + req_vddc = table->entries[i].v; + break; + } + } + + vddc_table = table_info->vdd_dep_on_sclk; + for (i = 0; i < vddc_table->count; i++) { + if (req_vddc <= vddc_table->entries[i].vddc) { + req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE); + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_VddC_Request, req_volt); + return; + } + } + pr_err("DAL requested level can not" + " found a available voltage in VDDC DPM Table \n"); +} + +int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, + uint32_t sclk, uint16_t id, uint16_t *voltage) +{ + uint32_t vol; + int ret = 0; + + if (hwmgr->chip_id < CHIP_TONGA) { + ret = atomctrl_get_voltage_evv(hwmgr, id, voltage); + } else if (hwmgr->chip_id < CHIP_POLARIS10) { + ret = atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage); + if (*voltage >= 2000 || *voltage == 0) + *voltage = 1150; + } else { + ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol); + *voltage = (uint16_t)(vol/100); + } + return ret; +} + + diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h new file mode 100644 index 000000000000..a1a491300348 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h @@ -0,0 +1,180 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef _SMU_HELPER_H_ +#define _SMU_HELPER_H_ + +struct pp_atomctrl_voltage_table; +struct pp_hwmgr; +struct phm_ppt_v1_voltage_lookup_table; + +extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, + uint32_t index, + uint32_t value, uint32_t mask); +extern int phm_wait_for_indirect_register_unequal( + struct pp_hwmgr *hwmgr, + uint32_t indirect_port, uint32_t index, + uint32_t value, uint32_t mask); + + +extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); +extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); +extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr); + +extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table); +extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); +extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); +extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table); +extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table); +extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max); +extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes); +extern int32_t phm_get_dpm_level_enable_mask_value(void *table); +extern uint8_t phm_get_voltage_id(struct pp_atomctrl_voltage_table *voltage_table, + uint32_t voltage); +extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage); +extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci); +extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level); +extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table, + uint16_t virtual_voltage_id, int32_t *sclk); +extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); +extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask); +extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); + +extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, + uint32_t sclk, uint16_t id, uint16_t *voltage); + +extern uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size); + +extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, + uint32_t value, uint32_t mask); + +extern int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, + uint32_t indirect_port, + uint32_t index, + uint32_t value, + uint32_t mask); + +#define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT +#define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK + +#define PHM_SET_FIELD(origval, reg, field, fieldval) \ + (((origval) & ~PHM_FIELD_MASK(reg, field)) | \ + (PHM_FIELD_MASK(reg, field) & ((fieldval) << PHM_FIELD_SHIFT(reg, field)))) + +#define PHM_GET_FIELD(value, reg, field) \ + (((value) & PHM_FIELD_MASK(reg, field)) >> \ + PHM_FIELD_SHIFT(reg, field)) + + +/* Operations on named fields. */ + +#define PHM_READ_FIELD(device, reg, field) \ + PHM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field) + +#define PHM_READ_INDIRECT_FIELD(device, port, reg, field) \ + PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ + reg, field) + +#define PHM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field) \ + PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ + reg, field) + +#define PHM_WRITE_FIELD(device, reg, field, fieldval) \ + cgs_write_register(device, mm##reg, PHM_SET_FIELD( \ + cgs_read_register(device, mm##reg), reg, field, fieldval)) + +#define PHM_WRITE_INDIRECT_FIELD(device, port, reg, field, fieldval) \ + cgs_write_ind_register(device, port, ix##reg, \ + PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ + reg, field, fieldval)) + +#define PHM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval) \ + cgs_write_ind_register(device, port, ix##reg, \ + PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ + reg, field, fieldval)) + +#define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \ + phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask) + + +#define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ + PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) + +#define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ + PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \ + << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) + +#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \ + phm_wait_for_indirect_register_unequal(hwmgr, \ + mm##port##_INDEX, index, value, mask) + +#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ + PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) + +#define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ + PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ + (fieldval) << PHM_FIELD_SHIFT(reg, field), \ + PHM_FIELD_MASK(reg, field) ) + + +#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ + port, index, value, mask) \ + phm_wait_for_indirect_register_unequal(hwmgr, \ + mm##port##_INDEX_11, index, value, mask) + +#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ + PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) + +#define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ + PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ + (fieldval) << PHM_FIELD_SHIFT(reg, field), \ + PHM_FIELD_MASK(reg, field)) + + +#define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, \ + port, index, value, mask) \ + phm_wait_on_indirect_register(hwmgr, \ + mm##port##_INDEX_11, index, value, mask) + +#define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ + PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) + +#define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ + PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, \ + (fieldval) << PHM_FIELD_SHIFT(reg, field), \ + PHM_FIELD_MASK(reg, field)) + +#define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ + index, value, mask) \ + phm_wait_for_register_unequal(hwmgr, \ + index, value, mask) + +#define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask) \ + PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ + mm##reg, value, mask) + +#define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval) \ + PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, \ + (fieldval) << PHM_FIELD_SHIFT(reg, field), \ + PHM_FIELD_MASK(reg, field)) + +#endif /* _SMU_HELPER_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index f23861f2c685..2fcbb17b794d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -4874,12 +4874,12 @@ static int vega10_register_thermal_interrupt(struct pp_hwmgr *hwmgr, hwmgr->thermal_controller.ucType == ATOM_VEGA10_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) { PP_ASSERT_WITH_CODE(!cgs_add_irq_source(hwmgr->device, - 0xf, /* AMDGPU_IH_CLIENTID_THM */ + SOC15_IH_CLIENTID_THM, 0, 0, irq_src[0].set, irq_src[0].handler, hwmgr), "Failed to register high thermal interrupt!", return -EINVAL); PP_ASSERT_WITH_CODE(!cgs_add_irq_source(hwmgr->device, - 0xf, /* AMDGPU_IH_CLIENTID_THM */ + SOC15_IH_CLIENTID_THM, 1, 0, irq_src[1].set, irq_src[1].handler, hwmgr), "Failed to register low thermal interrupt!", return -EINVAL); @@ -4887,7 +4887,7 @@ static int vega10_register_thermal_interrupt(struct pp_hwmgr *hwmgr, /* Register CTF(GPIO_19) interrupt */ PP_ASSERT_WITH_CODE(!cgs_add_irq_source(hwmgr->device, - 0x16, /* AMDGPU_IH_CLIENTID_ROM_SMUIO, */ + SOC15_IH_CLIENTID_ROM_SMUIO, 83, 0, irq_src[2].set, irq_src[2].handler, hwmgr), "Failed to register CTF thermal interrupt!", return -EINVAL); diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index b151ad85666a..85b46ad68546 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -25,16 +25,14 @@ #include <linux/seq_file.h> #include "amd_powerplay.h" -#include "pp_instance.h" #include "hardwaremanager.h" #include "pp_power_source.h" #include "hwmgr_ppt.h" #include "ppatomctrl.h" #include "hwmgr_ppt.h" #include "power_state.h" -#include "cgs_linux.h" +#include "smu_helper.h" -struct pp_instance; struct pp_hwmgr; struct phm_fan_speed_info; struct pp_atomctrl_voltage_table; @@ -237,6 +235,7 @@ struct pp_smumgr_func { bool (*is_dpm_running)(struct pp_hwmgr *hwmgr); bool (*is_hw_avfs_present)(struct pp_hwmgr *hwmgr); int (*update_dpm_settings)(struct pp_hwmgr *hwmgr, void *profile_setting); + int (*smc_table_manager)(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw); /*rw: true for read, false for write */ }; struct pp_hwmgr_func { @@ -702,6 +701,8 @@ struct pp_hwmgr { uint32_t chip_family; uint32_t chip_id; uint32_t smu_version; + bool pm_en; + struct mutex smu_lock; uint32_t pp_table_version; void *device; @@ -748,7 +749,7 @@ struct pp_hwmgr { struct pp_power_state *uvd_ps; struct amd_pp_display_configuration display_config; uint32_t feature_mask; - + bool avfs_supported; /* UMD Pstate */ bool en_umd_pstate; uint32_t power_profile_mode; @@ -768,168 +769,17 @@ struct cgs_irq_src_funcs { cgs_irq_handler_func_t handler; }; -extern int hwmgr_early_init(struct pp_instance *handle); -extern int hwmgr_hw_init(struct pp_instance *handle); -extern int hwmgr_hw_fini(struct pp_instance *handle); -extern int hwmgr_hw_suspend(struct pp_instance *handle); -extern int hwmgr_hw_resume(struct pp_instance *handle); -extern int hwmgr_handle_task(struct pp_instance *handle, +extern int hwmgr_early_init(struct pp_hwmgr *hwmgr); +extern int hwmgr_hw_init(struct pp_hwmgr *hwmgr); +extern int hwmgr_hw_fini(struct pp_hwmgr *hwmgr); +extern int hwmgr_hw_suspend(struct pp_hwmgr *hwmgr); +extern int hwmgr_hw_resume(struct pp_hwmgr *hwmgr); +extern int hwmgr_handle_task(struct pp_hwmgr *hwmgr, enum amd_pp_task task_id, enum amd_pm_state_type *user_state); -extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, - uint32_t value, uint32_t mask); - -extern int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, - uint32_t indirect_port, - uint32_t index, - uint32_t value, - uint32_t mask); - -extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, - uint32_t index, - uint32_t value, uint32_t mask); -extern int phm_wait_for_indirect_register_unequal( - struct pp_hwmgr *hwmgr, - uint32_t indirect_port, uint32_t index, - uint32_t value, uint32_t mask); - - -extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); -extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); -extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr); - -extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table); -extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); -extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); -extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table); -extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table); -extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max); -extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes); -extern int32_t phm_get_dpm_level_enable_mask_value(void *table); -extern uint8_t phm_get_voltage_id(struct pp_atomctrl_voltage_table *voltage_table, - uint32_t voltage); -extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage); -extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci); -extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level); -extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table, - uint16_t virtual_voltage_id, int32_t *sclk); -extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); -extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask); -extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); - -extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); -extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr); -extern int rv_init_function_pointers(struct pp_hwmgr *hwmgr); - -extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, - uint32_t sclk, uint16_t id, uint16_t *voltage); - -extern uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size); - -#define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU - -#define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT -#define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK - -#define PHM_SET_FIELD(origval, reg, field, fieldval) \ - (((origval) & ~PHM_FIELD_MASK(reg, field)) | \ - (PHM_FIELD_MASK(reg, field) & ((fieldval) << PHM_FIELD_SHIFT(reg, field)))) - -#define PHM_GET_FIELD(value, reg, field) \ - (((value) & PHM_FIELD_MASK(reg, field)) >> \ - PHM_FIELD_SHIFT(reg, field)) - - -/* Operations on named fields. */ - -#define PHM_READ_FIELD(device, reg, field) \ - PHM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field) - -#define PHM_READ_INDIRECT_FIELD(device, port, reg, field) \ - PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ - reg, field) - -#define PHM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field) \ - PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ - reg, field) - -#define PHM_WRITE_FIELD(device, reg, field, fieldval) \ - cgs_write_register(device, mm##reg, PHM_SET_FIELD( \ - cgs_read_register(device, mm##reg), reg, field, fieldval)) - -#define PHM_WRITE_INDIRECT_FIELD(device, port, reg, field, fieldval) \ - cgs_write_ind_register(device, port, ix##reg, \ - PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ - reg, field, fieldval)) - -#define PHM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval) \ - cgs_write_ind_register(device, port, ix##reg, \ - PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ - reg, field, fieldval)) - -#define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \ - phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask) -#define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ - PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) - -#define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ - PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \ - << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) - -#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \ - phm_wait_for_indirect_register_unequal(hwmgr, \ - mm##port##_INDEX, index, value, mask) - -#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ - PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) - -#define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ - PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ - (fieldval) << PHM_FIELD_SHIFT(reg, field), \ - PHM_FIELD_MASK(reg, field) ) - - -#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ - port, index, value, mask) \ - phm_wait_for_indirect_register_unequal(hwmgr, \ - mm##port##_INDEX_11, index, value, mask) - -#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ - PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) - -#define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ - PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ - (fieldval) << PHM_FIELD_SHIFT(reg, field), \ - PHM_FIELD_MASK(reg, field)) - - -#define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, \ - port, index, value, mask) \ - phm_wait_on_indirect_register(hwmgr, \ - mm##port##_INDEX_11, index, value, mask) - -#define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ - PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) - -#define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ - PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, \ - (fieldval) << PHM_FIELD_SHIFT(reg, field), \ - PHM_FIELD_MASK(reg, field)) - -#define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ - index, value, mask) \ - phm_wait_for_register_unequal(hwmgr, \ - index, value, mask) - -#define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask) \ - PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ - mm##reg, value, mask) +#define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU -#define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval) \ - PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, \ - (fieldval) << PHM_FIELD_SHIFT(reg, field), \ - PHM_FIELD_MASK(reg, field)) #endif /* _HWMGR_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h deleted file mode 100644 index 6c2fa33bd63a..000000000000 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _PP_INSTANCE_H_ -#define _PP_INSTANCE_H_ - -struct pp_hwmgr; - -struct pp_instance { - void *parent; /* e.g. amdgpu_device */ - void *device; /* e.g. cgs_device */ - bool pm_en; - struct pp_hwmgr *hwmgr; - struct mutex pp_lock; -}; - -#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h index 9bba0a069ed6..fc3a2a533586 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h @@ -26,27 +26,6 @@ #include "amd_powerplay.h" #include "hwmgr.h" -enum AVFS_BTC_STATUS { - AVFS_BTC_BOOT = 0, - AVFS_BTC_BOOT_STARTEDSMU, - AVFS_LOAD_VIRUS, - AVFS_BTC_VIRUS_LOADED, - AVFS_BTC_VIRUS_FAIL, - AVFS_BTC_COMPLETED_PREVIOUSLY, - AVFS_BTC_ENABLEAVFS, - AVFS_BTC_STARTED, - AVFS_BTC_FAILED, - AVFS_BTC_RESTOREVFT_FAILED, - AVFS_BTC_SAVEVFT_FAILED, - AVFS_BTC_DPMTABLESETUP_FAILED, - AVFS_BTC_COMPLETED_UNSAVED, - AVFS_BTC_COMPLETED_SAVED, - AVFS_BTC_COMPLETED_RESTORED, - AVFS_BTC_DISABLED, - AVFS_BTC_NOTSUPPORTED, - AVFS_BTC_SMUMSG_ERROR -}; - enum SMU_TABLE { SMU_UVD_TABLE = 0, SMU_VCE_TABLE, @@ -90,6 +69,11 @@ enum SMU_MAC_DEFINITION { SMU_UVD_MCLK_HANDSHAKE_DISABLE, }; +enum SMU10_TABLE_ID { + SMU10_WMTABLE = 0, + SMU10_CLOCKTABLE, +}; + extern int smum_get_argument(struct pp_hwmgr *hwmgr); extern int smum_download_powerplay_table(struct pp_hwmgr *hwmgr, void **table); @@ -121,4 +105,6 @@ extern bool smum_is_hw_avfs_present(struct pp_hwmgr *hwmgr); extern int smum_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting); +extern int smum_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw); + #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile index 98e701e4f553..735c38624ce1 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile @@ -23,9 +23,9 @@ # Makefile for the 'smu manager' sub-component of powerplay. # It provides the smu management services for the driver. -SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o \ +SMU_MGR = smumgr.o smu8_smumgr.o tonga_smumgr.o fiji_smumgr.o \ polaris10_smumgr.o iceland_smumgr.o \ - smu7_smumgr.o vega10_smumgr.o rv_smumgr.o ci_smumgr.o + smu7_smumgr.o vega10_smumgr.o smu10_smumgr.o ci_smumgr.o AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c deleted file mode 100644 index 957739aa6db9..000000000000 --- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include <linux/delay.h> -#include <linux/gfp.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/types.h> - -#include "cgs_common.h" -#include "smu/smu_8_0_d.h" -#include "smu/smu_8_0_sh_mask.h" -#include "smu8.h" -#include "smu8_fusion.h" -#include "cz_smumgr.h" -#include "cz_ppsmc.h" -#include "smu_ucode_xfer_cz.h" -#include "gca/gfx_8_0_d.h" -#include "gca/gfx_8_0_sh_mask.h" -#include "smumgr.h" - -#define SIZE_ALIGN_32(x) (((x) + 31) / 32 * 32) - -static const enum cz_scratch_entry firmware_list[] = { - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, -}; - -static int cz_smum_get_argument(struct pp_hwmgr *hwmgr) -{ - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - return cgs_read_register(hwmgr->device, - mmSMU_MP1_SRBM2P_ARG_0); -} - -static int cz_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - int result = 0; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - result = PHM_WAIT_FIELD_UNEQUAL(hwmgr, - SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); - if (result != 0) { - pr_err("cz_send_msg_to_smc_async (0x%04x) failed\n", msg); - return result; - } - - cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0); - cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg); - - return 0; -} - -/* Send a message to the SMC, and wait for its response.*/ -static int cz_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - int result = 0; - - result = cz_send_msg_to_smc_async(hwmgr, msg); - if (result != 0) - return result; - - return PHM_WAIT_FIELD_UNEQUAL(hwmgr, - SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); -} - -static int cz_set_smc_sram_address(struct pp_hwmgr *hwmgr, - uint32_t smc_address, uint32_t limit) -{ - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - if (0 != (3 & smc_address)) { - pr_err("SMC address must be 4 byte aligned\n"); - return -EINVAL; - } - - if (limit <= (smc_address + 3)) { - pr_err("SMC address beyond the SMC RAM area\n"); - return -EINVAL; - } - - cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX_0, - SMN_MP1_SRAM_START_ADDR + smc_address); - - return 0; -} - -static int cz_write_smc_sram_dword(struct pp_hwmgr *hwmgr, - uint32_t smc_address, uint32_t value, uint32_t limit) -{ - int result; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - result = cz_set_smc_sram_address(hwmgr, smc_address, limit); - if (!result) - cgs_write_register(hwmgr->device, mmMP0PUB_IND_DATA_0, value); - - return result; -} - -static int cz_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, - uint16_t msg, uint32_t parameter) -{ - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter); - - return cz_send_msg_to_smc(hwmgr, msg); -} - -static int cz_check_fw_load_finish(struct pp_hwmgr *hwmgr, - uint32_t firmware) -{ - int i; - uint32_t index = SMN_MP1_SRAM_START_ADDR + - SMU8_FIRMWARE_HEADER_LOCATION + - offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); - - for (i = 0; i < hwmgr->usec_timeout; i++) { - if (firmware == - (cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA) & firmware)) - break; - udelay(1); - } - - if (i >= hwmgr->usec_timeout) { - pr_err("SMU check loaded firmware failed.\n"); - return -EINVAL; - } - - return 0; -} - -static int cz_load_mec_firmware(struct pp_hwmgr *hwmgr) -{ - uint32_t reg_data; - uint32_t tmp; - int ret = 0; - struct cgs_firmware_info info = {0}; - struct cz_smumgr *cz_smu; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - ret = cgs_get_firmware_info(hwmgr->device, - CGS_UCODE_ID_CP_MEC, &info); - - if (ret) - return -EINVAL; - - /* Disable MEC parsing/prefetching */ - tmp = cgs_read_register(hwmgr->device, - mmCP_MEC_CNTL); - tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1); - tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1); - cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, tmp); - - tmp = cgs_read_register(hwmgr->device, - mmCP_CPC_IC_BASE_CNTL); - - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0); - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0); - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0); - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1); - cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_CNTL, tmp); - - reg_data = lower_32_bits(info.mc_addr) & - PHM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO); - cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_LO, reg_data); - - reg_data = upper_32_bits(info.mc_addr) & - PHM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI); - cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_HI, reg_data); - - return 0; -} - -static uint8_t cz_translate_firmware_enum_to_arg(struct pp_hwmgr *hwmgr, - enum cz_scratch_entry firmware_enum) -{ - uint8_t ret = 0; - - switch (firmware_enum) { - case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0: - ret = UCODE_ID_SDMA0; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1: - if (hwmgr->chip_id == CHIP_STONEY) - ret = UCODE_ID_SDMA0; - else - ret = UCODE_ID_SDMA1; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE: - ret = UCODE_ID_CP_CE; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP: - ret = UCODE_ID_CP_PFP; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME: - ret = UCODE_ID_CP_ME; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1: - ret = UCODE_ID_CP_MEC_JT1; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2: - if (hwmgr->chip_id == CHIP_STONEY) - ret = UCODE_ID_CP_MEC_JT1; - else - ret = UCODE_ID_CP_MEC_JT2; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG: - ret = UCODE_ID_GMCON_RENG; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G: - ret = UCODE_ID_RLC_G; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH: - ret = UCODE_ID_RLC_SCRATCH; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM: - ret = UCODE_ID_RLC_SRM_ARAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM: - ret = UCODE_ID_RLC_SRM_DRAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM: - ret = UCODE_ID_DMCU_ERAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM: - ret = UCODE_ID_DMCU_IRAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING: - ret = TASK_ARG_INIT_MM_PWR_LOG; - break; - case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT: - case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING: - case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS: - case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT: - case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START: - case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS: - ret = TASK_ARG_REG_MMIO; - break; - case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE: - ret = TASK_ARG_INIT_CLK_TABLE; - break; - } - - return ret; -} - -static enum cgs_ucode_id cz_convert_fw_type_to_cgs(uint32_t fw_type) -{ - enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; - - switch (fw_type) { - case UCODE_ID_SDMA0: - result = CGS_UCODE_ID_SDMA0; - break; - case UCODE_ID_SDMA1: - result = CGS_UCODE_ID_SDMA1; - break; - case UCODE_ID_CP_CE: - result = CGS_UCODE_ID_CP_CE; - break; - case UCODE_ID_CP_PFP: - result = CGS_UCODE_ID_CP_PFP; - break; - case UCODE_ID_CP_ME: - result = CGS_UCODE_ID_CP_ME; - break; - case UCODE_ID_CP_MEC_JT1: - result = CGS_UCODE_ID_CP_MEC_JT1; - break; - case UCODE_ID_CP_MEC_JT2: - result = CGS_UCODE_ID_CP_MEC_JT2; - break; - case UCODE_ID_RLC_G: - result = CGS_UCODE_ID_RLC_G; - break; - default: - break; - } - - return result; -} - -static int cz_smu_populate_single_scratch_task( - struct pp_hwmgr *hwmgr, - enum cz_scratch_entry fw_enum, - uint8_t type, bool is_last) -{ - uint8_t i; - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++]; - - task->type = type; - task->arg = cz_translate_firmware_enum_to_arg(hwmgr, fw_enum); - task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count; - - for (i = 0; i < cz_smu->scratch_buffer_length; i++) - if (cz_smu->scratch_buffer[i].firmware_ID == fw_enum) - break; - - if (i >= cz_smu->scratch_buffer_length) { - pr_err("Invalid Firmware Type\n"); - return -EINVAL; - } - - task->addr.low = lower_32_bits(cz_smu->scratch_buffer[i].mc_addr); - task->addr.high = upper_32_bits(cz_smu->scratch_buffer[i].mc_addr); - task->size_bytes = cz_smu->scratch_buffer[i].data_size; - - if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) { - struct cz_ih_meta_data *pIHReg_restore = - (struct cz_ih_meta_data *)cz_smu->scratch_buffer[i].kaddr; - pIHReg_restore->command = - METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD; - } - - return 0; -} - -static int cz_smu_populate_single_ucode_load_task( - struct pp_hwmgr *hwmgr, - enum cz_scratch_entry fw_enum, - bool is_last) -{ - uint8_t i; - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++]; - - task->type = TASK_TYPE_UCODE_LOAD; - task->arg = cz_translate_firmware_enum_to_arg(hwmgr, fw_enum); - task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count; - - for (i = 0; i < cz_smu->driver_buffer_length; i++) - if (cz_smu->driver_buffer[i].firmware_ID == fw_enum) - break; - - if (i >= cz_smu->driver_buffer_length) { - pr_err("Invalid Firmware Type\n"); - return -EINVAL; - } - - task->addr.low = lower_32_bits(cz_smu->driver_buffer[i].mc_addr); - task->addr.high = upper_32_bits(cz_smu->driver_buffer[i].mc_addr); - task->size_bytes = cz_smu->driver_buffer[i].data_size; - - return 0; -} - -static int cz_smu_construct_toc_for_rlc_aram_save(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_aram = cz_smu->toc_entry_used_count; - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - TASK_TYPE_UCODE_SAVE, true); - - return 0; -} - -static int cz_smu_initialize_toc_empty_job_list(struct pp_hwmgr *hwmgr) -{ - int i; - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - - for (i = 0; i < NUM_JOBLIST_ENTRIES; i++) - toc->JobList[i] = (uint8_t)IGNORE_JOB; - - return 0; -} - -static int cz_smu_construct_toc_for_vddgfx_enter(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - - toc->JobList[JOB_GFX_SAVE] = (uint8_t)cz_smu->toc_entry_used_count; - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - TASK_TYPE_UCODE_SAVE, false); - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - TASK_TYPE_UCODE_SAVE, true); - - return 0; -} - - -static int cz_smu_construct_toc_for_vddgfx_exit(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - - toc->JobList[JOB_GFX_RESTORE] = (uint8_t)cz_smu->toc_entry_used_count; - - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); - - if (hwmgr->chip_id == CHIP_STONEY) - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); - else - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); - - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false); - - /* populate scratch */ - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - TASK_TYPE_UCODE_LOAD, false); - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - TASK_TYPE_UCODE_LOAD, false); - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - TASK_TYPE_UCODE_LOAD, true); - - return 0; -} - -static int cz_smu_construct_toc_for_power_profiling(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_power_profiling_index = cz_smu->toc_entry_used_count; - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, - TASK_TYPE_INITIALIZE, true); - return 0; -} - -static int cz_smu_construct_toc_for_bootup(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_initialize_index = cz_smu->toc_entry_used_count; - - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false); - if (hwmgr->chip_id != CHIP_STONEY) - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); - if (hwmgr->chip_id != CHIP_STONEY) - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true); - - return 0; -} - -static int cz_smu_construct_toc_for_clock_table(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_clock_table = cz_smu->toc_entry_used_count; - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, - TASK_TYPE_INITIALIZE, true); - - return 0; -} - -static int cz_smu_construct_toc(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_used_count = 0; - cz_smu_initialize_toc_empty_job_list(hwmgr); - cz_smu_construct_toc_for_rlc_aram_save(hwmgr); - cz_smu_construct_toc_for_vddgfx_enter(hwmgr); - cz_smu_construct_toc_for_vddgfx_exit(hwmgr); - cz_smu_construct_toc_for_power_profiling(hwmgr); - cz_smu_construct_toc_for_bootup(hwmgr); - cz_smu_construct_toc_for_clock_table(hwmgr); - - return 0; -} - -static int cz_smu_populate_firmware_entries(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - uint32_t firmware_type; - uint32_t i; - int ret; - enum cgs_ucode_id ucode_id; - struct cgs_firmware_info info = {0}; - - cz_smu->driver_buffer_length = 0; - - for (i = 0; i < ARRAY_SIZE(firmware_list); i++) { - - firmware_type = cz_translate_firmware_enum_to_arg(hwmgr, - firmware_list[i]); - - ucode_id = cz_convert_fw_type_to_cgs(firmware_type); - - ret = cgs_get_firmware_info(hwmgr->device, - ucode_id, &info); - - if (ret == 0) { - cz_smu->driver_buffer[i].mc_addr = info.mc_addr; - - cz_smu->driver_buffer[i].data_size = info.image_size; - - cz_smu->driver_buffer[i].firmware_ID = firmware_list[i]; - cz_smu->driver_buffer_length++; - } - } - - return 0; -} - -static int cz_smu_populate_single_scratch_entry( - struct pp_hwmgr *hwmgr, - enum cz_scratch_entry scratch_type, - uint32_t ulsize_byte, - struct cz_buffer_entry *entry) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte); - - entry->data_size = ulsize_byte; - entry->kaddr = (char *) cz_smu->smu_buffer.kaddr + - cz_smu->smu_buffer_used_bytes; - entry->mc_addr = cz_smu->smu_buffer.mc_addr + cz_smu->smu_buffer_used_bytes; - entry->firmware_ID = scratch_type; - - cz_smu->smu_buffer_used_bytes += ulsize_aligned; - - return 0; -} - -static int cz_download_pptable_settings(struct pp_hwmgr *hwmgr, void **table) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - unsigned long i; - - for (i = 0; i < cz_smu->scratch_buffer_length; i++) { - if (cz_smu->scratch_buffer[i].firmware_ID - == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) - break; - } - - *table = (struct SMU8_Fusion_ClkTable *)cz_smu->scratch_buffer[i].kaddr; - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrHi, - upper_32_bits(cz_smu->scratch_buffer[i].mc_addr)); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrLo, - lower_32_bits(cz_smu->scratch_buffer[i].mc_addr)); - - cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_clock_table); - - cz_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToDram); - - return 0; -} - -static int cz_upload_pptable_settings(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - unsigned long i; - - for (i = 0; i < cz_smu->scratch_buffer_length; i++) { - if (cz_smu->scratch_buffer[i].firmware_ID - == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) - break; - } - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrHi, - upper_32_bits(cz_smu->scratch_buffer[i].mc_addr)); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrLo, - lower_32_bits(cz_smu->scratch_buffer[i].mc_addr)); - - cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_clock_table); - - cz_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToSmu); - - return 0; -} - -static int cz_request_smu_load_fw(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)(hwmgr->smu_backend); - uint32_t smc_address; - - if (!hwmgr->reload_fw) { - pr_info("skip reloading...\n"); - return 0; - } - - cz_smu_populate_firmware_entries(hwmgr); - - cz_smu_construct_toc(hwmgr); - - smc_address = SMU8_FIRMWARE_HEADER_LOCATION + - offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); - - cz_write_smc_sram_dword(hwmgr, smc_address, 0, smc_address+4); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_DriverDramAddrHi, - upper_32_bits(cz_smu->toc_buffer.mc_addr)); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_DriverDramAddrLo, - lower_32_bits(cz_smu->toc_buffer.mc_addr)); - - cz_send_msg_to_smc(hwmgr, PPSMC_MSG_InitJobs); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_aram); - cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_power_profiling_index); - - return cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_initialize_index); -} - -static int cz_start_smu(struct pp_hwmgr *hwmgr) -{ - int ret = 0; - uint32_t fw_to_check = 0; - struct cgs_firmware_info info = {0}; - uint32_t index = SMN_MP1_SRAM_START_ADDR + - SMU8_FIRMWARE_HEADER_LOCATION + - offsetof(struct SMU8_Firmware_Header, Version); - - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); - hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); - info.version = hwmgr->smu_version >> 8; - cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, &info); - - fw_to_check = UCODE_ID_RLC_G_MASK | - UCODE_ID_SDMA0_MASK | - UCODE_ID_SDMA1_MASK | - UCODE_ID_CP_CE_MASK | - UCODE_ID_CP_ME_MASK | - UCODE_ID_CP_PFP_MASK | - UCODE_ID_CP_MEC_JT1_MASK | - UCODE_ID_CP_MEC_JT2_MASK; - - if (hwmgr->chip_id == CHIP_STONEY) - fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK); - - ret = cz_request_smu_load_fw(hwmgr); - if (ret) - pr_err("SMU firmware load failed\n"); - - cz_check_fw_load_finish(hwmgr, fw_to_check); - - ret = cz_load_mec_firmware(hwmgr); - if (ret) - pr_err("Mec Firmware load failed\n"); - - return ret; -} - -static int cz_smu_init(struct pp_hwmgr *hwmgr) -{ - int ret = 0; - struct cz_smumgr *cz_smu; - - cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL); - if (cz_smu == NULL) - return -ENOMEM; - - hwmgr->smu_backend = cz_smu; - - cz_smu->toc_buffer.data_size = 4096; - cz_smu->smu_buffer.data_size = - ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) + - ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) + - ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) + - ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) + - ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32); - - ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, - cz_smu->toc_buffer.data_size, - PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &cz_smu->toc_buffer.handle, - &cz_smu->toc_buffer.mc_addr, - &cz_smu->toc_buffer.kaddr); - if (ret) - return -EINVAL; - - ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, - cz_smu->smu_buffer.data_size, - PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &cz_smu->smu_buffer.handle, - &cz_smu->smu_buffer.mc_addr, - &cz_smu->smu_buffer.kaddr); - if (ret) { - amdgpu_bo_free_kernel(&cz_smu->toc_buffer.handle, - &cz_smu->toc_buffer.mc_addr, - &cz_smu->toc_buffer.kaddr); - return -EINVAL; - } - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - UCODE_ID_RLC_SCRATCH_SIZE_BYTE, - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, - sizeof(struct SMU8_MultimediaPowerLogData), - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, - sizeof(struct SMU8_Fusion_ClkTable), - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - return 0; -} - -static int cz_smu_fini(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - if (cz_smu) { - amdgpu_bo_free_kernel(&cz_smu->toc_buffer.handle, - &cz_smu->toc_buffer.mc_addr, - &cz_smu->toc_buffer.kaddr); - amdgpu_bo_free_kernel(&cz_smu->smu_buffer.handle, - &cz_smu->smu_buffer.mc_addr, - &cz_smu->smu_buffer.kaddr); - kfree(cz_smu); - } - - return 0; -} - -static bool cz_dpm_check_smu_features(struct pp_hwmgr *hwmgr, - unsigned long check_feature) -{ - int result; - unsigned long features; - - result = cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetFeatureStatus, 0); - if (result == 0) { - features = smum_get_argument(hwmgr); - if (features & check_feature) - return true; - } - - return false; -} - -static bool cz_is_dpm_running(struct pp_hwmgr *hwmgr) -{ - if (cz_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn)) - return true; - return false; -} - -const struct pp_smumgr_func cz_smu_funcs = { - .smu_init = cz_smu_init, - .smu_fini = cz_smu_fini, - .start_smu = cz_start_smu, - .check_fw_load_finish = cz_check_fw_load_finish, - .request_smu_load_fw = NULL, - .request_smu_load_specific_fw = NULL, - .get_argument = cz_smum_get_argument, - .send_msg_to_smc = cz_send_msg_to_smc, - .send_msg_to_smc_with_parameter = cz_send_msg_to_smc_with_parameter, - .download_pptable_settings = cz_download_pptable_settings, - .upload_pptable_settings = cz_upload_pptable_settings, - .is_dpm_running = cz_is_dpm_running, -}; - diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index 0b2b5d155e5e..95fcda37f890 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -205,9 +205,9 @@ static int fiji_start_avfs_btc(struct pp_hwmgr *hwmgr) int result = 0; struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - if (0 != smu_data->avfs.avfs_btc_param) { + if (0 != smu_data->avfs_btc_param) { if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) { + PPSMC_MSG_PerformBtc, smu_data->avfs_btc_param)) { pr_info("[AVFS][Fiji_PerformBtc] PerformBTC SMU msg failed"); result = -EINVAL; } @@ -261,43 +261,21 @@ static int fiji_setup_graphics_level_structure(struct pp_hwmgr *hwmgr) return 0; } -static int fiji_avfs_event_mgr(struct pp_hwmgr *hwmgr, bool smu_started) +static int fiji_avfs_event_mgr(struct pp_hwmgr *hwmgr) { - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - - switch (smu_data->avfs.avfs_btc_status) { - case AVFS_BTC_COMPLETED_PREVIOUSLY: - break; + PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(hwmgr), + "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level" + " table over to SMU", + return -EINVAL); + PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), + "[AVFS][fiji_avfs_event_mgr] Could not setup " + "Pwr Virus for AVFS ", + return -EINVAL); + PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(hwmgr), + "[AVFS][fiji_avfs_event_mgr] Failure at " + "fiji_start_avfs_btc. AVFS Disabled", + return -EINVAL); - case AVFS_BTC_BOOT: /*Cold Boot State - Post SMU Start*/ - if (!smu_started) - break; - smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED; - PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(hwmgr), - "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level" - " table over to SMU", - return -EINVAL;); - smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL; - PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), - "[AVFS][fiji_avfs_event_mgr] Could not setup " - "Pwr Virus for AVFS ", - return -EINVAL;); - smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED; - PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(hwmgr), - "[AVFS][fiji_avfs_event_mgr] Failure at " - "fiji_start_avfs_btc. AVFS Disabled", - return -EINVAL;); - - smu_data->avfs.avfs_btc_status = AVFS_BTC_ENABLEAVFS; - break; - case AVFS_BTC_DISABLED: /* Do nothing */ - case AVFS_BTC_NOTSUPPORTED: /* Do nothing */ - case AVFS_BTC_ENABLEAVFS: - break; - default: - pr_err("AVFS failed status is %x !\n", smu_data->avfs.avfs_btc_status); - break; - } return 0; } @@ -309,8 +287,6 @@ static int fiji_start_smu(struct pp_hwmgr *hwmgr) /* Only start SMC if SMC RAM is not running */ if (!(smu7_is_smc_ram_running(hwmgr) || cgs_is_virtualization_enabled(hwmgr->device))) { - fiji_avfs_event_mgr(hwmgr, false); - /* Check if SMU is running in protected mode */ if (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, @@ -323,7 +299,8 @@ static int fiji_start_smu(struct pp_hwmgr *hwmgr) if (result) return result; } - fiji_avfs_event_mgr(hwmgr, true); + if (fiji_avfs_event_mgr(hwmgr)) + hwmgr->avfs_supported = false; } /* To initialize all clock gating before RLC loaded and running.*/ @@ -377,8 +354,10 @@ static int fiji_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = fiji_priv; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(fiji_priv); return -EINVAL; + } return 0; } @@ -2315,19 +2294,12 @@ static int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) static int fiji_thermal_avfs_enable(struct pp_hwmgr *hwmgr) { - int ret; - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - - if (smu_data->avfs.avfs_btc_status != AVFS_BTC_ENABLEAVFS) + if (!hwmgr->avfs_supported) return 0; - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs); - if (!ret) - /* If this param is not changed, this function could fire unnecessarily */ - smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY; - - return ret; + return 0; } static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c index 6255edf58721..4e2f62e659ef 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c @@ -271,8 +271,10 @@ static int iceland_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = iceland_priv; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(iceland_priv); return -EINVAL; + } return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index 632d1ca2f69c..03ec1e59876b 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -99,13 +99,13 @@ static int polaris10_perform_btc(struct pp_hwmgr *hwmgr) int result = 0; struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - if (0 != smu_data->avfs.avfs_btc_param) { - if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) { + if (0 != smu_data->avfs_btc_param) { + if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_PerformBtc, smu_data->avfs_btc_param)) { pr_info("[AVFS][SmuPolaris10_PerformBtc] PerformBTC SMU msg failed"); result = -1; } } - if (smu_data->avfs.avfs_btc_param > 1) { + if (smu_data->avfs_btc_param > 1) { /* Soft-Reset to reset the engine before loading uCode */ /* halt */ cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, 0x50000000); @@ -173,46 +173,25 @@ static int polaris10_setup_graphics_level_structure(struct pp_hwmgr *hwmgr) static int -polaris10_avfs_event_mgr(struct pp_hwmgr *hwmgr, bool SMU_VFT_INTACT) +polaris10_avfs_event_mgr(struct pp_hwmgr *hwmgr) { struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - switch (smu_data->avfs.avfs_btc_status) { - case AVFS_BTC_COMPLETED_PREVIOUSLY: - break; - - case AVFS_BTC_BOOT: /* Cold Boot State - Post SMU Start */ - - smu_data->avfs.avfs_btc_status = AVFS_BTC_DPMTABLESETUP_FAILED; - PP_ASSERT_WITH_CODE(0 == polaris10_setup_graphics_level_structure(hwmgr), - "[AVFS][Polaris10_AVFSEventMgr] Could not Copy Graphics Level table over to SMU", - return -EINVAL); - - if (smu_data->avfs.avfs_btc_param > 1) { - pr_info("[AVFS][Polaris10_AVFSEventMgr] AC BTC has not been successfully verified on Fiji. There may be in this setting."); - smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL; - PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), - "[AVFS][Polaris10_AVFSEventMgr] Could not setup Pwr Virus for AVFS ", - return -EINVAL); - } + PP_ASSERT_WITH_CODE(0 == polaris10_setup_graphics_level_structure(hwmgr), + "[AVFS][Polaris10_AVFSEventMgr] Could not Copy Graphics Level table over to SMU", + return -EINVAL); - smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED; - PP_ASSERT_WITH_CODE(0 == polaris10_perform_btc(hwmgr), - "[AVFS][Polaris10_AVFSEventMgr] Failure at SmuPolaris10_PerformBTC. AVFS Disabled", - return -EINVAL); - smu_data->avfs.avfs_btc_status = AVFS_BTC_ENABLEAVFS; - break; - - case AVFS_BTC_DISABLED: - case AVFS_BTC_ENABLEAVFS: - case AVFS_BTC_NOTSUPPORTED: - break; - - default: - pr_err("AVFS failed status is %x!\n", smu_data->avfs.avfs_btc_status); - break; + if (smu_data->avfs_btc_param > 1) { + pr_info("[AVFS][Polaris10_AVFSEventMgr] AC BTC has not been successfully verified on Fiji. There may be in this setting."); + PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), + "[AVFS][Polaris10_AVFSEventMgr] Could not setup Pwr Virus for AVFS ", + return -EINVAL); } + PP_ASSERT_WITH_CODE(0 == polaris10_perform_btc(hwmgr), + "[AVFS][Polaris10_AVFSEventMgr] Failure at SmuPolaris10_PerformBTC. AVFS Disabled", + return -EINVAL); + return 0; } @@ -312,11 +291,10 @@ static int polaris10_start_smu(struct pp_hwmgr *hwmgr) { int result = 0; struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smu_backend); - bool SMU_VFT_INTACT; /* Only start SMC if SMC RAM is not running */ - if (!smu7_is_smc_ram_running(hwmgr)) { - SMU_VFT_INTACT = false; + if (!(smu7_is_smc_ram_running(hwmgr) + || cgs_is_virtualization_enabled(hwmgr->device))) { smu_data->protected_mode = (uint8_t) (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_MODE)); smu_data->smu7_data.security_hard_key = (uint8_t) (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_SEL)); @@ -337,11 +315,9 @@ static int polaris10_start_smu(struct pp_hwmgr *hwmgr) if (result != 0) PP_ASSERT_WITH_CODE(0, "Failed to load SMU ucode.", return result); - polaris10_avfs_event_mgr(hwmgr, true); - } else - SMU_VFT_INTACT = true; /*Driver went offline but SMU was still alive and contains the VFT table */ + polaris10_avfs_event_mgr(hwmgr); + } - polaris10_avfs_event_mgr(hwmgr, SMU_VFT_INTACT); /* Setup SoftRegsStart here for register lookup in case DummyBackEnd is used and ProcessFirmwareHeader is not executed */ smu7_read_smc_sram_dword(hwmgr, SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, SoftRegisters), &(smu_data->smu7_data.soft_regs_start), 0x40000); @@ -373,8 +349,10 @@ static int polaris10_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = smu_data; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(smu_data); return -EINVAL; + } return 0; } @@ -1732,8 +1710,8 @@ static int polaris10_populate_avfs_parameters(struct pp_hwmgr *hwmgr) table_info->vdd_dep_on_sclk; - if (((struct smu7_smumgr *)smu_data)->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) - return result; + if (!hwmgr->avfs_supported) + return 0; result = atomctrl_get_avfs_information(hwmgr, &avfs_params); @@ -2070,24 +2048,17 @@ static int polaris10_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) int polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr) { - int ret; - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) + if (!hwmgr->avfs_supported) return 0; - ret = smum_send_msg_to_smc_with_parameter(hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetGBDroopSettings, data->avfs_vdroop_override_setting); - ret = (smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs) == 0) ? - 0 : -1; + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs); - if (!ret) - /* If this param is not changed, this function could fire unnecessarily */ - smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY; - - return ret; + return 0; } static int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c deleted file mode 100644 index e2ee23ade5c5..000000000000 --- a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "smumgr.h" -#include "rv_inc.h" -#include "pp_soc15.h" -#include "rv_smumgr.h" -#include "ppatomctrl.h" -#include "rv_ppsmc.h" -#include "smu10_driver_if.h" -#include "smu10.h" -#include "ppatomctrl.h" -#include "pp_debug.h" -#include "smu_ucode_xfer_vi.h" -#include "smu7_smumgr.h" - -#define VOLTAGE_SCALE 4 - -#define BUFFER_SIZE 80000 -#define MAX_STRING_SIZE 15 -#define BUFFER_SIZETWO 131072 - -#define MP0_Public 0x03800000 -#define MP0_SRAM 0x03900000 -#define MP1_Public 0x03b00000 -#define MP1_SRAM 0x03c00004 - -#define smnMP1_FIRMWARE_FLAGS 0x3010028 - - -bool rv_is_smc_ram_running(struct pp_hwmgr *hwmgr) -{ - uint32_t mp1_fw_flags, reg; - - reg = soc15_get_register_offset(NBIF_HWID, 0, - mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2); - - cgs_write_register(hwmgr->device, reg, - (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); - - reg = soc15_get_register_offset(NBIF_HWID, 0, - mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2); - - mp1_fw_flags = cgs_read_register(hwmgr->device, reg); - - if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) - return true; - - return false; -} - -static uint32_t rv_wait_for_response(struct pp_hwmgr *hwmgr) -{ - uint32_t reg; - - if (!rv_is_smc_ram_running(hwmgr)) - return -EINVAL; - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - - phm_wait_for_register_unequal(hwmgr, reg, - 0, MP1_C2PMSG_90__CONTENT_MASK); - - return cgs_read_register(hwmgr->device, reg); -} - -int rv_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, - uint16_t msg) -{ - uint32_t reg; - - if (!rv_is_smc_ram_running(hwmgr)) - return -EINVAL; - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); - cgs_write_register(hwmgr->device, reg, msg); - - return 0; -} - -int rv_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg) -{ - uint32_t reg; - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); - - *arg = cgs_read_register(hwmgr->device, reg); - - return 0; -} - -int rv_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - uint32_t reg; - - rv_wait_for_response(hwmgr); - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - cgs_write_register(hwmgr->device, reg, 0); - - rv_send_msg_to_smc_without_waiting(hwmgr, msg); - - if (rv_wait_for_response(hwmgr) == 0) - printk("Failed to send Message %x.\n", msg); - - return 0; -} - - -int rv_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, - uint16_t msg, uint32_t parameter) -{ - uint32_t reg; - - rv_wait_for_response(hwmgr); - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - cgs_write_register(hwmgr->device, reg, 0); - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); - cgs_write_register(hwmgr->device, reg, parameter); - - rv_send_msg_to_smc_without_waiting(hwmgr, msg); - - - if (rv_wait_for_response(hwmgr) == 0) - printk("Failed to send Message %x.\n", msg); - - return 0; -} - -int rv_copy_table_from_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id) -{ - struct rv_smumgr *priv = - (struct rv_smumgr *)(hwmgr->smu_backend); - - PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, - "Invalid SMU Table ID!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, - "Invalid SMU Table version!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, - "Invalid SMU Table Length!", return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrHigh, - upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrLow, - lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_TransferTableSmu2Dram, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", - return -EINVAL;); - - memcpy(table, (uint8_t *)priv->smu_tables.entry[table_id].table, - priv->smu_tables.entry[table_id].size); - - return 0; -} - -int rv_copy_table_to_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id) -{ - struct rv_smumgr *priv = - (struct rv_smumgr *)(hwmgr->smu_backend); - - PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, - "Invalid SMU Table ID!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, - "Invalid SMU Table version!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, - "Invalid SMU Table Length!", return -EINVAL;); - - memcpy(priv->smu_tables.entry[table_id].table, table, - priv->smu_tables.entry[table_id].size); - - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrHigh, - upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrLow, - lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_TransferTableDram2Smu, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", - return -EINVAL;); - - return 0; -} - -static int rv_verify_smc_interface(struct pp_hwmgr *hwmgr) -{ - uint32_t smc_driver_if_version; - - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetDriverIfVersion), - "Attempt to get SMC IF Version Number Failed!", - return -EINVAL); - PP_ASSERT_WITH_CODE(!rv_read_arg_from_smc(hwmgr, - &smc_driver_if_version), - "Attempt to read SMC IF Version Number Failed!", - return -EINVAL); - - if (smc_driver_if_version != SMU10_DRIVER_IF_VERSION) - return -EINVAL; - - return 0; -} - -/* sdma is disabled by default in vbios, need to re-enable in driver */ -static int rv_smc_enable_sdma(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr, - PPSMC_MSG_PowerUpSdma), - "Attempt to power up sdma Failed!", - return -EINVAL); - - return 0; -} - -static int rv_smc_disable_sdma(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr, - PPSMC_MSG_PowerDownSdma), - "Attempt to power down sdma Failed!", - return -EINVAL); - - return 0; -} - -/* vcn is disabled by default in vbios, need to re-enable in driver */ -static int rv_smc_enable_vcn(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_PowerUpVcn, 0), - "Attempt to power up vcn Failed!", - return -EINVAL); - - return 0; -} - -static int rv_smc_disable_vcn(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_PowerDownVcn, 0), - "Attempt to power down vcn Failed!", - return -EINVAL); - - return 0; -} - -static int rv_smu_fini(struct pp_hwmgr *hwmgr) -{ - struct rv_smumgr *priv = - (struct rv_smumgr *)(hwmgr->smu_backend); - - if (priv) { - rv_smc_disable_sdma(hwmgr); - rv_smc_disable_vcn(hwmgr); - amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, - &priv->smu_tables.entry[WMTABLE].mc_addr, - priv->smu_tables.entry[WMTABLE].table); - amdgpu_bo_free_kernel(&priv->smu_tables.entry[CLOCKTABLE].handle, - &priv->smu_tables.entry[CLOCKTABLE].mc_addr, - priv->smu_tables.entry[CLOCKTABLE].table); - kfree(hwmgr->smu_backend); - hwmgr->smu_backend = NULL; - } - - return 0; -} - -static int rv_start_smu(struct pp_hwmgr *hwmgr) -{ - struct cgs_firmware_info info = {0}; - - smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion); - rv_read_arg_from_smc(hwmgr, &hwmgr->smu_version); - info.version = hwmgr->smu_version >> 8; - - cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, &info); - - if (rv_verify_smc_interface(hwmgr)) - return -EINVAL; - if (rv_smc_enable_sdma(hwmgr)) - return -EINVAL; - if (rv_smc_enable_vcn(hwmgr)) - return -EINVAL; - - return 0; -} - -static int rv_smu_init(struct pp_hwmgr *hwmgr) -{ - struct amdgpu_bo *handle = NULL; - struct rv_smumgr *priv; - uint64_t mc_addr; - void *kaddr = NULL; - int r; - - priv = kzalloc(sizeof(struct rv_smumgr), GFP_KERNEL); - - if (!priv) - return -ENOMEM; - - hwmgr->smu_backend = priv; - - /* allocate space for watermarks table */ - r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, - sizeof(Watermarks_t), - PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &handle, - &mc_addr, - &kaddr); - - if (r) - return -EINVAL; - - priv->smu_tables.entry[WMTABLE].version = 0x01; - priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); - priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; - priv->smu_tables.entry[WMTABLE].mc_addr = mc_addr; - priv->smu_tables.entry[WMTABLE].table = kaddr; - priv->smu_tables.entry[WMTABLE].handle = handle; - - /* allocate space for watermarks table */ - r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, - sizeof(DpmClocks_t), - PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &handle, - &mc_addr, - &kaddr); - - if (r) { - amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, - &priv->smu_tables.entry[WMTABLE].mc_addr, - &priv->smu_tables.entry[WMTABLE].table); - return -EINVAL; - } - - priv->smu_tables.entry[CLOCKTABLE].version = 0x01; - priv->smu_tables.entry[CLOCKTABLE].size = sizeof(DpmClocks_t); - priv->smu_tables.entry[CLOCKTABLE].table_id = TABLE_DPMCLOCKS; - priv->smu_tables.entry[CLOCKTABLE].mc_addr = mc_addr; - priv->smu_tables.entry[CLOCKTABLE].table = kaddr; - priv->smu_tables.entry[CLOCKTABLE].handle = handle; - - return 0; -} - -const struct pp_smumgr_func rv_smu_funcs = { - .smu_init = &rv_smu_init, - .smu_fini = &rv_smu_fini, - .start_smu = &rv_start_smu, - .request_smu_load_specific_fw = NULL, - .send_msg_to_smc = &rv_send_msg_to_smc, - .send_msg_to_smc_with_parameter = &rv_send_msg_to_smc_with_parameter, - .download_pptable_settings = NULL, - .upload_pptable_settings = NULL, -}; - - diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c new file mode 100644 index 000000000000..bc53f2beda30 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c @@ -0,0 +1,344 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "smumgr.h" +#include "smu10_inc.h" +#include "pp_soc15.h" +#include "smu10_smumgr.h" +#include "ppatomctrl.h" +#include "rv_ppsmc.h" +#include "smu10_driver_if.h" +#include "smu10.h" +#include "ppatomctrl.h" +#include "pp_debug.h" + + +#define VOLTAGE_SCALE 4 + +#define BUFFER_SIZE 80000 +#define MAX_STRING_SIZE 15 +#define BUFFER_SIZETWO 131072 + +#define MP0_Public 0x03800000 +#define MP0_SRAM 0x03900000 +#define MP1_Public 0x03b00000 +#define MP1_SRAM 0x03c00004 + +#define smnMP1_FIRMWARE_FLAGS 0x3010028 + + +static uint32_t smu10_wait_for_response(struct pp_hwmgr *hwmgr) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + + phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_90__CONTENT_MASK); + + return cgs_read_register(hwmgr->device, reg); +} + +static int smu10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, + uint16_t msg) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); + cgs_write_register(hwmgr->device, reg, msg); + + return 0; +} + +static int smu10_read_arg_from_smc(struct pp_hwmgr *hwmgr) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); + + return cgs_read_register(hwmgr->device, reg); +} + +static int smu10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + uint32_t reg; + + smu10_wait_for_response(hwmgr); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + cgs_write_register(hwmgr->device, reg, 0); + + smu10_send_msg_to_smc_without_waiting(hwmgr, msg); + + if (smu10_wait_for_response(hwmgr) == 0) + printk("Failed to send Message %x.\n", msg); + + return 0; +} + + +static int smu10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, + uint16_t msg, uint32_t parameter) +{ + uint32_t reg; + + smu10_wait_for_response(hwmgr); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + cgs_write_register(hwmgr->device, reg, 0); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); + cgs_write_register(hwmgr->device, reg, parameter); + + smu10_send_msg_to_smc_without_waiting(hwmgr, msg); + + + if (smu10_wait_for_response(hwmgr) == 0) + printk("Failed to send Message %x.\n", msg); + + return 0; +} + +static int smu10_copy_table_from_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id) +{ + struct smu10_smumgr *priv = + (struct smu10_smumgr *)(hwmgr->smu_backend); + + PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, + "Invalid SMU Table ID!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, + "Invalid SMU Table version!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, + "Invalid SMU Table Length!", return -EINVAL;); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrHigh, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrLow, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_TransferTableSmu2Dram, + priv->smu_tables.entry[table_id].table_id); + + memcpy(table, (uint8_t *)priv->smu_tables.entry[table_id].table, + priv->smu_tables.entry[table_id].size); + + return 0; +} + +static int smu10_copy_table_to_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id) +{ + struct smu10_smumgr *priv = + (struct smu10_smumgr *)(hwmgr->smu_backend); + + PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, + "Invalid SMU Table ID!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, + "Invalid SMU Table version!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, + "Invalid SMU Table Length!", return -EINVAL;); + + memcpy(priv->smu_tables.entry[table_id].table, table, + priv->smu_tables.entry[table_id].size); + + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrHigh, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrLow, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_TransferTableDram2Smu, + priv->smu_tables.entry[table_id].table_id); + + return 0; +} + +static int smu10_verify_smc_interface(struct pp_hwmgr *hwmgr) +{ + uint32_t smc_driver_if_version; + + smu10_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetDriverIfVersion); + smc_driver_if_version = smu10_read_arg_from_smc(hwmgr); + + if (smc_driver_if_version != SMU10_DRIVER_IF_VERSION) { + pr_err("Attempt to read SMC IF Version Number Failed!\n"); + return -EINVAL; + } + + return 0; +} + +/* sdma is disabled by default in vbios, need to re-enable in driver */ +static void smu10_smc_enable_sdma(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc(hwmgr, + PPSMC_MSG_PowerUpSdma); +} + +static void smu10_smc_disable_sdma(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc(hwmgr, + PPSMC_MSG_PowerDownSdma); +} + +/* vcn is disabled by default in vbios, need to re-enable in driver */ +static void smu10_smc_enable_vcn(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_PowerUpVcn, 0); +} + +static void smu10_smc_disable_vcn(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_PowerDownVcn, 0); +} + +static int smu10_smu_fini(struct pp_hwmgr *hwmgr) +{ + struct smu10_smumgr *priv = + (struct smu10_smumgr *)(hwmgr->smu_backend); + + if (priv) { + smu10_smc_disable_sdma(hwmgr); + smu10_smc_disable_vcn(hwmgr); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_WMTABLE].handle, + &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_WMTABLE].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_CLOCKTABLE].handle, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].table); + kfree(hwmgr->smu_backend); + hwmgr->smu_backend = NULL; + } + + return 0; +} + +static int smu10_start_smu(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion); + hwmgr->smu_version = smu10_read_arg_from_smc(hwmgr); + adev->pm.fw_version = hwmgr->smu_version >> 8; + + if (smu10_verify_smc_interface(hwmgr)) + return -EINVAL; + smu10_smc_enable_sdma(hwmgr); + smu10_smc_enable_vcn(hwmgr); + return 0; +} + +static int smu10_smu_init(struct pp_hwmgr *hwmgr) +{ + struct smu10_smumgr *priv; + int r; + + priv = kzalloc(sizeof(struct smu10_smumgr), GFP_KERNEL); + + if (!priv) + return -ENOMEM; + + hwmgr->smu_backend = priv; + + /* allocate space for watermarks table */ + r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(Watermarks_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[SMU10_WMTABLE].handle, + &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_WMTABLE].table); + + if (r) + goto err0; + + priv->smu_tables.entry[SMU10_WMTABLE].version = 0x01; + priv->smu_tables.entry[SMU10_WMTABLE].size = sizeof(Watermarks_t); + priv->smu_tables.entry[SMU10_WMTABLE].table_id = TABLE_WATERMARKS; + + /* allocate space for watermarks table */ + r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(DpmClocks_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].handle, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].table); + + if (r) + goto err1; + + priv->smu_tables.entry[SMU10_CLOCKTABLE].version = 0x01; + priv->smu_tables.entry[SMU10_CLOCKTABLE].size = sizeof(DpmClocks_t); + priv->smu_tables.entry[SMU10_CLOCKTABLE].table_id = TABLE_DPMCLOCKS; + + return 0; + +err1: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_WMTABLE].handle, + &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_WMTABLE].table); +err0: + kfree(priv); + return -EINVAL; +} + +static int smu10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw) +{ + int ret; + + if (rw) + ret = smu10_copy_table_from_smc(hwmgr, table, table_id); + else + ret = smu10_copy_table_to_smc(hwmgr, table, table_id); + + return ret; +} + + +const struct pp_smumgr_func smu10_smu_funcs = { + .smu_init = &smu10_smu_init, + .smu_fini = &smu10_smu_fini, + .start_smu = &smu10_start_smu, + .request_smu_load_specific_fw = NULL, + .send_msg_to_smc = &smu10_send_msg_to_smc, + .send_msg_to_smc_with_parameter = &smu10_send_msg_to_smc_with_parameter, + .download_pptable_settings = NULL, + .upload_pptable_settings = NULL, + .get_argument = smu10_read_arg_from_smc, + .smc_table_manager = smu10_smc_table_manager, +}; + + diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h index 0ff4ac5838f7..9c2be74a2b2f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h @@ -21,17 +21,13 @@ * */ -#ifndef PP_RAVEN_SMUMANAGER_H -#define PP_RAVEN_SMUMANAGER_H +#ifndef PP_SMU10_SMUMANAGER_H +#define PP_SMU10_SMUMANAGER_H #include "rv_ppsmc.h" #include "smu10_driver_if.h" -enum SMU_TABLE_ID { - WMTABLE = 0, - CLOCKTABLE, - MAX_SMU_TABLE, -}; +#define MAX_SMU_TABLE 2 struct smu_table_entry { uint32_t version; @@ -46,16 +42,9 @@ struct smu_table_array { struct smu_table_entry entry[MAX_SMU_TABLE]; }; -struct rv_smumgr { +struct smu10_smumgr { struct smu_table_array smu_tables; }; -int rv_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg); -bool rv_is_smc_ram_running(struct pp_hwmgr *hwmgr); -int rv_copy_table_from_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id); -int rv_copy_table_to_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id); - #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c index 7394bb46b8b2..0399c10d2be0 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c @@ -585,7 +585,6 @@ int smu7_setup_pwr_virus(struct pp_hwmgr *hwmgr) int smu7_init(struct pp_hwmgr *hwmgr) { struct smu7_smumgr *smu_data; - uint8_t *internal_buf; uint64_t mc_addr = 0; int r; /* Allocate memory for backend private data */ @@ -627,13 +626,10 @@ int smu7_init(struct pp_hwmgr *hwmgr) &smu_data->header_buffer.kaddr); return -EINVAL; } - internal_buf = smu_data->smu_buffer.kaddr; smu_data->smu_buffer.mc_addr = mc_addr; if (smum_is_hw_avfs_present(hwmgr)) - smu_data->avfs.avfs_btc_status = AVFS_BTC_BOOT; - else - smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED; + hwmgr->avfs_supported = true; return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h index 64334a82b77b..126d300259ba 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h @@ -36,11 +36,6 @@ struct smu7_buffer_entry { struct amdgpu_bo *handle; }; -struct smu7_avfs { - enum AVFS_BTC_STATUS avfs_btc_status; - uint32_t avfs_btc_param; -}; - struct smu7_smumgr { uint8_t *header; uint8_t *mec_image; @@ -55,7 +50,7 @@ struct smu7_smumgr { uint32_t ulv_setting_starts; uint8_t security_hard_key; uint32_t acpi_optimization; - struct smu7_avfs avfs; + uint32_t avfs_btc_param; }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c new file mode 100644 index 000000000000..8c49704b81af --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c @@ -0,0 +1,891 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <linux/delay.h> +#include <linux/gfp.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "cgs_common.h" +#include "smu/smu_8_0_d.h" +#include "smu/smu_8_0_sh_mask.h" +#include "smu8.h" +#include "smu8_fusion.h" +#include "smu8_smumgr.h" +#include "cz_ppsmc.h" +#include "smu_ucode_xfer_cz.h" +#include "gca/gfx_8_0_d.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "smumgr.h" + +#define SIZE_ALIGN_32(x) (((x) + 31) / 32 * 32) + +static const enum smu8_scratch_entry firmware_list[] = { + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, +}; + +static int smu8_smum_get_argument(struct pp_hwmgr *hwmgr) +{ + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + return cgs_read_register(hwmgr->device, + mmSMU_MP1_SRBM2P_ARG_0); +} + +static int smu8_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + int result = 0; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + result = PHM_WAIT_FIELD_UNEQUAL(hwmgr, + SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); + if (result != 0) { + pr_err("smu8_send_msg_to_smc_async (0x%04x) failed\n", msg); + return result; + } + + cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0); + cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg); + + return 0; +} + +/* Send a message to the SMC, and wait for its response.*/ +static int smu8_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + int result = 0; + + result = smu8_send_msg_to_smc_async(hwmgr, msg); + if (result != 0) + return result; + + return PHM_WAIT_FIELD_UNEQUAL(hwmgr, + SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); +} + +static int smu8_set_smc_sram_address(struct pp_hwmgr *hwmgr, + uint32_t smc_address, uint32_t limit) +{ + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + if (0 != (3 & smc_address)) { + pr_err("SMC address must be 4 byte aligned\n"); + return -EINVAL; + } + + if (limit <= (smc_address + 3)) { + pr_err("SMC address beyond the SMC RAM area\n"); + return -EINVAL; + } + + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX_0, + SMN_MP1_SRAM_START_ADDR + smc_address); + + return 0; +} + +static int smu8_write_smc_sram_dword(struct pp_hwmgr *hwmgr, + uint32_t smc_address, uint32_t value, uint32_t limit) +{ + int result; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + result = smu8_set_smc_sram_address(hwmgr, smc_address, limit); + if (!result) + cgs_write_register(hwmgr->device, mmMP0PUB_IND_DATA_0, value); + + return result; +} + +static int smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, + uint16_t msg, uint32_t parameter) +{ + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter); + + return smu8_send_msg_to_smc(hwmgr, msg); +} + +static int smu8_check_fw_load_finish(struct pp_hwmgr *hwmgr, + uint32_t firmware) +{ + int i; + uint32_t index = SMN_MP1_SRAM_START_ADDR + + SMU8_FIRMWARE_HEADER_LOCATION + + offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); + + for (i = 0; i < hwmgr->usec_timeout; i++) { + if (firmware == + (cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA) & firmware)) + break; + udelay(1); + } + + if (i >= hwmgr->usec_timeout) { + pr_err("SMU check loaded firmware failed.\n"); + return -EINVAL; + } + + return 0; +} + +static int smu8_load_mec_firmware(struct pp_hwmgr *hwmgr) +{ + uint32_t reg_data; + uint32_t tmp; + int ret = 0; + struct cgs_firmware_info info = {0}; + struct smu8_smumgr *smu8_smu; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + smu8_smu = hwmgr->smu_backend; + ret = cgs_get_firmware_info(hwmgr->device, + CGS_UCODE_ID_CP_MEC, &info); + + if (ret) + return -EINVAL; + + /* Disable MEC parsing/prefetching */ + tmp = cgs_read_register(hwmgr->device, + mmCP_MEC_CNTL); + tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1); + tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1); + cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, tmp); + + tmp = cgs_read_register(hwmgr->device, + mmCP_CPC_IC_BASE_CNTL); + + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0); + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0); + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0); + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1); + cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_CNTL, tmp); + + reg_data = lower_32_bits(info.mc_addr) & + PHM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO); + cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_LO, reg_data); + + reg_data = upper_32_bits(info.mc_addr) & + PHM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI); + cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_HI, reg_data); + + return 0; +} + +static uint8_t smu8_translate_firmware_enum_to_arg(struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry firmware_enum) +{ + uint8_t ret = 0; + + switch (firmware_enum) { + case SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0: + ret = UCODE_ID_SDMA0; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1: + if (hwmgr->chip_id == CHIP_STONEY) + ret = UCODE_ID_SDMA0; + else + ret = UCODE_ID_SDMA1; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE: + ret = UCODE_ID_CP_CE; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP: + ret = UCODE_ID_CP_PFP; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME: + ret = UCODE_ID_CP_ME; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1: + ret = UCODE_ID_CP_MEC_JT1; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2: + if (hwmgr->chip_id == CHIP_STONEY) + ret = UCODE_ID_CP_MEC_JT1; + else + ret = UCODE_ID_CP_MEC_JT2; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG: + ret = UCODE_ID_GMCON_RENG; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G: + ret = UCODE_ID_RLC_G; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH: + ret = UCODE_ID_RLC_SCRATCH; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM: + ret = UCODE_ID_RLC_SRM_ARAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM: + ret = UCODE_ID_RLC_SRM_DRAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM: + ret = UCODE_ID_DMCU_ERAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM: + ret = UCODE_ID_DMCU_IRAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING: + ret = TASK_ARG_INIT_MM_PWR_LOG; + break; + case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_HALT: + case SMU8_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING: + case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS: + case SMU8_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT: + case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_START: + case SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS: + ret = TASK_ARG_REG_MMIO; + break; + case SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE: + ret = TASK_ARG_INIT_CLK_TABLE; + break; + } + + return ret; +} + +static enum cgs_ucode_id smu8_convert_fw_type_to_cgs(uint32_t fw_type) +{ + enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; + + switch (fw_type) { + case UCODE_ID_SDMA0: + result = CGS_UCODE_ID_SDMA0; + break; + case UCODE_ID_SDMA1: + result = CGS_UCODE_ID_SDMA1; + break; + case UCODE_ID_CP_CE: + result = CGS_UCODE_ID_CP_CE; + break; + case UCODE_ID_CP_PFP: + result = CGS_UCODE_ID_CP_PFP; + break; + case UCODE_ID_CP_ME: + result = CGS_UCODE_ID_CP_ME; + break; + case UCODE_ID_CP_MEC_JT1: + result = CGS_UCODE_ID_CP_MEC_JT1; + break; + case UCODE_ID_CP_MEC_JT2: + result = CGS_UCODE_ID_CP_MEC_JT2; + break; + case UCODE_ID_RLC_G: + result = CGS_UCODE_ID_RLC_G; + break; + default: + break; + } + + return result; +} + +static int smu8_smu_populate_single_scratch_task( + struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry fw_enum, + uint8_t type, bool is_last) +{ + uint8_t i; + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + struct SMU_Task *task = &toc->tasks[smu8_smu->toc_entry_used_count++]; + + task->type = type; + task->arg = smu8_translate_firmware_enum_to_arg(hwmgr, fw_enum); + task->next = is_last ? END_OF_TASK_LIST : smu8_smu->toc_entry_used_count; + + for (i = 0; i < smu8_smu->scratch_buffer_length; i++) + if (smu8_smu->scratch_buffer[i].firmware_ID == fw_enum) + break; + + if (i >= smu8_smu->scratch_buffer_length) { + pr_err("Invalid Firmware Type\n"); + return -EINVAL; + } + + task->addr.low = lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr); + task->addr.high = upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr); + task->size_bytes = smu8_smu->scratch_buffer[i].data_size; + + if (SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) { + struct smu8_ih_meta_data *pIHReg_restore = + (struct smu8_ih_meta_data *)smu8_smu->scratch_buffer[i].kaddr; + pIHReg_restore->command = + METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD; + } + + return 0; +} + +static int smu8_smu_populate_single_ucode_load_task( + struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry fw_enum, + bool is_last) +{ + uint8_t i; + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + struct SMU_Task *task = &toc->tasks[smu8_smu->toc_entry_used_count++]; + + task->type = TASK_TYPE_UCODE_LOAD; + task->arg = smu8_translate_firmware_enum_to_arg(hwmgr, fw_enum); + task->next = is_last ? END_OF_TASK_LIST : smu8_smu->toc_entry_used_count; + + for (i = 0; i < smu8_smu->driver_buffer_length; i++) + if (smu8_smu->driver_buffer[i].firmware_ID == fw_enum) + break; + + if (i >= smu8_smu->driver_buffer_length) { + pr_err("Invalid Firmware Type\n"); + return -EINVAL; + } + + task->addr.low = lower_32_bits(smu8_smu->driver_buffer[i].mc_addr); + task->addr.high = upper_32_bits(smu8_smu->driver_buffer[i].mc_addr); + task->size_bytes = smu8_smu->driver_buffer[i].data_size; + + return 0; +} + +static int smu8_smu_construct_toc_for_rlc_aram_save(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_aram = smu8_smu->toc_entry_used_count; + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + TASK_TYPE_UCODE_SAVE, true); + + return 0; +} + +static int smu8_smu_initialize_toc_empty_job_list(struct pp_hwmgr *hwmgr) +{ + int i; + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + + for (i = 0; i < NUM_JOBLIST_ENTRIES; i++) + toc->JobList[i] = (uint8_t)IGNORE_JOB; + + return 0; +} + +static int smu8_smu_construct_toc_for_vddgfx_enter(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + + toc->JobList[JOB_GFX_SAVE] = (uint8_t)smu8_smu->toc_entry_used_count; + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + TASK_TYPE_UCODE_SAVE, false); + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + TASK_TYPE_UCODE_SAVE, true); + + return 0; +} + + +static int smu8_smu_construct_toc_for_vddgfx_exit(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + + toc->JobList[JOB_GFX_RESTORE] = (uint8_t)smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); + + if (hwmgr->chip_id == CHIP_STONEY) + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); + else + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); + + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, false); + + /* populate scratch */ + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + TASK_TYPE_UCODE_LOAD, false); + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + TASK_TYPE_UCODE_LOAD, false); + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + TASK_TYPE_UCODE_LOAD, true); + + return 0; +} + +static int smu8_smu_construct_toc_for_power_profiling(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_power_profiling_index = smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, + TASK_TYPE_INITIALIZE, true); + return 0; +} + +static int smu8_smu_construct_toc_for_bootup(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_initialize_index = smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0, false); + if (hwmgr->chip_id != CHIP_STONEY) + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); + if (hwmgr->chip_id != CHIP_STONEY) + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, true); + + return 0; +} + +static int smu8_smu_construct_toc_for_clock_table(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_clock_table = smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, + TASK_TYPE_INITIALIZE, true); + + return 0; +} + +static int smu8_smu_construct_toc(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_used_count = 0; + smu8_smu_initialize_toc_empty_job_list(hwmgr); + smu8_smu_construct_toc_for_rlc_aram_save(hwmgr); + smu8_smu_construct_toc_for_vddgfx_enter(hwmgr); + smu8_smu_construct_toc_for_vddgfx_exit(hwmgr); + smu8_smu_construct_toc_for_power_profiling(hwmgr); + smu8_smu_construct_toc_for_bootup(hwmgr); + smu8_smu_construct_toc_for_clock_table(hwmgr); + + return 0; +} + +static int smu8_smu_populate_firmware_entries(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + uint32_t firmware_type; + uint32_t i; + int ret; + enum cgs_ucode_id ucode_id; + struct cgs_firmware_info info = {0}; + + smu8_smu->driver_buffer_length = 0; + + for (i = 0; i < ARRAY_SIZE(firmware_list); i++) { + + firmware_type = smu8_translate_firmware_enum_to_arg(hwmgr, + firmware_list[i]); + + ucode_id = smu8_convert_fw_type_to_cgs(firmware_type); + + ret = cgs_get_firmware_info(hwmgr->device, + ucode_id, &info); + + if (ret == 0) { + smu8_smu->driver_buffer[i].mc_addr = info.mc_addr; + + smu8_smu->driver_buffer[i].data_size = info.image_size; + + smu8_smu->driver_buffer[i].firmware_ID = firmware_list[i]; + smu8_smu->driver_buffer_length++; + } + } + + return 0; +} + +static int smu8_smu_populate_single_scratch_entry( + struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry scratch_type, + uint32_t ulsize_byte, + struct smu8_buffer_entry *entry) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte); + + entry->data_size = ulsize_byte; + entry->kaddr = (char *) smu8_smu->smu_buffer.kaddr + + smu8_smu->smu_buffer_used_bytes; + entry->mc_addr = smu8_smu->smu_buffer.mc_addr + smu8_smu->smu_buffer_used_bytes; + entry->firmware_ID = scratch_type; + + smu8_smu->smu_buffer_used_bytes += ulsize_aligned; + + return 0; +} + +static int smu8_download_pptable_settings(struct pp_hwmgr *hwmgr, void **table) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + unsigned long i; + + for (i = 0; i < smu8_smu->scratch_buffer_length; i++) { + if (smu8_smu->scratch_buffer[i].firmware_ID + == SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) + break; + } + + *table = (struct SMU8_Fusion_ClkTable *)smu8_smu->scratch_buffer[i].kaddr; + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrHi, + upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrLo, + lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_clock_table); + + smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToDram); + + return 0; +} + +static int smu8_upload_pptable_settings(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + unsigned long i; + + for (i = 0; i < smu8_smu->scratch_buffer_length; i++) { + if (smu8_smu->scratch_buffer[i].firmware_ID + == SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) + break; + } + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrHi, + upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrLo, + lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_clock_table); + + smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToSmu); + + return 0; +} + +static int smu8_request_smu_load_fw(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + uint32_t smc_address; + + if (!hwmgr->reload_fw) { + pr_info("skip reloading...\n"); + return 0; + } + + smu8_smu_populate_firmware_entries(hwmgr); + + smu8_smu_construct_toc(hwmgr); + + smc_address = SMU8_FIRMWARE_HEADER_LOCATION + + offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); + + smu8_write_smc_sram_dword(hwmgr, smc_address, 0, smc_address+4); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DriverDramAddrHi, + upper_32_bits(smu8_smu->toc_buffer.mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DriverDramAddrLo, + lower_32_bits(smu8_smu->toc_buffer.mc_addr)); + + smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_InitJobs); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_aram); + smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_power_profiling_index); + + return smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_initialize_index); +} + +static int smu8_start_smu(struct pp_hwmgr *hwmgr) +{ + int ret = 0; + uint32_t fw_to_check = 0; + struct amdgpu_device *adev = hwmgr->adev; + + uint32_t index = SMN_MP1_SRAM_START_ADDR + + SMU8_FIRMWARE_HEADER_LOCATION + + offsetof(struct SMU8_Firmware_Header, Version); + + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); + hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); + adev->pm.fw_version = hwmgr->smu_version >> 8; + + fw_to_check = UCODE_ID_RLC_G_MASK | + UCODE_ID_SDMA0_MASK | + UCODE_ID_SDMA1_MASK | + UCODE_ID_CP_CE_MASK | + UCODE_ID_CP_ME_MASK | + UCODE_ID_CP_PFP_MASK | + UCODE_ID_CP_MEC_JT1_MASK | + UCODE_ID_CP_MEC_JT2_MASK; + + if (hwmgr->chip_id == CHIP_STONEY) + fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK); + + ret = smu8_request_smu_load_fw(hwmgr); + if (ret) + pr_err("SMU firmware load failed\n"); + + smu8_check_fw_load_finish(hwmgr, fw_to_check); + + ret = smu8_load_mec_firmware(hwmgr); + if (ret) + pr_err("Mec Firmware load failed\n"); + + return ret; +} + +static int smu8_smu_init(struct pp_hwmgr *hwmgr) +{ + int ret = 0; + struct smu8_smumgr *smu8_smu; + + smu8_smu = kzalloc(sizeof(struct smu8_smumgr), GFP_KERNEL); + if (smu8_smu == NULL) + return -ENOMEM; + + hwmgr->smu_backend = smu8_smu; + + smu8_smu->toc_buffer.data_size = 4096; + smu8_smu->smu_buffer.data_size = + ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) + + ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) + + ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) + + ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) + + ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32); + + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + smu8_smu->toc_buffer.data_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &smu8_smu->toc_buffer.handle, + &smu8_smu->toc_buffer.mc_addr, + &smu8_smu->toc_buffer.kaddr); + if (ret) + goto err2; + + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + smu8_smu->smu_buffer.data_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &smu8_smu->smu_buffer.handle, + &smu8_smu->smu_buffer.mc_addr, + &smu8_smu->smu_buffer.kaddr); + if (ret) + goto err1; + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + UCODE_ID_RLC_SCRATCH_SIZE_BYTE, + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, + sizeof(struct SMU8_MultimediaPowerLogData), + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, + sizeof(struct SMU8_Fusion_ClkTable), + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + return 0; + +err0: + amdgpu_bo_free_kernel(&smu8_smu->smu_buffer.handle, + &smu8_smu->smu_buffer.mc_addr, + &smu8_smu->smu_buffer.kaddr); +err1: + amdgpu_bo_free_kernel(&smu8_smu->toc_buffer.handle, + &smu8_smu->toc_buffer.mc_addr, + &smu8_smu->toc_buffer.kaddr); +err2: + kfree(smu8_smu); + return -EINVAL; +} + +static int smu8_smu_fini(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + smu8_smu = hwmgr->smu_backend; + if (smu8_smu) { + amdgpu_bo_free_kernel(&smu8_smu->toc_buffer.handle, + &smu8_smu->toc_buffer.mc_addr, + &smu8_smu->toc_buffer.kaddr); + amdgpu_bo_free_kernel(&smu8_smu->smu_buffer.handle, + &smu8_smu->smu_buffer.mc_addr, + &smu8_smu->smu_buffer.kaddr); + kfree(smu8_smu); + } + + return 0; +} + +static bool smu8_dpm_check_smu_features(struct pp_hwmgr *hwmgr, + unsigned long check_feature) +{ + int result; + unsigned long features; + + result = smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetFeatureStatus, 0); + if (result == 0) { + features = smum_get_argument(hwmgr); + if (features & check_feature) + return true; + } + + return false; +} + +static bool smu8_is_dpm_running(struct pp_hwmgr *hwmgr) +{ + if (smu8_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn)) + return true; + return false; +} + +const struct pp_smumgr_func smu8_smu_funcs = { + .smu_init = smu8_smu_init, + .smu_fini = smu8_smu_fini, + .start_smu = smu8_start_smu, + .check_fw_load_finish = smu8_check_fw_load_finish, + .request_smu_load_fw = NULL, + .request_smu_load_specific_fw = NULL, + .get_argument = smu8_smum_get_argument, + .send_msg_to_smc = smu8_send_msg_to_smc, + .send_msg_to_smc_with_parameter = smu8_send_msg_to_smc_with_parameter, + .download_pptable_settings = smu8_download_pptable_settings, + .upload_pptable_settings = smu8_upload_pptable_settings, + .is_dpm_running = smu8_is_dpm_running, +}; + diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.h index c13ab8377e26..c7b61222d258 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.h @@ -20,63 +20,63 @@ * OTHER DEALINGS IN THE SOFTWARE. * */ -#ifndef _CZ_SMUMGR_H_ -#define _CZ_SMUMGR_H_ +#ifndef _SMU8_SMUMGR_H_ +#define _SMU8_SMUMGR_H_ #define MAX_NUM_FIRMWARE 8 #define MAX_NUM_SCRATCH 11 -#define CZ_SCRATCH_SIZE_NONGFX_CLOCKGATING 1024 -#define CZ_SCRATCH_SIZE_NONGFX_GOLDENSETTING 2048 -#define CZ_SCRATCH_SIZE_SDMA_METADATA 1024 -#define CZ_SCRATCH_SIZE_IH ((2*256+1)*4) +#define SMU8_SCRATCH_SIZE_NONGFX_CLOCKGATING 1024 +#define SMU8_SCRATCH_SIZE_NONGFX_GOLDENSETTING 2048 +#define SMU8_SCRATCH_SIZE_SDMA_METADATA 1024 +#define SMU8_SCRATCH_SIZE_IH ((2*256+1)*4) #define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 -enum cz_scratch_entry { - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, - CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM, - CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM, - CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, - CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT, - CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING, - CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS, - CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT, - CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START, - CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS, - CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE +enum smu8_scratch_entry { + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, + SMU8_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, + SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_HALT, + SMU8_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING, + SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS, + SMU8_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT, + SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_START, + SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS, + SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE }; -struct cz_buffer_entry { +struct smu8_buffer_entry { uint32_t data_size; uint64_t mc_addr; void *kaddr; - enum cz_scratch_entry firmware_ID; + enum smu8_scratch_entry firmware_ID; struct amdgpu_bo *handle; /* as bo handle used when release bo */ }; -struct cz_register_index_data_pair { +struct smu8_register_index_data_pair { uint32_t offset; uint32_t value; }; -struct cz_ih_meta_data { +struct smu8_ih_meta_data { uint32_t command; - struct cz_register_index_data_pair register_index_value_pair[1]; + struct smu8_register_index_data_pair register_index_value_pair[1]; }; -struct cz_smumgr { +struct smu8_smumgr { uint8_t driver_buffer_length; uint8_t scratch_buffer_length; uint16_t toc_entry_used_count; @@ -88,12 +88,12 @@ struct cz_smumgr { uint16_t ih_register_restore_task_size; uint16_t smu_buffer_used_bytes; - struct cz_buffer_entry toc_buffer; - struct cz_buffer_entry smu_buffer; - struct cz_buffer_entry firmware_buffer; - struct cz_buffer_entry driver_buffer[MAX_NUM_FIRMWARE]; - struct cz_buffer_entry meta_data_buffer[MAX_NUM_FIRMWARE]; - struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH]; + struct smu8_buffer_entry toc_buffer; + struct smu8_buffer_entry smu_buffer; + struct smu8_buffer_entry firmware_buffer; + struct smu8_buffer_entry driver_buffer[MAX_NUM_FIRMWARE]; + struct smu8_buffer_entry meta_data_buffer[MAX_NUM_FIRMWARE]; + struct smu8_buffer_entry scratch_buffer[MAX_NUM_SCRATCH]; }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index 3645127c8ee2..04c45c236a73 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c @@ -28,7 +28,6 @@ #include <linux/types.h> #include <drm/amdgpu_drm.h> #include "smumgr.h" -#include "cgs_common.h" MODULE_FIRMWARE("amdgpu/topaz_smc.bin"); MODULE_FIRMWARE("amdgpu/topaz_k_smc.bin"); @@ -200,3 +199,11 @@ int smum_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting) return -EINVAL; } + +int smum_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw) +{ + if (hwmgr->smumgr_funcs->smc_table_manager) + return hwmgr->smumgr_funcs->smc_table_manager(hwmgr, table, table_id, rw); + + return -EINVAL; +} diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 39d6f4ef96ce..26cca8cce8f1 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -229,8 +229,10 @@ static int tonga_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = tonga_priv; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(tonga_priv); return -EINVAL; + } return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index 15e1afa28018..e08a6116ac05 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -27,11 +27,9 @@ #include "vega10_smumgr.h" #include "vega10_ppsmc.h" #include "smu9_driver_if.h" - #include "ppatomctrl.h" #include "pp_debug.h" -#include "smu_ucode_xfer_vi.h" -#include "smu7_smumgr.h" + #define AVFS_EN_MSB 1568 #define AVFS_EN_LSB 1568 @@ -377,16 +375,13 @@ static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) static int vega10_smu_init(struct pp_hwmgr *hwmgr) { - struct amdgpu_bo *handle = NULL; struct vega10_smumgr *priv; - uint64_t mc_addr; - void *kaddr = NULL; unsigned long tools_size; int ret; struct cgs_firmware_info info = {0}; ret = cgs_get_firmware_info(hwmgr->device, - smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), + CGS_UCODE_ID_SMU, &info); if (ret || !info.kptr) return -EINVAL; @@ -403,28 +398,24 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr) sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, - &handle, - &mc_addr, - &kaddr); - + &priv->smu_tables.entry[PPTABLE].handle, + &priv->smu_tables.entry[PPTABLE].mc_addr, + &priv->smu_tables.entry[PPTABLE].table); if (ret) - return -EINVAL; + goto free_backend; priv->smu_tables.entry[PPTABLE].version = 0x01; priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; - priv->smu_tables.entry[PPTABLE].mc_addr = mc_addr; - priv->smu_tables.entry[PPTABLE].table = kaddr; - priv->smu_tables.entry[PPTABLE].handle = handle; /* allocate space for watermarks table */ ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, - &handle, - &mc_addr, - &kaddr); + &priv->smu_tables.entry[WMTABLE].handle, + &priv->smu_tables.entry[WMTABLE].mc_addr, + &priv->smu_tables.entry[WMTABLE].table); if (ret) goto err0; @@ -432,18 +423,15 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr) priv->smu_tables.entry[WMTABLE].version = 0x01; priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; - priv->smu_tables.entry[WMTABLE].mc_addr = mc_addr; - priv->smu_tables.entry[WMTABLE].table = kaddr; - priv->smu_tables.entry[WMTABLE].handle = handle; /* allocate space for AVFS table */ ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, sizeof(AvfsTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, - &handle, - &mc_addr, - &kaddr); + &priv->smu_tables.entry[AVFSTABLE].handle, + &priv->smu_tables.entry[AVFSTABLE].mc_addr, + &priv->smu_tables.entry[AVFSTABLE].table); if (ret) goto err1; @@ -451,9 +439,6 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr) priv->smu_tables.entry[AVFSTABLE].version = 0x01; priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; - priv->smu_tables.entry[AVFSTABLE].mc_addr = mc_addr; - priv->smu_tables.entry[AVFSTABLE].table = kaddr; - priv->smu_tables.entry[AVFSTABLE].handle = handle; tools_size = 0x19000; if (tools_size) { @@ -461,17 +446,14 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr) tools_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, - &handle, - &mc_addr, - &kaddr); + &priv->smu_tables.entry[TOOLSTABLE].handle, + &priv->smu_tables.entry[TOOLSTABLE].mc_addr, + &priv->smu_tables.entry[TOOLSTABLE].table); if (ret) goto err2; priv->smu_tables.entry[TOOLSTABLE].version = 0x01; priv->smu_tables.entry[TOOLSTABLE].size = tools_size; priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; - priv->smu_tables.entry[TOOLSTABLE].mc_addr = mc_addr; - priv->smu_tables.entry[TOOLSTABLE].table = kaddr; - priv->smu_tables.entry[TOOLSTABLE].handle = handle; } /* allocate space for AVFS Fuse table */ @@ -479,18 +461,16 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr) sizeof(AvfsFuseOverride_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, - &handle, - &mc_addr, - &kaddr); + &priv->smu_tables.entry[AVFSFUSETABLE].handle, + &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, + &priv->smu_tables.entry[AVFSFUSETABLE].table); if (ret) goto err3; priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01; priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t); priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE; - priv->smu_tables.entry[AVFSFUSETABLE].mc_addr = mc_addr; - priv->smu_tables.entry[AVFSFUSETABLE].table = kaddr; - priv->smu_tables.entry[AVFSFUSETABLE].handle = handle; + return 0; @@ -511,6 +491,9 @@ err0: amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, &priv->smu_tables.entry[PPTABLE].mc_addr, &priv->smu_tables.entry[PPTABLE].table); +free_backend: + kfree(hwmgr->smu_backend); + return -EINVAL; } diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 904fff80917b..fcc62bc60f6a 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -288,8 +288,14 @@ static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc, s->enhancer_enable = ((h_upscale_factor >> 16) >= 2 || (v_upscale_factor >> 16) >= 2); - s->input_w = pstate->src_w >> 16; - s->input_h = pstate->src_h >> 16; + if (pstate->rotation & MALIDP_ROTATED_MASK) { + s->input_w = pstate->src_h >> 16; + s->input_h = pstate->src_w >> 16; + } else { + s->input_w = pstate->src_w >> 16; + s->input_h = pstate->src_h >> 16; + } + s->output_w = pstate->crtc_w; s->output_h = pstate->crtc_h; @@ -525,14 +531,13 @@ int malidp_crtc_init(struct drm_device *drm) if (!primary) { DRM_ERROR("no primary plane found\n"); - ret = -EINVAL; - goto crtc_cleanup_planes; + return -EINVAL; } ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL, &malidp_crtc_funcs, NULL); if (ret) - goto crtc_cleanup_planes; + return ret; drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(&malidp->crtc, MALIDP_GAMMA_LUT_SIZE); @@ -542,9 +547,4 @@ int malidp_crtc_init(struct drm_device *drm) malidp_se_set_enh_coeffs(malidp->dev); return 0; - -crtc_cleanup_planes: - malidp_de_planes_destroy(drm); - - return ret; } diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 3d82712d8002..8d20faa198cf 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -185,25 +185,29 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm) static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) { - struct drm_pending_vblank_event *event; struct drm_device *drm = state->dev; struct malidp_drm *malidp = drm->dev_private; - if (malidp->crtc.enabled) { - /* only set config_valid if the CRTC is enabled */ - if (malidp_set_and_wait_config_valid(drm)) - DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n"); - } + malidp->event = malidp->crtc.state->event; + malidp->crtc.state->event = NULL; - event = malidp->crtc.state->event; - if (event) { - malidp->crtc.state->event = NULL; + if (malidp->crtc.state->active) { + /* + * if we have an event to deliver to userspace, make sure + * the vblank is enabled as we are sending it from the IRQ + * handler. + */ + if (malidp->event) + drm_crtc_vblank_get(&malidp->crtc); + /* only set config_valid if the CRTC is enabled */ + if (malidp_set_and_wait_config_valid(drm) < 0) + DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n"); + } else if (malidp->event) { + /* CRTC inactive means vblank IRQ is disabled, send event directly */ spin_lock_irq(&drm->event_lock); - if (drm_crtc_vblank_get(&malidp->crtc) == 0) - drm_crtc_arm_vblank_event(&malidp->crtc, event); - else - drm_crtc_send_vblank_event(&malidp->crtc, event); + drm_crtc_send_vblank_event(&malidp->crtc, malidp->event); + malidp->event = NULL; spin_unlock_irq(&drm->event_lock); } drm_atomic_helper_commit_hw_done(state); @@ -232,8 +236,6 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) malidp_atomic_commit_hw_done(state); - drm_atomic_helper_wait_for_vblanks(drm, state); - pm_runtime_put(drm->dev); drm_atomic_helper_cleanup_planes(drm, state); @@ -276,7 +278,7 @@ static int malidp_init(struct drm_device *drm) static void malidp_fini(struct drm_device *drm) { - malidp_de_planes_destroy(drm); + drm_atomic_helper_shutdown(drm); drm_mode_config_cleanup(drm); } @@ -312,13 +314,26 @@ static int malidp_irq_init(struct platform_device *pdev) DEFINE_DRM_GEM_CMA_FOPS(fops); +static int malidp_dumb_create(struct drm_file *file_priv, + struct drm_device *drm, + struct drm_mode_create_dumb *args) +{ + struct malidp_drm *malidp = drm->dev_private; + /* allocate for the worst case scenario, i.e. rotated buffers */ + u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 1); + + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), alignment); + + return drm_gem_cma_dumb_create_internal(file_priv, drm, args); +} + static struct drm_driver malidp_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_PRIME, .lastclose = drm_fb_helper_lastclose, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, - .dumb_create = drm_gem_cma_dumb_create, + .dumb_create = malidp_dumb_create, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = drm_gem_prime_export, @@ -662,8 +677,10 @@ static void malidp_unbind(struct device *dev) drm_fb_cma_fbdev_fini(drm); drm_kms_helper_poll_fini(drm); pm_runtime_get_sync(dev); + drm_crtc_vblank_off(&malidp->crtc); malidp_se_irq_fini(drm); malidp_de_irq_fini(drm); + drm->irq_enabled = false; component_unbind_all(dev, drm); of_node_put(malidp->crtc.port); malidp->crtc.port = NULL; diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index e0d12c9fc6b8..c70989b93387 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -22,6 +22,7 @@ struct malidp_drm { struct malidp_hw_device *dev; struct drm_crtc crtc; wait_queue_head_t wq; + struct drm_pending_vblank_event *event; atomic_t config_valid; u32 core_id; }; @@ -59,7 +60,6 @@ struct malidp_crtc_state { #define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base) int malidp_de_planes_init(struct drm_device *drm); -void malidp_de_planes_destroy(struct drm_device *drm); int malidp_crtc_init(struct drm_device *drm); /* often used combination of rotational bits */ diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 2bfb542135ac..d789b46dc817 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -75,16 +75,16 @@ static const struct malidp_format_id malidp550_de_formats[] = { }; static const struct malidp_layer malidp500_layers[] = { - { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0 }, - { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE }, - { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE }, + { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB }, + { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, + { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, }; static const struct malidp_layer malidp550_layers[] = { - { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0 }, - { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE }, - { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0 }, - { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE }, + { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, + { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, + { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, + { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 }, }; #define SE_N_SCALING_COEFFS 96 @@ -782,9 +782,15 @@ static irqreturn_t malidp_de_irq(int irq, void *arg) /* first handle the config valid IRQ */ dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); if (dc_status & hw->map.dc_irq_map.vsync_irq) { - /* we have a page flip event */ - atomic_set(&malidp->config_valid, 1); malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status); + /* do we have a page flip event? */ + if (malidp->event != NULL) { + spin_lock(&drm->event_lock); + drm_crtc_send_vblank_event(&malidp->crtc, malidp->event); + malidp->event = NULL; + spin_unlock(&drm->event_lock); + } + atomic_set(&malidp->config_valid, 1); ret = IRQ_WAKE_THREAD; } @@ -794,7 +800,7 @@ static irqreturn_t malidp_de_irq(int irq, void *arg) mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ); status &= mask; - if (status & de->vsync_irq) + if ((status & de->vsync_irq) && malidp->crtc.enabled) drm_crtc_handle_vblank(&malidp->crtc); malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status); diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index b0690ebb3565..b5dd6c73ec9f 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -58,7 +58,8 @@ struct malidp_layer { u16 id; /* layer ID */ u16 base; /* address offset for the register bank */ u16 ptr; /* address offset for the pointer register */ - u16 stride_offset; /* Offset to the first stride register. */ + u16 stride_offset; /* offset to the first stride register. */ + s16 yuv2rgb_offset; /* offset to the YUV->RGB matrix entries */ }; enum malidp_scaling_coeff_set { @@ -285,10 +286,16 @@ void malidp_se_irq_fini(struct drm_device *drm); u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, u8 layer_id, u32 format); -static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev, - unsigned int pitch) +static inline u8 malidp_hw_get_pitch_align(struct malidp_hw_device *hwdev, bool rotated) { - return !(pitch & (hwdev->hw->map.bus_align_bytes - 1)); + /* + * only hardware that cannot do 8 bytes bus alignments have further + * constraints on rotated planes + */ + if (hwdev->hw->map.bus_align_bytes == 8) + return 8; + else + return hwdev->hw->map.bus_align_bytes << (rotated ? 2 : 0); } /* U16.16 */ diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index ee32361c87ac..7a44897c50fe 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -35,6 +35,9 @@ #define LAYER_COMP_MASK (0x3 << 12) #define LAYER_COMP_PIXEL (0x3 << 12) #define LAYER_COMP_PLANE (0x2 << 12) +#define LAYER_ALPHA_OFFSET (16) +#define LAYER_ALPHA_MASK (0xff) +#define LAYER_ALPHA(x) (((x) & LAYER_ALPHA_MASK) << LAYER_ALPHA_OFFSET) #define MALIDP_LAYER_COMPOSE 0x008 #define MALIDP_LAYER_SIZE 0x00c #define LAYER_H_VAL(x) (((x) & 0x1fff) << 0) @@ -56,12 +59,8 @@ static void malidp_de_plane_destroy(struct drm_plane *plane) { struct malidp_plane *mp = to_malidp_plane(plane); - if (mp->base.fb) - drm_framebuffer_put(mp->base.fb); - - drm_plane_helper_disable(plane); drm_plane_cleanup(plane); - devm_kfree(plane->dev->dev, mp); + kfree(mp); } /* @@ -147,13 +146,21 @@ static int malidp_se_check_scaling(struct malidp_plane *mp, if (!crtc_state) return -EINVAL; + mc = to_malidp_crtc_state(crtc_state); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0, INT_MAX, true, true); if (ret) return ret; - src_w = state->src_w >> 16; - src_h = state->src_h >> 16; + if (state->rotation & MALIDP_ROTATED_MASK) { + src_w = state->src_h >> 16; + src_h = state->src_w >> 16; + } else { + src_w = state->src_w >> 16; + src_h = state->src_h >> 16; + } + if ((state->crtc_w == src_w) && (state->crtc_h == src_h)) { /* Scaling not necessary for this plane. */ mc->scaled_planes_mask &= ~(mp->layer->id); @@ -163,8 +170,6 @@ static int malidp_se_check_scaling(struct malidp_plane *mp, if (mp->layer->id & (DE_SMART | DE_GRAPHICS2)) return -EINVAL; - mc = to_malidp_crtc_state(crtc_state); - mc->scaled_planes_mask |= mp->layer->id; /* Defer scaling requirements calculation to the crtc check. */ return 0; @@ -175,6 +180,7 @@ static int malidp_de_plane_check(struct drm_plane *plane, { struct malidp_plane *mp = to_malidp_plane(plane); struct malidp_plane_state *ms = to_malidp_plane_state(state); + bool rotated = state->rotation & MALIDP_ROTATED_MASK; struct drm_framebuffer *fb; int i, ret; @@ -191,7 +197,8 @@ static int malidp_de_plane_check(struct drm_plane *plane, ms->n_planes = fb->format->num_planes; for (i = 0; i < ms->n_planes; i++) { - if (!malidp_hw_pitch_valid(mp->hwdev, fb->pitches[i])) { + u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated); + if (fb->pitches[i] & (alignment - 1)) { DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n", fb->pitches[i], i); return -EINVAL; @@ -259,6 +266,60 @@ static void malidp_de_set_plane_pitches(struct malidp_plane *mp, mp->layer->stride_offset + i * 4); } +static const s16 +malidp_yuv2rgb_coeffs[][DRM_COLOR_RANGE_MAX][MALIDP_COLORADJ_NUM_COEFFS] = { + [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = { + 1192, 0, 1634, + 1192, -401, -832, + 1192, 2066, 0, + 64, 512, 512 + }, + [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = { + 1024, 0, 1436, + 1024, -352, -731, + 1024, 1815, 0, + 0, 512, 512 + }, + [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = { + 1192, 0, 1836, + 1192, -218, -546, + 1192, 2163, 0, + 64, 512, 512 + }, + [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = { + 1024, 0, 1613, + 1024, -192, -479, + 1024, 1900, 0, + 0, 512, 512 + }, + [DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_LIMITED_RANGE] = { + 1024, 0, 1476, + 1024, -165, -572, + 1024, 1884, 0, + 0, 512, 512 + }, + [DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_FULL_RANGE] = { + 1024, 0, 1510, + 1024, -168, -585, + 1024, 1927, 0, + 0, 512, 512 + } +}; + +static void malidp_de_set_color_encoding(struct malidp_plane *plane, + enum drm_color_encoding enc, + enum drm_color_range range) +{ + unsigned int i; + + for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) { + /* coefficients are signed, two's complement values */ + malidp_hw_write(plane->hwdev, malidp_yuv2rgb_coeffs[enc][range][i], + plane->layer->base + plane->layer->yuv2rgb_offset + + i * 4); + } +} + static void malidp_de_plane_update(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -266,6 +327,7 @@ static void malidp_de_plane_update(struct drm_plane *plane, struct malidp_plane_state *ms = to_malidp_plane_state(plane->state); u32 src_w, src_h, dest_w, dest_h, val; int i; + bool format_has_alpha = plane->state->fb->format->has_alpha; mp = to_malidp_plane(plane); @@ -289,6 +351,11 @@ static void malidp_de_plane_update(struct drm_plane *plane, malidp_de_set_plane_pitches(mp, ms->n_planes, plane->state->fb->pitches); + if ((plane->state->color_encoding != old_state->color_encoding) || + (plane->state->color_range != old_state->color_range)) + malidp_de_set_color_encoding(mp, plane->state->color_encoding, + plane->state->color_range); + malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h), mp->layer->base + MALIDP_LAYER_SIZE); @@ -317,12 +384,25 @@ static void malidp_de_plane_update(struct drm_plane *plane, if (plane->state->rotation & DRM_MODE_REFLECT_Y) val |= LAYER_V_FLIP; - /* - * always enable pixel alpha blending until we have a way to change - * blend modes - */ val &= ~LAYER_COMP_MASK; - val |= LAYER_COMP_PIXEL; + if (format_has_alpha) { + + /* + * always enable pixel alpha blending until we have a way + * to change blend modes + */ + val |= LAYER_COMP_PIXEL; + } else { + + /* + * do not enable pixel alpha blending as the color channel + * does not have any alpha information + */ + val |= LAYER_COMP_PLANE; + + /* Set layer alpha coefficient to 0xff ie fully opaque */ + val |= LAYER_ALPHA(0xff); + } val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK); if (plane->state->crtc) { @@ -417,6 +497,26 @@ int malidp_de_planes_init(struct drm_device *drm) drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, flags); malidp_hw_write(malidp->dev, MALIDP_ALPHA_LUT, plane->layer->base + MALIDP_LAYER_COMPOSE); + + /* Attach the YUV->RGB property only to video layers */ + if (id & (DE_VIDEO1 | DE_VIDEO2)) { + /* default encoding for YUV->RGB is BT601 NARROW */ + enum drm_color_encoding enc = DRM_COLOR_YCBCR_BT601; + enum drm_color_range range = DRM_COLOR_YCBCR_LIMITED_RANGE; + + ret = drm_plane_create_color_properties(&plane->base, + BIT(DRM_COLOR_YCBCR_BT601) | \ + BIT(DRM_COLOR_YCBCR_BT709) | \ + BIT(DRM_COLOR_YCBCR_BT2020), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | \ + BIT(DRM_COLOR_YCBCR_FULL_RANGE), + enc, range); + if (!ret) + /* program the HW registers */ + malidp_de_set_color_encoding(plane, enc, range); + else + DRM_WARN("Failed to create video layer %d color properties\n", id); + } } kfree(formats); @@ -424,18 +524,7 @@ int malidp_de_planes_init(struct drm_device *drm) return 0; cleanup: - malidp_de_planes_destroy(drm); kfree(formats); return ret; } - -void malidp_de_planes_destroy(struct drm_device *drm) -{ - struct drm_plane *p, *pt; - - list_for_each_entry_safe(p, pt, &drm->mode_config.plane_list, head) { - drm_plane_cleanup(p); - kfree(p); - } -} diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 2039f857f77d..149024fb4432 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -170,10 +170,7 @@ #define MALIDP500_CONFIG_3D 0x00038 #define MALIDP500_BGND_COLOR 0x0003c #define MALIDP500_OUTPUT_DEPTH 0x00044 -#define MALIDP500_YUV_RGB_COEF 0x00048 -#define MALIDP500_COLOR_ADJ_COEF 0x00078 -#define MALIDP500_COEF_TABLE_ADDR 0x000a8 -#define MALIDP500_COEF_TABLE_DATA 0x000ac +#define MALIDP500_COEFFS_BASE 0x00078 /* * The YUV2RGB coefficients on the DP500 are not in the video layer's register @@ -181,11 +178,6 @@ * the negative offset. */ #define MALIDP500_LV_YUV2RGB ((s16)(-0xB8)) -/* - * To match DP550/650, the start of the coeffs registers is - * at COLORADJ_COEFF0 instead of at YUV_RGB_COEF1. - */ -#define MALIDP500_COEFFS_BASE 0x00078 #define MALIDP500_DE_LV_BASE 0x00100 #define MALIDP500_DE_LV_PTR_BASE 0x00124 #define MALIDP500_DE_LG1_BASE 0x00200 @@ -213,6 +205,7 @@ #define MALIDP550_DE_BGND_COLOR 0x00044 #define MALIDP550_DE_OUTPUT_DEPTH 0x0004c #define MALIDP550_COEFFS_BASE 0x00050 +#define MALIDP550_LV_YUV2RGB 0x00084 #define MALIDP550_DE_LV1_BASE 0x00100 #define MALIDP550_DE_LV1_PTR_BASE 0x00124 #define MALIDP550_DE_LV2_BASE 0x00200 diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 211224f6bdd3..fe354ebf374d 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -199,8 +199,8 @@ static struct ttm_backend_func ast_tt_backend_func = { }; -static struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +static struct ttm_tt *ast_ttm_tt_create(struct ttm_buffer_object *bo, + uint32_t page_flags) { struct ttm_tt *tt; @@ -208,7 +208,7 @@ static struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &ast_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags)) { + if (ttm_tt_init(tt, bo, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 18b95329f631..39cd08416773 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -176,8 +176,7 @@ static struct ttm_backend_func bochs_tt_backend_func = { .destroy = &bochs_ttm_backend_destroy, }; -static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, +static struct ttm_tt *bochs_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags) { struct ttm_tt *tt; @@ -186,7 +185,7 @@ static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &bochs_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags)) { + if (ttm_tt_init(tt, bo, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index a693ab3078f0..5c52307146c7 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/of_gpio.h> @@ -35,6 +36,8 @@ #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) +static const bool verify_fast_training; + struct bridge_init { struct i2c_client *client; struct device_node *node; @@ -98,18 +101,18 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -int analogix_dp_psr_supported(struct analogix_dp_device *dp) +int analogix_dp_psr_enabled(struct analogix_dp_device *dp) { - return dp->psr_support; + return dp->psr_enable; } -EXPORT_SYMBOL_GPL(analogix_dp_psr_supported); +EXPORT_SYMBOL_GPL(analogix_dp_psr_enabled); int analogix_dp_enable_psr(struct analogix_dp_device *dp) { struct edp_vsc_psr psr_vsc; - if (!dp->psr_support) + if (!dp->psr_enable) return 0; /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ @@ -122,8 +125,7 @@ int analogix_dp_enable_psr(struct analogix_dp_device *dp) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_vsc, true); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -132,7 +134,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp) struct edp_vsc_psr psr_vsc; int ret; - if (!dp->psr_support) + if (!dp->psr_enable) return 0; /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ @@ -149,8 +151,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp) if (ret != 1) dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret); - analogix_dp_send_psr_spd(dp, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_vsc, false); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); @@ -530,7 +531,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) { int lane, lane_count, retval; u32 reg; - u8 link_align, link_status[2], adjust_request[2]; + u8 link_align, link_status[2], adjust_request[2], spread; usleep_range(400, 401); @@ -573,6 +574,20 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) dev_dbg(dp->dev, "final lane count = %.2x\n", dp->link_train.lane_count); + retval = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, + &spread); + if (retval != 1) { + dev_err(dp->dev, "failed to read downspread %d\n", + retval); + dp->fast_train_support = false; + } else { + dp->fast_train_support = + (spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING) ? + true : false; + } + dev_dbg(dp->dev, "fast link training %s\n", + dp->fast_train_support ? "supported" : "unsupported"); + /* set enhanced mode if available */ analogix_dp_set_enhanced_mode(dp); dp->link_train.lt_state = FINISHED; @@ -629,10 +644,12 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, *lane_count = DPCD_MAX_LANE_COUNT(data); } -static void analogix_dp_init_training(struct analogix_dp_device *dp, - enum link_lane_count_type max_lane, - int max_rate) +static int analogix_dp_full_link_train(struct analogix_dp_device *dp, + u32 max_lanes, u32 max_rate) { + int retval = 0; + bool training_finished = false; + /* * MACRO_RST must be applied after the PLL_LOCK to avoid * the DP inter pair skew issue for at least 10 us @@ -658,18 +675,13 @@ static void analogix_dp_init_training(struct analogix_dp_device *dp, } /* Setup TX lane count & rate */ - if (dp->link_train.lane_count > max_lane) - dp->link_train.lane_count = max_lane; + if (dp->link_train.lane_count > max_lanes) + dp->link_train.lane_count = max_lanes; if (dp->link_train.link_rate > max_rate) dp->link_train.link_rate = max_rate; /* All DP analog module power up */ analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); -} - -static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) -{ - int retval = 0, training_finished = 0; dp->link_train.lt_state = START; @@ -704,22 +716,88 @@ static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) return retval; } -static int analogix_dp_set_link_train(struct analogix_dp_device *dp, - u32 count, u32 bwtype) +static int analogix_dp_fast_link_train(struct analogix_dp_device *dp) { - int i; - int retval; + int i, ret; + u8 link_align, link_status[2]; + enum pll_status status; - for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) { - analogix_dp_init_training(dp, count, bwtype); - retval = analogix_dp_sw_link_training(dp); - if (retval == 0) - break; + analogix_dp_reset_macro(dp); + + analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); + analogix_dp_set_lane_count(dp, dp->link_train.lane_count); - usleep_range(100, 110); + for (i = 0; i < dp->link_train.lane_count; i++) { + analogix_dp_set_lane_link_training(dp, + dp->link_train.training_lane[i], i); } - return retval; + ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status, + status != PLL_UNLOCKED, 120, + 120 * DP_TIMEOUT_LOOP_COUNT); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", ret); + return ret; + } + + /* source Set training pattern 1 */ + analogix_dp_set_training_pattern(dp, TRAINING_PTN1); + /* From DP spec, pattern must be on-screen for a minimum 500us */ + usleep_range(500, 600); + + analogix_dp_set_training_pattern(dp, TRAINING_PTN2); + /* From DP spec, pattern must be on-screen for a minimum 500us */ + usleep_range(500, 600); + + /* TODO: enhanced_mode?*/ + analogix_dp_set_training_pattern(dp, DP_NONE); + + /* + * Useful for debugging issues with fast link training, disable for more + * speed + */ + if (verify_fast_training) { + ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, + &link_align); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "Read align status failed %d\n", + ret); + return ret; + } + + ret = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, + 2); + if (ret < 0) { + DRM_DEV_ERROR(dp->dev, "Read link status failed %d\n", + ret); + return ret; + } + + if (analogix_dp_clock_recovery_ok(link_status, + dp->link_train.lane_count)) { + DRM_DEV_ERROR(dp->dev, "Clock recovery failed\n"); + analogix_dp_reduce_link_rate(dp); + return -EIO; + } + + if (analogix_dp_channel_eq_ok(link_status, link_align, + dp->link_train.lane_count)) { + DRM_DEV_ERROR(dp->dev, "Channel EQ failed\n"); + analogix_dp_reduce_link_rate(dp); + return -EIO; + } + } + + return 0; +} + +static int analogix_dp_train_link(struct analogix_dp_device *dp) +{ + if (dp->fast_train_support) + return analogix_dp_fast_link_train(dp); + + return analogix_dp_full_link_train(dp, dp->video_info.max_lane_count, + dp->video_info.max_link_rate); } static int analogix_dp_config_video(struct analogix_dp_device *dp) @@ -848,10 +926,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) DRM_ERROR("failed to disable the panel\n"); } - ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count, - dp->video_info.max_link_rate); + ret = readx_poll_timeout(analogix_dp_train_link, dp, ret, !ret, 100, + DP_TIMEOUT_TRAINING_US * 5); if (ret) { - dev_err(dp->dev, "unable to do link train\n"); + dev_err(dp->dev, "unable to do link train, ret=%d\n", ret); return; } @@ -873,8 +951,8 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); - dp->psr_support = analogix_dp_detect_sink_psr(dp); - if (dp->psr_support) + dp->psr_enable = analogix_dp_detect_sink_psr(dp); + if (dp->psr_enable) analogix_dp_enable_sink_psr(dp); } @@ -1119,6 +1197,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) if (ret) DRM_ERROR("failed to setup the panel ret = %d\n", ret); + dp->psr_enable = false; dp->dpms_mode = DRM_MODE_DPMS_OFF; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 5c6a28806129..6a96ef7e6934 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -20,6 +20,10 @@ #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 +/* Training takes 22ms if AUX channel comm fails. Use this as retry interval */ +#define DP_TIMEOUT_TRAINING_US 22000 +#define DP_TIMEOUT_PSR_LOOP_MS 300 + /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) @@ -168,7 +172,8 @@ struct analogix_dp_device { int dpms_mode; int hpd_gpio; bool force_hpd; - bool psr_support; + bool psr_enable; + bool fast_train_support; struct mutex panel_lock; bool panel_is_modeset; @@ -247,8 +252,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, + struct edp_vsc_psr *vsc, bool blocking); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 303083ad28e3..9df2f3ef000c 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -10,10 +10,11 @@ * option) any later version. */ -#include <linux/device.h> -#include <linux/io.h> #include <linux/delay.h> +#include <linux/device.h> #include <linux/gpio.h> +#include <linux/io.h> +#include <linux/iopoll.h> #include <drm/bridge/analogix_dp.h> @@ -992,10 +993,25 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +static ssize_t analogix_dp_get_psr_status(struct analogix_dp_device *dp) +{ + ssize_t val; + u8 status; + + val = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &status); + if (val < 0) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%zd", val); + return val; + } + return status; +} + +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, + struct edp_vsc_psr *vsc, bool blocking) { unsigned int val; + int ret; + ssize_t psr_status; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1036,6 +1052,20 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + if (!blocking) + return 0; + + ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status, + psr_status >= 0 && + ((vsc->DB1 && psr_status == DP_PSR_SINK_ACTIVE_RFB) || + (!vsc->DB1 && psr_status == DP_PSR_SINK_INACTIVE)), 1500, + DP_TIMEOUT_PSR_LOOP_MS * 1000); + if (ret) { + dev_warn(dp->dev, "Failed to apply PSR %d\n", ret); + return ret; + } + return 0; } ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 53ebbe2904b6..ec8d0006ef7c 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -147,7 +147,6 @@ struct dw_hdmi { int vic; u8 edid[HDMI_EDID_LEN]; - bool cable_plugin; struct { const struct dw_hdmi_phy_ops *ops; @@ -1679,12 +1678,6 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); } -static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi) -{ - hdmi_writeb(hdmi, 0, HDMI_FC_MASK2); - hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2); -} - static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) { hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK, @@ -1774,8 +1767,6 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) hdmi_tx_hdcp_config(hdmi); dw_hdmi_clear_overflow(hdmi); - if (hdmi->cable_plugin && hdmi->sink_is_hdmi) - hdmi_enable_overflow_interrupts(hdmi); return 0; } diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 6cd0233b3bf8..f21953243790 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -199,8 +199,8 @@ static struct ttm_backend_func cirrus_tt_backend_func = { }; -static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_buffer_object *bo, + uint32_t page_flags) { struct ttm_tt *tt; @@ -208,7 +208,7 @@ static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &cirrus_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags)) { + if (ttm_tt_init(tt, bo, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 34b7d420e555..7d25c42f22db 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -391,8 +391,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, if (blob) { if (blob->length != sizeof(struct drm_mode_modeinfo) || drm_mode_convert_umode(state->crtc->dev, &state->mode, - (const struct drm_mode_modeinfo *) - blob->data)) + blob->data)) return -EINVAL; state->mode_blob = drm_property_blob_get(blob); @@ -409,11 +408,36 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, } EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); +/** + * drm_atomic_replace_property_blob_from_id - lookup the new blob and replace the old one with it + * @dev: DRM device + * @blob: a pointer to the member blob to be replaced + * @blob_id: ID of the new blob + * @expected_size: total expected size of the blob data (in bytes) + * @expected_elem_size: expected element size of the blob data (in bytes) + * @replaced: did the blob get replaced? + * + * Replace @blob with another blob with the ID @blob_id. If @blob_id is zero + * @blob becomes NULL. + * + * If @expected_size is positive the new blob length is expected to be equal + * to @expected_size bytes. If @expected_elem_size is positive the new blob + * length is expected to be a multiple of @expected_elem_size bytes. Otherwise + * an error is returned. + * + * @replaced will indicate to the caller whether the blob was replaced or not. + * If the old and new blobs were in fact the same blob @replaced will be false + * otherwise it will be true. + * + * RETURNS: + * Zero on success, error code on failure. + */ static int drm_atomic_replace_property_blob_from_id(struct drm_device *dev, struct drm_property_blob **blob, uint64_t blob_id, ssize_t expected_size, + ssize_t expected_elem_size, bool *replaced) { struct drm_property_blob *new_blob = NULL; @@ -423,7 +447,13 @@ drm_atomic_replace_property_blob_from_id(struct drm_device *dev, if (new_blob == NULL) return -EINVAL; - if (expected_size > 0 && expected_size != new_blob->length) { + if (expected_size > 0 && + new_blob->length != expected_size) { + drm_property_blob_put(new_blob); + return -EINVAL; + } + if (expected_elem_size > 0 && + new_blob->length % expected_elem_size != 0) { drm_property_blob_put(new_blob); return -EINVAL; } @@ -471,7 +501,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ret = drm_atomic_replace_property_blob_from_id(dev, &state->degamma_lut, val, - -1, + -1, sizeof(struct drm_color_lut), &replaced); state->color_mgmt_changed |= replaced; return ret; @@ -479,7 +509,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ret = drm_atomic_replace_property_blob_from_id(dev, &state->ctm, val, - sizeof(struct drm_color_ctm), + sizeof(struct drm_color_ctm), -1, &replaced); state->color_mgmt_changed |= replaced; return ret; @@ -487,7 +517,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ret = drm_atomic_replace_property_blob_from_id(dev, &state->gamma_lut, val, - -1, + -1, sizeof(struct drm_color_lut), &replaced); state->color_mgmt_changed |= replaced; return ret; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 00c78c1c9681..c35654591c12 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3818,7 +3818,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, } /* Prepare GAMMA_LUT with the legacy values. */ - blob_data = (struct drm_color_lut *) blob->data; + blob_data = blob->data; for (i = 0; i < size; i++) { blob_data[i].red = red[i]; blob_data[i].green = green[i]; diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 1ee84dd802d4..ba8cfe65c65b 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -129,10 +129,10 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash, * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where * applicable and if supported by the kernel. */ -static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, +static int drm_addmap_core(struct drm_device *dev, resource_size_t offset, unsigned int size, enum drm_map_type type, enum drm_map_flags flags, - struct drm_map_list ** maplist) + struct drm_map_list **maplist) { struct drm_local_map *map; struct drm_map_list *list; @@ -224,7 +224,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, case _DRM_SHM: list = drm_find_matching_map(dev, map); if (list != NULL) { - if(list->map->size != map->size) { + if (list->map->size != map->size) { DRM_DEBUG("Matching maps of type %d with " "mismatched sizes, (%ld vs %ld)\n", map->type, map->size, list->map->size); @@ -361,7 +361,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, return 0; } -int drm_legacy_addmap(struct drm_device * dev, resource_size_t offset, +int drm_legacy_addmap(struct drm_device *dev, resource_size_t offset, unsigned int size, enum drm_map_type type, enum drm_map_flags flags, struct drm_local_map **map_ptr) { @@ -637,8 +637,8 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data, * * Frees any pages and buffers associated with the given entry. */ -static void drm_cleanup_buf_error(struct drm_device * dev, - struct drm_buf_entry * entry) +static void drm_cleanup_buf_error(struct drm_device *dev, + struct drm_buf_entry *entry) { int i; @@ -1446,8 +1446,8 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data, int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p, void __user **v, int (*f)(void *, int, unsigned long, - struct drm_buf *), - struct drm_file *file_priv) + struct drm_buf *), + struct drm_file *file_priv) { struct drm_device_dma *dma = dev->dma; int retcode = 0; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a797bbf1cab8..49147b2aa288 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1554,8 +1554,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, struct edid *override = NULL; if (connector->override_edid) - override = drm_edid_duplicate((const struct edid *) - connector->edid_blob_ptr->data); + override = drm_edid_duplicate(connector->edid_blob_ptr->data); if (!override) override = drm_load_edid_firmware(connector); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 035784ddd133..0646b108030b 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1351,7 +1351,7 @@ static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc, if (IS_ERR(gamma_lut)) return gamma_lut; - lut = (struct drm_color_lut *)gamma_lut->data; + lut = gamma_lut->data; if (cmap->start || cmap->len != size) { u16 *r = crtc->gamma_store; u16 *g = r + crtc->gamma_size; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 5a13ff29f4f0..0eebe8ba8a2c 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -158,9 +158,10 @@ static int framebuffer_check(struct drm_device *dev, info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); if (!info) { struct drm_format_name_buf format_name; + DRM_DEBUG_KMS("bad framebuffer format %s\n", - drm_get_format_name(r->pixel_format, - &format_name)); + drm_get_format_name(r->pixel_format, + &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 5a8033fda4e3..f6b7c0e36a1a 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -773,24 +773,23 @@ EXPORT_SYMBOL(drm_mode_hsync); int drm_mode_vrefresh(const struct drm_display_mode *mode) { int refresh = 0; - unsigned int calc_val; if (mode->vrefresh > 0) refresh = mode->vrefresh; else if (mode->htotal > 0 && mode->vtotal > 0) { - int vtotal; - vtotal = mode->vtotal; - /* work out vrefresh the value will be x1000 */ - calc_val = (mode->clock * 1000); - calc_val /= mode->htotal; - refresh = (calc_val + vtotal / 2) / vtotal; + unsigned int num, den; + + num = mode->clock * 1000; + den = mode->htotal * mode->vtotal; if (mode->flags & DRM_MODE_FLAG_INTERLACE) - refresh *= 2; + num *= 2; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - refresh /= 2; + den *= 2; if (mode->vscan > 1) - refresh /= mode->vscan; + den *= mode->vscan; + + refresh = DIV_ROUND_CLOSEST(num, den); } return refresh; } @@ -1596,12 +1595,8 @@ int drm_mode_convert_umode(struct drm_device *dev, struct drm_display_mode *out, const struct drm_mode_modeinfo *in) { - int ret = -EINVAL; - - if (in->clock > INT_MAX || in->vrefresh > INT_MAX) { - ret = -ERANGE; - goto out; - } + if (in->clock > INT_MAX || in->vrefresh > INT_MAX) + return -ERANGE; out->clock = in->clock; out->hdisplay = in->hdisplay; @@ -1622,14 +1617,11 @@ int drm_mode_convert_umode(struct drm_device *dev, out->status = drm_mode_validate_driver(dev, out); if (out->status != MODE_OK) - goto out; + return -EINVAL; drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V); - ret = 0; - -out: - return ret; + return 0; } /** diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index a5d1fc7e8a37..6d2a6e428a3e 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -104,7 +104,7 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane if (IS_ERR(blob)) return -1; - blob_data = (struct drm_format_modifier_blob *)blob->data; + blob_data = blob->data; blob_data->version = FORMAT_BLOB_CURRENT; blob_data->count_formats = plane->format_count; blob_data->formats_offset = sizeof(struct drm_format_modifier_blob); diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 781518fd88e3..b25f98f33f6c 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -63,16 +63,34 @@ void drm_printf(struct drm_printer *p, const char *f, ...) } EXPORT_SYMBOL(drm_printf); -#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV" - void drm_dev_printk(const struct device *dev, const char *level, - unsigned int category, const char *function_name, - const char *prefix, const char *format, ...) + const char *format, ...) { struct va_format vaf; va_list args; - if (category != DRM_UT_NONE && !(drm_debug & category)) + va_start(args, format); + vaf.fmt = format; + vaf.va = &args; + + if (dev) + dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV", + __builtin_return_address(0), &vaf); + else + printk("%s" "[" DRM_NAME ":%ps] %pV", + level, __builtin_return_address(0), &vaf); + + va_end(args); +} +EXPORT_SYMBOL(drm_dev_printk); + +void drm_dev_dbg(const struct device *dev, unsigned int category, + const char *format, ...) +{ + struct va_format vaf; + va_list args; + + if (!(drm_debug & category)) return; va_start(args, format); @@ -80,32 +98,47 @@ void drm_dev_printk(const struct device *dev, const char *level, vaf.va = &args; if (dev) - dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix, - &vaf); + dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV", + __builtin_return_address(0), &vaf); else - printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); + printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV", + __builtin_return_address(0), &vaf); va_end(args); } -EXPORT_SYMBOL(drm_dev_printk); +EXPORT_SYMBOL(drm_dev_dbg); -void drm_printk(const char *level, unsigned int category, - const char *format, ...) +void drm_dbg(unsigned int category, const char *format, ...) { struct va_format vaf; va_list args; - if (category != DRM_UT_NONE && !(drm_debug & category)) + if (!(drm_debug & category)) return; va_start(args, format); vaf.fmt = format; vaf.va = &args; - printk("%s" "[" DRM_NAME ":%ps]%s %pV", - level, __builtin_return_address(0), - strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf); + printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV", + __builtin_return_address(0), &vaf); + + va_end(args); +} +EXPORT_SYMBOL(drm_dbg); + +void drm_err(const char *format, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, format); + vaf.fmt = format; + vaf.va = &args; + + printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV", + __builtin_return_address(0), &vaf); va_end(args); } -EXPORT_SYMBOL(drm_printk); +EXPORT_SYMBOL(drm_err); diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index 6ac6ee41a6a3..8f4672daac7f 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -567,6 +567,7 @@ drm_property_create_blob(struct drm_device *dev, size_t length, /* This must be explicitly initialised, so we can safely call list_del * on it in the removal handler, even if it isn't in a file list. */ INIT_LIST_HEAD(&blob->head_file); + blob->data = (void *)blob + sizeof(*blob); blob->length = length; blob->dev = dev; diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig index 3f58b4077767..e5bfeca361bd 100644 --- a/drivers/gpu/drm/etnaviv/Kconfig +++ b/drivers/gpu/drm/etnaviv/Kconfig @@ -11,6 +11,7 @@ config DRM_ETNAVIV select WANT_DEV_COREDUMP select CMA if HAVE_DMA_CONTIGUOUS select DMA_CMA if HAVE_DMA_CONTIGUOUS + select DRM_SCHED help DRM driver for Vivante GPUs. diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile index 1281c8d4fae5..46e5ffad69a6 100644 --- a/drivers/gpu/drm/etnaviv/Makefile +++ b/drivers/gpu/drm/etnaviv/Makefile @@ -9,9 +9,11 @@ etnaviv-y := \ etnaviv_gem_submit.o \ etnaviv_gem.o \ etnaviv_gpu.o \ + etnaviv_hwdb.o \ etnaviv_iommu_v2.o \ etnaviv_iommu.o \ etnaviv_mmu.o \ - etnaviv_perfmon.o + etnaviv_perfmon.o \ + etnaviv_sched.o obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o diff --git a/drivers/gpu/drm/etnaviv/common.xml.h b/drivers/gpu/drm/etnaviv/common.xml.h index 207f45c999c3..001faea80fef 100644 --- a/drivers/gpu/drm/etnaviv/common.xml.h +++ b/drivers/gpu/drm/etnaviv/common.xml.h @@ -8,15 +8,12 @@ http://0x04.net/cgit/index.cgi/rules-ng-ng git clone git://0x04.net/rules-ng-ng The rules-ng-ng source files this header was generated from are: -- state.xml ( 19930 bytes, from 2017-03-09 15:43:43) -- common.xml ( 23473 bytes, from 2017-03-09 15:43:43) -- state_hi.xml ( 26403 bytes, from 2017-03-09 15:43:43) -- copyright.xml ( 1597 bytes, from 2016-12-08 16:37:56) -- state_2d.xml ( 51552 bytes, from 2016-12-08 16:37:56) -- state_3d.xml ( 66957 bytes, from 2017-03-09 15:43:43) -- state_vg.xml ( 5975 bytes, from 2016-12-08 16:37:56) +- texdesc_3d.xml ( 3183 bytes, from 2017-12-18 16:51:59) +- copyright.xml ( 1597 bytes, from 2016-12-08 16:37:56) +- common.xml ( 35468 bytes, from 2018-01-22 13:48:54) +- common_3d.xml ( 14615 bytes, from 2017-12-18 16:51:59) -Copyright (C) 2012-2017 by the following authors: +Copyright (C) 2012-2018 by the following authors: - Wladimir J. van der Laan <laanwj@gmail.com> - Christian Gmeiner <christian.gmeiner@gmail.com> - Lucas Stach <l.stach@pengutronix.de> @@ -49,12 +46,7 @@ DEALINGS IN THE SOFTWARE. #define SYNC_RECIPIENT_RA 0x00000005 #define SYNC_RECIPIENT_PE 0x00000007 #define SYNC_RECIPIENT_DE 0x0000000b -#define SYNC_RECIPIENT_VG 0x0000000f -#define SYNC_RECIPIENT_TESSELATOR 0x00000010 -#define SYNC_RECIPIENT_VG2 0x00000011 -#define SYNC_RECIPIENT_TESSELATOR2 0x00000012 -#define SYNC_RECIPIENT_VG3 0x00000013 -#define SYNC_RECIPIENT_TESSELATOR3 0x00000014 +#define SYNC_RECIPIENT_BLT 0x00000010 #define ENDIAN_MODE_NO_SWAP 0x00000000 #define ENDIAN_MODE_SWAP_16 0x00000001 #define ENDIAN_MODE_SWAP_32 0x00000002 @@ -77,6 +69,7 @@ DEALINGS IN THE SOFTWARE. #define chipModel_GC800 0x00000800 #define chipModel_GC860 0x00000860 #define chipModel_GC880 0x00000880 +#define chipModel_GC900 0x00000900 #define chipModel_GC1000 0x00001000 #define chipModel_GC1500 0x00001500 #define chipModel_GC2000 0x00002000 @@ -88,6 +81,12 @@ DEALINGS IN THE SOFTWARE. #define chipModel_GC5000 0x00005000 #define chipModel_GC5200 0x00005200 #define chipModel_GC6400 0x00006400 +#define chipModel_GC7000 0x00007000 +#define chipModel_GC7400 0x00007400 +#define chipModel_GC8000 0x00008000 +#define chipModel_GC8100 0x00008100 +#define chipModel_GC8200 0x00008200 +#define chipModel_GC8400 0x00008400 #define RGBA_BITS_R 0x00000001 #define RGBA_BITS_G 0x00000002 #define RGBA_BITS_B 0x00000004 @@ -203,7 +202,7 @@ DEALINGS IN THE SOFTWARE. #define chipMinorFeatures2_RGB888 0x00001000 #define chipMinorFeatures2_TX__YUV_ASSEMBLER 0x00002000 #define chipMinorFeatures2_DYNAMIC_FREQUENCY_SCALING 0x00004000 -#define chipMinorFeatures2_EXTRA_TEXTURE_STATE 0x00008000 +#define chipMinorFeatures2_TX_FILTER 0x00008000 #define chipMinorFeatures2_FULL_DIRECTFB 0x00010000 #define chipMinorFeatures2_2D_TILING 0x00020000 #define chipMinorFeatures2_THREAD_WALKER_IN_PS 0x00040000 @@ -242,36 +241,36 @@ DEALINGS IN THE SOFTWARE. #define chipMinorFeatures3_TX_ENHANCEMENTS1 0x00080000 #define chipMinorFeatures3_SH_ENHANCEMENTS1 0x00100000 #define chipMinorFeatures3_SH_ENHANCEMENTS2 0x00200000 -#define chipMinorFeatures3_UNK22 0x00400000 +#define chipMinorFeatures3_PE_ENHANCEMENTS1 0x00400000 #define chipMinorFeatures3_2D_FC_SOURCE 0x00800000 -#define chipMinorFeatures3_UNK24 0x01000000 -#define chipMinorFeatures3_UNK25 0x02000000 +#define chipMinorFeatures3_BUG_FIXES_14 0x01000000 +#define chipMinorFeatures3_POWER_OPTIMIZATIONS_0 0x02000000 #define chipMinorFeatures3_NEW_HZ 0x04000000 -#define chipMinorFeatures3_UNK27 0x08000000 -#define chipMinorFeatures3_UNK28 0x10000000 +#define chipMinorFeatures3_PE_DITHER_FIX 0x08000000 +#define chipMinorFeatures3_DE_ENHANCEMENTS3 0x10000000 #define chipMinorFeatures3_SH_ENHANCEMENTS3 0x20000000 -#define chipMinorFeatures3_UNK30 0x40000000 -#define chipMinorFeatures3_UNK31 0x80000000 -#define chipMinorFeatures4_UNK0 0x00000001 +#define chipMinorFeatures3_SH_ENHANCEMENTS4 0x40000000 +#define chipMinorFeatures3_TX_ENHANCEMENTS2 0x80000000 +#define chipMinorFeatures4_FE_ENHANCEMENTS1 0x00000001 #define chipMinorFeatures4_PE_ENHANCEMENTS2 0x00000002 #define chipMinorFeatures4_FRUSTUM_CLIP_FIX 0x00000004 -#define chipMinorFeatures4_UNK3 0x00000008 -#define chipMinorFeatures4_UNK4 0x00000010 +#define chipMinorFeatures4_DE_NO_GAMMA 0x00000008 +#define chipMinorFeatures4_PA_ENHANCEMENTS_2 0x00000010 #define chipMinorFeatures4_2D_GAMMA 0x00000020 #define chipMinorFeatures4_SINGLE_BUFFER 0x00000040 -#define chipMinorFeatures4_UNK7 0x00000080 -#define chipMinorFeatures4_UNK8 0x00000100 -#define chipMinorFeatures4_UNK9 0x00000200 -#define chipMinorFeatures4_UNK10 0x00000400 +#define chipMinorFeatures4_HI_ENHANCEMENTS_1 0x00000080 +#define chipMinorFeatures4_TX_ENHANCEMENTS_3 0x00000100 +#define chipMinorFeatures4_SH_ENHANCEMENTS_5 0x00000200 +#define chipMinorFeatures4_FE_ENHANCEMENTS_2 0x00000400 #define chipMinorFeatures4_TX_LERP_PRECISION_FIX 0x00000800 #define chipMinorFeatures4_2D_COLOR_SPACE_CONVERSION 0x00001000 #define chipMinorFeatures4_TEXTURE_ASTC 0x00002000 -#define chipMinorFeatures4_UNK14 0x00004000 -#define chipMinorFeatures4_UNK15 0x00008000 +#define chipMinorFeatures4_PE_ENHANCEMENTS_4 0x00004000 +#define chipMinorFeatures4_MC_ENHANCEMENTS_1 0x00008000 #define chipMinorFeatures4_HALTI2 0x00010000 -#define chipMinorFeatures4_UNK17 0x00020000 +#define chipMinorFeatures4_2D_MIRROR_EXTENSION 0x00020000 #define chipMinorFeatures4_SMALL_MSAA 0x00040000 -#define chipMinorFeatures4_UNK19 0x00080000 +#define chipMinorFeatures4_BUG_FIXES_17 0x00080000 #define chipMinorFeatures4_NEW_RA 0x00100000 #define chipMinorFeatures4_2D_OPF_YUV_OUTPUT 0x00200000 #define chipMinorFeatures4_2D_MULTI_SOURCE_BLT_EX2 0x00400000 @@ -280,41 +279,207 @@ DEALINGS IN THE SOFTWARE. #define chipMinorFeatures4_BUG_FIXES18 0x02000000 #define chipMinorFeatures4_2D_COMPRESSION 0x04000000 #define chipMinorFeatures4_PROBE 0x08000000 -#define chipMinorFeatures4_UNK28 0x10000000 +#define chipMinorFeatures4_MEDIUM_PRECISION 0x10000000 #define chipMinorFeatures4_2D_SUPER_TILE_VERSION 0x20000000 -#define chipMinorFeatures4_UNK30 0x40000000 -#define chipMinorFeatures4_UNK31 0x80000000 -#define chipMinorFeatures5_UNK0 0x00000001 -#define chipMinorFeatures5_UNK1 0x00000002 -#define chipMinorFeatures5_UNK2 0x00000004 -#define chipMinorFeatures5_UNK3 0x00000008 +#define chipMinorFeatures4_BUG_FIXES19 0x40000000 +#define chipMinorFeatures4_SH_ENHANCEMENTS6 0x80000000 +#define chipMinorFeatures5_SH_ENHANCEMENTS7 0x00000001 +#define chipMinorFeatures5_BUG_FIXES20 0x00000002 +#define chipMinorFeatures5_DE_ADDRESS_40 0x00000004 +#define chipMinorFeatures5_MINI_MMU_FIX 0x00000008 #define chipMinorFeatures5_EEZ 0x00000010 -#define chipMinorFeatures5_UNK5 0x00000020 -#define chipMinorFeatures5_UNK6 0x00000040 -#define chipMinorFeatures5_UNK7 0x00000080 -#define chipMinorFeatures5_UNK8 0x00000100 +#define chipMinorFeatures5_BUG_FIXES21 0x00000020 +#define chipMinorFeatures5_EXTRA_VG_CAPS 0x00000040 +#define chipMinorFeatures5_MULTI_SRC_V15 0x00000080 +#define chipMinorFeatures5_BUG_FIXES22 0x00000100 #define chipMinorFeatures5_HALTI3 0x00000200 -#define chipMinorFeatures5_UNK10 0x00000400 +#define chipMinorFeatures5_TESSELATION_SHADERS 0x00000400 #define chipMinorFeatures5_2D_ONE_PASS_FILTER_TAP 0x00000800 -#define chipMinorFeatures5_UNK12 0x00001000 +#define chipMinorFeatures5_MULTI_SRC_V2_STR_QUAD 0x00001000 #define chipMinorFeatures5_SEPARATE_SRC_DST 0x00002000 #define chipMinorFeatures5_HALTI4 0x00004000 -#define chipMinorFeatures5_UNK15 0x00008000 +#define chipMinorFeatures5_RA_WRITE_DEPTH 0x00008000 #define chipMinorFeatures5_ANDROID_ONLY 0x00010000 #define chipMinorFeatures5_HAS_PRODUCTID 0x00020000 -#define chipMinorFeatures5_UNK18 0x00040000 -#define chipMinorFeatures5_UNK19 0x00080000 +#define chipMinorFeatures5_TX_SUPPORT_DEC 0x00040000 +#define chipMinorFeatures5_S8_MSAA_COMPRESSION 0x00080000 #define chipMinorFeatures5_PE_DITHER_FIX2 0x00100000 -#define chipMinorFeatures5_UNK21 0x00200000 -#define chipMinorFeatures5_UNK22 0x00400000 -#define chipMinorFeatures5_UNK23 0x00800000 -#define chipMinorFeatures5_UNK24 0x01000000 -#define chipMinorFeatures5_UNK25 0x02000000 -#define chipMinorFeatures5_UNK26 0x04000000 +#define chipMinorFeatures5_L2_CACHE_REMOVE 0x00200000 +#define chipMinorFeatures5_FE_ALLOW_RND_VTX_CNT 0x00400000 +#define chipMinorFeatures5_CUBE_MAP_FL28 0x00800000 +#define chipMinorFeatures5_TX_6BIT_FRAC 0x01000000 +#define chipMinorFeatures5_FE_ALLOW_STALL_PREFETCH_ENG 0x02000000 +#define chipMinorFeatures5_THIRD_PARTY_COMPRESSION 0x04000000 #define chipMinorFeatures5_RS_DEPTHSTENCIL_NATIVE_SUPPORT 0x08000000 #define chipMinorFeatures5_V2_MSAA_COMP_FIX 0x10000000 -#define chipMinorFeatures5_UNK29 0x20000000 -#define chipMinorFeatures5_UNK30 0x40000000 -#define chipMinorFeatures5_UNK31 0x80000000 +#define chipMinorFeatures5_HALTI5 0x20000000 +#define chipMinorFeatures5_EVIS 0x40000000 +#define chipMinorFeatures5_BLT_ENGINE 0x80000000 +#define chipMinorFeatures6_BUG_FIXES_23 0x00000001 +#define chipMinorFeatures6_BUG_FIXES_24 0x00000002 +#define chipMinorFeatures6_DEC 0x00000004 +#define chipMinorFeatures6_VS_TILE_NV12 0x00000008 +#define chipMinorFeatures6_VS_TILE_NV12_10BIT 0x00000010 +#define chipMinorFeatures6_RENDER_TARGET_8 0x00000020 +#define chipMinorFeatures6_TEX_LOD_FLOW_CORR 0x00000040 +#define chipMinorFeatures6_FACE_LOD 0x00000080 +#define chipMinorFeatures6_MULTI_CORE_SEMAPHORE_STALL_V2 0x00000100 +#define chipMinorFeatures6_VMSAA 0x00000200 +#define chipMinorFeatures6_CHIP_ENABLE_LINK 0x00000400 +#define chipMinorFeatures6_MULTI_SRC_BLT_1_5_ENHANCEMENT 0x00000800 +#define chipMinorFeatures6_MULTI_SRC_BLT_BILINEAR_FILTER 0x00001000 +#define chipMinorFeatures6_RA_HZEZ_CLOCK_CONTROL 0x00002000 +#define chipMinorFeatures6_CACHE128B256BPERLINE 0x00004000 +#define chipMinorFeatures6_V4_COMPRESSION 0x00008000 +#define chipMinorFeatures6_PE2D_MAJOR_SUPER_TILE 0x00010000 +#define chipMinorFeatures6_PE_32BPC_COLORMASK_FIX 0x00020000 +#define chipMinorFeatures6_ALPHA_BLENDING_OPT 0x00040000 +#define chipMinorFeatures6_NEW_GPIPE 0x00080000 +#define chipMinorFeatures6_PIPELINE_32_ATTRIBUTES 0x00100000 +#define chipMinorFeatures6_MSAA_SHADING 0x00200000 +#define chipMinorFeatures6_NO_ANISTRO_FILTER 0x00400000 +#define chipMinorFeatures6_NO_ASTC 0x00800000 +#define chipMinorFeatures6_NO_DXT 0x01000000 +#define chipMinorFeatures6_HWTFB 0x02000000 +#define chipMinorFeatures6_RA_DEPTH_WRITE_MSAA1X_FIX 0x04000000 +#define chipMinorFeatures6_EZHZ_CLOCKGATE_FIX 0x08000000 +#define chipMinorFeatures6_SH_SNAP2PAGE_FIX 0x10000000 +#define chipMinorFeatures6_SH_HALFDEPENDENCY_FIX 0x20000000 +#define chipMinorFeatures6_USC_MCFILL_FIX 0x40000000 +#define chipMinorFeatures6_TPG_TCPERF_FIX 0x80000000 +#define chipMinorFeatures7_USC_MDFIFO_OVERFLOW_FIX 0x00000001 +#define chipMinorFeatures7_SH_TEXLD_BARRIER_IN_CS_FIX 0x00000002 +#define chipMinorFeatures7_RS_NEW_BASEADDR 0x00000004 +#define chipMinorFeatures7_PE_8BPP_DUALPIPE_FIX 0x00000008 +#define chipMinorFeatures7_SH_ADVANCED_INSTR 0x00000010 +#define chipMinorFeatures7_SH_FLAT_INTERPOLATION_DUAL16_FIX 0x00000020 +#define chipMinorFeatures7_USC_CONTINUOUS_FLUS_FIX 0x00000040 +#define chipMinorFeatures7_SH_SUPPORT_V4 0x00000080 +#define chipMinorFeatures7_SH_SUPPORT_ALPHA_KILL 0x00000100 +#define chipMinorFeatures7_PE_NO_ALPHA_TEST 0x00000200 +#define chipMinorFeatures7_TX_LOD_NEAREST_SELECT 0x00000400 +#define chipMinorFeatures7_SH_FIX_LDEXP 0x00000800 +#define chipMinorFeatures7_SUPPORT_MOVAI 0x00001000 +#define chipMinorFeatures7_SH_SNAP2PAGE_MAXPAGES_FIX 0x00002000 +#define chipMinorFeatures7_PE_RGBA16I_FIX 0x00004000 +#define chipMinorFeatures7_BLT_8bpp_256TILE_FC_FIX 0x00008000 +#define chipMinorFeatures7_PE_64BIT_FENCE_FIX 0x00010000 +#define chipMinorFeatures7_USC_FULL_CACHE_FIX 0x00020000 +#define chipMinorFeatures7_TX_YUV_ASSEMBLER_10BIT 0x00040000 +#define chipMinorFeatures7_FE_32BIT_INDEX_FIX 0x00080000 +#define chipMinorFeatures7_BLT_64BPP_MASKED_CLEAR_FIX 0x00100000 +#define chipMinorFeatures7_BIT_SECURITY 0x00200000 +#define chipMinorFeatures7_BIT_ROBUSTNESS 0x00400000 +#define chipMinorFeatures7_USC_ATOMIC_FIX 0x00800000 +#define chipMinorFeatures7_SH_PSO_MSAA1x_FIX 0x01000000 +#define chipMinorFeatures7_BIT_USC_VX_PERF_FIX 0x02000000 +#define chipMinorFeatures7_EVIS_NO_ABSDIFF 0x04000000 +#define chipMinorFeatures7_EVIS_NO_BITREPLACE 0x08000000 +#define chipMinorFeatures7_EVIS_NO_BOXFILTER 0x10000000 +#define chipMinorFeatures7_EVIS_NO_CORDIAC 0x20000000 +#define chipMinorFeatures7_EVIS_NO_DP32 0x40000000 +#define chipMinorFeatures7_EVIS_NO_FILTER 0x80000000 +#define chipMinorFeatures8_EVIS_NO_IADD 0x00000001 +#define chipMinorFeatures8_EVIS_NO_SELECTADD 0x00000002 +#define chipMinorFeatures8_EVIS_LERP_7OUTPUT 0x00000004 +#define chipMinorFeatures8_EVIS_ACCSQ_8OUTPUT 0x00000008 +#define chipMinorFeatures8_USC_GOS_ADDR_FIX 0x00000010 +#define chipMinorFeatures8_TX_8BIT_UVFRAC 0x00000020 +#define chipMinorFeatures8_TX_DESC_CACHE_CLOCKGATE_FIX 0x00000040 +#define chipMinorFeatures8_RSBLT_MSAA_DECOMPRESSION 0x00000080 +#define chipMinorFeatures8_TX_INTEGER_COORDINATE 0x00000100 +#define chipMinorFeatures8_DRAWID 0x00000200 +#define chipMinorFeatures8_PSIO_SAMPLEMASK_IN_R0ZW_FIX 0x00000400 +#define chipMinorFeatures8_TX_INTEGER_COORDINATE_V2 0x00000800 +#define chipMinorFeatures8_MULTI_CORE_BLOCK_SET_CONFIG 0x00001000 +#define chipMinorFeatures8_VG_RESOLVE_ENGINE 0x00002000 +#define chipMinorFeatures8_VG_PE_COLOR_KEY 0x00004000 +#define chipMinorFeatures8_VG_IM_INDEX_FORMAT 0x00008000 +#define chipMinorFeatures8_SNAPPAGE_CMD 0x00010000 +#define chipMinorFeatures8_SH_NO_INDEX_CONST_ON_A0 0x00020000 +#define chipMinorFeatures8_SH_NO_ONECONST_LIMIT 0x00040000 +#define chipMinorFeatures8_SH_IMG_LDST_ON_TEMP 0x00080000 +#define chipMinorFeatures8_COMPUTE_ONLY 0x00100000 +#define chipMinorFeatures8_SH_IMG_LDST_CLAMP 0x00200000 +#define chipMinorFeatures8_SH_ICACHE_ALLOC_COUNT_FIX 0x00400000 +#define chipMinorFeatures8_SH_ICACHE_PREFETCH 0x00800000 +#define chipMinorFeatures8_PE2D_SEPARATE_CACHE 0x01000000 +#define chipMinorFeatures8_VG_AYUV_INPUT_OUTPUT 0x02000000 +#define chipMinorFeatures8_VG_DOUBLE_IMAGE 0x04000000 +#define chipMinorFeatures8_VG_RECTANGLE_STRIPE_MODE 0x08000000 +#define chipMinorFeatures8_VG_MMU 0x10000000 +#define chipMinorFeatures8_VG_IM_FILTER 0x20000000 +#define chipMinorFeatures8_VG_IM_YUV_PACKET 0x40000000 +#define chipMinorFeatures8_VG_IM_YUV_PLANAR 0x80000000 +#define chipMinorFeatures9_VG_PE_YUV_PACKET 0x00000001 +#define chipMinorFeatures9_VG_COLOR_PRECISION_8_BIT 0x00000002 +#define chipMinorFeatures9_PE_MSAA_OQ_FIX 0x00000004 +#define chipMinorFeatures9_PSIO_MSAA_CL_FIX 0x00000008 +#define chipMinorFeatures9_USC_DEFER_FILL_FIX 0x00000010 +#define chipMinorFeatures9_SH_CLOCK_GATE_FIX 0x00000020 +#define chipMinorFeatures9_FE_NEED_DUMMYDRAW 0x00000040 +#define chipMinorFeatures9_PE2D_LINEAR_YUV420_OUTPUT 0x00000080 +#define chipMinorFeatures9_PE2D_LINEAR_YUV420_10BIT 0x00000100 +#define chipMinorFeatures9_MULTI_CLUSTER 0x00000200 +#define chipMinorFeatures9_VG_TS_CULLING 0x00000400 +#define chipMinorFeatures9_VG_FP25 0x00000800 +#define chipMinorFeatures9_SH_MULTI_WG_PACK 0x00001000 +#define chipMinorFeatures9_SH_DUAL16_SAMPLEMASK_ZW 0x00002000 +#define chipMinorFeatures9_TPG_TRIVIAL_MODE_FIX 0x00004000 +#define chipMinorFeatures9_TX_ASTC_MULTISLICE_FIX 0x00008000 +#define chipMinorFeatures9_FE_ROBUST_FIX 0x00010000 +#define chipMinorFeatures9_SH_GPIPE_ACCESS_FULLTEMPS 0x00020000 +#define chipMinorFeatures9_PSIO_INTERLOCK 0x00040000 +#define chipMinorFeatures9_PA_WIDELINE_FIX 0x00080000 +#define chipMinorFeatures9_WIDELINE_HELPER_FIX 0x00100000 +#define chipMinorFeatures9_G2D_3RD_PARTY_COMPRESSION_1_1 0x00200000 +#define chipMinorFeatures9_TX_FLUSH_L1CACHE 0x00400000 +#define chipMinorFeatures9_PE_DITHER_FIX2 0x00800000 +#define chipMinorFeatures9_G2D_DEC400 0x01000000 +#define chipMinorFeatures9_SH_TEXLD_U_FIX 0x02000000 +#define chipMinorFeatures9_MC_FCCACHE_BYTEMASK 0x04000000 +#define chipMinorFeatures9_SH_MULTI_WG_PACK_FIX 0x08000000 +#define chipMinorFeatures9_DC_OVERLAY_SCALING 0x10000000 +#define chipMinorFeatures9_DC_SOURCE_ROTATION 0x20000000 +#define chipMinorFeatures9_DC_TILED 0x40000000 +#define chipMinorFeatures9_DC_YUV_L1 0x80000000 +#define chipMinorFeatures10_DC_D30_OUTPUT 0x00000001 +#define chipMinorFeatures10_DC_MMU 0x00000002 +#define chipMinorFeatures10_DC_COMPRESSION 0x00000004 +#define chipMinorFeatures10_DC_QOS 0x00000008 +#define chipMinorFeatures10_PE_ADVANCE_BLEND_PART0 0x00000010 +#define chipMinorFeatures10_FE_PATCHLIST_FETCH_FIX 0x00000020 +#define chipMinorFeatures10_RA_CG_FIX 0x00000040 +#define chipMinorFeatures10_EVIS_VX2 0x00000080 +#define chipMinorFeatures10_NN_FLOAT 0x00000100 +#define chipMinorFeatures10_DEC400 0x00000200 +#define chipMinorFeatures10_LS_SUPPORT_PERCOMP_DEPENDENCY 0x00000400 +#define chipMinorFeatures10_TP_ENGINE 0x00000800 +#define chipMinorFeatures10_MULTI_CORE_BLOCK_SET_CONFIG2 0x00001000 +#define chipMinorFeatures10_PE_VMSAA_COVERAGE_CACHE_FIX 0x00002000 +#define chipMinorFeatures10_SECURITY_AHB 0x00004000 +#define chipMinorFeatures10_MULTICORE_SEMAPHORESTALL_V3 0x00008000 +#define chipMinorFeatures10_SMALLBATCH 0x00010000 +#define chipMinorFeatures10_SH_CMPLX 0x00020000 +#define chipMinorFeatures10_SH_IDIV0_SWZL_EHS 0x00040000 +#define chipMinorFeatures10_TX_LERP_LESS_BIT 0x00080000 +#define chipMinorFeatures10_SH_GM_ENDIAN 0x00100000 +#define chipMinorFeatures10_SH_GM_USC_UNALLOC 0x00200000 +#define chipMinorFeatures10_SH_END_OF_BB 0x00400000 +#define chipMinorFeatures10_VIP_V7 0x00800000 +#define chipMinorFeatures10_TX_BORDER_CLAMP_FIX 0x01000000 +#define chipMinorFeatures10_SH_IMG_LD_LASTPIXEL_FIX 0x02000000 +#define chipMinorFeatures10_ASYNC_BLT 0x04000000 +#define chipMinorFeatures10_ASYNC_FE_FENCE_FIX 0x08000000 +#define chipMinorFeatures10_PSCS_THROTTLE 0x10000000 +#define chipMinorFeatures10_SEPARATE_LS 0x20000000 +#define chipMinorFeatures10_MCFE 0x40000000 +#define chipMinorFeatures10_WIDELINE_TRIANGLE_EMU 0x80000000 +#define chipMinorFeatures11_VG_RESOLUTION_8K 0x00000001 +#define chipMinorFeatures11_FENCE_32BIT 0x00000002 +#define chipMinorFeatures11_FENCE_64BIT 0x00000004 +#define chipMinorFeatures11_NN_INTERLEVE8 0x00000008 +#define chipMinorFeatures11_TP_REORDER 0x00000010 +#define chipMinorFeatures11_PE_DEPTH_ONLY_OQFIX 0x00000020 #endif /* COMMON_XML */ diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 99ad2f073c6e..bfc6d4aa3b7c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -215,6 +215,24 @@ u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe return buffer->user_size / 8; } +u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu) +{ + struct etnaviv_cmdbuf *buffer = &gpu->buffer; + + lockdep_assert_held(&gpu->lock); + + buffer->user_size = 0; + + CMD_LOAD_STATE(buffer, VIVS_MMUv2_PTA_CONFIG, + VIVS_MMUv2_PTA_CONFIG_INDEX(0)); + + CMD_END(buffer); + + buffer->user_size = ALIGN(buffer->user_size, 8); + + return buffer->user_size / 8; +} + void etnaviv_buffer_end(struct etnaviv_gpu *gpu) { struct etnaviv_cmdbuf *buffer = &gpu->buffer; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 6faf4042db23..ab50090d066c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -101,12 +101,25 @@ static void load_gpu(struct drm_device *dev) static int etnaviv_open(struct drm_device *dev, struct drm_file *file) { + struct etnaviv_drm_private *priv = dev->dev_private; struct etnaviv_file_private *ctx; + int i; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + for (i = 0; i < ETNA_MAX_PIPES; i++) { + struct etnaviv_gpu *gpu = priv->gpu[i]; + + if (gpu) { + drm_sched_entity_init(&gpu->sched, + &ctx->sched_entity[i], + &gpu->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL], + 32, NULL); + } + } + file->driver_priv = ctx; return 0; @@ -126,6 +139,9 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) if (gpu->lastctx == ctx) gpu->lastctx = NULL; mutex_unlock(&gpu->lock); + + drm_sched_entity_fini(&gpu->sched, + &ctx->sched_entity[i]); } } @@ -637,25 +653,21 @@ static int compare_str(struct device *dev, void *data) static int etnaviv_pdev_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; struct component_match *match = NULL; dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (node) { + if (!dev->platform_data) { struct device_node *core_node; - int i; - for (i = 0; ; i++) { - core_node = of_parse_phandle(node, "cores", i); - if (!core_node) - break; + for_each_compatible_node(core_node, NULL, "vivante,gc") { + if (!of_device_is_available(core_node)) + continue; drm_of_component_match_add(&pdev->dev, &match, compare_of, core_node); - of_node_put(core_node); } - } else if (dev->platform_data) { + } else { char **names = dev->platform_data; unsigned i; @@ -673,25 +685,18 @@ static int etnaviv_pdev_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id dt_match[] = { - { .compatible = "fsl,imx-gpu-subsystem" }, - { .compatible = "marvell,dove-gpu-subsystem" }, - {} -}; -MODULE_DEVICE_TABLE(of, dt_match); - static struct platform_driver etnaviv_platform_driver = { .probe = etnaviv_pdev_probe, .remove = etnaviv_pdev_remove, .driver = { .name = "etnaviv", - .of_match_table = dt_match, }, }; static int __init etnaviv_init(void) { int ret; + struct device_node *np; etnaviv_validate_init(); @@ -703,6 +708,19 @@ static int __init etnaviv_init(void) if (ret != 0) platform_driver_unregister(&etnaviv_gpu_driver); + /* + * If the DT contains at least one available GPU device, instantiate + * the DRM platform device. + */ + for_each_compatible_node(np, NULL, "vivante,gc") { + if (!of_device_is_available(np)) + continue; + + platform_device_register_simple("etnaviv", -1, NULL, 0); + of_node_put(np); + break; + } + return ret; } module_init(etnaviv_init); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index a54f0b758a5c..ddb17ee565e9 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -34,6 +34,7 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> #include <drm/etnaviv_drm.h> +#include <drm/gpu_scheduler.h> struct etnaviv_cmdbuf; struct etnaviv_gpu; @@ -42,11 +43,11 @@ struct etnaviv_gem_object; struct etnaviv_gem_submit; struct etnaviv_file_private { - /* currently we don't do anything useful with this.. but when - * per-context address spaces are supported we'd keep track of + /* + * When per-context address spaces are supported we'd keep track of * the context's page-tables here. */ - int dummy; + struct drm_sched_entity sched_entity[ETNA_MAX_PIPES]; }; struct etnaviv_drm_private { @@ -85,6 +86,7 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file, uintptr_t ptr, u32 size, u32 flags, u32 *handle); u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu); u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr); +u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu); void etnaviv_buffer_end(struct etnaviv_gpu *gpu); void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event); void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index 6d0909c589d1..48aef6cf6a42 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -20,9 +20,13 @@ #include "etnaviv_gem.h" #include "etnaviv_gpu.h" #include "etnaviv_mmu.h" +#include "etnaviv_sched.h" #include "state.xml.h" #include "state_hi.xml.h" +static bool etnaviv_dump_core = true; +module_param_named(dump_core, etnaviv_dump_core, bool, 0600); + struct core_dump_iterator { void *start; struct etnaviv_dump_object_header *hdr; @@ -121,10 +125,16 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) struct etnaviv_vram_mapping *vram; struct etnaviv_gem_object *obj; struct etnaviv_gem_submit *submit; + struct drm_sched_job *s_job; unsigned int n_obj, n_bomap_pages; size_t file_size, mmu_size; __le64 *bomap, *bomap_start; + /* Only catch the first event, or when manually re-armed */ + if (!etnaviv_dump_core) + return; + etnaviv_dump_core = false; + mmu_size = etnaviv_iommu_dump_size(gpu->mmu); /* We always dump registers, mmu, ring and end marker */ @@ -135,10 +145,13 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) mmu_size + gpu->buffer.size; /* Add in the active command buffers */ - list_for_each_entry(submit, &gpu->active_submit_list, node) { + spin_lock(&gpu->sched.job_list_lock); + list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { + submit = to_etnaviv_submit(s_job); file_size += submit->cmdbuf.size; n_obj++; } + spin_unlock(&gpu->sched.job_list_lock); /* Add in the active buffer objects */ list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) { @@ -180,10 +193,14 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) gpu->buffer.size, etnaviv_cmdbuf_get_va(&gpu->buffer)); - list_for_each_entry(submit, &gpu->active_submit_list, node) + spin_lock(&gpu->sched.job_list_lock); + list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { + submit = to_etnaviv_submit(s_job); etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, submit->cmdbuf.vaddr, submit->cmdbuf.size, etnaviv_cmdbuf_get_va(&submit->cmdbuf)); + } + spin_unlock(&gpu->sched.job_list_lock); /* Reserve space for the bomap */ if (n_bomap_pages) { diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index be72a9833f2b..93e696fcc14f 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -94,6 +94,9 @@ struct etnaviv_gem_submit_bo { u32 flags; struct etnaviv_gem_object *obj; struct etnaviv_vram_mapping *mapping; + struct dma_fence *excl; + unsigned int nr_shared; + struct dma_fence **shared; }; /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, @@ -101,9 +104,11 @@ struct etnaviv_gem_submit_bo { * make it easier to unwind when things go wrong, etc). */ struct etnaviv_gem_submit { + struct drm_sched_job sched_job; struct kref refcount; struct etnaviv_gpu *gpu; struct dma_fence *out_fence, *in_fence; + int out_fence_id; struct list_head node; /* GPU active submit list */ struct etnaviv_cmdbuf cmdbuf; bool runtime_resumed; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 1f8202bca061..46ecd3e66ac9 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -22,6 +22,7 @@ #include "etnaviv_gpu.h" #include "etnaviv_gem.h" #include "etnaviv_perfmon.h" +#include "etnaviv_sched.h" /* * Cmdstream submission: @@ -169,29 +170,33 @@ fail: return ret; } -static int submit_fence_sync(const struct etnaviv_gem_submit *submit) +static int submit_fence_sync(struct etnaviv_gem_submit *submit) { - unsigned int context = submit->gpu->fence_context; int i, ret = 0; for (i = 0; i < submit->nr_bos; i++) { - struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; - bool write = submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE; - bool explicit = !!(submit->flags & ETNA_SUBMIT_NO_IMPLICIT); + struct etnaviv_gem_submit_bo *bo = &submit->bos[i]; + struct reservation_object *robj = bo->obj->resv; - ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write, - explicit); - if (ret) - break; - } + if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) { + ret = reservation_object_reserve_shared(robj); + if (ret) + return ret; + } + + if (submit->flags & ETNA_SUBMIT_NO_IMPLICIT) + continue; + + if (bo->flags & ETNA_SUBMIT_BO_WRITE) { + ret = reservation_object_get_fences_rcu(robj, &bo->excl, + &bo->nr_shared, + &bo->shared); + if (ret) + return ret; + } else { + bo->excl = reservation_object_get_excl_rcu(robj); + } - if (submit->flags & ETNA_SUBMIT_FENCE_FD_IN) { - /* - * Wait if the fence is from a foreign context, or if the fence - * array contains any fence from a foreign context. - */ - if (!dma_fence_match_context(submit->in_fence, context)) - ret = dma_fence_wait(submit->in_fence, true); } return ret; @@ -381,8 +386,13 @@ static void submit_cleanup(struct kref *kref) if (submit->in_fence) dma_fence_put(submit->in_fence); - if (submit->out_fence) + if (submit->out_fence) { + /* first remove from IDR, so fence can not be found anymore */ + mutex_lock(&submit->gpu->fence_idr_lock); + idr_remove(&submit->gpu->fence_idr, submit->out_fence_id); + mutex_unlock(&submit->gpu->fence_idr_lock); dma_fence_put(submit->out_fence); + } kfree(submit->pmrs); kfree(submit); } @@ -395,6 +405,7 @@ void etnaviv_submit_put(struct etnaviv_gem_submit *submit) int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file) { + struct etnaviv_file_private *ctx = file->driver_priv; struct etnaviv_drm_private *priv = dev->dev_private; struct drm_etnaviv_gem_submit *args = data; struct drm_etnaviv_gem_submit_reloc *relocs; @@ -503,10 +514,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto err_submit_objects; - ret = submit_lock_objects(submit, &ticket); - if (ret) - goto err_submit_objects; - if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4, relocs, args->nr_relocs)) { ret = -EINVAL; @@ -521,10 +528,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, } } - ret = submit_fence_sync(submit); - if (ret) - goto err_submit_objects; - ret = submit_pin_objects(submit); if (ret) goto err_submit_objects; @@ -539,9 +542,16 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, goto err_submit_objects; memcpy(submit->cmdbuf.vaddr, stream, args->stream_size); - submit->cmdbuf.user_size = ALIGN(args->stream_size, 8); - ret = etnaviv_gpu_submit(gpu, submit); + ret = submit_lock_objects(submit, &ticket); + if (ret) + goto err_submit_objects; + + ret = submit_fence_sync(submit); + if (ret) + goto err_submit_objects; + + ret = etnaviv_sched_push_job(&ctx->sched_entity[args->pipe], submit); if (ret) goto err_submit_objects; @@ -563,7 +573,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, } args->fence_fd = out_fence_fd; - args->fence = submit->out_fence->seqno; + args->fence = submit->out_fence_id; err_submit_objects: etnaviv_submit_put(submit); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 21d0d22f1168..8a88799bf79b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -26,19 +26,21 @@ #include "etnaviv_gem.h" #include "etnaviv_mmu.h" #include "etnaviv_perfmon.h" +#include "etnaviv_sched.h" #include "common.xml.h" #include "state.xml.h" #include "state_hi.xml.h" #include "cmdstream.xml.h" +#ifndef PHYS_OFFSET +#define PHYS_OFFSET 0 +#endif + static const struct platform_device_id gpu_ids[] = { { .name = "etnaviv-gpu,2d" }, { }, }; -static bool etnaviv_dump_core = true; -module_param_named(dump_core, etnaviv_dump_core, bool, 0600); - /* * Driver functions: */ @@ -82,6 +84,30 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) *value = gpu->identity.minor_features5; break; + case ETNAVIV_PARAM_GPU_FEATURES_7: + *value = gpu->identity.minor_features6; + break; + + case ETNAVIV_PARAM_GPU_FEATURES_8: + *value = gpu->identity.minor_features7; + break; + + case ETNAVIV_PARAM_GPU_FEATURES_9: + *value = gpu->identity.minor_features8; + break; + + case ETNAVIV_PARAM_GPU_FEATURES_10: + *value = gpu->identity.minor_features9; + break; + + case ETNAVIV_PARAM_GPU_FEATURES_11: + *value = gpu->identity.minor_features10; + break; + + case ETNAVIV_PARAM_GPU_FEATURES_12: + *value = gpu->identity.minor_features11; + break; + case ETNAVIV_PARAM_GPU_STREAM_COUNT: *value = gpu->identity.stream_count; break; @@ -348,6 +374,13 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu) dev_info(gpu->dev, "model: GC%x, revision: %x\n", gpu->identity.model, gpu->identity.revision); + /* + * If there is a match in the HWDB, we aren't interested in the + * remaining register values, as they might be wrong. + */ + if (etnaviv_fill_identity_from_hwdb(gpu)) + return; + gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE); /* Disable fast clear on GC700. */ @@ -448,9 +481,14 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU; gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); - /* set soft reset. */ - control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET; - gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); + if (gpu->sec_mode == ETNA_SEC_KERNEL) { + gpu_write(gpu, VIVS_MMUv2_AHB_CONTROL, + VIVS_MMUv2_AHB_CONTROL_RESET); + } else { + /* set soft reset. */ + control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET; + gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); + } /* wait for reset. */ usleep_range(10, 20); @@ -561,6 +599,12 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch) gpu_write(gpu, VIVS_FE_COMMAND_CONTROL, VIVS_FE_COMMAND_CONTROL_ENABLE | VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch)); + + if (gpu->sec_mode == ETNA_SEC_KERNEL) { + gpu_write(gpu, VIVS_MMUv2_SEC_COMMAND_CONTROL, + VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE | + VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch)); + } } static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu) @@ -634,6 +678,12 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config); } + if (gpu->sec_mode == ETNA_SEC_KERNEL) { + u32 val = gpu_read(gpu, VIVS_MMUv2_AHB_CONTROL); + val |= VIVS_MMUv2_AHB_CONTROL_NONSEC_ACCESS; + gpu_write(gpu, VIVS_MMUv2_AHB_CONTROL, val); + } + /* setup the pulse eater */ etnaviv_gpu_setup_pulse_eater(gpu); @@ -696,6 +746,14 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) gpu->identity.features &= ~chipFeatures_FAST_CLEAR; } + /* + * On cores with security features supported, we claim control over the + * security states. + */ + if ((gpu->identity.minor_features7 & chipMinorFeatures7_BIT_SECURITY) && + (gpu->identity.minor_features10 & chipMinorFeatures10_SECURITY_AHB)) + gpu->sec_mode = ETNA_SEC_KERNEL; + ret = etnaviv_hw_reset(gpu); if (ret) { dev_err(gpu->dev, "GPU reset failed\n"); @@ -807,6 +865,8 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) verify_dma(gpu, &debug); seq_puts(m, "\tfeatures\n"); + seq_printf(m, "\t major_features: 0x%08x\n", + gpu->identity.features); seq_printf(m, "\t minor_features0: 0x%08x\n", gpu->identity.minor_features0); seq_printf(m, "\t minor_features1: 0x%08x\n", @@ -819,6 +879,18 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) gpu->identity.minor_features4); seq_printf(m, "\t minor_features5: 0x%08x\n", gpu->identity.minor_features5); + seq_printf(m, "\t minor_features6: 0x%08x\n", + gpu->identity.minor_features6); + seq_printf(m, "\t minor_features7: 0x%08x\n", + gpu->identity.minor_features7); + seq_printf(m, "\t minor_features8: 0x%08x\n", + gpu->identity.minor_features8); + seq_printf(m, "\t minor_features9: 0x%08x\n", + gpu->identity.minor_features9); + seq_printf(m, "\t minor_features10: 0x%08x\n", + gpu->identity.minor_features10); + seq_printf(m, "\t minor_features11: 0x%08x\n", + gpu->identity.minor_features11); seq_puts(m, "\tspecs\n"); seq_printf(m, "\t stream_count: %d\n", @@ -912,38 +984,24 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) } #endif -/* - * Hangcheck detection for locked gpu: - */ -static void recover_worker(struct work_struct *work) +void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) { - struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, - recover_work); unsigned long flags; unsigned int i = 0; - dev_err(gpu->dev, "hangcheck recover!\n"); + dev_err(gpu->dev, "recover hung GPU!\n"); if (pm_runtime_get_sync(gpu->dev) < 0) return; mutex_lock(&gpu->lock); - /* Only catch the first event, or when manually re-armed */ - if (etnaviv_dump_core) { - etnaviv_core_dump(gpu); - etnaviv_dump_core = false; - } - etnaviv_hw_reset(gpu); /* complete all events, the GPU won't do it after the reset */ spin_lock_irqsave(&gpu->event_spinlock, flags); - for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) { - dma_fence_signal(gpu->event[i].fence); - gpu->event[i].fence = NULL; + for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) complete(&gpu->event_free); - } bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS); spin_unlock_irqrestore(&gpu->event_spinlock, flags); gpu->completed_fence = gpu->active_fence; @@ -955,56 +1013,6 @@ static void recover_worker(struct work_struct *work) mutex_unlock(&gpu->lock); pm_runtime_mark_last_busy(gpu->dev); pm_runtime_put_autosuspend(gpu->dev); - - /* Retire the buffer objects in a work */ - queue_work(gpu->wq, &gpu->retire_work); -} - -static void hangcheck_timer_reset(struct etnaviv_gpu *gpu) -{ - DBG("%s", dev_name(gpu->dev)); - mod_timer(&gpu->hangcheck_timer, - round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES)); -} - -static void hangcheck_handler(struct timer_list *t) -{ - struct etnaviv_gpu *gpu = from_timer(gpu, t, hangcheck_timer); - u32 fence = gpu->completed_fence; - bool progress = false; - - if (fence != gpu->hangcheck_fence) { - gpu->hangcheck_fence = fence; - progress = true; - } - - if (!progress) { - u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); - int change = dma_addr - gpu->hangcheck_dma_addr; - - if (change < 0 || change > 16) { - gpu->hangcheck_dma_addr = dma_addr; - progress = true; - } - } - - if (!progress && fence_after(gpu->active_fence, fence)) { - dev_err(gpu->dev, "hangcheck detected gpu lockup!\n"); - dev_err(gpu->dev, " completed fence: %u\n", fence); - dev_err(gpu->dev, " active fence: %u\n", - gpu->active_fence); - queue_work(gpu->wq, &gpu->recover_work); - } - - /* if still more pending work, reset the hangcheck timer: */ - if (fence_after(gpu->active_fence, gpu->hangcheck_fence)) - hangcheck_timer_reset(gpu); -} - -static void hangcheck_disable(struct etnaviv_gpu *gpu) -{ - del_timer_sync(&gpu->hangcheck_timer); - cancel_work_sync(&gpu->recover_work); } /* fence object management */ @@ -1080,54 +1088,6 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) return &f->base; } -int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj, - unsigned int context, bool exclusive, bool explicit) -{ - struct reservation_object *robj = etnaviv_obj->resv; - struct reservation_object_list *fobj; - struct dma_fence *fence; - int i, ret; - - if (!exclusive) { - ret = reservation_object_reserve_shared(robj); - if (ret) - return ret; - } - - if (explicit) - return 0; - - /* - * If we have any shared fences, then the exclusive fence - * should be ignored as it will already have been signalled. - */ - fobj = reservation_object_get_list(robj); - if (!fobj || fobj->shared_count == 0) { - /* Wait on any existing exclusive fence which isn't our own */ - fence = reservation_object_get_excl(robj); - if (fence && fence->context != context) { - ret = dma_fence_wait(fence, true); - if (ret) - return ret; - } - } - - if (!exclusive || !fobj) - return 0; - - for (i = 0; i < fobj->shared_count; i++) { - fence = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(robj)); - if (fence->context != context) { - ret = dma_fence_wait(fence, true); - if (ret) - return ret; - } - } - - return 0; -} - /* * event management: */ @@ -1194,67 +1154,47 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event) /* * Cmdstream submission/retirement: */ - -static void retire_worker(struct work_struct *work) -{ - struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, - retire_work); - u32 fence = gpu->completed_fence; - struct etnaviv_gem_submit *submit, *tmp; - LIST_HEAD(retire_list); - - mutex_lock(&gpu->lock); - list_for_each_entry_safe(submit, tmp, &gpu->active_submit_list, node) { - if (!dma_fence_is_signaled(submit->out_fence)) - break; - - list_move(&submit->node, &retire_list); - } - - gpu->retired_fence = fence; - - mutex_unlock(&gpu->lock); - - list_for_each_entry_safe(submit, tmp, &retire_list, node) - etnaviv_submit_put(submit); -} - int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, - u32 fence, struct timespec *timeout) + u32 id, struct timespec *timeout) { + struct dma_fence *fence; int ret; - if (fence_after(fence, gpu->next_fence)) { - DRM_ERROR("waiting on invalid fence: %u (of %u)\n", - fence, gpu->next_fence); - return -EINVAL; - } + /* + * Look up the fence and take a reference. We might still find a fence + * whose refcount has already dropped to zero. dma_fence_get_rcu + * pretends we didn't find a fence in that case. + */ + rcu_read_lock(); + fence = idr_find(&gpu->fence_idr, id); + if (fence) + fence = dma_fence_get_rcu(fence); + rcu_read_unlock(); + + if (!fence) + return 0; if (!timeout) { /* No timeout was requested: just test for completion */ - ret = fence_completed(gpu, fence) ? 0 : -EBUSY; + ret = dma_fence_is_signaled(fence) ? 0 : -EBUSY; } else { unsigned long remaining = etnaviv_timeout_to_jiffies(timeout); - ret = wait_event_interruptible_timeout(gpu->fence_event, - fence_completed(gpu, fence), - remaining); - if (ret == 0) { - DBG("timeout waiting for fence: %u (retired: %u completed: %u)", - fence, gpu->retired_fence, - gpu->completed_fence); + ret = dma_fence_wait_timeout(fence, true, remaining); + if (ret == 0) ret = -ETIMEDOUT; - } else if (ret != -ERESTARTSYS) { + else if (ret != -ERESTARTSYS) ret = 0; - } + } + dma_fence_put(fence); return ret; } /* * Wait for an object to become inactive. This, on it's own, is not race - * free: the object is moved by the retire worker off the active list, and + * free: the object is moved by the scheduler off the active list, and * then the iova is put. Moreover, the object could be re-submitted just * after we notice that it's become inactive. * @@ -1343,16 +1283,19 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, /* add bo's to gpu's ring, and kick gpu: */ -int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, - struct etnaviv_gem_submit *submit) +struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) { + struct etnaviv_gpu *gpu = submit->gpu; + struct dma_fence *gpu_fence; unsigned int i, nr_events = 1, event[3]; int ret; - ret = pm_runtime_get_sync(gpu->dev); - if (ret < 0) - return ret; - submit->runtime_resumed = true; + if (!submit->runtime_resumed) { + ret = pm_runtime_get_sync(gpu->dev); + if (ret < 0) + return NULL; + submit->runtime_resumed = true; + } /* * if there are performance monitor requests we need to have @@ -1367,21 +1310,20 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, ret = event_alloc(gpu, nr_events, event); if (ret) { DRM_ERROR("no free events\n"); - return ret; + return NULL; } mutex_lock(&gpu->lock); - submit->out_fence = etnaviv_gpu_fence_alloc(gpu); - if (!submit->out_fence) { + gpu_fence = etnaviv_gpu_fence_alloc(gpu); + if (!gpu_fence) { for (i = 0; i < nr_events; i++) event_free(gpu, event[i]); - ret = -ENOMEM; goto out_unlock; } - gpu->active_fence = submit->out_fence->seqno; + gpu->active_fence = gpu_fence->seqno; if (submit->nr_pmrs) { gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre; @@ -1390,8 +1332,8 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, etnaviv_sync_point_queue(gpu, event[1]); } - kref_get(&submit->refcount); - gpu->event[event[0]].fence = submit->out_fence; + gpu->event[event[0]].fence = gpu_fence; + submit->cmdbuf.user_size = submit->cmdbuf.size - 8; etnaviv_buffer_queue(gpu, submit->exec_state, event[0], &submit->cmdbuf); @@ -1402,15 +1344,10 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, etnaviv_sync_point_queue(gpu, event[2]); } - list_add_tail(&submit->node, &gpu->active_submit_list); - - hangcheck_timer_reset(gpu); - ret = 0; - out_unlock: mutex_unlock(&gpu->lock); - return ret; + return gpu_fence; } static void sync_point_worker(struct work_struct *work) @@ -1428,9 +1365,35 @@ static void sync_point_worker(struct work_struct *work) etnaviv_gpu_start_fe(gpu, addr + 2, 2); } -/* - * Init/Cleanup: - */ +static void dump_mmu_fault(struct etnaviv_gpu *gpu) +{ + u32 status_reg, status; + int i; + + if (gpu->sec_mode == ETNA_SEC_NONE) + status_reg = VIVS_MMUv2_STATUS; + else + status_reg = VIVS_MMUv2_SEC_STATUS; + + status = gpu_read(gpu, status_reg); + dev_err_ratelimited(gpu->dev, "MMU fault status 0x%08x\n", status); + + for (i = 0; i < 4; i++) { + u32 address_reg; + + if (!(status & (VIVS_MMUv2_STATUS_EXCEPTION0__MASK << (i * 4)))) + continue; + + if (gpu->sec_mode == ETNA_SEC_NONE) + address_reg = VIVS_MMUv2_EXCEPTION_ADDR(i); + else + address_reg = VIVS_MMUv2_SEC_EXCEPTION_ADDR; + + dev_err_ratelimited(gpu->dev, "MMU %d fault addr 0x%08x\n", i, + gpu_read(gpu, address_reg)); + } +} + static irqreturn_t irq_handler(int irq, void *data) { struct etnaviv_gpu *gpu = data; @@ -1451,17 +1414,7 @@ static irqreturn_t irq_handler(int irq, void *data) } if (intr & VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION) { - int i; - - dev_err_ratelimited(gpu->dev, - "MMU fault status 0x%08x\n", - gpu_read(gpu, VIVS_MMUv2_STATUS)); - for (i = 0; i < 4; i++) { - dev_err_ratelimited(gpu->dev, - "MMU %d fault addr 0x%08x\n", - i, gpu_read(gpu, - VIVS_MMUv2_EXCEPTION_ADDR(i))); - } + dump_mmu_fault(gpu); intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION; } @@ -1484,7 +1437,6 @@ static irqreturn_t irq_handler(int irq, void *data) continue; gpu->event[event].fence = NULL; - dma_fence_signal(fence); /* * Events can be processed out of order. Eg, @@ -1497,13 +1449,11 @@ static irqreturn_t irq_handler(int irq, void *data) */ if (fence_after(fence->seqno, gpu->completed_fence)) gpu->completed_fence = fence->seqno; + dma_fence_signal(fence); event_free(gpu, event); } - /* Retire the buffer objects in a work */ - queue_work(gpu->wq, &gpu->retire_work); - ret = IRQ_HANDLED; } @@ -1514,6 +1464,12 @@ static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu) { int ret; + if (gpu->clk_reg) { + ret = clk_prepare_enable(gpu->clk_reg); + if (ret) + return ret; + } + if (gpu->clk_bus) { ret = clk_prepare_enable(gpu->clk_bus); if (ret) @@ -1552,6 +1508,8 @@ static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu) clk_disable_unprepare(gpu->clk_core); if (gpu->clk_bus) clk_disable_unprepare(gpu->clk_bus); + if (gpu->clk_reg) + clk_disable_unprepare(gpu->clk_reg); return 0; } @@ -1675,41 +1633,49 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, gpu->wq = alloc_ordered_workqueue(dev_name(dev), 0); if (!gpu->wq) { - if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) - thermal_cooling_device_unregister(gpu->cooling); - return -ENOMEM; + ret = -ENOMEM; + goto out_thermal; } + ret = etnaviv_sched_init(gpu); + if (ret) + goto out_workqueue; + #ifdef CONFIG_PM ret = pm_runtime_get_sync(gpu->dev); #else ret = etnaviv_gpu_clk_enable(gpu); #endif - if (ret < 0) { - destroy_workqueue(gpu->wq); - if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) - thermal_cooling_device_unregister(gpu->cooling); - return ret; - } + if (ret < 0) + goto out_sched; + gpu->drm = drm; gpu->fence_context = dma_fence_context_alloc(1); + idr_init(&gpu->fence_idr); spin_lock_init(&gpu->fence_spinlock); - INIT_LIST_HEAD(&gpu->active_submit_list); - INIT_WORK(&gpu->retire_work, retire_worker); INIT_WORK(&gpu->sync_point_work, sync_point_worker); - INIT_WORK(&gpu->recover_work, recover_worker); init_waitqueue_head(&gpu->fence_event); - timer_setup(&gpu->hangcheck_timer, hangcheck_handler, TIMER_DEFERRABLE); - priv->gpu[priv->num_gpus++] = gpu; pm_runtime_mark_last_busy(gpu->dev); pm_runtime_put_autosuspend(gpu->dev); return 0; + +out_sched: + etnaviv_sched_fini(gpu); + +out_workqueue: + destroy_workqueue(gpu->wq); + +out_thermal: + if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) + thermal_cooling_device_unregister(gpu->cooling); + + return ret; } static void etnaviv_gpu_unbind(struct device *dev, struct device *master, @@ -1719,11 +1685,11 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, DBG("%s", dev_name(gpu->dev)); - hangcheck_disable(gpu); - flush_workqueue(gpu->wq); destroy_workqueue(gpu->wq); + etnaviv_sched_fini(gpu); + #ifdef CONFIG_PM pm_runtime_get_sync(gpu->dev); pm_runtime_put_sync_suspend(gpu->dev); @@ -1745,6 +1711,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, } gpu->drm = NULL; + idr_destroy(&gpu->fence_idr); if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) thermal_cooling_device_unregister(gpu->cooling); @@ -1762,6 +1729,7 @@ static const struct of_device_id etnaviv_gpu_match[] = { }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, etnaviv_gpu_match); static int etnaviv_gpu_platform_probe(struct platform_device *pdev) { @@ -1775,6 +1743,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) gpu->dev = &pdev->dev; mutex_init(&gpu->lock); + mutex_init(&gpu->fence_idr_lock); /* Map registers: */ gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev)); @@ -1796,6 +1765,11 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) } /* Get Clocks: */ + gpu->clk_reg = devm_clk_get(&pdev->dev, "reg"); + DBG("clk_reg: %p", gpu->clk_reg); + if (IS_ERR(gpu->clk_reg)) + gpu->clk_reg = NULL; + gpu->clk_bus = devm_clk_get(&pdev->dev, "bus"); DBG("clk_bus: %p", gpu->clk_bus); if (IS_ERR(gpu->clk_bus)) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 7623905210dc..3c3005501846 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -38,21 +38,17 @@ struct etnaviv_chip_identity { /* Supported minor feature fields. */ u32 minor_features0; - - /* Supported minor feature 1 fields. */ u32 minor_features1; - - /* Supported minor feature 2 fields. */ u32 minor_features2; - - /* Supported minor feature 3 fields. */ u32 minor_features3; - - /* Supported minor feature 4 fields. */ u32 minor_features4; - - /* Supported minor feature 5 fields. */ u32 minor_features5; + u32 minor_features6; + u32 minor_features7; + u32 minor_features8; + u32 minor_features9; + u32 minor_features10; + u32 minor_features11; /* Number of streams supported. */ u32 stream_count; @@ -88,6 +84,12 @@ struct etnaviv_chip_identity { u8 varyings_count; }; +enum etnaviv_sec_mode { + ETNA_SEC_NONE = 0, + ETNA_SEC_KERNEL, + ETNA_SEC_TZ +}; + struct etnaviv_event { struct dma_fence *fence; struct etnaviv_gem_submit *submit; @@ -106,8 +108,10 @@ struct etnaviv_gpu { struct device *dev; struct mutex lock; struct etnaviv_chip_identity identity; + enum etnaviv_sec_mode sec_mode; struct etnaviv_file_private *lastctx; struct workqueue_struct *wq; + struct drm_gpu_scheduler sched; /* 'ring'-buffer: */ struct etnaviv_cmdbuf buffer; @@ -122,23 +126,18 @@ struct etnaviv_gpu { struct completion event_free; spinlock_t event_spinlock; - /* list of currently in-flight command buffers */ - struct list_head active_submit_list; - u32 idle_mask; /* Fencing support */ + struct mutex fence_idr_lock; + struct idr fence_idr; u32 next_fence; u32 active_fence; u32 completed_fence; - u32 retired_fence; wait_queue_head_t fence_event; u64 fence_context; spinlock_t fence_spinlock; - /* worker for handling active-list retiring: */ - struct work_struct retire_work; - /* worker for handling 'sync' points: */ struct work_struct sync_point_work; int sync_point_event; @@ -151,16 +150,10 @@ struct etnaviv_gpu { /* Power Control: */ struct clk *clk_bus; + struct clk *clk_reg; struct clk *clk_core; struct clk *clk_shader; - /* Hang Detction: */ -#define DRM_ETNAVIV_HANGCHECK_PERIOD 500 /* in ms */ -#define DRM_ETNAVIV_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_ETNAVIV_HANGCHECK_PERIOD) - struct timer_list hangcheck_timer; - u32 hangcheck_fence; - u32 hangcheck_dma_addr; - struct work_struct recover_work; unsigned int freq_scale; unsigned long base_rate_core; unsigned long base_rate_shader; @@ -181,29 +174,22 @@ static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence) return fence_after_eq(gpu->completed_fence, fence); } -static inline bool fence_retired(struct etnaviv_gpu *gpu, u32 fence) -{ - return fence_after_eq(gpu->retired_fence, fence); -} - int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value); int etnaviv_gpu_init(struct etnaviv_gpu *gpu); +bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu); #ifdef CONFIG_DEBUG_FS int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m); #endif -int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj, - unsigned int context, bool exclusive, bool implicit); - +void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu); void etnaviv_gpu_retire(struct etnaviv_gpu *gpu); int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, u32 fence, struct timespec *timeout); int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout); -int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, - struct etnaviv_gem_submit *submit); +struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit); int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu); void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu); int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c new file mode 100644 index 000000000000..ea08bb38caaf --- /dev/null +++ b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 Etnaviv Project + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "etnaviv_gpu.h" + +static const struct etnaviv_chip_identity etnaviv_chip_identities[] = { + { + .model = 0x7000, + .revision = 0x6214, + .stream_count = 16, + .register_max = 64, + .thread_count = 1024, + .shader_core_count = 4, + .vertex_cache_size = 16, + .vertex_output_buffer_size = 1024, + .pixel_pipes = 2, + .instruction_count = 512, + .num_constants = 320, + .buffer_size = 0, + .varyings_count = 16, + .features = 0xe0287cad, + .minor_features0 = 0xc1799eff, + .minor_features1 = 0xfefbfad9, + .minor_features2 = 0xeb9d4fbf, + .minor_features3 = 0xedfffced, + .minor_features4 = 0xdb0dafc7, + .minor_features5 = 0xbb5ac333, + .minor_features6 = 0xfc8ee200, + .minor_features7 = 0x03fbfa6f, + .minor_features8 = 0x00ef0ef0, + .minor_features9 = 0x0edbf03c, + .minor_features10 = 0x90044250, + .minor_features11 = 0x00000024, + }, +}; + +bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu) +{ + struct etnaviv_chip_identity *ident = &gpu->identity; + int i; + + for (i = 0; i < ARRAY_SIZE(etnaviv_chip_identities); i++) { + if (etnaviv_chip_identities[i].model == ident->model && + etnaviv_chip_identities[i].revision == ident->revision) { + memcpy(ident, &etnaviv_chip_identities[i], + sizeof(*ident)); + return true; + } + } + + return false; +} diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c index 7a8c94731748..4b9b11ca6f03 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c @@ -158,7 +158,7 @@ void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable); } -const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = { +static const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = { .free = etnaviv_iommuv1_domain_free, .map = etnaviv_iommuv1_map, .unmap = etnaviv_iommuv1_unmap, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c index 1e956e266aa3..9752dbd5d28b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c @@ -40,6 +40,9 @@ struct etnaviv_iommuv2_domain { struct etnaviv_iommu_domain base; + /* P(age) T(able) A(rray) */ + u64 *pta_cpu; + dma_addr_t pta_dma; /* M(aster) TLB aka first level pagetable */ u32 *mtlb_cpu; dma_addr_t mtlb_dma; @@ -114,6 +117,15 @@ static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) for (i = 0; i < SZ_4K / 4; i++) *p++ = 0xdead55aa; + etnaviv_domain->pta_cpu = dma_alloc_coherent(etnaviv_domain->base.dev, + SZ_4K, + &etnaviv_domain->pta_dma, + GFP_KERNEL); + if (!etnaviv_domain->pta_cpu) { + ret = -ENOMEM; + goto fail_mem; + } + etnaviv_domain->mtlb_cpu = dma_alloc_coherent(etnaviv_domain->base.dev, SZ_4K, &etnaviv_domain->mtlb_dma, @@ -150,6 +162,11 @@ fail_mem: etnaviv_domain->base.bad_page_cpu, etnaviv_domain->base.bad_page_dma); + if (etnaviv_domain->pta_cpu) + dma_free_coherent(etnaviv_domain->base.dev, SZ_4K, + etnaviv_domain->pta_cpu, + etnaviv_domain->pta_dma); + if (etnaviv_domain->mtlb_cpu) dma_free_coherent(etnaviv_domain->base.dev, SZ_4K, etnaviv_domain->mtlb_cpu, @@ -176,6 +193,10 @@ static void etnaviv_iommuv2_domain_free(struct etnaviv_iommu_domain *domain) etnaviv_domain->base.bad_page_dma); dma_free_coherent(etnaviv_domain->base.dev, SZ_4K, + etnaviv_domain->pta_cpu, + etnaviv_domain->pta_dma); + + dma_free_coherent(etnaviv_domain->base.dev, SZ_4K, etnaviv_domain->mtlb_cpu, etnaviv_domain->mtlb_dma); @@ -216,7 +237,7 @@ static void etnaviv_iommuv2_dump(struct etnaviv_iommu_domain *domain, void *buf) memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K); } -void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) +static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu *gpu) { struct etnaviv_iommuv2_domain *etnaviv_domain = to_etnaviv_domain(gpu->mmu->domain); @@ -236,7 +257,60 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE); } -const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = { +static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu *gpu) +{ + struct etnaviv_iommuv2_domain *etnaviv_domain = + to_etnaviv_domain(gpu->mmu->domain); + u16 prefetch; + + /* If the MMU is already enabled the state is still there. */ + if (gpu_read(gpu, VIVS_MMUv2_SEC_CONTROL) & VIVS_MMUv2_SEC_CONTROL_ENABLE) + return; + + gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_LOW, + lower_32_bits(etnaviv_domain->pta_dma)); + gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_HIGH, + upper_32_bits(etnaviv_domain->pta_dma)); + gpu_write(gpu, VIVS_MMUv2_PTA_CONTROL, VIVS_MMUv2_PTA_CONTROL_ENABLE); + + gpu_write(gpu, VIVS_MMUv2_NONSEC_SAFE_ADDR_LOW, + lower_32_bits(etnaviv_domain->base.bad_page_dma)); + gpu_write(gpu, VIVS_MMUv2_SEC_SAFE_ADDR_LOW, + lower_32_bits(etnaviv_domain->base.bad_page_dma)); + gpu_write(gpu, VIVS_MMUv2_SAFE_ADDRESS_CONFIG, + VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH( + upper_32_bits(etnaviv_domain->base.bad_page_dma)) | + VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH( + upper_32_bits(etnaviv_domain->base.bad_page_dma))); + + etnaviv_domain->pta_cpu[0] = etnaviv_domain->mtlb_dma | + VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K; + + /* trigger a PTA load through the FE */ + prefetch = etnaviv_buffer_config_pta(gpu); + etnaviv_gpu_start_fe(gpu, (u32)etnaviv_cmdbuf_get_pa(&gpu->buffer), + prefetch); + etnaviv_gpu_wait_idle(gpu, 100); + + gpu_write(gpu, VIVS_MMUv2_SEC_CONTROL, VIVS_MMUv2_SEC_CONTROL_ENABLE); +} + +void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) +{ + switch (gpu->sec_mode) { + case ETNA_SEC_NONE: + etnaviv_iommuv2_restore_nonsec(gpu); + break; + case ETNA_SEC_KERNEL: + etnaviv_iommuv2_restore_sec(gpu); + break; + default: + WARN(1, "unhandled GPU security mode\n"); + break; + } +} + +static const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = { .free = etnaviv_iommuv2_domain_free, .map = etnaviv_iommuv2_map, .unmap = etnaviv_iommuv2_unmap, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index d113fe06e6b5..49e049713a52 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -29,7 +29,7 @@ static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain, size_t pgsize = SZ_4K; if (!IS_ALIGNED(iova | size, pgsize)) { - pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n", + pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%zx\n", iova, size, pgsize); return; } @@ -54,7 +54,7 @@ static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain, int ret = 0; if (!IS_ALIGNED(iova | paddr | size, pgsize)) { - pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n", + pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%zx\n", iova, &paddr, size, pgsize); return -EINVAL; } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c new file mode 100644 index 000000000000..6cf0775dbcd7 --- /dev/null +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2017 Etnaviv Project + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kthread.h> + +#include "etnaviv_drv.h" +#include "etnaviv_dump.h" +#include "etnaviv_gem.h" +#include "etnaviv_gpu.h" +#include "etnaviv_sched.h" + +static int etnaviv_job_hang_limit = 0; +module_param_named(job_hang_limit, etnaviv_job_hang_limit, int , 0444); +static int etnaviv_hw_jobs_limit = 4; +module_param_named(hw_job_limit, etnaviv_hw_jobs_limit, int , 0444); + +static struct dma_fence * +etnaviv_sched_dependency(struct drm_sched_job *sched_job, + struct drm_sched_entity *entity) +{ + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + struct dma_fence *fence; + int i; + + if (unlikely(submit->in_fence)) { + fence = submit->in_fence; + submit->in_fence = NULL; + + if (!dma_fence_is_signaled(fence)) + return fence; + + dma_fence_put(fence); + } + + for (i = 0; i < submit->nr_bos; i++) { + struct etnaviv_gem_submit_bo *bo = &submit->bos[i]; + int j; + + if (bo->excl) { + fence = bo->excl; + bo->excl = NULL; + + if (!dma_fence_is_signaled(fence)) + return fence; + + dma_fence_put(fence); + } + + for (j = 0; j < bo->nr_shared; j++) { + if (!bo->shared[j]) + continue; + + fence = bo->shared[j]; + bo->shared[j] = NULL; + + if (!dma_fence_is_signaled(fence)) + return fence; + + dma_fence_put(fence); + } + kfree(bo->shared); + bo->nr_shared = 0; + bo->shared = NULL; + } + + return NULL; +} + +static struct dma_fence *etnaviv_sched_run_job(struct drm_sched_job *sched_job) +{ + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + struct dma_fence *fence = NULL; + + if (likely(!sched_job->s_fence->finished.error)) + fence = etnaviv_gpu_submit(submit); + else + dev_dbg(submit->gpu->dev, "skipping bad job\n"); + + return fence; +} + +static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job) +{ + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + struct etnaviv_gpu *gpu = submit->gpu; + + /* block scheduler */ + kthread_park(gpu->sched.thread); + drm_sched_hw_job_reset(&gpu->sched, sched_job); + + /* get the GPU back into the init state */ + etnaviv_core_dump(gpu); + etnaviv_gpu_recover_hang(gpu); + + /* restart scheduler after GPU is usable again */ + drm_sched_job_recovery(&gpu->sched); + kthread_unpark(gpu->sched.thread); +} + +static void etnaviv_sched_free_job(struct drm_sched_job *sched_job) +{ + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + + etnaviv_submit_put(submit); +} + +static const struct drm_sched_backend_ops etnaviv_sched_ops = { + .dependency = etnaviv_sched_dependency, + .run_job = etnaviv_sched_run_job, + .timedout_job = etnaviv_sched_timedout_job, + .free_job = etnaviv_sched_free_job, +}; + +int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, + struct etnaviv_gem_submit *submit) +{ + int ret; + + ret = drm_sched_job_init(&submit->sched_job, &submit->gpu->sched, + sched_entity, submit->cmdbuf.ctx); + if (ret) + return ret; + + submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished); + mutex_lock(&submit->gpu->fence_idr_lock); + submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr, + submit->out_fence, 0, + INT_MAX, GFP_KERNEL); + mutex_unlock(&submit->gpu->fence_idr_lock); + if (submit->out_fence_id < 0) + return -ENOMEM; + + /* the scheduler holds on to the job now */ + kref_get(&submit->refcount); + + drm_sched_entity_push_job(&submit->sched_job, sched_entity); + + return 0; +} + +int etnaviv_sched_init(struct etnaviv_gpu *gpu) +{ + int ret; + + ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, + etnaviv_hw_jobs_limit, etnaviv_job_hang_limit, + msecs_to_jiffies(500), dev_name(gpu->dev)); + if (ret) + return ret; + + return 0; +} + +void etnaviv_sched_fini(struct etnaviv_gpu *gpu) +{ + drm_sched_fini(&gpu->sched); +} diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.h b/drivers/gpu/drm/etnaviv/etnaviv_sched.h new file mode 100644 index 000000000000..097635fa78ae --- /dev/null +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 Etnaviv Project + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ETNAVIV_SCHED_H__ +#define __ETNAVIV_SCHED_H__ + +#include <drm/gpu_scheduler.h> + +struct etnaviv_gpu; + +static inline +struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job) +{ + return container_of(sched_job, struct etnaviv_gem_submit, sched_job); +} + +int etnaviv_sched_init(struct etnaviv_gpu *gpu); +void etnaviv_sched_fini(struct etnaviv_gpu *gpu); +int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, + struct etnaviv_gem_submit *submit); + +#endif /* __ETNAVIV_SCHED_H__ */ diff --git a/drivers/gpu/drm/etnaviv/state.xml.h b/drivers/gpu/drm/etnaviv/state.xml.h index c27c1484cfa9..421cb7cc0053 100644 --- a/drivers/gpu/drm/etnaviv/state.xml.h +++ b/drivers/gpu/drm/etnaviv/state.xml.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: GPL-2.0 */ #ifndef STATE_XML #define STATE_XML @@ -9,14 +8,40 @@ http://0x04.net/cgit/index.cgi/rules-ng-ng git clone git://0x04.net/rules-ng-ng The rules-ng-ng source files this header was generated from are: -- state.xml ( 18882 bytes, from 2015-03-25 11:42:32) -- common.xml ( 18437 bytes, from 2015-03-25 11:27:41) -- state_hi.xml ( 23420 bytes, from 2015-03-25 11:47:21) -- state_2d.xml ( 51549 bytes, from 2015-03-25 11:25:06) -- state_3d.xml ( 54600 bytes, from 2015-03-25 11:25:19) -- state_vg.xml ( 5973 bytes, from 2015-03-25 11:26:01) - -Copyright (C) 2015 +- state.xml ( 26087 bytes, from 2017-12-18 16:51:59) +- common.xml ( 35468 bytes, from 2018-01-22 13:48:54) +- common_3d.xml ( 14615 bytes, from 2017-12-18 16:51:59) +- state_hi.xml ( 30232 bytes, from 2018-02-15 15:48:01) +- copyright.xml ( 1597 bytes, from 2016-12-08 16:37:56) +- state_2d.xml ( 51552 bytes, from 2016-12-08 16:37:56) +- state_3d.xml ( 79992 bytes, from 2017-12-18 16:51:59) +- state_blt.xml ( 13405 bytes, from 2017-12-18 16:51:59) +- state_vg.xml ( 5975 bytes, from 2016-12-08 16:37:56) + +Copyright (C) 2012-2017 by the following authors: +- Wladimir J. van der Laan <laanwj@gmail.com> +- Christian Gmeiner <christian.gmeiner@gmail.com> +- Lucas Stach <l.stach@pengutronix.de> +- Russell King <rmk@arm.linux.org.uk> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sub license, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. */ @@ -24,9 +49,25 @@ Copyright (C) 2015 #define VARYING_COMPONENT_USE_USED 0x00000001 #define VARYING_COMPONENT_USE_POINTCOORD_X 0x00000002 #define VARYING_COMPONENT_USE_POINTCOORD_Y 0x00000003 +#define FE_DATA_TYPE_BYTE 0x00000000 +#define FE_DATA_TYPE_UNSIGNED_BYTE 0x00000001 +#define FE_DATA_TYPE_SHORT 0x00000002 +#define FE_DATA_TYPE_UNSIGNED_SHORT 0x00000003 +#define FE_DATA_TYPE_INT 0x00000004 +#define FE_DATA_TYPE_UNSIGNED_INT 0x00000005 +#define FE_DATA_TYPE_FLOAT 0x00000008 +#define FE_DATA_TYPE_HALF_FLOAT 0x00000009 +#define FE_DATA_TYPE_FIXED 0x0000000b +#define FE_DATA_TYPE_INT_10_10_10_2 0x0000000c +#define FE_DATA_TYPE_UNSIGNED_INT_10_10_10_2 0x0000000d +#define FE_DATA_TYPE_BYTE_I 0x0000000e +#define FE_DATA_TYPE_SHORT_I 0x0000000f #define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK 0x000000ff #define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT 0 #define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x) (((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK) +#define FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__MASK 0x00ff0000 +#define FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__SHIFT 16 +#define FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR(x) (((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__MASK) #define VIVS_FE 0x00000000 #define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0) (0x00000600 + 0x4*(i0)) @@ -34,17 +75,7 @@ Copyright (C) 2015 #define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN 0x00000010 #define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK 0x0000000f #define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT 0 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE 0x00000000 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE 0x00000001 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT 0x00000002 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT 0x00000003 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT 0x00000004 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT 0x00000005 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT 0x00000008 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT 0x00000009 -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED 0x0000000b -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2 0x0000000c -#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2 0x0000000d +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK) #define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK 0x00000030 #define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT 4 #define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK) @@ -76,6 +107,7 @@ Copyright (C) 2015 #define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR 0x00000000 #define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT 0x00000001 #define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT 0x00000002 +#define VIVS_FE_INDEX_STREAM_CONTROL_PRIMITIVE_RESTART 0x00000100 #define VIVS_FE_VERTEX_STREAM_BASE_ADDR 0x0000064c @@ -151,6 +183,8 @@ Copyright (C) 2015 #define VIVS_FE_AUTO_FLUSH 0x00000670 +#define VIVS_FE_PRIMITIVE_RESTART_INDEX 0x00000674 + #define VIVS_FE_UNK00678 0x00000678 #define VIVS_FE_UNK0067C 0x0000067c @@ -163,17 +197,40 @@ Copyright (C) 2015 #define VIVS_FE_VERTEX_STREAMS_CONTROL(i0) (0x000006a0 + 0x4*(i0)) -#define VIVS_FE_UNK00700(i0) (0x00000700 + 0x4*(i0)) -#define VIVS_FE_UNK00700__ESIZE 0x00000004 -#define VIVS_FE_UNK00700__LEN 0x00000010 +#define VIVS_FE_GENERIC_ATTRIB(i0) (0x00000000 + 0x4*(i0)) +#define VIVS_FE_GENERIC_ATTRIB__ESIZE 0x00000004 +#define VIVS_FE_GENERIC_ATTRIB__LEN 0x00000010 + +#define VIVS_FE_GENERIC_ATTRIB_UNK006C0(i0) (0x000006c0 + 0x4*(i0)) + +#define VIVS_FE_GENERIC_ATTRIB_UNK00700(i0) (0x00000700 + 0x4*(i0)) + +#define VIVS_FE_GENERIC_ATTRIB_UNK00740(i0) (0x00000740 + 0x4*(i0)) + +#define VIVS_FE_GENERIC_ATTRIB_SCALE(i0) (0x00000780 + 0x4*(i0)) + +#define VIVS_FE_HALTI5_UNK007C4 0x000007c4 + +#define VIVS_FE_HALTI5_UNK007D0(i0) (0x000007d0 + 0x4*(i0)) +#define VIVS_FE_HALTI5_UNK007D0__ESIZE 0x00000004 +#define VIVS_FE_HALTI5_UNK007D0__LEN 0x00000002 + +#define VIVS_FE_HALTI5_UNK007D8 0x000007d8 + +#define VIVS_FE_DESC_START 0x000007dc + +#define VIVS_FE_DESC_END 0x000007e0 + +#define VIVS_FE_DESC_AVAIL 0x000007e4 +#define VIVS_FE_DESC_AVAIL_COUNT__MASK 0x0000007f +#define VIVS_FE_DESC_AVAIL_COUNT__SHIFT 0 +#define VIVS_FE_DESC_AVAIL_COUNT(x) (((x) << VIVS_FE_DESC_AVAIL_COUNT__SHIFT) & VIVS_FE_DESC_AVAIL_COUNT__MASK) + +#define VIVS_FE_FENCE_WAIT_DATA_LOW 0x000007e8 -#define VIVS_FE_UNK00740(i0) (0x00000740 + 0x4*(i0)) -#define VIVS_FE_UNK00740__ESIZE 0x00000004 -#define VIVS_FE_UNK00740__LEN 0x00000010 +#define VIVS_FE_FENCE_WAIT_DATA_HIGH 0x000007f4 -#define VIVS_FE_UNK00780(i0) (0x00000780 + 0x4*(i0)) -#define VIVS_FE_UNK00780__ESIZE 0x00000004 -#define VIVS_FE_UNK00780__LEN 0x00000010 +#define VIVS_FE_ROBUSTNESS_UNK007F8 0x000007f8 #define VIVS_GL 0x00000000 @@ -188,6 +245,7 @@ Copyright (C) 2015 #define VIVS_GL_EVENT_EVENT_ID(x) (((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK) #define VIVS_GL_EVENT_FROM_FE 0x00000020 #define VIVS_GL_EVENT_FROM_PE 0x00000040 +#define VIVS_GL_EVENT_FROM_BLT 0x00000080 #define VIVS_GL_EVENT_SOURCE__MASK 0x00001f00 #define VIVS_GL_EVENT_SOURCE__SHIFT 8 #define VIVS_GL_EVENT_SOURCE(x) (((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK) @@ -199,6 +257,9 @@ Copyright (C) 2015 #define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK 0x00001f00 #define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT 8 #define VIVS_GL_SEMAPHORE_TOKEN_TO(x) (((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK) +#define VIVS_GL_SEMAPHORE_TOKEN_UNK28__MASK 0x30000000 +#define VIVS_GL_SEMAPHORE_TOKEN_UNK28__SHIFT 28 +#define VIVS_GL_SEMAPHORE_TOKEN_UNK28(x) (((x) << VIVS_GL_SEMAPHORE_TOKEN_UNK28__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_UNK28__MASK) #define VIVS_GL_FLUSH_CACHE 0x0000380c #define VIVS_GL_FLUSH_CACHE_DEPTH 0x00000001 @@ -208,6 +269,10 @@ Copyright (C) 2015 #define VIVS_GL_FLUSH_CACHE_TEXTUREVS 0x00000010 #define VIVS_GL_FLUSH_CACHE_SHADER_L1 0x00000020 #define VIVS_GL_FLUSH_CACHE_SHADER_L2 0x00000040 +#define VIVS_GL_FLUSH_CACHE_UNK10 0x00000400 +#define VIVS_GL_FLUSH_CACHE_UNK11 0x00000800 +#define VIVS_GL_FLUSH_CACHE_DESCRIPTOR_UNK12 0x00001000 +#define VIVS_GL_FLUSH_CACHE_DESCRIPTOR_UNK13 0x00002000 #define VIVS_GL_FLUSH_MMU 0x00003810 #define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU 0x00000001 @@ -244,30 +309,8 @@ Copyright (C) 2015 #define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x) (((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK) #define VIVS_GL_VARYING_NUM_COMPONENTS 0x00003820 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK 0x00000007 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT 0 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK) -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK 0x00000070 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT 4 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK) -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK 0x00000700 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT 8 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK) -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK 0x00007000 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT 12 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK) -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK 0x00070000 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT 16 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK) -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK 0x00700000 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT 20 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK) -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK 0x07000000 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT 24 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK) -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK 0x70000000 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT 28 -#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK) + +#define VIVS_GL_OCCLUSION_QUERY_ADDR 0x00003824 #define VIVS_GL_VARYING_COMPONENT_USE(i0) (0x00003828 + 0x4*(i0)) #define VIVS_GL_VARYING_COMPONENT_USE__ESIZE 0x00000004 @@ -321,6 +364,10 @@ Copyright (C) 2015 #define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT 30 #define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK) +#define VIVS_GL_UNK0382C 0x0000382c + +#define VIVS_GL_OCCLUSION_QUERY_CONTROL 0x00003830 + #define VIVS_GL_UNK03834 0x00003834 #define VIVS_GL_UNK03838 0x00003838 @@ -332,8 +379,58 @@ Copyright (C) 2015 #define VIVS_GL_CONTEXT_POINTER 0x00003850 +#define VIVS_GL_UNK03854 0x00003854 + +#define VIVS_GL_BUG_FIXES 0x00003860 + +#define VIVS_GL_FENCE_OUT_ADDRESS 0x00003868 + +#define VIVS_GL_FENCE_OUT_DATA_LOW 0x0000386c + +#define VIVS_GL_HALTI5_UNK03884 0x00003884 + +#define VIVS_GL_HALTI5_SH_SPECIALS 0x00003888 +#define VIVS_GL_HALTI5_SH_SPECIALS_VS_PSIZE_OUT__MASK 0x0000007f +#define VIVS_GL_HALTI5_SH_SPECIALS_VS_PSIZE_OUT__SHIFT 0 +#define VIVS_GL_HALTI5_SH_SPECIALS_VS_PSIZE_OUT(x) (((x) << VIVS_GL_HALTI5_SH_SPECIALS_VS_PSIZE_OUT__SHIFT) & VIVS_GL_HALTI5_SH_SPECIALS_VS_PSIZE_OUT__MASK) +#define VIVS_GL_HALTI5_SH_SPECIALS_PS_PCOORD_IN__MASK 0x00007f00 +#define VIVS_GL_HALTI5_SH_SPECIALS_PS_PCOORD_IN__SHIFT 8 +#define VIVS_GL_HALTI5_SH_SPECIALS_PS_PCOORD_IN(x) (((x) << VIVS_GL_HALTI5_SH_SPECIALS_PS_PCOORD_IN__SHIFT) & VIVS_GL_HALTI5_SH_SPECIALS_PS_PCOORD_IN__MASK) +#define VIVS_GL_HALTI5_SH_SPECIALS_UNK16__MASK 0x007f0000 +#define VIVS_GL_HALTI5_SH_SPECIALS_UNK16__SHIFT 16 +#define VIVS_GL_HALTI5_SH_SPECIALS_UNK16(x) (((x) << VIVS_GL_HALTI5_SH_SPECIALS_UNK16__SHIFT) & VIVS_GL_HALTI5_SH_SPECIALS_UNK16__MASK) +#define VIVS_GL_HALTI5_SH_SPECIALS_UNK24__MASK 0xff000000 +#define VIVS_GL_HALTI5_SH_SPECIALS_UNK24__SHIFT 24 +#define VIVS_GL_HALTI5_SH_SPECIALS_UNK24(x) (((x) << VIVS_GL_HALTI5_SH_SPECIALS_UNK24__SHIFT) & VIVS_GL_HALTI5_SH_SPECIALS_UNK24__MASK) + +#define VIVS_GL_GS_UNK0388C 0x0000388c + +#define VIVS_GL_FENCE_OUT_DATA_HIGH 0x00003898 + +#define VIVS_GL_SHADER_INDEX 0x0000389c + +#define VIVS_GL_GS_UNK038A0(i0) (0x000038a0 + 0x4*(i0)) +#define VIVS_GL_GS_UNK038A0__ESIZE 0x00000004 +#define VIVS_GL_GS_UNK038A0__LEN 0x00000008 + +#define VIVS_GL_HALTI5_UNK038C0(i0) (0x000038c0 + 0x4*(i0)) +#define VIVS_GL_HALTI5_UNK038C0__ESIZE 0x00000004 +#define VIVS_GL_HALTI5_UNK038C0__LEN 0x00000010 + +#define VIVS_GL_SECURITY_UNK3900 0x00003900 + +#define VIVS_GL_SECURITY_UNK3904 0x00003904 + #define VIVS_GL_UNK03A00 0x00003a00 +#define VIVS_GL_UNK03A04 0x00003a04 + +#define VIVS_GL_UNK03A08 0x00003a08 + +#define VIVS_GL_UNK03A0C 0x00003a0c + +#define VIVS_GL_UNK03A10 0x00003a10 + #define VIVS_GL_STALL_TOKEN 0x00003c00 #define VIVS_GL_STALL_TOKEN_FROM__MASK 0x0000001f #define VIVS_GL_STALL_TOKEN_FROM__SHIFT 0 @@ -344,6 +441,59 @@ Copyright (C) 2015 #define VIVS_GL_STALL_TOKEN_FLIP0 0x40000000 #define VIVS_GL_STALL_TOKEN_FLIP1 0x80000000 +#define VIVS_NFE 0x00000000 + +#define VIVS_NFE_VERTEX_STREAMS(i0) (0x00000000 + 0x4*(i0)) +#define VIVS_NFE_VERTEX_STREAMS__ESIZE 0x00000004 +#define VIVS_NFE_VERTEX_STREAMS__LEN 0x00000010 + +#define VIVS_NFE_VERTEX_STREAMS_BASE_ADDR(i0) (0x00014600 + 0x4*(i0)) + +#define VIVS_NFE_VERTEX_STREAMS_CONTROL(i0) (0x00014640 + 0x4*(i0)) + +#define VIVS_NFE_VERTEX_STREAMS_UNK14680(i0) (0x00014680 + 0x4*(i0)) + +#define VIVS_NFE_VERTEX_STREAMS_ROBUSTNESS_UNK146C0(i0) (0x000146c0 + 0x4*(i0)) + +#define VIVS_NFE_GENERIC_ATTRIB(i0) (0x00000000 + 0x4*(i0)) +#define VIVS_NFE_GENERIC_ATTRIB__ESIZE 0x00000004 +#define VIVS_NFE_GENERIC_ATTRIB__LEN 0x00000020 + +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0(i0) (0x00017800 + 0x4*(i0)) +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_TYPE__MASK 0x0000000f +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_TYPE__SHIFT 0 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_TYPE(x) (((x) << VIVS_NFE_GENERIC_ATTRIB_CONFIG0_TYPE__SHIFT) & VIVS_NFE_GENERIC_ATTRIB_CONFIG0_TYPE__MASK) +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_ENDIAN__MASK 0x00000030 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_ENDIAN__SHIFT 4 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_ENDIAN(x) (((x) << VIVS_NFE_GENERIC_ATTRIB_CONFIG0_ENDIAN__SHIFT) & VIVS_NFE_GENERIC_ATTRIB_CONFIG0_ENDIAN__MASK) +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_STREAM__MASK 0x00000700 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_STREAM__SHIFT 8 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_STREAM(x) (((x) << VIVS_NFE_GENERIC_ATTRIB_CONFIG0_STREAM__SHIFT) & VIVS_NFE_GENERIC_ATTRIB_CONFIG0_STREAM__MASK) +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NUM__MASK 0x00003000 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NUM__SHIFT 12 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NUM(x) (((x) << VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NUM__SHIFT) & VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NUM__MASK) +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NORMALIZE__MASK 0x0000c000 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NORMALIZE__SHIFT 14 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NORMALIZE_OFF 0x00000000 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NORMALIZE_ON 0x00008000 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_START__MASK 0x00ff0000 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_START__SHIFT 16 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG0_START(x) (((x) << VIVS_NFE_GENERIC_ATTRIB_CONFIG0_START__SHIFT) & VIVS_NFE_GENERIC_ATTRIB_CONFIG0_START__MASK) + +#define VIVS_NFE_GENERIC_ATTRIB_UNK17880(i0) (0x00017880 + 0x4*(i0)) + +#define VIVS_NFE_GENERIC_ATTRIB_UNK17900(i0) (0x00017900 + 0x4*(i0)) + +#define VIVS_NFE_GENERIC_ATTRIB_UNK17980(i0) (0x00017980 + 0x4*(i0)) + +#define VIVS_NFE_GENERIC_ATTRIB_SCALE(i0) (0x00017a00 + 0x4*(i0)) + +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG1(i0) (0x00017a80 + 0x4*(i0)) +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG1_END__MASK 0x000000ff +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG1_END__SHIFT 0 +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG1_END(x) (((x) << VIVS_NFE_GENERIC_ATTRIB_CONFIG1_END__SHIFT) & VIVS_NFE_GENERIC_ATTRIB_CONFIG1_END__MASK) +#define VIVS_NFE_GENERIC_ATTRIB_CONFIG1_NONCONSECUTIVE 0x00000800 + #define VIVS_DUMMY 0x00000000 #define VIVS_DUMMY_DUMMY 0x0003fffc diff --git a/drivers/gpu/drm/etnaviv/state_3d.xml.h b/drivers/gpu/drm/etnaviv/state_3d.xml.h index 73a97d35c51b..ebbd4fcf3096 100644 --- a/drivers/gpu/drm/etnaviv/state_3d.xml.h +++ b/drivers/gpu/drm/etnaviv/state_3d.xml.h @@ -7,4 +7,9 @@ #define VIVS_TS_FLUSH_CACHE 0x00001650 #define VIVS_TS_FLUSH_CACHE_FLUSH 0x00000001 +#define VIVS_NTE_DESCRIPTOR_FLUSH 0x00014c44 +#define VIVS_NTE_DESCRIPTOR_FLUSH_UNK28__MASK 0xf0000000 +#define VIVS_NTE_DESCRIPTOR_FLUSH_UNK28__SHIFT 28 +#define VIVS_NTE_DESCRIPTOR_FLUSH_UNK28(x) (((x) << VIVS_NTE_DESCRIPTOR_FLUSH_UNK28__SHIFT) & VIVS_NTE_DESCRIPTOR_FLUSH_UNK28__MASK) + #endif /* STATE_3D_XML */ diff --git a/drivers/gpu/drm/etnaviv/state_blt.xml.h b/drivers/gpu/drm/etnaviv/state_blt.xml.h new file mode 100644 index 000000000000..daae55995def --- /dev/null +++ b/drivers/gpu/drm/etnaviv/state_blt.xml.h @@ -0,0 +1,52 @@ +#ifndef STATE_BLT_XML +#define STATE_BLT_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://0x04.net/cgit/index.cgi/rules-ng-ng +git clone git://0x04.net/rules-ng-ng + +The rules-ng-ng source files this header was generated from are: +- state.xml ( 26087 bytes, from 2017-12-18 16:51:59) +- common.xml ( 35468 bytes, from 2018-01-22 13:48:54) +- common_3d.xml ( 14615 bytes, from 2017-12-18 16:51:59) +- state_hi.xml ( 30232 bytes, from 2018-02-15 15:48:01) +- copyright.xml ( 1597 bytes, from 2016-12-08 16:37:56) +- state_2d.xml ( 51552 bytes, from 2016-12-08 16:37:56) +- state_3d.xml ( 79992 bytes, from 2017-12-18 16:51:59) +- state_blt.xml ( 13405 bytes, from 2017-12-18 16:51:59) +- state_vg.xml ( 5975 bytes, from 2016-12-08 16:37:56) + +Copyright (C) 2012-2017 by the following authors: +- Wladimir J. van der Laan <laanwj@gmail.com> +- Christian Gmeiner <christian.gmeiner@gmail.com> +- Lucas Stach <l.stach@pengutronix.de> +- Russell King <rmk@arm.linux.org.uk> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sub license, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +/* This is a cut-down version of the state_blt.xml.h file */ + +#define VIVS_BLT_ENABLE 0x000140b8 +#define VIVS_BLT_ENABLE_ENABLE 0x00000001 + +#endif /* STATE_BLT_XML */ diff --git a/drivers/gpu/drm/etnaviv/state_hi.xml.h b/drivers/gpu/drm/etnaviv/state_hi.xml.h index 60808daf7e8d..41d8da2b6f4f 100644 --- a/drivers/gpu/drm/etnaviv/state_hi.xml.h +++ b/drivers/gpu/drm/etnaviv/state_hi.xml.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: GPL-2.0 */ #ifndef STATE_HI_XML #define STATE_HI_XML @@ -9,10 +8,40 @@ http://0x04.net/cgit/index.cgi/rules-ng-ng git clone git://0x04.net/rules-ng-ng The rules-ng-ng source files this header was generated from are: -- state_hi.xml ( 25620 bytes, from 2016-08-19 22:07:37) -- common.xml ( 20583 bytes, from 2016-06-07 05:22:38) - -Copyright (C) 2016 +- state.xml ( 26087 bytes, from 2017-12-18 16:51:59) +- common.xml ( 35468 bytes, from 2018-01-22 13:48:54) +- common_3d.xml ( 14615 bytes, from 2017-12-18 16:51:59) +- state_hi.xml ( 30232 bytes, from 2018-02-15 15:48:01) +- copyright.xml ( 1597 bytes, from 2016-12-08 16:37:56) +- state_2d.xml ( 51552 bytes, from 2016-12-08 16:37:56) +- state_3d.xml ( 79992 bytes, from 2017-12-18 16:51:59) +- state_blt.xml ( 13405 bytes, from 2017-12-18 16:51:59) +- state_vg.xml ( 5975 bytes, from 2016-12-08 16:37:56) + +Copyright (C) 2012-2018 by the following authors: +- Wladimir J. van der Laan <laanwj@gmail.com> +- Christian Gmeiner <christian.gmeiner@gmail.com> +- Lucas Stach <l.stach@pengutronix.de> +- Russell King <rmk@arm.linux.org.uk> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sub license, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. */ @@ -192,6 +221,9 @@ Copyright (C) 2016 #define VIVS_HI_CHIP_SPECS_3_GPU_CORE_COUNT__SHIFT 0 #define VIVS_HI_CHIP_SPECS_3_GPU_CORE_COUNT(x) (((x) << VIVS_HI_CHIP_SPECS_3_GPU_CORE_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_3_GPU_CORE_COUNT__MASK) +#define VIVS_HI_COMPRESSION_FLAGS 0x00000090 +#define VIVS_HI_COMPRESSION_FLAGS_DEC300 0x00000040 + #define VIVS_HI_CHIP_MINOR_FEATURE_4 0x00000094 #define VIVS_HI_CHIP_SPECS_4 0x0000009c @@ -203,6 +235,10 @@ Copyright (C) 2016 #define VIVS_HI_CHIP_PRODUCT_ID 0x000000a8 +#define VIVS_HI_BLT_INTR 0x000000d4 + +#define VIVS_HI_AUXBIT 0x000000ec + #define VIVS_PM 0x00000000 #define VIVS_PM_POWER_CONTROLS 0x00000100 @@ -239,6 +275,17 @@ Copyright (C) 2016 #define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_TX 0x00000080 #define VIVS_PM_PULSE_EATER 0x0000010c +#define VIVS_PM_PULSE_EATER_DISABLE 0x00000001 +#define VIVS_PM_PULSE_EATER_DVFS_PERIOD__MASK 0x0000ff00 +#define VIVS_PM_PULSE_EATER_DVFS_PERIOD__SHIFT 8 +#define VIVS_PM_PULSE_EATER_DVFS_PERIOD(x) (((x) << VIVS_PM_PULSE_EATER_DVFS_PERIOD__SHIFT) & VIVS_PM_PULSE_EATER_DVFS_PERIOD__MASK) +#define VIVS_PM_PULSE_EATER_UNK16 0x00010000 +#define VIVS_PM_PULSE_EATER_UNK17 0x00020000 +#define VIVS_PM_PULSE_EATER_INTERNAL_DFS 0x00040000 +#define VIVS_PM_PULSE_EATER_UNK19 0x00080000 +#define VIVS_PM_PULSE_EATER_UNK20 0x00100000 +#define VIVS_PM_PULSE_EATER_UNK22 0x00400000 +#define VIVS_PM_PULSE_EATER_UNK23 0x00800000 #define VIVS_MMUv2 0x00000000 @@ -280,6 +327,68 @@ Copyright (C) 2016 #define VIVS_MMUv2_EXCEPTION_ADDR__ESIZE 0x00000004 #define VIVS_MMUv2_EXCEPTION_ADDR__LEN 0x00000004 +#define VIVS_MMUv2_PROFILE_BLT_READ 0x000001a4 + +#define VIVS_MMUv2_PTA_CONFIG 0x000001ac +#define VIVS_MMUv2_PTA_CONFIG_INDEX__MASK 0x0000ffff +#define VIVS_MMUv2_PTA_CONFIG_INDEX__SHIFT 0 +#define VIVS_MMUv2_PTA_CONFIG_INDEX(x) (((x) << VIVS_MMUv2_PTA_CONFIG_INDEX__SHIFT) & VIVS_MMUv2_PTA_CONFIG_INDEX__MASK) +#define VIVS_MMUv2_PTA_CONFIG_UNK16 0x00010000 + +#define VIVS_MMUv2_AXI_POLICY(i0) (0x000001c0 + 0x4*(i0)) +#define VIVS_MMUv2_AXI_POLICY__ESIZE 0x00000004 +#define VIVS_MMUv2_AXI_POLICY__LEN 0x00000008 + +#define VIVS_MMUv2_SEC_EXCEPTION_ADDR 0x00000380 + +#define VIVS_MMUv2_SEC_STATUS 0x00000384 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION0__MASK 0x00000003 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION0__SHIFT 0 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION0(x) (((x) << VIVS_MMUv2_SEC_STATUS_EXCEPTION0__SHIFT) & VIVS_MMUv2_SEC_STATUS_EXCEPTION0__MASK) +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION1__MASK 0x00000030 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION1__SHIFT 4 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION1(x) (((x) << VIVS_MMUv2_SEC_STATUS_EXCEPTION1__SHIFT) & VIVS_MMUv2_SEC_STATUS_EXCEPTION1__MASK) +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION2__MASK 0x00000300 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION2__SHIFT 8 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION2(x) (((x) << VIVS_MMUv2_SEC_STATUS_EXCEPTION2__SHIFT) & VIVS_MMUv2_SEC_STATUS_EXCEPTION2__MASK) +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION3__MASK 0x00003000 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION3__SHIFT 12 +#define VIVS_MMUv2_SEC_STATUS_EXCEPTION3(x) (((x) << VIVS_MMUv2_SEC_STATUS_EXCEPTION3__SHIFT) & VIVS_MMUv2_SEC_STATUS_EXCEPTION3__MASK) + +#define VIVS_MMUv2_SEC_CONTROL 0x00000388 +#define VIVS_MMUv2_SEC_CONTROL_ENABLE 0x00000001 + +#define VIVS_MMUv2_PTA_ADDRESS_LOW 0x0000038c + +#define VIVS_MMUv2_PTA_ADDRESS_HIGH 0x00000390 + +#define VIVS_MMUv2_PTA_CONTROL 0x00000394 +#define VIVS_MMUv2_PTA_CONTROL_ENABLE 0x00000001 + +#define VIVS_MMUv2_NONSEC_SAFE_ADDR_LOW 0x00000398 + +#define VIVS_MMUv2_SEC_SAFE_ADDR_LOW 0x0000039c + +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG 0x000003a0 +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH__MASK 0x000000ff +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH__SHIFT 0 +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH(x) (((x) << VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH__SHIFT) & VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH__MASK) +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_UNK15 0x00008000 +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH__MASK 0x00ff0000 +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH__SHIFT 16 +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH(x) (((x) << VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH__SHIFT) & VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH__MASK) +#define VIVS_MMUv2_SAFE_ADDRESS_CONFIG_UNK31 0x80000000 + +#define VIVS_MMUv2_SEC_COMMAND_CONTROL 0x000003a4 +#define VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH__MASK 0x0000ffff +#define VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH__SHIFT 0 +#define VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(x) (((x) << VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH__MASK) +#define VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE 0x00010000 + +#define VIVS_MMUv2_AHB_CONTROL 0x000003a8 +#define VIVS_MMUv2_AHB_CONTROL_RESET 0x00000001 +#define VIVS_MMUv2_AHB_CONTROL_NONSEC_ACCESS 0x00000002 + #define VIVS_MC 0x00000000 #define VIVS_MC_MMU_FE_PAGE_TABLE 0x00000400 @@ -340,13 +449,13 @@ Copyright (C) 2016 #define VIVS_MC_PROFILE_HI_READ 0x0000046c #define VIVS_MC_PROFILE_CONFIG0 0x00000470 -#define VIVS_MC_PROFILE_CONFIG0_FE__MASK 0x0000000f +#define VIVS_MC_PROFILE_CONFIG0_FE__MASK 0x000000ff #define VIVS_MC_PROFILE_CONFIG0_FE__SHIFT 0 #define VIVS_MC_PROFILE_CONFIG0_FE_RESET 0x0000000f -#define VIVS_MC_PROFILE_CONFIG0_DE__MASK 0x00000f00 +#define VIVS_MC_PROFILE_CONFIG0_DE__MASK 0x0000ff00 #define VIVS_MC_PROFILE_CONFIG0_DE__SHIFT 8 #define VIVS_MC_PROFILE_CONFIG0_DE_RESET 0x00000f00 -#define VIVS_MC_PROFILE_CONFIG0_PE__MASK 0x000f0000 +#define VIVS_MC_PROFILE_CONFIG0_PE__MASK 0x00ff0000 #define VIVS_MC_PROFILE_CONFIG0_PE__SHIFT 16 #define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE 0x00000000 #define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE 0x00010000 @@ -354,7 +463,7 @@ Copyright (C) 2016 #define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE 0x00030000 #define VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D 0x000b0000 #define VIVS_MC_PROFILE_CONFIG0_PE_RESET 0x000f0000 -#define VIVS_MC_PROFILE_CONFIG0_SH__MASK 0x0f000000 +#define VIVS_MC_PROFILE_CONFIG0_SH__MASK 0xff000000 #define VIVS_MC_PROFILE_CONFIG0_SH__SHIFT 24 #define VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES 0x04000000 #define VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER 0x07000000 @@ -368,7 +477,7 @@ Copyright (C) 2016 #define VIVS_MC_PROFILE_CONFIG0_SH_RESET 0x0f000000 #define VIVS_MC_PROFILE_CONFIG1 0x00000474 -#define VIVS_MC_PROFILE_CONFIG1_PA__MASK 0x0000000f +#define VIVS_MC_PROFILE_CONFIG1_PA__MASK 0x000000ff #define VIVS_MC_PROFILE_CONFIG1_PA__SHIFT 0 #define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER 0x00000003 #define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER 0x00000004 @@ -377,12 +486,12 @@ Copyright (C) 2016 #define VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER 0x00000007 #define VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER 0x00000008 #define VIVS_MC_PROFILE_CONFIG1_PA_RESET 0x0000000f -#define VIVS_MC_PROFILE_CONFIG1_SE__MASK 0x00000f00 +#define VIVS_MC_PROFILE_CONFIG1_SE__MASK 0x0000ff00 #define VIVS_MC_PROFILE_CONFIG1_SE__SHIFT 8 #define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT 0x00000000 #define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT 0x00000100 #define VIVS_MC_PROFILE_CONFIG1_SE_RESET 0x00000f00 -#define VIVS_MC_PROFILE_CONFIG1_RA__MASK 0x000f0000 +#define VIVS_MC_PROFILE_CONFIG1_RA__MASK 0x00ff0000 #define VIVS_MC_PROFILE_CONFIG1_RA__SHIFT 16 #define VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT 0x00000000 #define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT 0x00010000 @@ -392,7 +501,7 @@ Copyright (C) 2016 #define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER 0x000a0000 #define VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT 0x000b0000 #define VIVS_MC_PROFILE_CONFIG1_RA_RESET 0x000f0000 -#define VIVS_MC_PROFILE_CONFIG1_TX__MASK 0x0f000000 +#define VIVS_MC_PROFILE_CONFIG1_TX__MASK 0xff000000 #define VIVS_MC_PROFILE_CONFIG1_TX__SHIFT 24 #define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS 0x00000000 #define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS 0x01000000 @@ -407,18 +516,21 @@ Copyright (C) 2016 #define VIVS_MC_PROFILE_CONFIG1_TX_RESET 0x0f000000 #define VIVS_MC_PROFILE_CONFIG2 0x00000478 -#define VIVS_MC_PROFILE_CONFIG2_MC__MASK 0x0000000f +#define VIVS_MC_PROFILE_CONFIG2_MC__MASK 0x000000ff #define VIVS_MC_PROFILE_CONFIG2_MC__SHIFT 0 #define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE 0x00000001 #define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP 0x00000002 #define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE 0x00000003 #define VIVS_MC_PROFILE_CONFIG2_MC_RESET 0x0000000f -#define VIVS_MC_PROFILE_CONFIG2_HI__MASK 0x00000f00 +#define VIVS_MC_PROFILE_CONFIG2_HI__MASK 0x0000ff00 #define VIVS_MC_PROFILE_CONFIG2_HI__SHIFT 8 #define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED 0x00000000 #define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED 0x00000100 #define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED 0x00000200 #define VIVS_MC_PROFILE_CONFIG2_HI_RESET 0x00000f00 +#define VIVS_MC_PROFILE_CONFIG2_BLT__MASK 0xff000000 +#define VIVS_MC_PROFILE_CONFIG2_BLT__SHIFT 24 +#define VIVS_MC_PROFILE_CONFIG2_BLT_UNK0 0x00000000 #define VIVS_MC_PROFILE_CONFIG3 0x0000047c @@ -432,7 +544,13 @@ Copyright (C) 2016 #define VIVS_MC_START_COMPOSITION 0x00000554 -#define VIVS_MC_128B_MERGE 0x00000558 +#define VIVS_MC_FLAGS 0x00000558 +#define VIVS_MC_FLAGS_128B_MERGE 0x00000001 +#define VIVS_MC_FLAGS_TPCV11_COMPRESSION 0x08000000 + +#define VIVS_MC_L2_CACHE_CONFIG 0x0000055c + +#define VIVS_MC_PROFILE_L2_READ 0x00000564 #endif /* STATE_HI_XML */ diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 8dfffdbb6b07..4871025f7573 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -200,8 +200,7 @@ static struct ttm_backend_func hibmc_tt_backend_func = { .destroy = &hibmc_ttm_backend_destroy, }; -static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, +static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_buffer_object *bo, u32 page_flags) { struct ttm_tt *tt; @@ -213,7 +212,7 @@ static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev, return NULL; } tt->func = &hibmc_tt_backend_func; - ret = ttm_tt_init(tt, bdev, size, page_flags); + ret = ttm_tt_init(tt, bo, page_flags); if (ret) { DRM_ERROR("failed to initialize ttm_tt: %d\n", ret); kfree(tt); diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c index 89ab0f70aa22..c6a7beabd58d 100644 --- a/drivers/gpu/drm/i915/intel_color.c +++ b/drivers/gpu/drm/i915/intel_color.c @@ -39,7 +39,7 @@ #define CTM_COEFF_NEGATIVE(coeff) (((coeff) & CTM_COEFF_SIGN) != 0) #define CTM_COEFF_ABS(coeff) ((coeff) & (CTM_COEFF_SIGN - 1)) -#define LEGACY_LUT_LENGTH (sizeof(struct drm_color_lut) * 256) +#define LEGACY_LUT_LENGTH 256 /* Post offset values for RGB->YCBCR conversion */ #define POSTOFF_RGB_TO_YUV_HI 0x800 @@ -79,7 +79,7 @@ static bool crtc_state_is_legacy_gamma(struct drm_crtc_state *state) return !state->degamma_lut && !state->ctm && state->gamma_lut && - state->gamma_lut->length == LEGACY_LUT_LENGTH; + drm_color_lut_size(state->gamma_lut) == LEGACY_LUT_LENGTH; } /* @@ -153,8 +153,7 @@ static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state) ilk_load_ycbcr_conversion_matrix(intel_crtc); return; } else if (crtc_state->ctm) { - struct drm_color_ctm *ctm = - (struct drm_color_ctm *)crtc_state->ctm->data; + struct drm_color_ctm *ctm = crtc_state->ctm->data; const u64 *input; u64 temp[9]; @@ -262,8 +261,7 @@ static void cherryview_load_csc_matrix(struct drm_crtc_state *state) uint32_t mode; if (state->ctm) { - struct drm_color_ctm *ctm = - (struct drm_color_ctm *) state->ctm->data; + struct drm_color_ctm *ctm = state->ctm->data; uint16_t coeffs[9] = { 0, }; int i; @@ -330,7 +328,7 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc, } if (blob) { - struct drm_color_lut *lut = (struct drm_color_lut *) blob->data; + struct drm_color_lut *lut = blob->data; for (i = 0; i < 256; i++) { uint32_t word = (drm_color_lut_extract(lut[i].red, 8) << 16) | @@ -400,8 +398,7 @@ static void bdw_load_degamma_lut(struct drm_crtc_state *state) PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT); if (state->degamma_lut) { - struct drm_color_lut *lut = - (struct drm_color_lut *) state->degamma_lut->data; + struct drm_color_lut *lut = state->degamma_lut->data; for (i = 0; i < lut_size; i++) { uint32_t word = @@ -435,8 +432,7 @@ static void bdw_load_gamma_lut(struct drm_crtc_state *state, u32 offset) offset); if (state->gamma_lut) { - struct drm_color_lut *lut = - (struct drm_color_lut *) state->gamma_lut->data; + struct drm_color_lut *lut = state->gamma_lut->data; for (i = 0; i < lut_size; i++) { uint32_t word = @@ -568,7 +564,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state) } if (state->degamma_lut) { - lut = (struct drm_color_lut *) state->degamma_lut->data; + lut = state->degamma_lut->data; lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size; for (i = 0; i < lut_size; i++) { /* Write LUT in U0.14 format. */ @@ -583,7 +579,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state) } if (state->gamma_lut) { - lut = (struct drm_color_lut *) state->gamma_lut->data; + lut = state->gamma_lut->data; lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; for (i = 0; i < lut_size; i++) { /* Write LUT in U0.10 format. */ @@ -623,19 +619,17 @@ int intel_color_check(struct drm_crtc *crtc, struct drm_i915_private *dev_priv = to_i915(crtc->dev); size_t gamma_length, degamma_length; - degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size * - sizeof(struct drm_color_lut); - gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size * - sizeof(struct drm_color_lut); + degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size; + gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size; /* * We allow both degamma & gamma luts at the right size or * NULL. */ if ((!crtc_state->degamma_lut || - crtc_state->degamma_lut->length == degamma_length) && + drm_color_lut_size(crtc_state->degamma_lut) == degamma_length) && (!crtc_state->gamma_lut || - crtc_state->gamma_lut->length == gamma_length)) + drm_color_lut_size(crtc_state->gamma_lut) == gamma_length)) return 0; /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 331084082545..3b48fd2561fe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11059,24 +11059,17 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n, static void __printf(3, 4) pipe_config_err(bool adjust, const char *name, const char *format, ...) { - char *level; - unsigned int category; struct va_format vaf; va_list args; - if (adjust) { - level = KERN_DEBUG; - category = DRM_UT_KMS; - } else { - level = KERN_ERR; - category = DRM_UT_NONE; - } - va_start(args, format); vaf.fmt = format; vaf.va = &args; - drm_printk(level, category, "mismatch in %s %pV", name, &vaf); + if (adjust) + drm_dbg(DRM_UT_KMS, "mismatch in %s %pV", name, &vaf); + else + drm_err("mismatch in %s %pV", name, &vaf); va_end(args); } diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index f9ad0e960263..32b1a6cdecfc 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -189,40 +189,55 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) - return PTR_ERR(regs); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + goto free_drm; + } priv->io_base = regs; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi"); + if (!res) + return -EINVAL; /* Simply ioremap since it may be a shared register zone */ regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) - return -EADDRNOTAVAIL; + if (!regs) { + ret = -EADDRNOTAVAIL; + goto free_drm; + } priv->hhi = devm_regmap_init_mmio(dev, regs, &meson_regmap_config); if (IS_ERR(priv->hhi)) { dev_err(&pdev->dev, "Couldn't create the HHI regmap\n"); - return PTR_ERR(priv->hhi); + ret = PTR_ERR(priv->hhi); + goto free_drm; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); + if (!res) + return -EINVAL; /* Simply ioremap since it may be a shared register zone */ regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) - return -EADDRNOTAVAIL; + if (!regs) { + ret = -EADDRNOTAVAIL; + goto free_drm; + } priv->dmc = devm_regmap_init_mmio(dev, regs, &meson_regmap_config); if (IS_ERR(priv->dmc)) { dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); - return PTR_ERR(priv->dmc); + ret = PTR_ERR(priv->dmc); + goto free_drm; } priv->vsync_irq = platform_get_irq(pdev, 0); - drm_vblank_init(drm, 1); + ret = drm_vblank_init(drm, 1); + if (ret) + goto free_drm; + drm_mode_config_init(drm); drm->mode_config.max_width = 3840; drm->mode_config.max_height = 2160; @@ -281,7 +296,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) return 0; free_drm: - drm_dev_unref(drm); + drm_dev_put(drm); return ret; } @@ -300,7 +315,7 @@ static void meson_drv_unbind(struct device *dev) drm_kms_helper_poll_fini(drm); drm_fbdev_cma_fini(priv->fbdev); drm_mode_config_cleanup(drm); - drm_dev_unref(drm); + drm_dev_put(drm); } diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index d49af17310c9..a393095aac1a 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -538,7 +538,6 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) return IRQ_HANDLED; } -/* TOFIX Enable support for non-vic modes */ static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector, const struct drm_display_mode *mode) @@ -555,12 +554,12 @@ dw_hdmi_mode_valid(struct drm_connector *connector, mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->type, mode->flags); - /* For now, only accept VIC modes */ - if (!vic) - return MODE_BAD; - - /* For now, filter by supported VIC modes */ - if (!meson_venc_hdmi_supported_vic(vic)) + /* Check against non-VIC supported modes */ + if (!vic) { + if (!meson_venc_hdmi_supported_mode(mode)) + return MODE_BAD; + /* Check against supported VIC modes */ + } else if (!meson_venc_hdmi_supported_vic(vic)) return MODE_BAD; vclk_freq = mode->clock; @@ -586,9 +585,14 @@ dw_hdmi_mode_valid(struct drm_connector *connector, /* Finally filter by configurable vclk frequencies */ switch (vclk_freq) { + case 25175: + case 40000: case 54000: + case 65000: case 74250: + case 108000: case 148500: + case 162000: case 297000: case 594000: return MODE_OK; @@ -653,10 +657,6 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n", mode->base.id, mode->name, vic); - /* Should have been filtered */ - if (!vic) - return; - /* VENC + VENC-DVI Mode setup */ meson_venc_hdmi_mode_set(priv, vic, mode); diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 47677047e42d..f0511220317f 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -328,14 +328,24 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) #define MESON_VCLK_HDMI_DDR_54000 2 /* 2970 /4 /1 /1 /5 /1 => /1 /2 */ #define MESON_VCLK_HDMI_DDR_148500 3 +/* 4028 /4 /4 /1 /5 /2 => /1 /1 */ +#define MESON_VCLK_HDMI_25175 4 +/* 3200 /4 /2 /1 /5 /2 => /1 /1 */ +#define MESON_VCLK_HDMI_40000 5 +/* 5200 /4 /2 /1 /5 /2 => /1 /1 */ +#define MESON_VCLK_HDMI_65000 6 /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_74250 4 +#define MESON_VCLK_HDMI_74250 7 +/* 4320 /4 /1 /1 /5 /2 => /1 /1 */ +#define MESON_VCLK_HDMI_108000 8 /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_148500 5 +#define MESON_VCLK_HDMI_148500 9 +/* 3240 /2 /1 /1 /5 /2 => /1 /1 */ +#define MESON_VCLK_HDMI_162000 10 /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_297000 6 +#define MESON_VCLK_HDMI_297000 11 /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_594000 7 +#define MESON_VCLK_HDMI_594000 12 struct meson_vclk_params { unsigned int pll_base_freq; @@ -401,6 +411,46 @@ struct meson_vclk_params { .vid_pll_div = VID_PLL_DIV_5, .vclk_div = 1, }, + [MESON_VCLK_HDMI_25175] = { + .pll_base_freq = 4028000, + .pll_od1 = 4, + .pll_od2 = 4, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 2, + }, + [MESON_VCLK_HDMI_40000] = { + .pll_base_freq = 3200000, + .pll_od1 = 4, + .pll_od2 = 2, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 2, + }, + [MESON_VCLK_HDMI_65000] = { + .pll_base_freq = 5200000, + .pll_od1 = 4, + .pll_od2 = 2, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 2, + }, + [MESON_VCLK_HDMI_108000] = { + .pll_base_freq = 4320000, + .pll_od1 = 4, + .pll_od2 = 1, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 2, + }, + [MESON_VCLK_HDMI_162000] = { + .pll_base_freq = 3240000, + .pll_od1 = 2, + .pll_od2 = 1, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 2, + }, }; static inline unsigned int pll_od_to_reg(unsigned int od) @@ -451,6 +501,90 @@ void meson_hdmi_pll_set(struct meson_drm *priv, 0xFFFF, 0x4e00); break; + case 3200000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + BIT(28), 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + + /* div_frac */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0xFFFF, 0x4aab); + break; + + case 3240000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + BIT(28), 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + + /* div_frac */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0xFFFF, 0x4800); + break; + + case 3865000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + BIT(28), 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + + /* div_frac */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0xFFFF, 0x4855); + break; + + case 4028000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + BIT(28), 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + + /* div_frac */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0xFFFF, 0x4eab); + break; + case 4320000: regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); @@ -485,6 +619,23 @@ void meson_hdmi_pll_set(struct meson_drm *priv, regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, (val & HDMI_PLL_LOCK), 10, 0); break; + + case 5200000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + BIT(28), 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + break; }; } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { @@ -498,6 +649,42 @@ void meson_hdmi_pll_set(struct meson_drm *priv, regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); break; + case 3200000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + + case 3240000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + + case 3865000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + + case 4028000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + case 4320000: regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); @@ -516,6 +703,15 @@ void meson_hdmi_pll_set(struct meson_drm *priv, regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); break; + case 5200000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + }; /* Reset PLL */ @@ -590,15 +786,30 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, else freq = MESON_VCLK_HDMI_DDR_54000; break; + case 25175: + freq = MESON_VCLK_HDMI_25175; + break; + case 40000: + freq = MESON_VCLK_HDMI_40000; + break; + case 65000: + freq = MESON_VCLK_HDMI_65000; + break; case 74250: freq = MESON_VCLK_HDMI_74250; break; + case 108000: + freq = MESON_VCLK_HDMI_108000; + break; case 148500: if (dac_freq != 148500) freq = MESON_VCLK_HDMI_DDR_148500; else freq = MESON_VCLK_HDMI_148500; break; + case 162000: + freq = MESON_VCLK_HDMI_162000; + break; case 297000: freq = MESON_VCLK_HDMI_297000; break; diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 9509017dbded..6e2701389801 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -697,6 +697,314 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { }, }; +union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + /* video_prog_mode */ + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + /* yfp1_htime */ + /* yfp2_htime */ + .max_pxcnt = 0x31f, + /* hspuls_begin */ + /* hspuls_end */ + /* hspuls_switch */ + /* vspuls_begin */ + /* vspuls_end */ + /* vspuls_bline */ + /* vspuls_eline */ + .havon_begin = 0x90, + .havon_end = 0x30f, + .vavon_bline = 0x23, + .vavon_eline = 0x202, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 0, + .hso_end = 0x60, + .vso_begin = 0x1e, + .vso_end = 0x32, + .vso_bline = 0, + .vso_eline = 2, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 0x20c, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + /* video_prog_mode */ + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + /* yfp1_htime */ + /* yfp2_htime */ + .max_pxcnt = 0x41f, + /* hspuls_begin */ + /* hspuls_end */ + /* hspuls_switch */ + /* vspuls_begin */ + /* vspuls_end */ + /* vspuls_bline */ + /* vspuls_eline */ + .havon_begin = 0xD8, + .havon_end = 0x3f7, + .vavon_bline = 0x1b, + .vavon_eline = 0x272, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 0, + .hso_end = 0x80, + .vso_begin = 0x1e, + .vso_end = 0x32, + .vso_bline = 0, + .vso_eline = 4, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 0x273, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + /* video_prog_mode */ + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + /* yfp1_htime */ + /* yfp2_htime */ + .max_pxcnt = 1343, + /* hspuls_begin */ + /* hspuls_end */ + /* hspuls_switch */ + /* vspuls_begin */ + /* vspuls_end */ + /* vspuls_bline */ + /* vspuls_eline */ + .havon_begin = 296, + .havon_end = 1319, + .vavon_bline = 35, + .vavon_eline = 802, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 0, + .hso_end = 136, + .vso_begin = 30, + .vso_end = 50, + .vso_bline = 0, + .vso_eline = 6, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 805, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + /* video_prog_mode */ + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + /* yfp1_htime */ + /* yfp2_htime */ + .max_pxcnt = 0x63f, + /* hspuls_begin */ + /* hspuls_end */ + /* hspuls_switch */ + /* vspuls_begin */ + /* vspuls_end */ + /* vspuls_bline */ + /* vspuls_eline */ + .havon_begin = 0x180, + .havon_end = 0x5ff, + .vavon_bline = 0x23, + .vavon_eline = 0x382, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 0, + .hso_end = 0x80, + .vso_begin = 0x1e, + .vso_end = 0x32, + .vso_bline = 0, + .vso_eline = 3, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 0x383, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + /* video_prog_mode */ + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + /* yfp1_htime */ + /* yfp2_htime */ + .max_pxcnt = 0x697, + /* hspuls_begin */ + /* hspuls_end */ + /* hspuls_switch */ + /* vspuls_begin */ + /* vspuls_end */ + /* vspuls_bline */ + /* vspuls_eline */ + .havon_begin = 0x168, + .havon_end = 0x667, + .vavon_bline = 0x29, + .vavon_eline = 0x428, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 0, + .hso_end = 0x70, + .vso_begin = 0x1e, + .vso_end = 0x32, + .vso_bline = 0, + .vso_eline = 3, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 0x429, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + /* video_prog_mode */ + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + /* yfp1_htime */ + /* yfp2_htime */ + .max_pxcnt = 0x86f, + /* hspuls_begin */ + /* hspuls_end */ + /* hspuls_switch */ + /* vspuls_begin */ + /* vspuls_end */ + /* vspuls_bline */ + /* vspuls_eline */ + .havon_begin = 0x1f0, + .havon_end = 0x82f, + .vavon_bline = 0x31, + .vavon_eline = 0x4e0, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 0, + .hso_end = 0xc0, + .vso_begin = 0x1e, + .vso_end = 0x32, + .vso_bline = 0, + .vso_eline = 3, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 0x4e1, + }, +}; + +struct meson_hdmi_venc_dmt_mode { + struct drm_display_mode drm_mode; + union meson_hdmi_venc_mode *mode; +} meson_hdmi_venc_dmt_modes[] = { + /* 640x480@60Hz */ + { + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + &meson_hdmi_encp_mode_640x480_60, + }, + /* 800x600@60Hz */ + { + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + &meson_hdmi_encp_mode_800x600_60, + }, + /* 1024x768@60Hz */ + { + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, + 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + &meson_hdmi_encp_mode_1024x768_60, + }, + /* 1152x864@75Hz */ + { + { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, + 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + &meson_hdmi_encp_mode_1152x864_75, + }, + /* 1280x1024@60Hz */ + { + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, + 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + &meson_hdmi_encp_mode_1280x1024_60, + }, + /* 1600x1200@60Hz */ + { + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, + 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + &meson_hdmi_encp_mode_1600x1200_60, + }, + /* 1920x1080@60Hz */ + { + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, + 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + &meson_hdmi_encp_mode_1080p60 + }, + { }, /* sentinel */ +}; + struct meson_hdmi_venc_vic_mode { unsigned int vic; union meson_hdmi_venc_mode *mode; @@ -736,6 +1044,20 @@ static unsigned long modulo(unsigned long a, unsigned long b) return a; } +bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode) +{ + struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; + + while (vmode->mode) { + if (drm_mode_equal(&vmode->drm_mode, mode)) + return true; + vmode++; + } + + return false; +} +EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode); + bool meson_venc_hdmi_supported_vic(int vic) { struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; @@ -750,6 +1072,20 @@ bool meson_venc_hdmi_supported_vic(int vic) } EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic); +static union meson_hdmi_venc_mode +*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode) +{ + struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; + + while (vmode->mode) { + if (drm_mode_equal(&vmode->drm_mode, mode)) + return vmode->mode; + vmode++; + } + + return NULL; +} + static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic) { struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; @@ -811,10 +1147,13 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int sof_lines; unsigned int vsync_lines; - vmode = meson_venc_hdmi_get_vic_vmode(vic); + if (meson_venc_hdmi_supported_vic(vic)) + vmode = meson_venc_hdmi_get_vic_vmode(vic); + else + vmode = meson_venc_hdmi_get_dmt_vmode(mode); if (!vmode) { - dev_err(priv->dev, "%s: Fatal Error, unsupported vic %d\n", - __func__, vic); + dev_err(priv->dev, "%s: Fatal Error, unsupported mode " + DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode)); return; } @@ -864,7 +1203,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, hsync_pixels_venc *= 2; /* Disable VDACs */ - writel_bits_relaxed(0x1f, 0x1f, + writel_bits_relaxed(0xff, 0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h index a1b96e898c14..7c18a36a0dd0 100644 --- a/drivers/gpu/drm/meson/meson_venc.h +++ b/drivers/gpu/drm/meson/meson_venc.h @@ -58,6 +58,7 @@ struct meson_cvbs_enci_mode { }; /* HDMI Clock parameters */ +bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); bool meson_venc_hdmi_supported_vic(int vic); bool meson_venc_hdmi_venc_repeat(int vic); diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 69beb2046008..05570f0de4d7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -199,8 +199,8 @@ static struct ttm_backend_func mgag200_tt_backend_func = { }; -static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_buffer_object *bo, + uint32_t page_flags) { struct ttm_tt *tt; @@ -208,7 +208,7 @@ static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &mgag200_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags)) { + if (ttm_tt_init(tt, bo, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 99d39b2aefa6..38cbde971b48 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -28,6 +28,19 @@ config DRM_MSM_REGISTER_LOGGING that can be parsed by envytools demsm tool. If enabled, register logging can be switched on via msm.reglog=y module param. +config DRM_MSM_GPU_SUDO + bool "Enable SUDO flag on submits" + depends on DRM_MSM && EXPERT + default n + help + Enable userspace that has CAP_SYS_RAWIO to submit GPU commands + that are run from RB instead of IB1. This essentially gives + userspace kernel level access, but is useful for firmware + debugging. + + Only use this if you are a driver developer. This should *not* + be enabled for production kernels. If unsure, say N. + config DRM_MSM_HDMI_HDCP bool "Enable HDMI HDCP support in MSM DRM driver" depends on DRM_MSM && QCOM_SCM @@ -81,3 +94,10 @@ config DRM_MSM_DSI_14NM_PHY default y help Choose this option if DSI PHY on 8996 is used on the platform. + +config DRM_MSM_DSI_10NM_PHY + bool "Enable DSI 10nm PHY driver in MSM DRM (used by SDM845)" + depends on DRM_MSM_DSI + default y + help + Choose this option if DSI PHY on SDM845 is used on the platform. diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 92b3844202d2..cd40c050b2d7 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -25,26 +25,26 @@ msm-y := \ edp/edp_connector.o \ edp/edp_ctrl.o \ edp/edp_phy.o \ - mdp/mdp_format.o \ - mdp/mdp_kms.o \ - mdp/mdp4/mdp4_crtc.o \ - mdp/mdp4/mdp4_dtv_encoder.o \ - mdp/mdp4/mdp4_lcdc_encoder.o \ - mdp/mdp4/mdp4_lvds_connector.o \ - mdp/mdp4/mdp4_irq.o \ - mdp/mdp4/mdp4_kms.o \ - mdp/mdp4/mdp4_plane.o \ - mdp/mdp5/mdp5_cfg.o \ - mdp/mdp5/mdp5_ctl.o \ - mdp/mdp5/mdp5_crtc.o \ - mdp/mdp5/mdp5_encoder.o \ - mdp/mdp5/mdp5_irq.o \ - mdp/mdp5/mdp5_mdss.o \ - mdp/mdp5/mdp5_kms.o \ - mdp/mdp5/mdp5_pipe.o \ - mdp/mdp5/mdp5_mixer.o \ - mdp/mdp5/mdp5_plane.o \ - mdp/mdp5/mdp5_smp.o \ + disp/mdp_format.o \ + disp/mdp_kms.o \ + disp/mdp4/mdp4_crtc.o \ + disp/mdp4/mdp4_dtv_encoder.o \ + disp/mdp4/mdp4_lcdc_encoder.o \ + disp/mdp4/mdp4_lvds_connector.o \ + disp/mdp4/mdp4_irq.o \ + disp/mdp4/mdp4_kms.o \ + disp/mdp4/mdp4_plane.o \ + disp/mdp5/mdp5_cfg.o \ + disp/mdp5/mdp5_ctl.o \ + disp/mdp5/mdp5_crtc.o \ + disp/mdp5/mdp5_encoder.o \ + disp/mdp5/mdp5_irq.o \ + disp/mdp5/mdp5_mdss.o \ + disp/mdp5/mdp5_kms.o \ + disp/mdp5/mdp5_pipe.o \ + disp/mdp5/mdp5_mixer.o \ + disp/mdp5/mdp5_plane.o \ + disp/mdp5/mdp5_smp.o \ msm_atomic.o \ msm_debugfs.o \ msm_drv.o \ @@ -62,31 +62,35 @@ msm-y := \ msm_ringbuffer.o \ msm_submitqueue.o +msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o + msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o -msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o +msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_phy_8996.o msm-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ - mdp/mdp4/mdp4_dsi_encoder.o \ + disp/mdp4/mdp4_dsi_encoder.o \ dsi/dsi_cfg.o \ dsi/dsi_host.o \ dsi/dsi_manager.o \ dsi/phy/dsi_phy.o \ - mdp/mdp5/mdp5_cmd_encoder.o + disp/mdp5/mdp5_cmd_encoder.o msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/phy/dsi_phy_14nm.o +msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/phy/dsi_phy_10nm.o ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y) msm-y += dsi/pll/dsi_pll.o msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/pll/dsi_pll_28nm_8960.o msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/pll/dsi_pll_14nm.o +msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/pll/dsi_pll_10nm.o endif obj-$(CONFIG_DRM_MSM) += msm.o diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 4baef2738178..3ebbeb3a9b68 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -35,6 +35,7 @@ A3XX_INT0_CP_RB_INT | \ A3XX_INT0_CP_REG_PROTECT_FAULT | \ A3XX_INT0_CP_AHB_ERROR_HALT | \ + A3XX_INT0_CACHE_FLUSH_TS | \ A3XX_INT0_UCHE_OOB_ACCESS) extern bool hang_debug; @@ -256,8 +257,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu) */ /* Load PM4: */ - ptr = (uint32_t *)(adreno_gpu->pm4->data); - len = adreno_gpu->pm4->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data); + len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; DBG("loading PM4 ucode version: %x", ptr[1]); gpu_write(gpu, REG_AXXX_CP_DEBUG, @@ -268,8 +269,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]); /* Load PFP: */ - ptr = (uint32_t *)(adreno_gpu->pfp->data); - len = adreno_gpu->pfp->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data); + len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4; DBG("loading PFP ucode version: %x", ptr[5]); gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 8199a4b9f2fa..16d3d596638e 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -27,6 +27,7 @@ A4XX_INT0_CP_RB_INT | \ A4XX_INT0_CP_REG_PROTECT_FAULT | \ A4XX_INT0_CP_AHB_ERROR_HALT | \ + A4XX_INT0_CACHE_FLUSH_TS | \ A4XX_INT0_UCHE_OOB_ACCESS) extern bool hang_debug; @@ -274,16 +275,16 @@ static int a4xx_hw_init(struct msm_gpu *gpu) return ret; /* Load PM4: */ - ptr = (uint32_t *)(adreno_gpu->pm4->data); - len = adreno_gpu->pm4->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data); + len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; DBG("loading PM4 ucode version: %u", ptr[0]); gpu_write(gpu, REG_A4XX_CP_ME_RAM_WADDR, 0); for (i = 1; i < len; i++) gpu_write(gpu, REG_A4XX_CP_ME_RAM_DATA, ptr[i]); /* Load PFP: */ - ptr = (uint32_t *)(adreno_gpu->pfp->data); - len = adreno_gpu->pfp->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data); + len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4; DBG("loading PFP ucode version: %u", ptr[0]); gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_ADDR, 0); diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c new file mode 100644 index 000000000000..059ec7d394d0 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c @@ -0,0 +1,187 @@ +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + + +#include <linux/types.h> +#include <linux/debugfs.h> +#include <drm/drm_print.h> + +#include "a5xx_gpu.h" + +static int pfp_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "PFP state:\n"); + + for (i = 0; i < 36; i++) { + gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i); + drm_printf(p, " %02x: %08x\n", i, + gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA)); + } + + return 0; +} + +static int me_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "ME state:\n"); + + for (i = 0; i < 29; i++) { + gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i); + drm_printf(p, " %02x: %08x\n", i, + gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA)); + } + + return 0; +} + +static int meq_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "MEQ state:\n"); + gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0); + + for (i = 0; i < 64; i++) { + drm_printf(p, " %02x: %08x\n", i, + gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA)); + } + + return 0; +} + +static int roq_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "ROQ state:\n"); + gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0); + + for (i = 0; i < 512 / 4; i++) { + uint32_t val[4]; + int j; + for (j = 0; j < 4; j++) + val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA); + drm_printf(p, " %02x: %08x %08x %08x %08x\n", i, + val[0], val[1], val[2], val[3]); + } + + return 0; +} + +static int show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct msm_drm_private *priv = dev->dev_private; + struct drm_printer p = drm_seq_file_printer(m); + int (*show)(struct msm_gpu *gpu, struct drm_printer *p) = + node->info_ent->data; + + return show(priv->gpu, &p); +} + +#define ENT(n) { .name = #n, .show = show, .data = n ##_print } +static struct drm_info_list a5xx_debugfs_list[] = { + ENT(pfp), + ENT(me), + ENT(meq), + ENT(roq), +}; + +/* for debugfs files that can be written to, we can't use drm helper: */ +static int +reset_set(void *data, u64 val) +{ + struct drm_device *dev = data; + struct msm_drm_private *priv = dev->dev_private; + struct msm_gpu *gpu = priv->gpu; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EINVAL; + + /* TODO do we care about trying to make sure the GPU is idle? + * Since this is just a debug feature limited to CAP_SYS_ADMIN, + * maybe it is fine to let the user keep both pieces if they + * try to reset an active GPU. + */ + + mutex_lock(&dev->struct_mutex); + + release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]); + adreno_gpu->fw[ADRENO_FW_PM4] = NULL; + + release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]); + adreno_gpu->fw[ADRENO_FW_PFP] = NULL; + + if (a5xx_gpu->pm4_bo) { + if (a5xx_gpu->pm4_iova) + msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); + drm_gem_object_unreference(a5xx_gpu->pm4_bo); + a5xx_gpu->pm4_bo = NULL; + } + + if (a5xx_gpu->pfp_bo) { + if (a5xx_gpu->pfp_iova) + msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace); + drm_gem_object_unreference(a5xx_gpu->pfp_bo); + a5xx_gpu->pfp_bo = NULL; + } + + gpu->needs_hw_init = true; + + pm_runtime_get_sync(&gpu->pdev->dev); + gpu->funcs->recover(gpu); + + pm_runtime_put_sync(&gpu->pdev->dev); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n"); + + +int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor) +{ + struct drm_device *dev; + struct dentry *ent; + int ret; + + if (!minor) + return 0; + + dev = minor->dev; + + ret = drm_debugfs_create_files(a5xx_debugfs_list, + ARRAY_SIZE(a5xx_debugfs_list), + minor->debugfs_root, minor); + + if (ret) { + dev_err(dev->dev, "could not install a5xx_debugfs_list\n"); + return ret; + } + + ent = debugfs_create_file("reset", S_IWUGO, + minor->debugfs_root, + dev, &reset_fops); + if (!ent) + return -ENOMEM; + + return 0; +} diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 7e09d44e4a15..a4f68affc13b 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -140,6 +140,65 @@ static void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); } +static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit, + struct msm_file_private *ctx) +{ + struct msm_drm_private *priv = gpu->dev->dev_private; + struct msm_ringbuffer *ring = submit->ring; + struct msm_gem_object *obj; + uint32_t *ptr, dwords; + unsigned int i; + + for (i = 0; i < submit->nr_cmds; i++) { + switch (submit->cmd[i].type) { + case MSM_SUBMIT_CMD_IB_TARGET_BUF: + break; + case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: + if (priv->lastctx == ctx) + break; + case MSM_SUBMIT_CMD_BUF: + /* copy commands into RB: */ + obj = submit->bos[submit->cmd[i].idx].obj; + dwords = submit->cmd[i].size; + + ptr = msm_gem_get_vaddr(&obj->base); + + /* _get_vaddr() shouldn't fail at this point, + * since we've already mapped it once in + * submit_reloc() + */ + if (WARN_ON(!ptr)) + return; + + for (i = 0; i < dwords; i++) { + /* normally the OUT_PKTn() would wait + * for space for the packet. But since + * we just OUT_RING() the whole thing, + * need to call adreno_wait_ring() + * ourself: + */ + adreno_wait_ring(ring, 1); + OUT_RING(ring, ptr[i]); + } + + msm_gem_put_vaddr(&obj->base); + + break; + } + } + + a5xx_flush(gpu, ring); + a5xx_preempt_trigger(gpu); + + /* we might not necessarily have a cmd from userspace to + * trigger an event to know that submit has completed, so + * do this manually: + */ + a5xx_idle(gpu, ring); + ring->memptrs->fence = submit->seqno; + msm_gpu_retire(gpu); +} + static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx) { @@ -149,6 +208,12 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_ringbuffer *ring = submit->ring; unsigned int i, ibs = 0; + if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) { + priv->lastctx = NULL; + a5xx_submit_in_rb(gpu, submit, ctx); + return; + } + OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); OUT_RING(ring, 0x02); @@ -432,25 +497,6 @@ static int a5xx_preempt_start(struct msm_gpu *gpu) return a5xx_idle(gpu, ring) ? 0 : -EINVAL; } - -static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu, - const struct firmware *fw, u64 *iova) -{ - struct drm_gem_object *bo; - void *ptr; - - ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4, - MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova); - - if (IS_ERR(ptr)) - return ERR_CAST(ptr); - - memcpy(ptr, &fw->data[4], fw->size - 4); - - msm_gem_put_vaddr(bo); - return bo; -} - static int a5xx_ucode_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -458,8 +504,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) int ret; if (!a5xx_gpu->pm4_bo) { - a5xx_gpu->pm4_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pm4, - &a5xx_gpu->pm4_iova); + a5xx_gpu->pm4_bo = adreno_fw_create_bo(gpu, + adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova); if (IS_ERR(a5xx_gpu->pm4_bo)) { ret = PTR_ERR(a5xx_gpu->pm4_bo); @@ -471,8 +517,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) } if (!a5xx_gpu->pfp_bo) { - a5xx_gpu->pfp_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pfp, - &a5xx_gpu->pfp_iova); + a5xx_gpu->pfp_bo = adreno_fw_create_bo(gpu, + adreno_gpu->fw[ADRENO_FW_PFP], &a5xx_gpu->pfp_iova); if (IS_ERR(a5xx_gpu->pfp_bo)) { ret = PTR_ERR(a5xx_gpu->pfp_bo); @@ -793,19 +839,19 @@ static void a5xx_destroy(struct msm_gpu *gpu) if (a5xx_gpu->pm4_bo) { if (a5xx_gpu->pm4_iova) msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(a5xx_gpu->pm4_bo); + drm_gem_object_put_unlocked(a5xx_gpu->pm4_bo); } if (a5xx_gpu->pfp_bo) { if (a5xx_gpu->pfp_iova) msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(a5xx_gpu->pfp_bo); + drm_gem_object_put_unlocked(a5xx_gpu->pfp_bo); } if (a5xx_gpu->gpmu_bo) { if (a5xx_gpu->gpmu_iova) msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo); + drm_gem_object_put_unlocked(a5xx_gpu->gpmu_bo); } adreno_gpu_cleanup(adreno_gpu); @@ -1195,6 +1241,7 @@ static const struct adreno_gpu_funcs funcs = { .destroy = a5xx_destroy, #ifdef CONFIG_DEBUG_FS .show = a5xx_show, + .debugfs_init = a5xx_debugfs_init, #endif .gpu_busy = a5xx_gpu_busy, }, diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h index 6fb8c2f9b9e4..7d71860c4bee 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -49,6 +49,10 @@ struct a5xx_gpu { #define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base) +#ifdef CONFIG_DEBUG_FS +int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor); +#endif + /* * In order to do lockless preemption we use a simple state machine to progress * through the process. diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c index 4e4d965fd9ab..e9c0e56dbec0 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_power.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c @@ -261,7 +261,6 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); struct drm_device *drm = gpu->dev; - const struct firmware *fw; uint32_t dwords = 0, offset = 0, bosize; unsigned int *data, *ptr, *cmds; unsigned int cmds_size; @@ -269,15 +268,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) if (a5xx_gpu->gpmu_bo) return; - /* Get the firmware */ - fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->gpmufw); - if (IS_ERR(fw)) { - DRM_ERROR("%s: Could not get GPMU firmware. GPMU will not be active\n", - gpu->name); - return; - } - - data = (unsigned int *) fw->data; + data = (unsigned int *) adreno_gpu->fw[ADRENO_FW_GPMU]->data; /* * The first dword is the size of the remaining data in dwords. Use it @@ -285,12 +276,14 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) * the firmware that we read */ - if (fw->size < 8 || (data[0] < 2) || (data[0] >= (fw->size >> 2))) - goto out; + if (adreno_gpu->fw[ADRENO_FW_GPMU]->size < 8 || + (data[0] < 2) || (data[0] >= + (adreno_gpu->fw[ADRENO_FW_GPMU]->size >> 2))) + return; /* The second dword is an ID - look for 2 (GPMU_FIRMWARE_ID) */ if (data[1] != 2) - goto out; + return; cmds = data + data[2] + 3; cmds_size = data[0] - data[2] - 2; @@ -325,8 +318,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) msm_gem_put_vaddr(a5xx_gpu->gpmu_bo); a5xx_gpu->gpmu_dwords = dwords; - goto out; - + return; err: if (a5xx_gpu->gpmu_iova) msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); @@ -336,8 +328,4 @@ err: a5xx_gpu->gpmu_bo = NULL; a5xx_gpu->gpmu_iova = 0; a5xx_gpu->gpmu_dwords = 0; - -out: - /* No need to keep that firmware laying around anymore */ - release_firmware(fw); } diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 62bdb7316da1..8e0cb161754b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -30,61 +30,75 @@ static const struct adreno_info gpulist[] = { .rev = ADRENO_REV(3, 0, 5, ANY_ID), .revn = 305, .name = "A305", - .pm4fw = "a300_pm4.fw", - .pfpfw = "a300_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a300_pm4.fw", + [ADRENO_FW_PFP] = "a300_pfp.fw", + }, .gmem = SZ_256K, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 0, 6, 0), .revn = 307, /* because a305c is revn==306 */ .name = "A306", - .pm4fw = "a300_pm4.fw", - .pfpfw = "a300_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a300_pm4.fw", + [ADRENO_FW_PFP] = "a300_pfp.fw", + }, .gmem = SZ_128K, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID), .revn = 320, .name = "A320", - .pm4fw = "a300_pm4.fw", - .pfpfw = "a300_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a300_pm4.fw", + [ADRENO_FW_PFP] = "a300_pfp.fw", + }, .gmem = SZ_512K, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 3, 0, ANY_ID), .revn = 330, .name = "A330", - .pm4fw = "a330_pm4.fw", - .pfpfw = "a330_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a330_pm4.fw", + [ADRENO_FW_PFP] = "a330_pfp.fw", + }, .gmem = SZ_1M, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(4, 2, 0, ANY_ID), .revn = 420, .name = "A420", - .pm4fw = "a420_pm4.fw", - .pfpfw = "a420_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a420_pm4.fw", + [ADRENO_FW_PFP] = "a420_pfp.fw", + }, .gmem = (SZ_1M + SZ_512K), .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(4, 3, 0, ANY_ID), .revn = 430, .name = "A430", - .pm4fw = "a420_pm4.fw", - .pfpfw = "a420_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a420_pm4.fw", + [ADRENO_FW_PFP] = "a420_pfp.fw", + }, .gmem = (SZ_1M + SZ_512K), .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(5, 3, 0, 2), .revn = 530, .name = "A530", - .pm4fw = "a530_pm4.fw", - .pfpfw = "a530_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a530_pm4.fw", + [ADRENO_FW_PFP] = "a530_pfp.fw", + [ADRENO_FW_GPMU] = "a530v3_gpmu.fw2", + }, .gmem = SZ_1M, .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI | ADRENO_QUIRK_FAULT_DETECT_MASK, .init = a5xx_gpu_init, - .gpmufw = "a530v3_gpmu.fw2", .zapfw = "a530_zap.mdt", }, }; @@ -150,6 +164,14 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) return NULL; } +#ifdef CONFIG_DEBUG_FS + if (gpu->funcs->debugfs_init) { + gpu->funcs->debugfs_init(gpu, dev->primary); + gpu->funcs->debugfs_init(gpu, dev->render); + gpu->funcs->debugfs_init(gpu, dev->control); + } +#endif + return gpu; } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index de63ff26a062..17d0506d058c 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -140,27 +140,47 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname) static int adreno_load_fw(struct adreno_gpu *adreno_gpu) { - const struct firmware *fw; + int i; - if (adreno_gpu->pm4) - return 0; + for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) { + const struct firmware *fw; + + if (!adreno_gpu->info->fw[i]) + continue; + + /* Skip if the firmware has already been loaded */ + if (adreno_gpu->fw[i]) + continue; - fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pm4fw); - if (IS_ERR(fw)) - return PTR_ERR(fw); - adreno_gpu->pm4 = fw; + fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->fw[i]); + if (IS_ERR(fw)) + return PTR_ERR(fw); - fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pfpfw); - if (IS_ERR(fw)) { - release_firmware(adreno_gpu->pm4); - adreno_gpu->pm4 = NULL; - return PTR_ERR(fw); + adreno_gpu->fw[i] = fw; } - adreno_gpu->pfp = fw; return 0; } +struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, + const struct firmware *fw, u64 *iova) +{ + struct drm_gem_object *bo; + void *ptr; + + ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4, + MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova); + + if (IS_ERR(ptr)) + return ERR_CAST(ptr); + + memcpy(ptr, &fw->data[4], fw->size - 4); + + msm_gem_put_vaddr(bo); + + return bo; +} + int adreno_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -293,26 +313,12 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, OUT_RING(ring, 0x00000000); } + /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */ OUT_PKT3(ring, CP_EVENT_WRITE, 3); - OUT_RING(ring, CACHE_FLUSH_TS); + OUT_RING(ring, CACHE_FLUSH_TS | BIT(31)); OUT_RING(ring, rbmemptr(ring, fence)); OUT_RING(ring, submit->seqno); - /* we could maybe be clever and only CP_COND_EXEC the interrupt: */ - OUT_PKT3(ring, CP_INTERRUPT, 1); - OUT_RING(ring, 0x80000000); - - /* Workaround for missing irq issue on 8x16/a306. Unsure if the - * root cause is a platform issue or some a306 quirk, but this - * keeps things humming along: - */ - if (adreno_is_a306(adreno_gpu)) { - OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); - OUT_RING(ring, 0x00000000); - OUT_PKT3(ring, CP_INTERRUPT, 1); - OUT_RING(ring, 0x80000000); - } - #if 0 if (adreno_is_a3xx(adreno_gpu)) { /* Dummy set-constant to trigger context rollover */ @@ -569,8 +575,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) { - release_firmware(adreno_gpu->pm4); - release_firmware(adreno_gpu->pfp); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) + release_firmware(adreno_gpu->fw[i]); msm_gpu_cleanup(&adreno_gpu->base); } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 8d3d0a924908..d6b0e7b813f4 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -48,6 +48,13 @@ enum adreno_regs { REG_ADRENO_REGISTER_MAX, }; +enum { + ADRENO_FW_PM4 = 0, + ADRENO_FW_PFP = 1, + ADRENO_FW_GPMU = 2, + ADRENO_FW_MAX, +}; + enum adreno_quirks { ADRENO_QUIRK_TWO_PASS_USE_WFI = 1, ADRENO_QUIRK_FAULT_DETECT_MASK = 2, @@ -72,8 +79,7 @@ struct adreno_info { struct adreno_rev rev; uint32_t revn; const char *name; - const char *pm4fw, *pfpfw; - const char *gpmufw; + const char *fw[ADRENO_FW_MAX]; uint32_t gmem; enum adreno_quirks quirks; struct msm_gpu *(*init)(struct drm_device *dev); @@ -115,7 +121,7 @@ struct adreno_gpu { } fwloc; /* firmware: */ - const struct firmware *pm4, *pfp; + const struct firmware *fw[ADRENO_FW_MAX]; /* * Register offsets are different between some GPUs. @@ -200,6 +206,8 @@ static inline int adreno_is_a530(struct adreno_gpu *gpu) int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname); +struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, + const struct firmware *fw, u64 *iova); int adreno_hw_init(struct msm_gpu *gpu); void adreno_recover(struct msm_gpu *gpu); void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/disp/mdp4/mdp4.xml.h index 576cea30d391..576cea30d391 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4.xml.h diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 14bd3bd3e040..6e5e1aa54ce1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -129,7 +129,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) struct msm_kms *kms = &mdp4_kms->base.base; msm_gem_put_iova(val, kms->aspace); - drm_gem_object_unreference_unlocked(val); + drm_gem_object_put_unlocked(val); } static void mdp4_crtc_destroy(struct drm_crtc *crtc) @@ -382,7 +382,7 @@ static void update_cursor(struct drm_crtc *crtc) if (next_bo) { /* take a obj ref + iova ref when we start scanning out: */ - drm_gem_object_reference(next_bo); + drm_gem_object_get(next_bo); msm_gem_get_iova(next_bo, kms->aspace, &iova); /* enable cursor: */ @@ -467,7 +467,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, return 0; fail: - drm_gem_object_unreference_unlocked(cursor_bo); + drm_gem_object_put_unlocked(cursor_bo); return ret; } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c index 6a1ebdace391..6a1ebdace391 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c index ba8e587f734b..ba8e587f734b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c index b764d7f10312..b764d7f10312 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index f7f087419ed8..4b646bf9c214 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -164,7 +164,7 @@ static void mdp4_destroy(struct msm_kms *kms) if (mdp4_kms->blank_cursor_iova) msm_gem_put_iova(mdp4_kms->blank_cursor_bo, kms->aspace); - drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); + drm_gem_object_put_unlocked(mdp4_kms->blank_cursor_bo); if (aspace) { aspace->mmu->funcs->detach(aspace->mmu, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h index a1b3e31e959e..0c13f8697bfe 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h @@ -22,7 +22,7 @@ #include "msm_drv.h" #include "msm_kms.h" -#include "mdp/mdp_kms.h" +#include "disp/mdp_kms.h" #include "mdp4.xml.h" struct device_node; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index 4a645926edb7..4a645926edb7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index e3b1c86b7aae..e3b1c86b7aae 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c index ce4245971673..ce4245971673 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c index 7a1ad3af08e3..7a1ad3af08e3 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5.xml.h index d9c10e02ee41..d9c10e02ee41 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5.xml.h diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c index 824067d2d427..824067d2d427 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h index 75910d0f2f4c..75910d0f2f4c 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c index 1abc7f5c345c..d6f79dc755b4 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c @@ -159,7 +159,7 @@ void mdp5_cmd_encoder_disable(struct drm_encoder *encoder) pingpong_tearcheck_disable(encoder); mdp5_ctl_set_encoder_state(ctl, pipeline, false); - mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); + mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); bs_set(mdp5_cmd_enc, 0); @@ -180,7 +180,7 @@ void mdp5_cmd_encoder_enable(struct drm_encoder *encoder) if (pingpong_tearcheck_enable(encoder)) return; - mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); + mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); mdp5_ctl_set_encoder_state(ctl, pipeline, true); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index e414850dbbda..9893e43ba6c5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -97,9 +97,13 @@ static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask) struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); struct mdp5_ctl *ctl = mdp5_cstate->ctl; struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline; + bool start = !mdp5_cstate->defer_start; + + mdp5_cstate->defer_start = false; DBG("%s: flush=%08x", crtc->name, flush_mask); - return mdp5_ctl_commit(ctl, pipeline, flush_mask); + + return mdp5_ctl_commit(ctl, pipeline, flush_mask, start); } /* @@ -170,7 +174,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) struct msm_kms *kms = &mdp5_kms->base.base; msm_gem_put_iova(val, kms->aspace); - drm_gem_object_unreference_unlocked(val); + drm_gem_object_put_unlocked(val); } static void mdp5_crtc_destroy(struct drm_crtc *crtc) @@ -947,12 +951,17 @@ mdp5_crtc_atomic_print_state(struct drm_printer *p, if (WARN_ON(!pipeline)) return; + if (mdp5_cstate->ctl) + drm_printf(p, "\tctl=%d\n", mdp5_ctl_get_ctl_id(mdp5_cstate->ctl)); + drm_printf(p, "\thwmixer=%s\n", pipeline->mixer ? pipeline->mixer->name : "(null)"); if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT) drm_printf(p, "\tright hwmixer=%s\n", pipeline->r_mixer ? pipeline->r_mixer->name : "(null)"); + + drm_printf(p, "\tcmd_mode=%d\n", mdp5_cstate->cmd_mode); } static void mdp5_crtc_reset(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c index 439e0a300e25..f93d5681267c 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c @@ -41,7 +41,9 @@ struct mdp5_ctl { u32 status; bool encoder_enabled; - uint32_t start_mask; + + /* pending flush_mask bits */ + u32 flush_mask; /* REG_MDP5_CTL_*(<id>) registers access info + lock: */ spinlock_t hw_lock; @@ -173,16 +175,8 @@ static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline) int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline) { - struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; - struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr); + struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm); struct mdp5_interface *intf = pipeline->intf; - struct mdp5_hw_mixer *mixer = pipeline->mixer; - struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; - - ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm) | - mdp_ctl_flush_mask_encoder(intf); - if (r_mixer) - ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm); /* Virtual interfaces need not set a display intf (e.g.: Writeback) */ if (!mdp5_cfg_intf_is_virtual(intf->type)) @@ -198,7 +192,7 @@ static bool start_signal_needed(struct mdp5_ctl *ctl, { struct mdp5_interface *intf = pipeline->intf; - if (!ctl->encoder_enabled || ctl->start_mask != 0) + if (!ctl->encoder_enabled) return false; switch (intf->type) { @@ -227,25 +221,6 @@ static void send_start_signal(struct mdp5_ctl *ctl) spin_unlock_irqrestore(&ctl->hw_lock, flags); } -static void refill_start_mask(struct mdp5_ctl *ctl, - struct mdp5_pipeline *pipeline) -{ - struct mdp5_interface *intf = pipeline->intf; - struct mdp5_hw_mixer *mixer = pipeline->mixer; - struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; - - ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm); - if (r_mixer) - ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm); - - /* - * Writeback encoder needs to program & flush - * address registers for each page flip.. - */ - if (intf->type == INTF_WB) - ctl->start_mask |= mdp_ctl_flush_mask_encoder(intf); -} - /** * mdp5_ctl_set_encoder_state() - set the encoder state * @@ -268,7 +243,6 @@ int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, if (start_signal_needed(ctl, pipeline)) { send_start_signal(ctl); - refill_start_mask(ctl, pipeline); } return 0; @@ -494,6 +468,8 @@ u32 mdp_ctl_flush_mask_lm(int lm) case 0: return MDP5_CTL_FLUSH_LM0; case 1: return MDP5_CTL_FLUSH_LM1; case 2: return MDP5_CTL_FLUSH_LM2; + case 3: return MDP5_CTL_FLUSH_LM3; + case 4: return MDP5_CTL_FLUSH_LM4; case 5: return MDP5_CTL_FLUSH_LM5; default: return 0; } @@ -557,17 +533,14 @@ static void fix_for_single_flush(struct mdp5_ctl *ctl, u32 *flush_mask, */ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, - u32 flush_mask) + u32 flush_mask, bool start) { struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; unsigned long flags; u32 flush_id = ctl->id; u32 curr_ctl_flush_mask; - ctl->start_mask &= ~flush_mask; - - VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask, - ctl->start_mask, ctl->pending_ctl_trigger); + VERB("flush_mask=%x, trigger=%x", flush_mask, ctl->pending_ctl_trigger); if (ctl->pending_ctl_trigger & flush_mask) { flush_mask |= MDP5_CTL_FLUSH_CTL; @@ -582,6 +555,14 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, fix_for_single_flush(ctl, &flush_mask, &flush_id); + if (!start) { + ctl->flush_mask |= flush_mask; + return curr_ctl_flush_mask; + } else { + flush_mask |= ctl->flush_mask; + ctl->flush_mask = 0; + } + if (flush_mask) { spin_lock_irqsave(&ctl->hw_lock, flags); ctl_write(ctl, REG_MDP5_CTL_FLUSH(flush_id), flush_mask); @@ -590,7 +571,6 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, if (start_signal_needed(ctl, pipeline)) { send_start_signal(ctl); - refill_start_mask(ctl, pipeline); } return curr_ctl_flush_mask; @@ -711,6 +691,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, struct mdp5_ctl_manager *ctl_mgr; const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd); int rev = mdp5_cfg_get_hw_rev(cfg_hnd); + unsigned dsi_cnt = 0; const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl; unsigned long flags; int c, ret; @@ -760,7 +741,10 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, * only write into CTL0's FLUSH register) to keep two DSI pipes in sync. * Single FLUSH is supported from hw rev v3.0. */ - if (rev >= 3) { + for (c = 0; c < ARRAY_SIZE(hw_cfg->intf.connect); c++) + if (hw_cfg->intf.connect[c] == INTF_DSI) + dsi_cnt++; + if ((rev >= 3) && (dsi_cnt > 1)) { ctl_mgr->single_flush_supported = true; /* Reserve CTL0/1 for INTF1/2 */ ctl_mgr->ctls[0].status |= CTL_STAT_BOOKED; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h index b63120388dc6..403b0db0fa4c 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h @@ -78,7 +78,7 @@ u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf); /* @flush_mask: see CTL flush masks definitions below */ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, - u32 flush_mask); + u32 flush_mask, bool start); u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c index 36ad3cbe5f79..9af94e35f678 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c @@ -228,7 +228,7 @@ static void mdp5_vid_encoder_disable(struct drm_encoder *encoder) spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0); spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); - mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); + mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); /* * Wait for a vsync so we know the ENABLE=0 latched before @@ -262,7 +262,7 @@ static void mdp5_vid_encoder_enable(struct drm_encoder *encoder) spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1); spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); - mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); + mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); mdp5_ctl_set_encoder_state(ctl, pipeline, true); @@ -319,6 +319,7 @@ static int mdp5_encoder_atomic_check(struct drm_encoder *encoder, mdp5_cstate->ctl = ctl; mdp5_cstate->pipeline.intf = intf; + mdp5_cstate->defer_start = true; return 0; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c index 280e368bc9bb..280e368bc9bb 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 3e9bba4d6624..6d8e3a9a6fc0 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -680,7 +680,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) } else { dev_info(&pdev->dev, "no iommu, fallback to phys contig buffers for scanout\n"); - aspace = NULL;; + aspace = NULL; } pm_runtime_put_sync(&pdev->dev); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h index 9b3fe01089d1..425a03d213e5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h @@ -20,7 +20,7 @@ #include "msm_drv.h" #include "msm_kms.h" -#include "mdp/mdp_kms.h" +#include "disp/mdp_kms.h" #include "mdp5_cfg.h" /* must be included before mdp5.xml.h */ #include "mdp5.xml.h" #include "mdp5_pipe.h" @@ -133,6 +133,14 @@ struct mdp5_crtc_state { u32 pp_done_irqmask; bool cmd_mode; + + /* should we not write CTL[n].START register on flush? If the + * encoder has changed this is set to true, since encoder->enable() + * is called after crtc state is committed, but we only want to + * write the CTL[n].START register once. This lets us defer + * writing CTL[n].START until encoder->enable() + */ + bool defer_start; }; #define to_mdp5_crtc_state(x) \ container_of(x, struct mdp5_crtc_state, base) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c index f2a0db7a8a03..f2a0db7a8a03 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c index 8a00991f03c7..8a00991f03c7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h index 9be94f567fbd..9be94f567fbd 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c index ff52c49095f9..ff52c49095f9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h index bb2b0ac7aa2b..bb2b0ac7aa2b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c index 44fc9fe4737a..a9f31da7d45a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c @@ -535,7 +535,7 @@ static void mdp5_plane_atomic_async_update(struct drm_plane *plane, ctl = mdp5_crtc_get_ctl(new_state->crtc); - mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane)); + mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane), true); } *to_mdp5_plane_state(plane->state) = diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index ae4983d9d0a5..ae4983d9d0a5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h index b41d0448fbe8..b41d0448fbe8 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/disp/mdp_common.xml.h index 1494c407be44..1494c407be44 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h +++ b/drivers/gpu/drm/msm/disp/mdp_common.xml.h diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c index b4a8aa4490ee..b4a8aa4490ee 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_format.c +++ b/drivers/gpu/drm/msm/disp/mdp_format.c diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/disp/mdp_kms.c index 64287304054d..64287304054d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp_kms.c diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/disp/mdp_kms.h index 1185487e7e5e..1185487e7e5e 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp_kms.h diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 98742d7af6dc..b744bcc7d8ad 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -192,13 +192,14 @@ void __exit msm_dsi_unregister(void) int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, struct drm_encoder *encoder) { - struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_private *priv; struct drm_bridge *ext_bridge; int ret; - if (WARN_ON(!encoder)) + if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev)) return -EINVAL; + priv = dev->dev_private; msm_dsi->dev = dev; ret = msm_dsi_host_modeset_init(msm_dsi->host, dev); @@ -245,19 +246,17 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, return 0; fail: - if (msm_dsi) { - /* bridge/connector are normally destroyed by drm: */ - if (msm_dsi->bridge) { - msm_dsi_manager_bridge_destroy(msm_dsi->bridge); - msm_dsi->bridge = NULL; - } + /* bridge/connector are normally destroyed by drm: */ + if (msm_dsi->bridge) { + msm_dsi_manager_bridge_destroy(msm_dsi->bridge); + msm_dsi->bridge = NULL; + } - /* don't destroy connector if we didn't make it */ - if (msm_dsi->connector && !msm_dsi->external_bridge) - msm_dsi->connector->funcs->destroy(msm_dsi->connector); + /* don't destroy connector if we didn't make it */ + if (msm_dsi->connector && !msm_dsi->external_bridge) + msm_dsi->connector->funcs->destroy(msm_dsi->connector); - msm_dsi->connector = NULL; - } + msm_dsi->connector = NULL; return ret; } diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 2302046197a8..70d9a9a47acd 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -36,6 +36,7 @@ enum msm_dsi_phy_type { MSM_DSI_PHY_20NM, MSM_DSI_PHY_28NM_8960, MSM_DSI_PHY_14NM, + MSM_DSI_PHY_10NM, MSM_DSI_PHY_MAX }; diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h index 479086ccf180..f6a9471b70c8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h @@ -8,19 +8,10 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37411 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 33004 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 41799 bytes, from 2017-06-16 12:32:42) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2017-05-17 13:21:27) - -Copyright (C) 2013-2017 by the following authors: +- /local/mnt/workspace/source_trees/envytools/rnndb/../rnndb/dsi/dsi.xml ( 37239 bytes, from 2018-01-12 09:09:22) +- /local/mnt/workspace/source_trees/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-05-09 06:32:54) + +Copyright (C) 2013-2018 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) - Ilia Mirkin <imirkin@alum.mit.edu> (imirkin) @@ -1556,5 +1547,175 @@ static inline uint32_t REG_DSI_14nm_PHY_LN_VREG_CNTRL(uint32_t i0) { return 0x00 #define REG_DSI_14nm_PHY_PLL_PLL_BANDGAP 0x00000108 +#define REG_DSI_10nm_PHY_CMN_REVISION_ID0 0x00000000 + +#define REG_DSI_10nm_PHY_CMN_REVISION_ID1 0x00000004 + +#define REG_DSI_10nm_PHY_CMN_REVISION_ID2 0x00000008 + +#define REG_DSI_10nm_PHY_CMN_REVISION_ID3 0x0000000c + +#define REG_DSI_10nm_PHY_CMN_CLK_CFG0 0x00000010 + +#define REG_DSI_10nm_PHY_CMN_CLK_CFG1 0x00000014 + +#define REG_DSI_10nm_PHY_CMN_GLBL_CTRL 0x00000018 + +#define REG_DSI_10nm_PHY_CMN_RBUF_CTRL 0x0000001c + +#define REG_DSI_10nm_PHY_CMN_VREG_CTRL 0x00000020 + +#define REG_DSI_10nm_PHY_CMN_CTRL_0 0x00000024 + +#define REG_DSI_10nm_PHY_CMN_CTRL_1 0x00000028 + +#define REG_DSI_10nm_PHY_CMN_CTRL_2 0x0000002c + +#define REG_DSI_10nm_PHY_CMN_LANE_CFG0 0x00000030 + +#define REG_DSI_10nm_PHY_CMN_LANE_CFG1 0x00000034 + +#define REG_DSI_10nm_PHY_CMN_PLL_CNTRL 0x00000038 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL0 0x00000098 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL1 0x0000009c + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL2 0x000000a0 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL3 0x000000a4 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL4 0x000000a8 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0 0x000000ac + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1 0x000000b0 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2 0x000000b4 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3 0x000000b8 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4 0x000000bc + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5 0x000000c0 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6 0x000000c4 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7 0x000000c8 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8 0x000000cc + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9 0x000000d0 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10 0x000000d4 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11 0x000000d8 + +#define REG_DSI_10nm_PHY_CMN_PHY_STATUS 0x000000ec + +#define REG_DSI_10nm_PHY_CMN_LANE_STATUS0 0x000000f4 + +#define REG_DSI_10nm_PHY_CMN_LANE_STATUS1 0x000000f8 + +static inline uint32_t REG_DSI_10nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG0(uint32_t i0) { return 0x00000000 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG1(uint32_t i0) { return 0x00000004 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG2(uint32_t i0) { return 0x00000008 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG3(uint32_t i0) { return 0x0000000c + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000010 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_PIN_SWAP(uint32_t i0) { return 0x00000014 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(uint32_t i0) { return 0x00000018 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(uint32_t i0) { return 0x0000001c + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(uint32_t i0) { return 0x00000020 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(uint32_t i0) { return 0x00000024 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_LPRX_CTRL(uint32_t i0) { return 0x00000028 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_TX_DCTRL(uint32_t i0) { return 0x0000002c + 0x80*i0; } + +#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE 0x00000000 + +#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO 0x00000004 + +#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE 0x00000010 + +#define REG_DSI_10nm_PHY_PLL_DSM_DIVIDER 0x0000001c + +#define REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER 0x00000020 + +#define REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES 0x00000024 + +#define REG_DSI_10nm_PHY_PLL_CMODE 0x0000002c + +#define REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS 0x00000030 + +#define REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE 0x00000054 + +#define REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE 0x00000064 + +#define REG_DSI_10nm_PHY_PLL_PFILT 0x0000007c + +#define REG_DSI_10nm_PHY_PLL_IFILT 0x00000080 + +#define REG_DSI_10nm_PHY_PLL_OUTDIV 0x00000094 + +#define REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE 0x000000a4 + +#define REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE 0x000000a8 + +#define REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO 0x000000b4 + +#define REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1 0x000000cc + +#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1 0x000000d0 + +#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1 0x000000d4 + +#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1 0x000000d8 + +#define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1 0x0000010c + +#define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1 0x00000110 + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1 0x00000114 + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1 0x00000118 + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1 0x0000011c + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1 0x00000120 + +#define REG_DSI_10nm_PHY_PLL_SSC_CONTROL 0x0000013c + +#define REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE 0x00000140 + +#define REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1 0x00000144 + +#define REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1 0x0000014c + +#define REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1 0x00000154 + +#define REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1 0x0000015c + +#define REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x00000164 + +#define REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE 0x00000180 + +#define REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY 0x00000184 + +#define REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS 0x0000018c + +#define REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE 0x000001a0 + #endif /* DSI_XML */ diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 65c1dfbbe019..0327bb54b01b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -118,6 +118,24 @@ static const struct msm_dsi_config msm8996_dsi_cfg = { .num_dsi = 2, }; +static const char * const dsi_sdm845_bus_clk_names[] = { + "iface", "bus", +}; + +static const struct msm_dsi_config sdm845_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .reg_cfg = { + .num = 1, + .regs = { + {"vdda", 21800, 4 }, /* 1.2 V */ + }, + }, + .bus_clk_names = dsi_sdm845_bus_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_sdm845_bus_clk_names), + .io_start = { 0xae94000, 0xae96000 }, + .num_dsi = 2, +}; + static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { {MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, &apq8064_dsi_cfg}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0, @@ -131,6 +149,7 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, &msm8994_dsi_cfg}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, &msm8916_dsi_cfg}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, &msm8996_dsi_cfg}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg}, }; const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 00a5da2663c6..9cfdcf1c95d5 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -25,6 +25,7 @@ #define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000 #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 +#define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 #define MSM_DSI_V2_VER_MINOR_8064 0x0 diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 0f7324a686ca..7a03a9489708 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -115,6 +115,7 @@ struct msm_dsi_host { struct clk *pixel_clk; struct clk *byte_clk_src; struct clk *pixel_clk_src; + struct clk *byte_intf_clk; u32 byte_clk_rate; u32 esc_clk_rate; @@ -214,7 +215,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( goto exit; } - ahb_clk = clk_get(dev, "iface_clk"); + ahb_clk = msm_clk_get(msm_host->pdev, "iface"); if (IS_ERR(ahb_clk)) { pr_err("%s: cannot get interface clock\n", __func__); goto put_gdsc; @@ -225,7 +226,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( ret = regulator_enable(gdsc_reg); if (ret) { pr_err("%s: unable to enable gdsc\n", __func__); - goto put_clk; + goto put_gdsc; } ret = clk_prepare_enable(ahb_clk); @@ -249,8 +250,6 @@ disable_clks: disable_gdsc: regulator_disable(gdsc_reg); pm_runtime_put_sync(dev); -put_clk: - clk_put(ahb_clk); put_gdsc: regulator_put(gdsc_reg); exit: @@ -379,6 +378,19 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) goto exit; } + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G && + cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V2_2_1) { + msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf"); + if (IS_ERR(msm_host->byte_intf_clk)) { + ret = PTR_ERR(msm_host->byte_intf_clk); + pr_err("%s: can't find byte_intf clock. ret=%d\n", + __func__, ret); + goto exit; + } + } else { + msm_host->byte_intf_clk = NULL; + } + msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk); if (!msm_host->byte_clk_src) { ret = -ENODEV; @@ -504,6 +516,16 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) goto error; } + if (msm_host->byte_intf_clk) { + ret = clk_set_rate(msm_host->byte_intf_clk, + msm_host->byte_clk_rate / 2); + if (ret) { + pr_err("%s: Failed to set rate byte intf clk, %d\n", + __func__, ret); + goto error; + } + } + ret = clk_prepare_enable(msm_host->esc_clk); if (ret) { pr_err("%s: Failed to enable dsi esc clk\n", __func__); @@ -522,8 +544,19 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) goto pixel_clk_err; } + if (msm_host->byte_intf_clk) { + ret = clk_prepare_enable(msm_host->byte_intf_clk); + if (ret) { + pr_err("%s: Failed to enable byte intf clk\n", + __func__); + goto byte_intf_clk_err; + } + } + return 0; +byte_intf_clk_err: + clk_disable_unprepare(msm_host->pixel_clk); pixel_clk_err: clk_disable_unprepare(msm_host->byte_clk); byte_clk_err: @@ -617,6 +650,8 @@ static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { clk_disable_unprepare(msm_host->esc_clk); clk_disable_unprepare(msm_host->pixel_clk); + if (msm_host->byte_intf_clk) + clk_disable_unprepare(msm_host->byte_intf_clk); clk_disable_unprepare(msm_host->byte_clk); } else { clk_disable_unprepare(msm_host->pixel_clk); @@ -1028,10 +1063,8 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) if (msm_host->tx_gem_obj) { msm_gem_put_iova(msm_host->tx_gem_obj, 0); - mutex_lock(&dev->struct_mutex); - msm_gem_free_object(msm_host->tx_gem_obj); + drm_gem_object_put_unlocked(msm_host->tx_gem_obj); msm_host->tx_gem_obj = NULL; - mutex_unlock(&dev->struct_mutex); } if (msm_host->tx_buf) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 855248132b2b..4cb1cb68878b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -88,6 +88,8 @@ static int dsi_mgr_setup_components(int id) msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE); src_pll = msm_dsi_phy_get_pll(msm_dsi->phy); + if (IS_ERR(src_pll)) + return PTR_ERR(src_pll); ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); } else if (!other_dsi) { ret = 0; @@ -116,6 +118,8 @@ static int dsi_mgr_setup_components(int id) msm_dsi_phy_set_usecase(clk_slave_dsi->phy, MSM_DSI_PHY_SLAVE); src_pll = msm_dsi_phy_get_pll(clk_master_dsi->phy); + if (IS_ERR(src_pll)) + return PTR_ERR(src_pll); ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); if (ret) return ret; @@ -858,7 +862,7 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi) int id = msm_dsi->id; int ret; - if (id > DSI_MAX) { + if (id >= DSI_MAX) { pr_err("%s: invalid id %d\n", __func__, id); return -EINVAL; } diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 790ca280cbfd..8e9d5c255820 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -395,6 +395,10 @@ static const struct of_device_id dsi_phy_dt_match[] = { { .compatible = "qcom,dsi-phy-14nm", .data = &dsi_phy_14nm_cfgs }, #endif +#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY + { .compatible = "qcom,dsi-phy-10nm", + .data = &dsi_phy_10nm_cfgs }, +#endif {} }; @@ -503,10 +507,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) goto fail; phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id); - if (!phy->pll) + if (IS_ERR_OR_NULL(phy->pll)) dev_info(dev, - "%s: pll init failed, need separate pll clk driver\n", - __func__); + "%s: pll init failed: %ld, need separate pll clk driver\n", + __func__, PTR_ERR(phy->pll)); dsi_phy_disable_resource(phy); diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 1733f6608a09..c56268cbdb3d 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -48,6 +48,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs; struct msm_dsi_dphy_timing { u32 clk_pre; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c new file mode 100644 index 000000000000..0af951aaeea1 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -0,0 +1,251 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018, The Linux Foundation + */ + +#include <linux/iopoll.h> + +#include "dsi_phy.h" +#include "dsi.xml.h" + +static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy) +{ + void __iomem *base = phy->base; + u32 data = 0; + + data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); + mb(); /* make sure read happened */ + + return (data & BIT(0)); +} + +static void dsi_phy_hw_v3_0_config_lpcdrx(struct msm_dsi_phy *phy, bool enable) +{ + void __iomem *lane_base = phy->lane_base; + int phy_lane_0 = 0; /* TODO: Support all lane swap configs */ + + /* + * LPRX and CDRX need to enabled only for physical data lane + * corresponding to the logical data lane 0 + */ + if (enable) + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0x3); + else + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0); +} + +static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) +{ + int i; + u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 }; + void __iomem *lane_base = phy->lane_base; + + /* Strength ctrl settings */ + for (i = 0; i < 5; i++) { + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i), + 0x55); + /* + * Disable LPRX and CDRX for all lanes. And later on, it will + * be only enabled for the physical data lane corresponding + * to the logical data lane 0 + */ + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(i), 0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_PIN_SWAP(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(i), + 0x88); + } + + dsi_phy_hw_v3_0_config_lpcdrx(phy, true); + + /* other settings */ + for (i = 0; i < 5; i++) { + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG0(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG1(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i), + i == 4 ? 0x80 : 0x0); + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0); + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i), + tx_dctrl[i]); + } + + /* Toggle BIT 0 to release freeze I/0 */ + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04); +} + +static int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, + struct msm_dsi_phy_clk_request *clk_req) +{ + /* + * TODO: These params need to be computed, they're currently hardcoded + * for a 1440x2560@60Hz panel with a byteclk of 100.618 Mhz, and a + * default escape clock of 19.2 Mhz. + */ + + timing->hs_halfbyte_en = 0; + timing->clk_zero = 0x1c; + timing->clk_prepare = 0x07; + timing->clk_trail = 0x07; + timing->hs_exit = 0x23; + timing->hs_zero = 0x21; + timing->hs_prepare = 0x07; + timing->hs_trail = 0x07; + timing->hs_rqst = 0x05; + timing->ta_sure = 0x00; + timing->ta_go = 0x03; + timing->ta_get = 0x04; + + timing->shared_timings.clk_pre = 0x2d; + timing->shared_timings.clk_post = 0x0d; + + return 0; +} + +static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, + struct msm_dsi_phy_clk_request *clk_req) +{ + int ret; + u32 status; + u32 const delay_us = 5; + u32 const timeout_us = 1000; + struct msm_dsi_dphy_timing *timing = &phy->timing; + void __iomem *base = phy->base; + u32 data; + + DBG(""); + + if (msm_dsi_dphy_timing_calc_v3(timing, clk_req)) { + dev_err(&phy->pdev->dev, + "%s: D-PHY timing calculation failed\n", __func__); + return -EINVAL; + } + + if (dsi_phy_hw_v3_0_is_pll_on(phy)) + pr_warn("PLL turned on before configuring PHY\n"); + + /* wait for REFGEN READY */ + ret = readl_poll_timeout_atomic(base + REG_DSI_10nm_PHY_CMN_PHY_STATUS, + status, (status & BIT(0)), + delay_us, timeout_us); + if (ret) { + pr_err("Ref gen not ready. Aborting\n"); + return -EINVAL; + } + + /* de-assert digital and pll power down */ + data = BIT(6) | BIT(5); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); + + /* Assert PLL core reset */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0x00); + + /* turn off resync FIFO */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x00); + + /* Select MS1 byte-clk */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10); + + /* Enable LDO */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59); + + /* Configure PHY lane swap (TODO: we need to calculate this) */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG1, 0x84); + + /* DSI PHY timings */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0, + timing->hs_halfbyte_en); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1, + timing->clk_zero); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2, + timing->clk_prepare); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3, + timing->clk_trail); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4, + timing->hs_exit); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5, + timing->hs_zero); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6, + timing->hs_prepare); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7, + timing->hs_trail); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8, + timing->hs_rqst); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9, + timing->ta_go | (timing->ta_sure << 3)); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10, + timing->ta_get); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11, + 0x00); + + /* Remove power down from all blocks */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, 0x7f); + + /* power up lanes */ + data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_CTRL_0); + + /* TODO: only power up lanes that are used */ + data |= 0x1F; + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0, 0x1F); + + /* Select full-rate mode */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_2, 0x40); + + ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase); + if (ret) { + dev_err(&phy->pdev->dev, "%s: set pll usecase failed, %d\n", + __func__, ret); + return ret; + } + + /* DSI lane settings */ + dsi_phy_hw_v3_0_lane_settings(phy); + + DBG("DSI%d PHY enabled", phy->id); + + return 0; +} + +static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy) +{ +} + +static int dsi_10nm_phy_init(struct msm_dsi_phy *phy) +{ + struct platform_device *pdev = phy->pdev; + + phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane", + "DSI_PHY_LANE"); + if (IS_ERR(phy->lane_base)) { + dev_err(&pdev->dev, "%s: failed to map phy lane base\n", + __func__); + return -ENOMEM; + } + + return 0; +} + +const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { + .type = MSM_DSI_PHY_10NM, + .src_pll_truthtable = { {false, false}, {true, false} }, + .reg_cfg = { + .num = 1, + .regs = { + {"vdds", 36000, 32}, + }, + }, + .ops = { + .enable = dsi_10nm_phy_enable, + .disable = dsi_10nm_phy_disable, + .init = dsi_10nm_phy_init, + }, + .io_start = { 0xae94400, 0xae96400 }, + .num_dsi_phy = 2, +}; diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c index bc289f5c9078..613e206fa4fc 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c @@ -166,6 +166,9 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, case MSM_DSI_PHY_14NM: pll = msm_dsi_pll_14nm_init(pdev, id); break; + case MSM_DSI_PHY_10NM: + pll = msm_dsi_pll_10nm_init(pdev, id); + break; default: pll = ERR_PTR(-ENXIO); break; @@ -173,7 +176,7 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, if (IS_ERR(pll)) { dev_err(dev, "%s: failed to init DSI PLL\n", __func__); - return NULL; + return pll; } pll->type = type; diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h index f63e7ada74a8..8b32271cbc24 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h @@ -115,5 +115,14 @@ msm_dsi_pll_14nm_init(struct platform_device *pdev, int id) return ERR_PTR(-ENODEV); } #endif +#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY +struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id); +#else +static inline struct msm_dsi_pll * +msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) +{ + return ERR_PTR(-ENODEV); +} +#endif #endif /* __DSI_PLL_H__ */ diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c new file mode 100644 index 000000000000..c4c37a7df637 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c @@ -0,0 +1,822 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018, The Linux Foundation + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/iopoll.h> + +#include "dsi_pll.h" +#include "dsi.xml.h" + +/* + * DSI PLL 10nm - clock diagram (eg: DSI0): + * + * dsi0_pll_out_div_clk dsi0_pll_bit_clk + * | | + * | | + * +---------+ | +----------+ | +----+ + * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0pllbyte + * +---------+ | +----------+ | +----+ + * | | + * | | dsi0_pll_by_2_bit_clk + * | | | + * | | +----+ | |\ dsi0_pclk_mux + * | |--| /2 |--o--| \ | + * | | +----+ | \ | +---------+ + * | --------------| |--o--| div_7_4 |-- dsi0pll + * |------------------------------| / +---------+ + * | +-----+ | / + * -----------| /4? |--o----------|/ + * +-----+ | | + * | |dsiclk_sel + * | + * dsi0_pll_post_out_div_clk + */ + +#define DSI_BYTE_PLL_CLK 0 +#define DSI_PIXEL_PLL_CLK 1 +#define NUM_PROVIDED_CLKS 2 + +struct dsi_pll_regs { + u32 pll_prop_gain_rate; + u32 pll_lockdet_rate; + u32 decimal_div_start; + u32 frac_div_start_low; + u32 frac_div_start_mid; + u32 frac_div_start_high; + u32 pll_clock_inverters; + u32 ssc_stepsize_low; + u32 ssc_stepsize_high; + u32 ssc_div_per_low; + u32 ssc_div_per_high; + u32 ssc_adjper_low; + u32 ssc_adjper_high; + u32 ssc_control; +}; + +struct dsi_pll_config { + u32 ref_freq; + bool div_override; + u32 output_div; + bool ignore_frac; + bool disable_prescaler; + bool enable_ssc; + bool ssc_center; + u32 dec_bits; + u32 frac_bits; + u32 lock_timer; + u32 ssc_freq; + u32 ssc_offset; + u32 ssc_adj_per; + u32 thresh_cycles; + u32 refclk_cycles; +}; + +struct pll_10nm_cached_state { + unsigned long vco_rate; + u8 bit_clk_div; + u8 pix_clk_div; + u8 pll_out_div; + u8 pll_mux; +}; + +struct dsi_pll_10nm { + struct msm_dsi_pll base; + + int id; + struct platform_device *pdev; + + void __iomem *phy_cmn_mmio; + void __iomem *mmio; + + u64 vco_ref_clk_rate; + u64 vco_current_rate; + + /* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */ + spinlock_t postdiv_lock; + + int vco_delay; + struct dsi_pll_config pll_configuration; + struct dsi_pll_regs reg_setup; + + /* private clocks: */ + struct clk_hw *hws[NUM_DSI_CLOCKS_MAX]; + u32 num_hws; + + /* clock-provider: */ + struct clk_hw_onecell_data *hw_data; + + struct pll_10nm_cached_state cached_state; + + enum msm_dsi_phy_usecase uc; + struct dsi_pll_10nm *slave; +}; + +#define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, base) + +/* + * Global list of private DSI PLL struct pointers. We need this for Dual DSI + * mode, where the master PLL's clk_ops needs access the slave's private data + */ +static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX]; + +static void dsi_pll_setup_config(struct dsi_pll_10nm *pll) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + + config->ref_freq = pll->vco_ref_clk_rate; + config->output_div = 1; + config->dec_bits = 8; + config->frac_bits = 18; + config->lock_timer = 64; + config->ssc_freq = 31500; + config->ssc_offset = 5000; + config->ssc_adj_per = 2; + config->thresh_cycles = 32; + config->refclk_cycles = 256; + + config->div_override = false; + config->ignore_frac = false; + config->disable_prescaler = false; + + config->enable_ssc = false; + config->ssc_center = 0; +} + +static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u64 fref = pll->vco_ref_clk_rate; + u64 pll_freq; + u64 divider; + u64 dec, dec_multiple; + u32 frac; + u64 multiplier; + + pll_freq = pll->vco_current_rate; + + if (config->disable_prescaler) + divider = fref; + else + divider = fref * 2; + + multiplier = 1 << config->frac_bits; + dec_multiple = div_u64(pll_freq * multiplier, divider); + div_u64_rem(dec_multiple, multiplier, &frac); + + dec = div_u64(dec_multiple, multiplier); + + if (pll_freq <= 1900000000UL) + regs->pll_prop_gain_rate = 8; + else if (pll_freq <= 3000000000UL) + regs->pll_prop_gain_rate = 10; + else + regs->pll_prop_gain_rate = 12; + if (pll_freq < 1100000000UL) + regs->pll_clock_inverters = 8; + else + regs->pll_clock_inverters = 0; + + regs->pll_lockdet_rate = config->lock_timer; + regs->decimal_div_start = dec; + regs->frac_div_start_low = (frac & 0xff); + regs->frac_div_start_mid = (frac & 0xff00) >> 8; + regs->frac_div_start_high = (frac & 0x30000) >> 16; +} + +#define SSC_CENTER BIT(0) +#define SSC_EN BIT(1) + +static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u32 ssc_per; + u32 ssc_mod; + u64 ssc_step_size; + u64 frac; + + if (!config->enable_ssc) { + DBG("SSC not enabled\n"); + return; + } + + ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1; + ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); + ssc_per -= ssc_mod; + + frac = regs->frac_div_start_low | + (regs->frac_div_start_mid << 8) | + (regs->frac_div_start_high << 16); + ssc_step_size = regs->decimal_div_start; + ssc_step_size *= (1 << config->frac_bits); + ssc_step_size += frac; + ssc_step_size *= config->ssc_offset; + ssc_step_size *= (config->ssc_adj_per + 1); + ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); + ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); + + regs->ssc_div_per_low = ssc_per & 0xFF; + regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; + regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); + regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); + regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; + regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; + + regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; + + pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", + regs->decimal_div_start, frac, config->frac_bits); + pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", + ssc_per, (u32)ssc_step_size, config->ssc_adj_per); +} + +static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll) +{ + void __iomem *base = pll->mmio; + struct dsi_pll_regs *regs = &pll->reg_setup; + + if (pll->pll_configuration.enable_ssc) { + pr_debug("SSC is enabled\n"); + + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, + regs->ssc_stepsize_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, + regs->ssc_stepsize_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, + regs->ssc_div_per_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, + regs->ssc_div_per_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, + regs->ssc_adjper_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, + regs->ssc_adjper_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, + SSC_EN | regs->ssc_control); + } +} + +static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) +{ + void __iomem *base = pll->mmio; + + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80); + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); + pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); + pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, + 0xba); + pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); + pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, + 0x4c); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); + pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); + pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); +} + +static void dsi_pll_commit(struct dsi_pll_10nm *pll) +{ + void __iomem *base = pll->mmio; + struct dsi_pll_regs *reg = &pll->reg_setup; + + pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); + pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, + reg->decimal_div_start); + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, + reg->frac_div_start_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, + reg->frac_div_start_mid); + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, + reg->frac_div_start_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); + pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); + pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, + reg->pll_clock_inverters); +} + +static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate, + parent_rate); + + pll_10nm->vco_current_rate = rate; + pll_10nm->vco_ref_clk_rate = parent_rate; + + dsi_pll_setup_config(pll_10nm); + + dsi_pll_calc_dec_frac(pll_10nm); + + dsi_pll_calc_ssc(pll_10nm); + + dsi_pll_commit(pll_10nm); + + dsi_pll_config_hzindep_reg(pll_10nm); + + dsi_pll_ssc_commit(pll_10nm); + + /* flush, ensure all register writes are done*/ + wmb(); + + return 0; +} + +static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll) +{ + int rc; + u32 status = 0; + u32 const delay_us = 100; + u32 const timeout_us = 5000; + + rc = readl_poll_timeout_atomic(pll->mmio + + REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE, + status, + ((status & BIT(0)) > 0), + delay_us, + timeout_us); + if (rc) + pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", + pll->id, status); + + return rc; +} + +static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) +{ + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); + + pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, + data & ~BIT(5)); + ndelay(250); +} + +static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) +{ + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); + + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, + data | BIT(5)); + pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); + ndelay(250); +} + +static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) +{ + u32 data; + + data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, + data & ~BIT(5)); +} + +static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) +{ + u32 data; + + data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, + data | BIT(5)); +} + +static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + int rc; + + dsi_pll_enable_pll_bias(pll_10nm); + if (pll_10nm->slave) + dsi_pll_enable_pll_bias(pll_10nm->slave); + + /* Start PLL */ + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, + 0x01); + + /* + * ensure all PLL configurations are written prior to checking + * for PLL lock. + */ + wmb(); + + /* Check for PLL lock */ + rc = dsi_pll_10nm_lock_status(pll_10nm); + if (rc) { + pr_err("PLL(%d) lock failed\n", pll_10nm->id); + goto error; + } + + pll->pll_on = true; + + dsi_pll_enable_global_clk(pll_10nm); + if (pll_10nm->slave) + dsi_pll_enable_global_clk(pll_10nm->slave); + + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, + 0x01); + if (pll_10nm->slave) + pll_write(pll_10nm->slave->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); + +error: + return rc; +} + +static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll) +{ + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0); + dsi_pll_disable_pll_bias(pll); +} + +static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + /* + * To avoid any stray glitches while abruptly powering down the PLL + * make sure to gate the clock using the clock enable bit before + * powering down the PLL + */ + dsi_pll_disable_global_clk(pll_10nm); + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0); + dsi_pll_disable_sub(pll_10nm); + if (pll_10nm->slave) { + dsi_pll_disable_global_clk(pll_10nm->slave); + dsi_pll_disable_sub(pll_10nm->slave); + } + /* flush, ensure all register writes are done */ + wmb(); + pll->pll_on = false; +} + +static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + void __iomem *base = pll_10nm->mmio; + u64 ref_clk = pll_10nm->vco_ref_clk_rate; + u64 vco_rate = 0x0; + u64 multiplier; + u32 frac; + u32 dec; + u64 pll_freq, tmp64; + + dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); + dec &= 0xff; + + frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); + frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) & + 0xff) << 8); + frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) & + 0x3) << 16); + + /* + * TODO: + * 1. Assumes prescaler is disabled + * 2. Multiplier is 2^18. it should be 2^(num_of_frac_bits) + */ + multiplier = 1 << 18; + pll_freq = dec * (ref_clk * 2); + tmp64 = (ref_clk * 2 * frac); + pll_freq += div_u64(tmp64, multiplier); + + vco_rate = pll_freq; + + DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", + pll_10nm->id, (unsigned long)vco_rate, dec, frac); + + return (unsigned long)vco_rate; +} + +static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { + .round_rate = msm_dsi_pll_helper_clk_round_rate, + .set_rate = dsi_pll_10nm_vco_set_rate, + .recalc_rate = dsi_pll_10nm_vco_recalc_rate, + .prepare = dsi_pll_10nm_vco_prepare, + .unprepare = dsi_pll_10nm_vco_unprepare, +}; + +/* + * PLL Callbacks + */ + +static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; + void __iomem *phy_base = pll_10nm->phy_cmn_mmio; + u32 cmn_clk_cfg0, cmn_clk_cfg1; + + cached->pll_out_div = pll_read(pll_10nm->mmio + + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); + cached->pll_out_div &= 0x3; + + cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); + cached->bit_clk_div = cmn_clk_cfg0 & 0xf; + cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; + + cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + cached->pll_mux = cmn_clk_cfg1 & 0x3; + + DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", + pll_10nm->id, cached->pll_out_div, cached->bit_clk_div, + cached->pix_clk_div, cached->pll_mux); +} + +static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; + void __iomem *phy_base = pll_10nm->phy_cmn_mmio; + u32 val; + + val = pll_read(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); + val &= ~0x3; + val |= cached->pll_out_div; + pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val); + + pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + cached->bit_clk_div | (cached->pix_clk_div << 4)); + + val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + val &= ~0x3; + val |= cached->pll_mux; + pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val); + + DBG("DSI PLL%d", pll_10nm->id); + + return 0; +} + +static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll, + enum msm_dsi_phy_usecase uc) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + void __iomem *base = pll_10nm->phy_cmn_mmio; + u32 data = 0x0; /* internal PLL */ + + DBG("DSI PLL%d", pll_10nm->id); + + switch (uc) { + case MSM_DSI_PHY_STANDALONE: + break; + case MSM_DSI_PHY_MASTER: + pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX]; + break; + case MSM_DSI_PHY_SLAVE: + data = 0x1; /* external PLL */ + break; + default: + return -EINVAL; + } + + /* set PLL src */ + pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2)); + + pll_10nm->uc = uc; + + return 0; +} + +static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, + struct clk **byte_clk_provider, + struct clk **pixel_clk_provider) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data; + + DBG("DSI PLL%d", pll_10nm->id); + + if (byte_clk_provider) + *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; + if (pixel_clk_provider) + *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; + + return 0; +} + +static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d", pll_10nm->id); +} + +/* + * The post dividers and mux clocks are created using the standard divider and + * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux + * state to follow the master PLL's divider/mux state. Therefore, we don't + * require special clock ops that also configure the slave PLL registers + */ +static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) +{ + char clk_name[32], parent[32], vco_name[32]; + char parent2[32], parent3[32], parent4[32]; + struct clk_init_data vco_init = { + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .name = vco_name, + .flags = CLK_IGNORE_UNUSED, + .ops = &clk_ops_dsi_pll_10nm_vco, + }; + struct device *dev = &pll_10nm->pdev->dev; + struct clk_hw **hws = pll_10nm->hws; + struct clk_hw_onecell_data *hw_data; + struct clk_hw *hw; + int num = 0; + int ret; + + DBG("DSI%d", pll_10nm->id); + + hw_data = devm_kzalloc(dev, sizeof(*hw_data) + + NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), + GFP_KERNEL); + if (!hw_data) + return -ENOMEM; + + snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id); + pll_10nm->base.clk_hw.init = &vco_init; + + ret = clk_hw_register(dev, &pll_10nm->base.clk_hw); + if (ret) + return ret; + + hws[num++] = &pll_10nm->base.clk_hw; + + snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id); + + hw = clk_hw_register_divider(dev, clk_name, + parent, CLK_SET_RATE_PARENT, + pll_10nm->mmio + + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + + /* BIT CLK: DIV_CTRL_3_0 */ + hw = clk_hw_register_divider(dev, clk_name, parent, + CLK_SET_RATE_PARENT, + pll_10nm->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 0, 4, CLK_DIVIDER_ONE_BASED, + &pll_10nm->postdiv_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%dpllbyte", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + + /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, + CLK_SET_RATE_PARENT, 1, 8); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + hw_data->hws[DSI_BYTE_PLL_CLK] = hw; + + snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, + 0, 1, 2); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, + 0, 1, 4); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); + snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); + + hw = clk_hw_register_mux(dev, clk_name, + (const char *[]){ + parent, parent2, parent3, parent4 + }, 4, 0, pll_10nm->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_CLK_CFG1, + 0, 2, 0, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%dpll", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id); + + /* PIX CLK DIV : DIV_CTRL_7_4*/ + hw = clk_hw_register_divider(dev, clk_name, parent, + 0, pll_10nm->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 4, 4, CLK_DIVIDER_ONE_BASED, + &pll_10nm->postdiv_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; + + pll_10nm->num_hws = num; + + hw_data->num = NUM_PROVIDED_CLKS; + pll_10nm->hw_data = hw_data; + + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + pll_10nm->hw_data); + if (ret) { + dev_err(dev, "failed to register clk provider: %d\n", ret); + return ret; + } + + return 0; +} + +struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) +{ + struct dsi_pll_10nm *pll_10nm; + struct msm_dsi_pll *pll; + int ret; + + if (!pdev) + return ERR_PTR(-ENODEV); + + pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL); + if (!pll_10nm) + return ERR_PTR(-ENOMEM); + + DBG("DSI PLL%d", id); + + pll_10nm->pdev = pdev; + pll_10nm->id = id; + pll_10nm_list[id] = pll_10nm; + + pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); + if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) { + dev_err(&pdev->dev, "failed to map CMN PHY base\n"); + return ERR_PTR(-ENOMEM); + } + + pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); + if (IS_ERR_OR_NULL(pll_10nm->mmio)) { + dev_err(&pdev->dev, "failed to map PLL base\n"); + return ERR_PTR(-ENOMEM); + } + + pll = &pll_10nm->base; + pll->min_rate = 1000000000UL; + pll->max_rate = 3500000000UL; + pll->get_provider = dsi_pll_10nm_get_provider; + pll->destroy = dsi_pll_10nm_destroy; + pll->save_state = dsi_pll_10nm_save_state; + pll->restore_state = dsi_pll_10nm_restore_state; + pll->set_usecase = dsi_pll_10nm_set_usecase; + + pll_10nm->vco_delay = 1; + + ret = pll_10nm_register(pll_10nm); + if (ret) { + dev_err(&pdev->dev, "failed to register PLL: %d\n", ret); + return ERR_PTR(ret); + } + + /* TODO: Remove this when we have proper display handover support */ + msm_dsi_pll_save_state(pll); + + return pll; +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c index 6e767979aab3..3656155e3793 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c @@ -769,7 +769,7 @@ static int msm_hdmi_hdcp_auth_part1_key_exchange(struct hdmi_hdcp_ctrl *hdcp_ctr if (rc) { pr_err("%s: wait key and an ready failed\n", __func__); return rc; - }; + } /* Read BCAPS and send to HDCP engine */ rc = msm_hdmi_hdcp_recv_bcaps(hdcp_ctrl); diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 1855182c76ce..ba74cb4f94df 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -161,8 +161,11 @@ int msm_debugfs_init(struct drm_minor *minor) return ret; } - if (priv->kms->funcs->debugfs_init) + if (priv->kms->funcs->debugfs_init) { ret = priv->kms->funcs->debugfs_init(priv->kms, minor); + if (ret) + return ret; + } return ret; } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d90ef1d78a1b..30cd514d8f7c 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -660,7 +660,7 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, ret = msm_gem_cpu_prep(obj, args->op, &timeout); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -678,7 +678,7 @@ static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, ret = msm_gem_cpu_fini(obj); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -718,7 +718,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, args->offset = msm_gem_mmap_offset(obj); } - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -783,7 +783,7 @@ static int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, ret = 0; } - drm_gem_object_unreference(obj); + drm_gem_object_put(obj); unlock: mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 0a653dd2e618..48ed5b9a8580 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -51,7 +51,6 @@ struct msm_rd_state; struct msm_perf_state; struct msm_gem_submit; struct msm_fence_context; -struct msm_fence_cb; struct msm_gem_address_space; struct msm_gem_vma; diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index fc175e724ad6..0e0c87252ab0 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -53,7 +53,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb) for (i = 0; i < n; i++) { struct drm_gem_object *bo = msm_fb->planes[i]; - drm_gem_object_unreference_unlocked(bo); + drm_gem_object_put_unlocked(bo); } kfree(msm_fb); @@ -160,7 +160,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, out_unref: for (i = 0; i < n; i++) - drm_gem_object_unreference_unlocked(bos[i]); + drm_gem_object_put_unlocked(bos[i]); return ERR_PTR(ret); } @@ -274,7 +274,7 @@ msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format /* note: if fb creation failed, we can't rely on fb destroy * to unref the bo: */ - drm_gem_object_unreference_unlocked(bo); + drm_gem_object_put_unlocked(bo); return ERR_CAST(fb); } diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 1aa6a4c6530c..b9fe059091f2 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -37,8 +37,6 @@ void msm_fence_context_free(struct msm_fence_context *fctx); int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, ktime_t *timeout, bool interruptible); -int msm_queue_fence_cb(struct msm_fence_context *fctx, - struct msm_fence_cb *cb, uint32_t fence); void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence); struct dma_fence * msm_fence_alloc(struct msm_fence_context *fctx); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 07376de9ff4c..95196479f651 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -470,7 +470,7 @@ int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, *offset = msm_gem_mmap_offset(obj); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); fail: return ret; @@ -798,6 +798,7 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) } #endif +/* don't call directly! Use drm_gem_object_put() and friends */ void msm_gem_free_object(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; @@ -854,7 +855,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, ret = drm_gem_handle_create(file, obj, handle); /* drop reference from allocate - handle holds it now */ - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -974,7 +975,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev, return obj; fail: - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ERR_PTR(ret); } @@ -1034,7 +1035,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, return obj; fail: - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ERR_PTR(ret); } @@ -1052,7 +1053,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size, if (iova) { ret = msm_gem_get_iova(obj, aspace, iova); if (ret) { - drm_gem_object_unreference(obj); + drm_gem_object_put(obj); return ERR_PTR(ret); } } @@ -1060,7 +1061,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size, vaddr = msm_gem_get_vaddr(obj); if (IS_ERR(vaddr)) { msm_gem_put_iova(obj, aspace); - drm_gem_object_unreference(obj); + drm_gem_object_put(obj); return ERR_CAST(vaddr); } diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 9320e184b48d..c5d9bd3e47a8 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -146,6 +146,7 @@ struct msm_gem_submit { struct msm_gpu_submitqueue *queue; struct pid *pid; /* submitting process */ bool valid; /* true if no cmdstream patching needed */ + bool in_rb; /* "sudo" mode, copy cmds into RB */ struct msm_ringbuffer *ring; unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index b8dc8f96caf2..7bd83e0afa97 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -430,6 +430,12 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS) return -EINVAL; + if (args->flags & MSM_SUBMIT_SUDO) { + if (!IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) || + !capable(CAP_SYS_RAWIO)) + return -EINVAL; + } + queue = msm_submitqueue_get(ctx, args->queueid); if (!queue) return -ENOENT; @@ -471,6 +477,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out_unlock; } + if (args->flags & MSM_SUBMIT_SUDO) + submit->in_rb = true; + ret = submit_lookup_objects(submit, args, file); if (ret) goto out; diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index d34e331554f3..ffbec224551b 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -96,6 +96,8 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, const char *name) { struct msm_gem_address_space *aspace; + u64 size = domain->geometry.aperture_end - + domain->geometry.aperture_start; aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); if (!aspace) @@ -106,7 +108,7 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, aspace->mmu = msm_iommu_new(dev, domain); drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT), - (domain->geometry.aperture_end >> PAGE_SHIFT) - 1); + size >> PAGE_SHIFT); kref_init(&aspace->kref); diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index bd376f9e18a7..1c09acfb4028 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -552,7 +552,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) /* move to inactive: */ msm_gem_move_to_inactive(&msm_obj->base); msm_gem_put_iova(&msm_obj->base, gpu->aspace); - drm_gem_object_unreference(&msm_obj->base); + drm_gem_object_put(&msm_obj->base); } pm_runtime_mark_last_busy(&gpu->pdev->dev); @@ -634,7 +634,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); /* submit takes a reference to the bo and iova until retired: */ - drm_gem_object_reference(&msm_obj->base); + drm_gem_object_get(&msm_obj->base); msm_gem_get_iova(&msm_obj->base, submit->gpu->aspace, &iova); @@ -682,8 +682,10 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) gpu->grp_clks = devm_kcalloc(dev, sizeof(struct clk *), gpu->nr_clocks, GFP_KERNEL); - if (!gpu->grp_clks) + if (!gpu->grp_clks) { + gpu->nr_clocks = 0; return -ENOMEM; + } of_property_for_each_string(dev->of_node, "clock-names", prop, name) { gpu->grp_clks[i] = get_clock(dev, name); @@ -865,7 +867,7 @@ fail: if (gpu->memptrs_bo) { msm_gem_put_vaddr(gpu->memptrs_bo); msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(gpu->memptrs_bo); + drm_gem_object_put_unlocked(gpu->memptrs_bo); } platform_set_drvdata(pdev, NULL); @@ -888,7 +890,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) if (gpu->memptrs_bo) { msm_gem_put_vaddr(gpu->memptrs_bo); msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(gpu->memptrs_bo); + drm_gem_object_put_unlocked(gpu->memptrs_bo); } if (!IS_ERR_OR_NULL(gpu->aspace)) { diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index fccfccd303af..b8241179175a 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -65,6 +65,8 @@ struct msm_gpu_funcs { #ifdef CONFIG_DEBUG_FS /* show GPU status in debugfs: */ void (*show)(struct msm_gpu *gpu, struct seq_file *m); + /* for generation specific debugfs: */ + int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); #endif int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value); }; diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 6ca98da35f63..6f5295b3f2f6 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -76,7 +76,7 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring) if (ring->bo) { msm_gem_put_iova(ring->bo, ring->gpu->aspace); msm_gem_put_vaddr(ring->bo); - drm_gem_object_unreference_unlocked(ring->bo); + drm_gem_object_put_unlocked(ring->bo); } kfree(ring); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 49cc8dfcb141..6f402c4f2bdd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -604,19 +604,17 @@ nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val) } static struct ttm_tt * -nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, - uint32_t page_flags) +nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags) { #if IS_ENABLED(CONFIG_AGP) - struct nouveau_drm *drm = nouveau_bdev(bdev); + struct nouveau_drm *drm = nouveau_bdev(bo->bdev); if (drm->agp.bridge) { - return ttm_agp_tt_create(bdev, drm->agp.bridge, size, - page_flags); + return ttm_agp_tt_create(bo, drm->agp.bridge, page_flags); } #endif - return nouveau_sgdma_create_ttm(bdev, size, page_flags); + return nouveau_sgdma_create_ttm(bo, page_flags); } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 3e293029e3a6..bbbf353682e1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -510,37 +510,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev, return 0; } -#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 - -static void -nouveau_get_hdmi_dev(struct nouveau_drm *drm) -{ - struct pci_dev *pdev = drm->dev->pdev; - - if (!pdev) { - NV_DEBUG(drm, "not a PCI device; no HDMI\n"); - drm->hdmi_device = NULL; - return; - } - - /* subfunction one is a hdmi audio device? */ - drm->hdmi_device = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), - (unsigned int)pdev->bus->number, - PCI_DEVFN(PCI_SLOT(pdev->devfn), 1)); - - if (!drm->hdmi_device) { - NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1); - return; - } - - if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) { - NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class); - pci_dev_put(drm->hdmi_device); - drm->hdmi_device = NULL; - return; - } -} - static int nouveau_drm_load(struct drm_device *dev, unsigned long flags) { @@ -568,8 +537,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) INIT_LIST_HEAD(&drm->clients); spin_lock_init(&drm->tile.lock); - nouveau_get_hdmi_dev(drm); - /* workaround an odd issue on nvc1 by disabling the device's * nosnoop capability. hopefully won't cause issues until a * better fix is found - assuming there is one... @@ -655,8 +622,6 @@ nouveau_drm_unload(struct drm_device *dev) nouveau_ttm_fini(drm); nouveau_vga_fini(drm); - if (drm->hdmi_device) - pci_dev_put(drm->hdmi_device); nouveau_cli_fini(&drm->client); nouveau_cli_fini(&drm->master); kfree(drm); @@ -856,7 +821,6 @@ nouveau_pmops_runtime_suspend(struct device *dev) } drm_kms_helper_poll_disable(drm_dev); - vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); nouveau_switcheroo_optimus_dsm(); ret = nouveau_do_suspend(drm_dev, true); pci_save_state(pdev); @@ -891,7 +855,6 @@ nouveau_pmops_runtime_resume(struct device *dev) /* do magic */ nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25)); - vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; /* Monitors may have been connected / disconnected during suspend */ @@ -913,15 +876,6 @@ nouveau_pmops_runtime_idle(struct device *dev) return -EBUSY; } - /* if we have a hdmi audio device - make sure it has a driver loaded */ - if (drm->hdmi_device) { - if (!drm->hdmi_device->driver) { - DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n"); - pm_runtime_mark_last_busy(dev); - return -EBUSY; - } - } - list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { if (crtc->enabled) { DRM_DEBUG_DRIVER("failing to power off - crtc active\n"); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 96f6bd8aee5d..881b44b89a01 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -208,7 +208,6 @@ struct nouveau_drm { bool have_disp_power_ref; struct dev_pm_domain vga_pm_domain; - struct pci_dev *hdmi_device; }; static inline struct nouveau_drm * diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 87b030437f4d..8ebdc74cc0ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -82,10 +82,9 @@ static struct ttm_backend_func nv50_sgdma_backend = { }; struct ttm_tt * -nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, uint32_t page_flags) { - struct nouveau_drm *drm = nouveau_bdev(bdev); + struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_sgdma_be *nvbe; nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL); @@ -97,7 +96,7 @@ nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev, else nvbe->ttm.ttm.func = &nv50_sgdma_backend; - if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags)) + if (ttm_dma_tt_init(&nvbe->ttm, bo, page_flags)) /* * A failing ttm_dma_tt_init() will call ttm_tt_destroy() * and thus our nouveau_sgdma_destroy() hook, so we don't need diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.h b/drivers/gpu/drm/nouveau/nouveau_ttm.h index 64e484ee5ef1..89929ad8c7cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.h +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.h @@ -12,8 +12,8 @@ extern const struct ttm_mem_type_manager_func nouveau_vram_manager; extern const struct ttm_mem_type_manager_func nouveau_gart_manager; extern const struct ttm_mem_type_manager_func nv04_gart_manager; -struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_bo_device *, - unsigned long size, u32 page_flags); +struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, + u32 page_flags); int nouveau_ttm_init(struct nouveau_drm *drm); void nouveau_ttm_fini(struct nouveau_drm *drm); diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c index 95ea6abae914..9eabd7201a12 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c @@ -40,14 +40,12 @@ static const struct videomode tvc_pal_vm = { DISPLAY_FLAGS_VSYNC_LOW, }; -static const struct of_device_id tvc_of_match[]; - #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) static int tvc_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; dev_dbg(ddata->dev, "connect\n"); @@ -55,10 +53,19 @@ static int tvc_connect(struct omap_dss_device *dssdev) if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node); + if (IS_ERR(in)) { + dev_err(ddata->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.atv->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -73,6 +80,9 @@ static void tvc_disconnect(struct omap_dss_device *dssdev) return; in->ops.atv->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tvc_enable(struct omap_dss_device *dssdev) @@ -175,32 +185,12 @@ static struct omap_dss_driver tvc_driver = { .set_wss = tvc_set_wss, }; -static int tvc_probe_of(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; - - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - - return 0; -} - static int tvc_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; struct omap_dss_device *dssdev; int r; - if (!pdev->dev.of_node) - return -ENODEV; - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; @@ -208,10 +198,6 @@ static int tvc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->dev = &pdev->dev; - r = tvc_probe_of(pdev); - if (r) - return r; - ddata->vm = tvc_pal_vm; dssdev = &ddata->dssdev; @@ -224,28 +210,22 @@ static int tvc_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit tvc_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(&ddata->dssdev); tvc_disable(dssdev); tvc_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c index 10b4b97d3595..6d8cbd9e2110 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c @@ -9,6 +9,7 @@ * the Free Software Foundation. */ +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -44,6 +45,14 @@ struct panel_drv_data { struct videomode vm; struct i2c_adapter *i2c_adapter; + + struct gpio_desc *hpd_gpio; + + void (*hpd_cb)(void *cb_data, enum drm_connector_status status); + void *hpd_cb_data; + bool hpd_enabled; + /* mutex for hpd fields above */ + struct mutex hpd_lock; }; #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) @@ -51,16 +60,25 @@ struct panel_drv_data { static int dvic_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dvi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -73,6 +91,9 @@ static void dvic_disconnect(struct omap_dss_device *dssdev) return; in->ops.dvi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int dvic_enable(struct omap_dss_device *dssdev) @@ -177,6 +198,9 @@ static int dvic_read_edid(struct omap_dss_device *dssdev, struct panel_drv_data *ddata = to_panel_data(dssdev); int r, l, bytes_read; + if (ddata->hpd_gpio && !gpiod_get_value_cansleep(ddata->hpd_gpio)) + return -ENODEV; + if (!ddata->i2c_adapter) return -ENODEV; @@ -208,6 +232,9 @@ static bool dvic_detect(struct omap_dss_device *dssdev) unsigned char out; int r; + if (ddata->hpd_gpio) + return gpiod_get_value_cansleep(ddata->hpd_gpio); + if (!ddata->i2c_adapter) return true; @@ -216,6 +243,60 @@ static bool dvic_detect(struct omap_dss_device *dssdev) return r == 0; } +static int dvic_register_hpd_cb(struct omap_dss_device *dssdev, + void (*cb)(void *cb_data, + enum drm_connector_status status), + void *cb_data) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return -ENOTSUPP; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_cb = cb; + ddata->hpd_cb_data = cb_data; + mutex_unlock(&ddata->hpd_lock); + return 0; +} + +static void dvic_unregister_hpd_cb(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_cb = NULL; + ddata->hpd_cb_data = NULL; + mutex_unlock(&ddata->hpd_lock); +} + +static void dvic_enable_hpd(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_enabled = true; + mutex_unlock(&ddata->hpd_lock); +} + +static void dvic_disable_hpd(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_enabled = false; + mutex_unlock(&ddata->hpd_lock); +} + static struct omap_dss_driver dvic_driver = { .connect = dvic_connect, .disconnect = dvic_disconnect, @@ -229,23 +310,60 @@ static struct omap_dss_driver dvic_driver = { .read_edid = dvic_read_edid, .detect = dvic_detect, + + .register_hpd_cb = dvic_register_hpd_cb, + .unregister_hpd_cb = dvic_unregister_hpd_cb, + .enable_hpd = dvic_enable_hpd, + .disable_hpd = dvic_disable_hpd, }; +static irqreturn_t dvic_hpd_isr(int irq, void *data) +{ + struct panel_drv_data *ddata = data; + + mutex_lock(&ddata->hpd_lock); + if (ddata->hpd_enabled && ddata->hpd_cb) { + enum drm_connector_status status; + + if (dvic_detect(&ddata->dssdev)) + status = connector_status_connected; + else + status = connector_status_disconnected; + + ddata->hpd_cb(ddata->hpd_cb_data, status); + } + mutex_unlock(&ddata->hpd_lock); + + return IRQ_HANDLED; +} + static int dvic_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; struct device_node *adapter_node; struct i2c_adapter *adapter; + struct gpio_desc *gpio; + int r; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); + gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); + if (IS_ERR(gpio)) { + dev_err(&pdev->dev, "failed to parse HPD gpio\n"); + return PTR_ERR(gpio); } - ddata->in = in; + ddata->hpd_gpio = gpio; + + mutex_init(&ddata->hpd_lock); + + if (ddata->hpd_gpio) { + r = devm_request_threaded_irq(&pdev->dev, + gpiod_to_irq(ddata->hpd_gpio), NULL, dvic_hpd_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "DVI HPD", ddata); + if (r) + return r; + } adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { @@ -253,7 +371,6 @@ static int dvic_probe_of(struct platform_device *pdev) of_node_put(adapter_node); if (adapter == NULL) { dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); - omap_dss_put_device(ddata->in); return -EPROBE_DEFER; } @@ -275,9 +392,6 @@ static int dvic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - r = dvic_probe_of(pdev); if (r) return r; @@ -300,9 +414,8 @@ static int dvic_probe(struct platform_device *pdev) return 0; err_reg: - omap_dss_put_device(ddata->in); - i2c_put_adapter(ddata->i2c_adapter); + mutex_destroy(&ddata->hpd_lock); return r; } @@ -311,17 +424,16 @@ static int __exit dvic_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(&ddata->dssdev); dvic_disable(dssdev); dvic_disconnect(dssdev); - omap_dss_put_device(in); - i2c_put_adapter(ddata->i2c_adapter); + mutex_destroy(&ddata->hpd_lock); + return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c index 2867476419dc..ca30ed9da7eb 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c @@ -55,7 +55,7 @@ struct panel_drv_data { static int hdmic_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; dev_dbg(ddata->dev, "connect\n"); @@ -63,10 +63,19 @@ static int hdmic_connect(struct omap_dss_device *dssdev) if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node); + if (IS_ERR(in)) { + dev_err(ddata->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.hdmi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -81,6 +90,9 @@ static void hdmic_disconnect(struct omap_dss_device *dssdev) return; in->ops.hdmi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int hdmic_enable(struct omap_dss_device *dssdev) @@ -302,7 +314,6 @@ static int hdmic_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int gpio; /* HPD GPIO */ @@ -312,14 +323,6 @@ static int hdmic_probe_of(struct platform_device *pdev) else ddata->hpd_gpio = -ENODEV; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -336,9 +339,6 @@ static int hdmic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->dev = &pdev->dev; - if (!pdev->dev.of_node) - return -ENODEV; - r = hdmic_probe_of(pdev); if (r) return r; @@ -349,7 +349,7 @@ static int hdmic_probe(struct platform_device *pdev) r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd"); if (r) - goto err_reg; + return r; r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio), @@ -358,7 +358,7 @@ static int hdmic_probe(struct platform_device *pdev) IRQF_ONESHOT, "hdmic hpd", ddata); if (r) - goto err_reg; + return r; } ddata->vm = hdmic_default_vm; @@ -373,28 +373,22 @@ static int hdmic_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit hdmic_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(&ddata->dssdev); hdmic_disable(dssdev); hdmic_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c index d523c67a3ae3..afee1b8b457a 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c @@ -36,7 +36,7 @@ static int opa362_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; dev_dbg(dssdev->dev, "connect\n"); @@ -44,13 +44,22 @@ static int opa362_connect(struct omap_dss_device *dssdev, if (omapdss_device_is_connected(dssdev)) return -EBUSY; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.atv->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } dst->src = dssdev; dssdev->dst = dst; + ddata->in = in; return 0; } @@ -74,6 +83,9 @@ static void opa362_disconnect(struct omap_dss_device *dssdev, dssdev->dst = NULL; in->ops.atv->disconnect(in, &ddata->dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int opa362_enable(struct omap_dss_device *dssdev) @@ -171,19 +183,13 @@ static const struct omapdss_atv_ops opa362_atv_ops = { static int opa362_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; struct panel_drv_data *ddata; - struct omap_dss_device *dssdev, *in; + struct omap_dss_device *dssdev; struct gpio_desc *gpio; int r; dev_dbg(&pdev->dev, "probe\n"); - if (node == NULL) { - dev_err(&pdev->dev, "Unable to find device tree\n"); - return -EINVAL; - } - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; @@ -196,14 +202,6 @@ static int opa362_probe(struct platform_device *pdev) ddata->enable_gpio = gpio; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - dssdev = &ddata->dssdev; dssdev->ops.atv = &opa362_atv_ops; dssdev->dev = &pdev->dev; @@ -214,20 +212,16 @@ static int opa362_probe(struct platform_device *pdev) r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); - goto err_reg; + return r; } return 0; -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit opa362_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_output(&ddata->dssdev); @@ -239,8 +233,6 @@ static int __exit opa362_remove(struct platform_device *pdev) if (omapdss_device_is_connected(dssdev)) opa362_disconnect(dssdev, dssdev->dst); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c index e01ab3db6d86..ed7ae384c3ed 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c @@ -32,19 +32,28 @@ static int tfp410_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return -EBUSY; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } dst->src = dssdev; dssdev->dst = dst; + ddata->in = in; return 0; } @@ -66,6 +75,9 @@ static void tfp410_disconnect(struct omap_dss_device *dssdev, dssdev->dst = NULL; in->ops.dpi->disconnect(in, &ddata->dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tfp410_enable(struct omap_dss_device *dssdev) @@ -165,7 +177,6 @@ static int tfp410_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int gpio; gpio = of_get_named_gpio(node, "powerdown-gpios", 0); @@ -178,14 +189,6 @@ static int tfp410_probe_of(struct platform_device *pdev) return gpio; } - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -201,9 +204,6 @@ static int tfp410_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - r = tfp410_probe_of(pdev); if (r) return r; @@ -214,7 +214,7 @@ static int tfp410_probe(struct platform_device *pdev) if (r) { dev_err(&pdev->dev, "Failed to request PD GPIO %d\n", ddata->pd_gpio); - goto err_gpio; + return r; } } @@ -229,21 +229,16 @@ static int tfp410_probe(struct platform_device *pdev) r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); - goto err_reg; + return r; } return 0; -err_reg: -err_gpio: - omap_dss_put_device(ddata->in); - return r; } static int __exit tfp410_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_output(&ddata->dssdev); @@ -255,8 +250,6 @@ static int __exit tfp410_remove(struct platform_device *pdev) if (omapdss_device_is_connected(dssdev)) tfp410_disconnect(dssdev, dssdev->dst); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index 1fd493e5fa3d..d275bf152da5 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -40,12 +40,20 @@ static int tpd_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.hdmi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } dst->src = dssdev; dssdev->dst = dst; @@ -56,6 +64,7 @@ static int tpd_connect(struct omap_dss_device *dssdev, /* DC-DC converter needs at max 300us to get to 90% of 5V */ udelay(300); + ddata->in = in; return 0; } @@ -77,6 +86,9 @@ static void tpd_disconnect(struct omap_dss_device *dssdev, dssdev->dst = NULL; in->ops.hdmi->disconnect(in, &ddata->dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tpd_enable(struct omap_dss_device *dssdev) @@ -269,23 +281,6 @@ static irqreturn_t tpd_hpd_isr(int irq, void *data) return IRQ_HANDLED; } -static int tpd_probe_of(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; - - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - - return 0; -} - static int tpd_probe(struct platform_device *pdev) { struct omap_dss_device *in, *dssdev; @@ -299,37 +294,24 @@ static int tpd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - - r = tpd_probe_of(pdev); - if (r) - return r; - gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) { - r = PTR_ERR(gpio); - goto err_gpio; - } + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->ct_cp_hpd_gpio = gpio; gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) { - r = PTR_ERR(gpio); - goto err_gpio; - } + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->ls_oe_gpio = gpio; gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, GPIOD_IN); - if (IS_ERR(gpio)) { - r = PTR_ERR(gpio); - goto err_gpio; - } + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->hpd_gpio = gpio; @@ -340,7 +322,7 @@ static int tpd_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "tpd12s015 hpd", ddata); if (r) - goto err_gpio; + return r; dssdev = &ddata->dssdev; dssdev->ops.hdmi = &tpd_hdmi_ops; @@ -355,21 +337,16 @@ static int tpd_probe(struct platform_device *pdev) r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); - goto err_reg; + return r; } return 0; -err_reg: -err_gpio: - omap_dss_put_device(ddata->in); - return r; } static int __exit tpd_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_output(&ddata->dssdev); @@ -381,8 +358,6 @@ static int __exit tpd_remove(struct platform_device *pdev) if (omapdss_device_is_connected(dssdev)) tpd_disconnect(dssdev, dssdev->dst); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c index 48a03f55610a..6cbf570d6727 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c @@ -38,16 +38,25 @@ struct panel_drv_data { static int panel_dpi_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -60,6 +69,9 @@ static void panel_dpi_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int panel_dpi_enable(struct omap_dss_device *dssdev) @@ -157,7 +169,6 @@ static int panel_dpi_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int r; struct display_timing timing; struct gpio_desc *gpio; @@ -195,14 +206,6 @@ static int panel_dpi_probe_of(struct platform_device *pdev) videomode_from_timing(&timing, &ddata->vm); - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -212,9 +215,6 @@ static int panel_dpi_probe(struct platform_device *pdev) struct omap_dss_device *dssdev; int r; - if (!pdev->dev.of_node) - return -ENODEV; - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (ddata == NULL) return -ENOMEM; @@ -235,29 +235,22 @@ static int panel_dpi_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit panel_dpi_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(dssdev); panel_dpi_disable(dssdev); panel_dpi_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 15399a1a666b..428de90fced1 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -86,7 +86,7 @@ struct panel_drv_data { struct workqueue_struct *workqueue; bool ulps_enabled; - unsigned ulps_timeout; + unsigned int ulps_timeout; struct delayed_work ulps_work; }; @@ -513,7 +513,7 @@ static ssize_t dsicm_show_ulps(struct device *dev, { struct platform_device *pdev = to_platform_device(dev); struct panel_drv_data *ddata = platform_get_drvdata(pdev); - unsigned t; + unsigned int t; mutex_lock(&ddata->lock); t = ddata->ulps_enabled; @@ -560,7 +560,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev, { struct platform_device *pdev = to_platform_device(dev); struct panel_drv_data *ddata = platform_get_drvdata(pdev); - unsigned t; + unsigned int t; mutex_lock(&ddata->lock); t = ddata->ulps_timeout; @@ -759,37 +759,46 @@ static int dsicm_panel_reset(struct panel_drv_data *ddata) static int dsicm_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; struct device *dev = &ddata->pdev->dev; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dsi->connect(in, dssdev); if (r) { dev_err(dev, "Failed to connect to video source\n"); - return r; + goto err_connect; } - r = in->ops.dsi->request_vc(ddata->in, &ddata->channel); + r = in->ops.dsi->request_vc(in, &ddata->channel); if (r) { dev_err(dev, "failed to get virtual channel\n"); goto err_req_vc; } - r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH); + r = in->ops.dsi->set_vc_id(in, ddata->channel, TCH); if (r) { dev_err(dev, "failed to set VC_ID\n"); goto err_vc_id; } + ddata->in = in; return 0; err_vc_id: - in->ops.dsi->release_vc(ddata->in, ddata->channel); + in->ops.dsi->release_vc(in, ddata->channel); err_req_vc: in->ops.dsi->disconnect(in, dssdev); +err_connect: + omap_dss_put_device(in); return r; } @@ -803,6 +812,9 @@ static void dsicm_disconnect(struct omap_dss_device *dssdev) in->ops.dsi->release_vc(in, ddata->channel); in->ops.dsi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int dsicm_enable(struct omap_dss_device *dssdev) @@ -1064,7 +1076,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev, int r; int first = 1; int plen; - unsigned buf_used = 0; + unsigned int buf_used = 0; if (size < w * h * 3) return -ENOMEM; @@ -1223,7 +1235,6 @@ static int dsicm_probe_of(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct device_node *backlight; struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct omap_dss_device *in; struct display_timing timing; int err; @@ -1259,12 +1270,6 @@ static int dsicm_probe_of(struct platform_device *pdev) ddata->height_mm = 0; of_property_read_u32(node, "height-mm", &ddata->height_mm); - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - ddata->vpnl = devm_regulator_get_optional(&pdev->dev, "vpnl"); if (IS_ERR(ddata->vpnl)) { err = PTR_ERR(ddata->vpnl); @@ -1281,8 +1286,6 @@ static int dsicm_probe_of(struct platform_device *pdev) ddata->vddi = NULL; } - ddata->in = in; - backlight = of_parse_phandle(node, "backlight", 0); if (backlight) { ddata->extbldev = of_find_backlight_by_node(backlight); @@ -1317,9 +1320,6 @@ static int dsicm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->pdev = pdev; - if (!pdev->dev.of_node) - return -ENODEV; - ddata->vm.hactive = 864; ddata->vm.vactive = 480; ddata->vm.pixelclock = 864 * 480 * 60; @@ -1424,8 +1424,6 @@ static int __exit dsicm_remove(struct platform_device *pdev) if (ddata->extbldev) put_device(&ddata->extbldev->dev); - omap_dss_put_device(ddata->in); - dsicm_cancel_ulps_work(ddata); destroy_workqueue(ddata->workqueue); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c index 57af22ce87c5..754197099440 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c @@ -119,18 +119,27 @@ static void init_lb035q02_panel(struct spi_device *spi) static int lb035q02_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } init_lb035q02_panel(ddata->spi); + ddata->in = in; return 0; } @@ -143,6 +152,9 @@ static void lb035q02_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int lb035q02_enable(struct omap_dss_device *dssdev) @@ -230,9 +242,7 @@ static struct omap_dss_driver lb035q02_ops = { static int lb035q02_probe_of(struct spi_device *spi) { - struct device_node *node = spi->dev.of_node; struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; struct gpio_desc *gpio; gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); @@ -243,14 +253,6 @@ static int lb035q02_probe_of(struct spi_device *spi) ddata->enable_gpio = gpio; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -268,9 +270,6 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) ddata->spi = spi; - if (!spi->dev.of_node) - return -ENODEV; - r = lb035q02_probe_of(spi); if (r) return r; @@ -287,29 +286,22 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) r = omapdss_register_display(dssdev); if (r) { dev_err(&spi->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int lb035q02_panel_spi_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(dssdev); lb035q02_disable(dssdev); lb035q02_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c index bf53676263ad..9a3b27fa5cb5 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c @@ -115,16 +115,25 @@ static int init_nec_8048_wvga_lcd(struct spi_device *spi) static int nec_8048_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -137,6 +146,9 @@ static void nec_8048_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int nec_8048_enable(struct omap_dss_device *dssdev) @@ -226,7 +238,6 @@ static int nec_8048_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; int gpio; gpio = of_get_named_gpio(node, "reset-gpios", 0); @@ -239,14 +250,6 @@ static int nec_8048_probe_of(struct spi_device *spi) /* XXX the panel spec doesn't mention any QVGA pin?? */ ddata->qvga_gpio = -ENOENT; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -277,9 +280,6 @@ static int nec_8048_probe(struct spi_device *spi) ddata->spi = spi; - if (!spi->dev.of_node) - return -ENODEV; - r = nec_8048_probe_of(spi); if (r) return r; @@ -288,14 +288,14 @@ static int nec_8048_probe(struct spi_device *spi) r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio, GPIOF_OUT_INIT_HIGH, "lcd QVGA"); if (r) - goto err_gpio; + return r; } if (gpio_is_valid(ddata->res_gpio)) { r = devm_gpio_request_one(&spi->dev, ddata->res_gpio, GPIOF_OUT_INIT_LOW, "lcd RES"); if (r) - goto err_gpio; + return r; } ddata->vm = nec_8048_panel_vm; @@ -310,22 +310,16 @@ static int nec_8048_probe(struct spi_device *spi) r = omapdss_register_display(dssdev); if (r) { dev_err(&spi->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: -err_gpio: - omap_dss_put_device(ddata->in); - return r; } static int nec_8048_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi->dev, "%s\n", __func__); @@ -334,8 +328,6 @@ static int nec_8048_remove(struct spi_device *spi) nec_8048_disable(dssdev); nec_8048_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c index 34555801fa4c..bb5b680cabfe 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c @@ -61,16 +61,25 @@ static const struct videomode sharp_ls_vm = { static int sharp_ls_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -83,6 +92,9 @@ static void sharp_ls_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int sharp_ls_enable(struct omap_dss_device *dssdev) @@ -210,8 +222,6 @@ static int sharp_ls_get_gpio_of(struct device *dev, int index, int val, static int sharp_ls_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int r; ddata->vcc = devm_regulator_get(&pdev->dev, "envdd"); @@ -245,14 +255,6 @@ static int sharp_ls_probe_of(struct platform_device *pdev) if (r) return r; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -268,9 +270,6 @@ static int sharp_ls_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - r = sharp_ls_probe_of(pdev); if (r) return r; @@ -287,29 +286,22 @@ static int sharp_ls_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit sharp_ls_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(dssdev); sharp_ls_disable(dssdev); sharp_ls_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index 8e5bff4e5226..92fe125ce22e 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -216,12 +216,12 @@ static void set_display_state(struct panel_drv_data *ddata, int enabled) static int panel_enabled(struct panel_drv_data *ddata) { + __be32 v; u32 disp_status; int enabled; - acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, - (u8 *)&disp_status, 4); - disp_status = __be32_to_cpu(disp_status); + acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, (u8 *)&v, 4); + disp_status = __be32_to_cpu(v); enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); dev_dbg(&ddata->spi->dev, "LCD panel %senabled by bootloader (status 0x%04x)\n", @@ -289,7 +289,7 @@ static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable) acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2); } -static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode) +static void set_cabc_mode(struct panel_drv_data *ddata, unsigned int mode) { u16 cabc_ctrl; @@ -303,12 +303,12 @@ static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode) acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); } -static unsigned get_cabc_mode(struct panel_drv_data *ddata) +static unsigned int get_cabc_mode(struct panel_drv_data *ddata) { return ddata->cabc_mode; } -static unsigned get_hw_cabc_mode(struct panel_drv_data *ddata) +static unsigned int get_hw_cabc_mode(struct panel_drv_data *ddata) { u8 cabc_ctrl; @@ -510,16 +510,25 @@ static const struct attribute_group bldev_attr_group = { static int acx565akm_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.sdi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -532,6 +541,9 @@ static void acx565akm_disconnect(struct omap_dss_device *dssdev) return; in->ops.sdi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int acx565akm_panel_power_on(struct omap_dss_device *dssdev) @@ -700,12 +712,6 @@ static int acx565akm_probe_of(struct spi_device *spi) ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); - ddata->in = omapdss_of_find_source_for_first_ep(np); - if (IS_ERR(ddata->in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(ddata->in); - } - return 0; } @@ -720,9 +726,6 @@ static int acx565akm_probe(struct spi_device *spi) dev_dbg(&spi->dev, "%s\n", __func__); - if (!spi->dev.of_node) - return -ENODEV; - spi->mode = SPI_MODE_3; ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); @@ -826,7 +829,6 @@ err_sysfs: err_reg_bl: err_detect: err_gpio: - omap_dss_put_device(ddata->in); return r; } @@ -834,7 +836,6 @@ static int acx565akm_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi->dev, "%s\n", __func__); @@ -846,8 +847,6 @@ static int acx565akm_remove(struct spi_device *spi) acx565akm_disable(dssdev); acx565akm_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index 2721a86ac5e7..b5d8a00df811 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -169,16 +169,25 @@ enum jbt_register { static int td028ttec1_panel_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -191,6 +200,9 @@ static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int td028ttec1_panel_enable(struct omap_dss_device *dssdev) @@ -362,23 +374,6 @@ static struct omap_dss_driver td028ttec1_ops = { .check_timings = td028ttec1_panel_check_timings, }; -static int td028ttec1_probe_of(struct spi_device *spi) -{ - struct device_node *node = spi->dev.of_node; - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; - - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - - return 0; -} - static int td028ttec1_panel_probe(struct spi_device *spi) { struct panel_drv_data *ddata; @@ -404,13 +399,6 @@ static int td028ttec1_panel_probe(struct spi_device *spi) ddata->spi_dev = spi; - if (!spi->dev.of_node) - return -ENODEV; - - r = td028ttec1_probe_of(spi); - if (r) - return r; - ddata->vm = td028ttec1_panel_vm; dssdev = &ddata->dssdev; @@ -423,21 +411,16 @@ static int td028ttec1_panel_probe(struct spi_device *spi) r = omapdss_register_display(dssdev); if (r) { dev_err(&spi->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int td028ttec1_panel_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__); @@ -446,8 +429,6 @@ static int td028ttec1_panel_remove(struct spi_device *spi) td028ttec1_panel_disable(dssdev); td028ttec1_panel_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c index ac4a6d4d134c..c08e22b43447 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c @@ -340,16 +340,25 @@ static void tpo_td043_power_off(struct panel_drv_data *ddata) static int tpo_td043_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -362,6 +371,9 @@ static void tpo_td043_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tpo_td043_enable(struct omap_dss_device *dssdev) @@ -463,7 +475,6 @@ static int tpo_td043_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; int gpio; gpio = of_get_named_gpio(node, "reset-gpios", 0); @@ -473,14 +484,6 @@ static int tpo_td043_probe_of(struct spi_device *spi) } ddata->nreset_gpio = gpio; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -509,9 +512,6 @@ static int tpo_td043_probe(struct spi_device *spi) ddata->spi = spi; - if (!spi->dev.of_node) - return -ENODEV; - r = tpo_td043_probe_of(spi); if (r) return r; @@ -564,7 +564,6 @@ err_reg: err_sysfs: err_gpio_req: err_regulator: - omap_dss_put_device(ddata->in); return r; } @@ -572,7 +571,6 @@ static int tpo_td043_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi->dev, "%s\n", __func__); @@ -581,8 +579,6 @@ static int tpo_td043_remove(struct spi_device *spi) tpo_td043_disable(dssdev); tpo_td043_disconnect(dssdev); - omap_dss_put_device(in); - sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group); return 0; diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 67cc87a4f1f6..99e8cb8dc65b 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -18,10 +18,11 @@ #include <linux/of.h> #include <linux/of_graph.h> #include <linux/list.h> + +#include "dss.h" #include "omapdss.h" -static bool dss_initialized; -static const struct dispc_ops *ops; +static struct dss_device *dss_device; static struct list_head omapdss_comp_list; @@ -31,27 +32,27 @@ struct omapdss_comp_node { bool dss_core_component; }; -void omapdss_set_is_initialized(bool set) +struct dss_device *omapdss_get_dss(void) { - dss_initialized = set; + return dss_device; } -EXPORT_SYMBOL(omapdss_set_is_initialized); +EXPORT_SYMBOL(omapdss_get_dss); -bool omapdss_is_initialized(void) +void omapdss_set_dss(struct dss_device *dss) { - return dss_initialized; + dss_device = dss; } -EXPORT_SYMBOL(omapdss_is_initialized); +EXPORT_SYMBOL(omapdss_set_dss); -void dispc_set_ops(const struct dispc_ops *o) +struct dispc_device *dispc_get_dispc(struct dss_device *dss) { - ops = o; + return dss->dispc; } -EXPORT_SYMBOL(dispc_set_ops); +EXPORT_SYMBOL(dispc_get_dispc); -const struct dispc_ops *dispc_get_ops(void) +const struct dispc_ops *dispc_get_ops(struct dss_device *dss) { - return ops; + return dss->dispc_ops; } EXPORT_SYMBOL(dispc_get_ops); diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 4e8f68efd169..5e2e65e88847 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -47,6 +47,8 @@ #include "dss.h" #include "dispc.h" +struct dispc_device; + /* DISPC */ #define DISPC_SZ_REGS SZ_4K @@ -56,11 +58,12 @@ enum omap_burst_size { BURST_SIZE_X8 = 2, }; -#define REG_GET(idx, start, end) \ - FLD_GET(dispc_read_reg(idx), start, end) +#define REG_GET(dispc, idx, start, end) \ + FLD_GET(dispc_read_reg(dispc, idx), start, end) -#define REG_FLD_MOD(idx, val, start, end) \ - dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) +#define REG_FLD_MOD(dispc, idx, val, start, end) \ + dispc_write_reg(dispc, idx, \ + FLD_MOD(dispc_read_reg(dispc, idx), val, start, end)) /* DISPC has feature id */ enum dispc_feature_id { @@ -105,7 +108,8 @@ struct dispc_features { unsigned int max_downscale; unsigned int max_line_width; unsigned int min_pcd; - int (*calc_scaling) (unsigned long pclk, unsigned long lclk, + int (*calc_scaling)(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, const struct videomode *vm, u16 width, u16 height, u16 out_width, u16 out_height, u32 fourcc, bool *five_taps, @@ -162,9 +166,12 @@ struct dispc_features { #define DISPC_MAX_NR_FIFOS 5 #define DISPC_MAX_CHANNEL_GAMMA 4 -static struct { +struct dispc_device { struct platform_device *pdev; void __iomem *base; + struct dss_device *dss; + + struct dss_debugfs_entry *debugfs; int irq; irq_handler_t user_handler; @@ -191,7 +198,7 @@ static struct { /* DISPC_CONTROL & DISPC_CONFIG lock*/ spinlock_t control_lock; -} dispc; +}; enum omap_color_component { /* used for all color formats for OMAP3 and earlier @@ -345,313 +352,315 @@ static const struct { }, }; -struct color_conv_coef { - int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; - int full_range; -}; - -static unsigned long dispc_fclk_rate(void); -static unsigned long dispc_core_clk_rate(void); -static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); -static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); +static unsigned long dispc_fclk_rate(struct dispc_device *dispc); +static unsigned long dispc_core_clk_rate(struct dispc_device *dispc); +static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc, + enum omap_channel channel); +static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc, + enum omap_channel channel); -static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane); -static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane); +static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane); +static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane); -static void dispc_clear_irqstatus(u32 mask); -static bool dispc_mgr_is_enabled(enum omap_channel channel); -static void dispc_clear_irqstatus(u32 mask); +static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask); -static inline void dispc_write_reg(const u16 idx, u32 val) +static inline void dispc_write_reg(struct dispc_device *dispc, u16 idx, u32 val) { - __raw_writel(val, dispc.base + idx); + __raw_writel(val, dispc->base + idx); } -static inline u32 dispc_read_reg(const u16 idx) +static inline u32 dispc_read_reg(struct dispc_device *dispc, u16 idx) { - return __raw_readl(dispc.base + idx); + return __raw_readl(dispc->base + idx); } -static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld) +static u32 mgr_fld_read(struct dispc_device *dispc, enum omap_channel channel, + enum mgr_reg_fields regfld) { const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; - return REG_GET(rfld.reg, rfld.high, rfld.low); + + return REG_GET(dispc, rfld.reg, rfld.high, rfld.low); } -static void mgr_fld_write(enum omap_channel channel, - enum mgr_reg_fields regfld, int val) { +static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel, + enum mgr_reg_fields regfld, int val) +{ const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG; unsigned long flags; - if (need_lock) - spin_lock_irqsave(&dispc.control_lock, flags); - - REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low); - - if (need_lock) - spin_unlock_irqrestore(&dispc.control_lock, flags); + if (need_lock) { + spin_lock_irqsave(&dispc->control_lock, flags); + REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); + spin_unlock_irqrestore(&dispc->control_lock, flags); + } else { + REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); + } } -static int dispc_get_num_ovls(void) +static int dispc_get_num_ovls(struct dispc_device *dispc) { - return dispc.feat->num_ovls; + return dispc->feat->num_ovls; } -static int dispc_get_num_mgrs(void) +static int dispc_get_num_mgrs(struct dispc_device *dispc) { - return dispc.feat->num_mgrs; + return dispc->feat->num_mgrs; } -static void dispc_get_reg_field(enum dispc_feat_reg_field id, +static void dispc_get_reg_field(struct dispc_device *dispc, + enum dispc_feat_reg_field id, u8 *start, u8 *end) { - if (id >= dispc.feat->num_reg_fields) + if (id >= dispc->feat->num_reg_fields) BUG(); - *start = dispc.feat->reg_fields[id].start; - *end = dispc.feat->reg_fields[id].end; + *start = dispc->feat->reg_fields[id].start; + *end = dispc->feat->reg_fields[id].end; } -static bool dispc_has_feature(enum dispc_feature_id id) +static bool dispc_has_feature(struct dispc_device *dispc, + enum dispc_feature_id id) { unsigned int i; - for (i = 0; i < dispc.feat->num_features; i++) { - if (dispc.feat->features[i] == id) + for (i = 0; i < dispc->feat->num_features; i++) { + if (dispc->feat->features[i] == id) return true; } return false; } -#define SR(reg) \ - dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) -#define RR(reg) \ - dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)]) +#define SR(dispc, reg) \ + dispc->ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(dispc, DISPC_##reg) +#define RR(dispc, reg) \ + dispc_write_reg(dispc, DISPC_##reg, dispc->ctx[DISPC_##reg / sizeof(u32)]) -static void dispc_save_context(void) +static void dispc_save_context(struct dispc_device *dispc) { int i, j; DSSDBG("dispc_save_context\n"); - SR(IRQENABLE); - SR(CONTROL); - SR(CONFIG); - SR(LINE_NUMBER); - if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) || - dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) - SR(GLOBAL_ALPHA); - if (dispc_has_feature(FEAT_MGR_LCD2)) { - SR(CONTROL2); - SR(CONFIG2); + SR(dispc, IRQENABLE); + SR(dispc, CONTROL); + SR(dispc, CONFIG); + SR(dispc, LINE_NUMBER); + if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || + dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) + SR(dispc, GLOBAL_ALPHA); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { + SR(dispc, CONTROL2); + SR(dispc, CONFIG2); } - if (dispc_has_feature(FEAT_MGR_LCD3)) { - SR(CONTROL3); - SR(CONFIG3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { + SR(dispc, CONTROL3); + SR(dispc, CONFIG3); } - for (i = 0; i < dispc_get_num_mgrs(); i++) { - SR(DEFAULT_COLOR(i)); - SR(TRANS_COLOR(i)); - SR(SIZE_MGR(i)); + for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { + SR(dispc, DEFAULT_COLOR(i)); + SR(dispc, TRANS_COLOR(i)); + SR(dispc, SIZE_MGR(i)); if (i == OMAP_DSS_CHANNEL_DIGIT) continue; - SR(TIMING_H(i)); - SR(TIMING_V(i)); - SR(POL_FREQ(i)); - SR(DIVISORo(i)); - - SR(DATA_CYCLE1(i)); - SR(DATA_CYCLE2(i)); - SR(DATA_CYCLE3(i)); - - if (dispc_has_feature(FEAT_CPR)) { - SR(CPR_COEF_R(i)); - SR(CPR_COEF_G(i)); - SR(CPR_COEF_B(i)); + SR(dispc, TIMING_H(i)); + SR(dispc, TIMING_V(i)); + SR(dispc, POL_FREQ(i)); + SR(dispc, DIVISORo(i)); + + SR(dispc, DATA_CYCLE1(i)); + SR(dispc, DATA_CYCLE2(i)); + SR(dispc, DATA_CYCLE3(i)); + + if (dispc_has_feature(dispc, FEAT_CPR)) { + SR(dispc, CPR_COEF_R(i)); + SR(dispc, CPR_COEF_G(i)); + SR(dispc, CPR_COEF_B(i)); } } - for (i = 0; i < dispc_get_num_ovls(); i++) { - SR(OVL_BA0(i)); - SR(OVL_BA1(i)); - SR(OVL_POSITION(i)); - SR(OVL_SIZE(i)); - SR(OVL_ATTRIBUTES(i)); - SR(OVL_FIFO_THRESHOLD(i)); - SR(OVL_ROW_INC(i)); - SR(OVL_PIXEL_INC(i)); - if (dispc_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(i)); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) { + SR(dispc, OVL_BA0(i)); + SR(dispc, OVL_BA1(i)); + SR(dispc, OVL_POSITION(i)); + SR(dispc, OVL_SIZE(i)); + SR(dispc, OVL_ATTRIBUTES(i)); + SR(dispc, OVL_FIFO_THRESHOLD(i)); + SR(dispc, OVL_ROW_INC(i)); + SR(dispc, OVL_PIXEL_INC(i)); + if (dispc_has_feature(dispc, FEAT_PRELOAD)) + SR(dispc, OVL_PRELOAD(i)); if (i == OMAP_DSS_GFX) { - SR(OVL_WINDOW_SKIP(i)); - SR(OVL_TABLE_BA(i)); + SR(dispc, OVL_WINDOW_SKIP(i)); + SR(dispc, OVL_TABLE_BA(i)); continue; } - SR(OVL_FIR(i)); - SR(OVL_PICTURE_SIZE(i)); - SR(OVL_ACCU0(i)); - SR(OVL_ACCU1(i)); + SR(dispc, OVL_FIR(i)); + SR(dispc, OVL_PICTURE_SIZE(i)); + SR(dispc, OVL_ACCU0(i)); + SR(dispc, OVL_ACCU1(i)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_H(i, j)); + SR(dispc, OVL_FIR_COEF_H(i, j)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_HV(i, j)); + SR(dispc, OVL_FIR_COEF_HV(i, j)); for (j = 0; j < 5; j++) - SR(OVL_CONV_COEF(i, j)); + SR(dispc, OVL_CONV_COEF(i, j)); - if (dispc_has_feature(FEAT_FIR_COEF_V)) { + if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_V(i, j)); + SR(dispc, OVL_FIR_COEF_V(i, j)); } - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - SR(OVL_BA0_UV(i)); - SR(OVL_BA1_UV(i)); - SR(OVL_FIR2(i)); - SR(OVL_ACCU2_0(i)); - SR(OVL_ACCU2_1(i)); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + SR(dispc, OVL_BA0_UV(i)); + SR(dispc, OVL_BA1_UV(i)); + SR(dispc, OVL_FIR2(i)); + SR(dispc, OVL_ACCU2_0(i)); + SR(dispc, OVL_ACCU2_1(i)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_H2(i, j)); + SR(dispc, OVL_FIR_COEF_H2(i, j)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_HV2(i, j)); + SR(dispc, OVL_FIR_COEF_HV2(i, j)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_V2(i, j)); + SR(dispc, OVL_FIR_COEF_V2(i, j)); } - if (dispc_has_feature(FEAT_ATTR2)) - SR(OVL_ATTRIBUTES2(i)); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + SR(dispc, OVL_ATTRIBUTES2(i)); } - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) - SR(DIVISOR); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) + SR(dispc, DIVISOR); - dispc.ctx_valid = true; + dispc->ctx_valid = true; DSSDBG("context saved\n"); } -static void dispc_restore_context(void) +static void dispc_restore_context(struct dispc_device *dispc) { int i, j; DSSDBG("dispc_restore_context\n"); - if (!dispc.ctx_valid) + if (!dispc->ctx_valid) return; - /*RR(IRQENABLE);*/ - /*RR(CONTROL);*/ - RR(CONFIG); - RR(LINE_NUMBER); - if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) || - dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) - RR(GLOBAL_ALPHA); - if (dispc_has_feature(FEAT_MGR_LCD2)) - RR(CONFIG2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - RR(CONFIG3); - - for (i = 0; i < dispc_get_num_mgrs(); i++) { - RR(DEFAULT_COLOR(i)); - RR(TRANS_COLOR(i)); - RR(SIZE_MGR(i)); + /*RR(dispc, IRQENABLE);*/ + /*RR(dispc, CONTROL);*/ + RR(dispc, CONFIG); + RR(dispc, LINE_NUMBER); + if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || + dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) + RR(dispc, GLOBAL_ALPHA); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + RR(dispc, CONFIG2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + RR(dispc, CONFIG3); + + for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { + RR(dispc, DEFAULT_COLOR(i)); + RR(dispc, TRANS_COLOR(i)); + RR(dispc, SIZE_MGR(i)); if (i == OMAP_DSS_CHANNEL_DIGIT) continue; - RR(TIMING_H(i)); - RR(TIMING_V(i)); - RR(POL_FREQ(i)); - RR(DIVISORo(i)); - - RR(DATA_CYCLE1(i)); - RR(DATA_CYCLE2(i)); - RR(DATA_CYCLE3(i)); - - if (dispc_has_feature(FEAT_CPR)) { - RR(CPR_COEF_R(i)); - RR(CPR_COEF_G(i)); - RR(CPR_COEF_B(i)); + RR(dispc, TIMING_H(i)); + RR(dispc, TIMING_V(i)); + RR(dispc, POL_FREQ(i)); + RR(dispc, DIVISORo(i)); + + RR(dispc, DATA_CYCLE1(i)); + RR(dispc, DATA_CYCLE2(i)); + RR(dispc, DATA_CYCLE3(i)); + + if (dispc_has_feature(dispc, FEAT_CPR)) { + RR(dispc, CPR_COEF_R(i)); + RR(dispc, CPR_COEF_G(i)); + RR(dispc, CPR_COEF_B(i)); } } - for (i = 0; i < dispc_get_num_ovls(); i++) { - RR(OVL_BA0(i)); - RR(OVL_BA1(i)); - RR(OVL_POSITION(i)); - RR(OVL_SIZE(i)); - RR(OVL_ATTRIBUTES(i)); - RR(OVL_FIFO_THRESHOLD(i)); - RR(OVL_ROW_INC(i)); - RR(OVL_PIXEL_INC(i)); - if (dispc_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(i)); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) { + RR(dispc, OVL_BA0(i)); + RR(dispc, OVL_BA1(i)); + RR(dispc, OVL_POSITION(i)); + RR(dispc, OVL_SIZE(i)); + RR(dispc, OVL_ATTRIBUTES(i)); + RR(dispc, OVL_FIFO_THRESHOLD(i)); + RR(dispc, OVL_ROW_INC(i)); + RR(dispc, OVL_PIXEL_INC(i)); + if (dispc_has_feature(dispc, FEAT_PRELOAD)) + RR(dispc, OVL_PRELOAD(i)); if (i == OMAP_DSS_GFX) { - RR(OVL_WINDOW_SKIP(i)); - RR(OVL_TABLE_BA(i)); + RR(dispc, OVL_WINDOW_SKIP(i)); + RR(dispc, OVL_TABLE_BA(i)); continue; } - RR(OVL_FIR(i)); - RR(OVL_PICTURE_SIZE(i)); - RR(OVL_ACCU0(i)); - RR(OVL_ACCU1(i)); + RR(dispc, OVL_FIR(i)); + RR(dispc, OVL_PICTURE_SIZE(i)); + RR(dispc, OVL_ACCU0(i)); + RR(dispc, OVL_ACCU1(i)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_H(i, j)); + RR(dispc, OVL_FIR_COEF_H(i, j)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_HV(i, j)); + RR(dispc, OVL_FIR_COEF_HV(i, j)); for (j = 0; j < 5; j++) - RR(OVL_CONV_COEF(i, j)); + RR(dispc, OVL_CONV_COEF(i, j)); - if (dispc_has_feature(FEAT_FIR_COEF_V)) { + if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_V(i, j)); + RR(dispc, OVL_FIR_COEF_V(i, j)); } - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - RR(OVL_BA0_UV(i)); - RR(OVL_BA1_UV(i)); - RR(OVL_FIR2(i)); - RR(OVL_ACCU2_0(i)); - RR(OVL_ACCU2_1(i)); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + RR(dispc, OVL_BA0_UV(i)); + RR(dispc, OVL_BA1_UV(i)); + RR(dispc, OVL_FIR2(i)); + RR(dispc, OVL_ACCU2_0(i)); + RR(dispc, OVL_ACCU2_1(i)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_H2(i, j)); + RR(dispc, OVL_FIR_COEF_H2(i, j)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_HV2(i, j)); + RR(dispc, OVL_FIR_COEF_HV2(i, j)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_V2(i, j)); + RR(dispc, OVL_FIR_COEF_V2(i, j)); } - if (dispc_has_feature(FEAT_ATTR2)) - RR(OVL_ATTRIBUTES2(i)); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + RR(dispc, OVL_ATTRIBUTES2(i)); } - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) - RR(DIVISOR); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) + RR(dispc, DIVISOR); /* enable last, because LCD & DIGIT enable are here */ - RR(CONTROL); - if (dispc_has_feature(FEAT_MGR_LCD2)) - RR(CONTROL2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - RR(CONTROL3); + RR(dispc, CONTROL); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + RR(dispc, CONTROL2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + RR(dispc, CONTROL3); /* clear spurious SYNC_LOST_DIGIT interrupts */ - dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT); + dispc_clear_irqstatus(dispc, DISPC_IRQ_SYNC_LOST_DIGIT); /* * enable last so IRQs won't trigger before * the context is fully restored */ - RR(IRQENABLE); + RR(dispc, IRQENABLE); DSSDBG("context restored\n"); } @@ -659,146 +668,159 @@ static void dispc_restore_context(void) #undef SR #undef RR -int dispc_runtime_get(void) +int dispc_runtime_get(struct dispc_device *dispc) { int r; DSSDBG("dispc_runtime_get\n"); - r = pm_runtime_get_sync(&dispc.pdev->dev); + r = pm_runtime_get_sync(&dispc->pdev->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } -void dispc_runtime_put(void) +void dispc_runtime_put(struct dispc_device *dispc) { int r; DSSDBG("dispc_runtime_put\n"); - r = pm_runtime_put_sync(&dispc.pdev->dev); + r = pm_runtime_put_sync(&dispc->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } -static u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) +static u32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc, + enum omap_channel channel) { return mgr_desc[channel].vsync_irq; } -static u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) +static u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc, + enum omap_channel channel) { - if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv) + if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv) return 0; return mgr_desc[channel].framedone_irq; } -static u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel) +static u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc, + enum omap_channel channel) { return mgr_desc[channel].sync_lost_irq; } -u32 dispc_wb_get_framedone_irq(void) +static u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) { return DISPC_IRQ_FRAMEDONEWB; } -static void dispc_mgr_enable(enum omap_channel channel, bool enable) +static void dispc_mgr_enable(struct dispc_device *dispc, + enum omap_channel channel, bool enable) { - mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_ENABLE, enable); /* flush posted write */ - mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); + mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE); } -static bool dispc_mgr_is_enabled(enum omap_channel channel) +static bool dispc_mgr_is_enabled(struct dispc_device *dispc, + enum omap_channel channel) { - return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); + return !!mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE); } -static bool dispc_mgr_go_busy(enum omap_channel channel) +static bool dispc_mgr_go_busy(struct dispc_device *dispc, + enum omap_channel channel) { - return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; + return mgr_fld_read(dispc, channel, DISPC_MGR_FLD_GO) == 1; } -static void dispc_mgr_go(enum omap_channel channel) +static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) { - WARN_ON(!dispc_mgr_is_enabled(channel)); - WARN_ON(dispc_mgr_go_busy(channel)); + WARN_ON(!dispc_mgr_is_enabled(dispc, channel)); + WARN_ON(dispc_mgr_go_busy(dispc, channel)); DSSDBG("GO %s\n", mgr_desc[channel].name); - mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1); } -bool dispc_wb_go_busy(void) +static bool dispc_wb_go_busy(struct dispc_device *dispc) { - return REG_GET(DISPC_CONTROL2, 6, 6) == 1; + return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; } -void dispc_wb_go(void) +static void dispc_wb_go(struct dispc_device *dispc) { enum omap_plane_id plane = OMAP_DSS_WB; bool enable, go; - enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; + enable = REG_GET(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; if (!enable) return; - go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; + go = REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; if (go) { DSSERR("GO bit not down for WB\n"); return; } - REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); + REG_FLD_MOD(dispc, DISPC_CONTROL2, 1, 6, 6); } -static void dispc_ovl_write_firh_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firh_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { - dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H(plane, reg), value); } -static void dispc_ovl_write_firhv_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firhv_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { - dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV(plane, reg), value); } -static void dispc_ovl_write_firv_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firv_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { - dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V(plane, reg), value); } -static void dispc_ovl_write_firh2_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firh2_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H2(plane, reg), value); } -static void dispc_ovl_write_firhv2_reg(enum omap_plane_id plane, int reg, - u32 value) +static void dispc_ovl_write_firhv2_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, + u32 value) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV2(plane, reg), value); } -static void dispc_ovl_write_firv2_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firv2_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V2(plane, reg), value); } -static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc, - int fir_vinc, int five_taps, - enum omap_color_component color_comp) +static void dispc_ovl_set_scale_coef(struct dispc_device *dispc, + enum omap_plane_id plane, int fir_hinc, + int fir_vinc, int five_taps, + enum omap_color_component color_comp) { const struct dispc_coef *h_coef, *v_coef; int i; @@ -819,11 +841,11 @@ static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc, | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { - dispc_ovl_write_firh_reg(plane, i, h); - dispc_ovl_write_firhv_reg(plane, i, hv); + dispc_ovl_write_firh_reg(dispc, plane, i, h); + dispc_ovl_write_firhv_reg(dispc, plane, i, hv); } else { - dispc_ovl_write_firh2_reg(plane, i, h); - dispc_ovl_write_firhv2_reg(plane, i, hv); + dispc_ovl_write_firh2_reg(dispc, plane, i, h); + dispc_ovl_write_firhv2_reg(dispc, plane, i, hv); } } @@ -834,72 +856,113 @@ static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc, v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) - dispc_ovl_write_firv_reg(plane, i, v); + dispc_ovl_write_firv_reg(dispc, plane, i, v); else - dispc_ovl_write_firv2_reg(plane, i, v); + dispc_ovl_write_firv2_reg(dispc, plane, i, v); } } } +struct csc_coef_yuv2rgb { + int ry, rcb, rcr, gy, gcb, gcr, by, bcb, bcr; + bool full_range; +}; + +struct csc_coef_rgb2yuv { + int yr, yg, yb, cbr, cbg, cbb, crr, crg, crb; + bool full_range; +}; + +static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc, + enum omap_plane_id plane, + const struct csc_coef_yuv2rgb *ct) +{ +#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) + + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); -static void dispc_ovl_write_color_conv_coef(enum omap_plane_id plane, - const struct color_conv_coef *ct) + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); + +#undef CVAL +} + +static void dispc_wb_write_color_conv_coef(struct dispc_device *dispc, + const struct csc_coef_rgb2yuv *ct) { + const enum omap_plane_id plane = OMAP_DSS_WB; + #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->yg, ct->yr)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->crr, ct->yb)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->crb, ct->crg)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->cbg, ct->cbr)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->cbb)); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); #undef CVAL } -static void dispc_setup_color_conv_coef(void) +static void dispc_setup_color_conv_coef(struct dispc_device *dispc) { int i; - int num_ovl = dispc_get_num_ovls(); - const struct color_conv_coef ctbl_bt601_5_ovl = { - /* YUV -> RGB */ - 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, + int num_ovl = dispc_get_num_ovls(dispc); + + /* YUV -> RGB, ITU-R BT.601, limited range */ + const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = { + 298, 0, 409, /* ry, rcb, rcr */ + 298, -100, -208, /* gy, gcb, gcr */ + 298, 516, 0, /* by, bcb, bcr */ + false, /* limited range */ }; - const struct color_conv_coef ctbl_bt601_5_wb = { - /* RGB -> YUV */ - 66, 129, 25, 112, -94, -18, -38, -74, 112, 0, + + /* RGB -> YUV, ITU-R BT.601, limited range */ + const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_lim = { + 66, 129, 25, /* yr, yg, yb */ + -38, -74, 112, /* cbr, cbg, cbb */ + 112, -94, -18, /* crr, crg, crb */ + false, /* limited range */ }; for (i = 1; i < num_ovl; i++) - dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); + dispc_ovl_write_color_conv_coef(dispc, i, &coefs_yuv2rgb_bt601_lim); - if (dispc.feat->has_writeback) - dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb); + if (dispc->feat->has_writeback) + dispc_wb_write_color_conv_coef(dispc, &coefs_rgb2yuv_bt601_lim); } -static void dispc_ovl_set_ba0(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba0(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA0(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA0(plane), paddr); } -static void dispc_ovl_set_ba1(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba1(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA1(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA1(plane), paddr); } -static void dispc_ovl_set_ba0_uv(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba0_uv(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA0_UV(plane), paddr); } -static void dispc_ovl_set_ba1_uv(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba1_uv(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA1_UV(plane), paddr); } -static void dispc_ovl_set_pos(enum omap_plane_id plane, - enum omap_overlay_caps caps, int x, int y) +static void dispc_ovl_set_pos(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, int x, int y) { u32 val; @@ -908,22 +971,24 @@ static void dispc_ovl_set_pos(enum omap_plane_id plane, val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); - dispc_write_reg(DISPC_OVL_POSITION(plane), val); + dispc_write_reg(dispc, DISPC_OVL_POSITION(plane), val); } -static void dispc_ovl_set_input_size(enum omap_plane_id plane, int width, - int height) +static void dispc_ovl_set_input_size(struct dispc_device *dispc, + enum omap_plane_id plane, int width, + int height) { u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) - dispc_write_reg(DISPC_OVL_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val); else - dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val); } -static void dispc_ovl_set_output_size(enum omap_plane_id plane, int width, - int height) +static void dispc_ovl_set_output_size(struct dispc_device *dispc, + enum omap_plane_id plane, int width, + int height) { u32 val; @@ -932,64 +997,72 @@ static void dispc_ovl_set_output_size(enum omap_plane_id plane, int width, val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); if (plane == OMAP_DSS_WB) - dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val); else - dispc_write_reg(DISPC_OVL_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val); } -static void dispc_ovl_set_zorder(enum omap_plane_id plane, - enum omap_overlay_caps caps, u8 zorder) +static void dispc_ovl_set_zorder(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, u8 zorder) { if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) return; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); } -static void dispc_ovl_enable_zorder_planes(void) +static void dispc_ovl_enable_zorder_planes(struct dispc_device *dispc) { int i; - if (!dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) + if (!dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) return; - for (i = 0; i < dispc_get_num_ovls(); i++) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); } -static void dispc_ovl_set_pre_mult_alpha(enum omap_plane_id plane, - enum omap_overlay_caps caps, bool enable) +static void dispc_ovl_set_pre_mult_alpha(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + bool enable) { if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) return; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); } -static void dispc_ovl_setup_global_alpha(enum omap_plane_id plane, - enum omap_overlay_caps caps, u8 global_alpha) +static void dispc_ovl_setup_global_alpha(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + u8 global_alpha) { - static const unsigned shifts[] = { 0, 8, 16, 24, }; + static const unsigned int shifts[] = { 0, 8, 16, 24, }; int shift; if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) return; shift = shifts[plane]; - REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); + REG_FLD_MOD(dispc, DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); } -static void dispc_ovl_set_pix_inc(enum omap_plane_id plane, s32 inc) +static void dispc_ovl_set_pix_inc(struct dispc_device *dispc, + enum omap_plane_id plane, s32 inc) { - dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc); + dispc_write_reg(dispc, DISPC_OVL_PIXEL_INC(plane), inc); } -static void dispc_ovl_set_row_inc(enum omap_plane_id plane, s32 inc) +static void dispc_ovl_set_row_inc(struct dispc_device *dispc, + enum omap_plane_id plane, s32 inc) { - dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc); + dispc_write_reg(dispc, DISPC_OVL_ROW_INC(plane), inc); } -static void dispc_ovl_set_color_mode(enum omap_plane_id plane, u32 fourcc) +static void dispc_ovl_set_color_mode(struct dispc_device *dispc, + enum omap_plane_id plane, u32 fourcc) { u32 m = 0; if (plane != OMAP_DSS_GFX) { @@ -1058,7 +1131,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane_id plane, u32 fourcc) } } - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } static bool format_is_yuv(u32 fourcc) @@ -1073,19 +1146,21 @@ static bool format_is_yuv(u32 fourcc) } } -static void dispc_ovl_configure_burst_type(enum omap_plane_id plane, - enum omap_dss_rotation_type rotation_type) +static void dispc_ovl_configure_burst_type(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_dss_rotation_type rotation) { - if (dispc_has_feature(FEAT_BURST_2D) == 0) + if (dispc_has_feature(dispc, FEAT_BURST_2D) == 0) return; - if (rotation_type == OMAP_DSS_ROT_TILER) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); + if (rotation == OMAP_DSS_ROT_TILER) + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); else - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); } -static void dispc_ovl_set_channel_out(enum omap_plane_id plane, +static void dispc_ovl_set_channel_out(struct dispc_device *dispc, + enum omap_plane_id plane, enum omap_channel channel) { int shift; @@ -1106,8 +1181,8 @@ static void dispc_ovl_set_channel_out(enum omap_plane_id plane, return; } - val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); - if (dispc_has_feature(FEAT_MGR_LCD2)) { + val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { switch (channel) { case OMAP_DSS_CHANNEL_LCD: chan = 0; @@ -1122,7 +1197,7 @@ static void dispc_ovl_set_channel_out(enum omap_plane_id plane, chan2 = 1; break; case OMAP_DSS_CHANNEL_LCD3: - if (dispc_has_feature(FEAT_MGR_LCD3)) { + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { chan = 0; chan2 = 2; } else { @@ -1144,10 +1219,11 @@ static void dispc_ovl_set_channel_out(enum omap_plane_id plane, } else { val = FLD_MOD(val, channel, shift, shift); } - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val); } -static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane) +static enum omap_channel dispc_ovl_get_channel_out(struct dispc_device *dispc, + enum omap_plane_id plane) { int shift; u32 val; @@ -1166,12 +1242,12 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane) return 0; } - val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); if (FLD_GET(val, shift, shift) == 1) return OMAP_DSS_CHANNEL_DIGIT; - if (!dispc_has_feature(FEAT_MGR_LCD2)) + if (!dispc_has_feature(dispc, FEAT_MGR_LCD2)) return OMAP_DSS_CHANNEL_LCD; switch (FLD_GET(val, 31, 30)) { @@ -1187,47 +1263,44 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane) } } -void dispc_wb_set_channel_in(enum dss_writeback_channel channel) -{ - enum omap_plane_id plane = OMAP_DSS_WB; - - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); -} - -static void dispc_ovl_set_burst_size(enum omap_plane_id plane, - enum omap_burst_size burst_size) +static void dispc_ovl_set_burst_size(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_burst_size burst_size) { - static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; + static const unsigned int shifts[] = { 6, 14, 14, 14, 14, }; int shift; shift = shifts[plane]; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), burst_size, + shift + 1, shift); } -static void dispc_configure_burst_sizes(void) +static void dispc_configure_burst_sizes(struct dispc_device *dispc) { int i; const int burst_size = BURST_SIZE_X8; /* Configure burst size always to maximum size */ - for (i = 0; i < dispc_get_num_ovls(); ++i) - dispc_ovl_set_burst_size(i, burst_size); - if (dispc.feat->has_writeback) - dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size); + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) + dispc_ovl_set_burst_size(dispc, i, burst_size); + if (dispc->feat->has_writeback) + dispc_ovl_set_burst_size(dispc, OMAP_DSS_WB, burst_size); } -static u32 dispc_ovl_get_burst_size(enum omap_plane_id plane) +static u32 dispc_ovl_get_burst_size(struct dispc_device *dispc, + enum omap_plane_id plane) { /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ - return dispc.feat->burst_size_unit * 8; + return dispc->feat->burst_size_unit * 8; } -static bool dispc_ovl_color_mode_supported(enum omap_plane_id plane, u32 fourcc) +static bool dispc_ovl_color_mode_supported(struct dispc_device *dispc, + enum omap_plane_id plane, u32 fourcc) { const u32 *modes; unsigned int i; - modes = dispc.feat->supported_color_modes[plane]; + modes = dispc->feat->supported_color_modes[plane]; for (i = 0; modes[i]; ++i) { if (modes[i] == fourcc) @@ -1237,21 +1310,24 @@ static bool dispc_ovl_color_mode_supported(enum omap_plane_id plane, u32 fourcc) return false; } -static const u32 *dispc_ovl_get_color_modes(enum omap_plane_id plane) +static const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc, + enum omap_plane_id plane) { - return dispc.feat->supported_color_modes[plane]; + return dispc->feat->supported_color_modes[plane]; } -static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_cpr(struct dispc_device *dispc, + enum omap_channel channel, bool enable) { if (channel == OMAP_DSS_CHANNEL_DIGIT) return; - mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_CPR, enable); } -static void dispc_mgr_set_cpr_coef(enum omap_channel channel, - const struct omap_dss_cpr_coefs *coefs) +static void dispc_mgr_set_cpr_coef(struct dispc_device *dispc, + enum omap_channel channel, + const struct omap_dss_cpr_coefs *coefs) { u32 coef_r, coef_g, coef_b; @@ -1265,48 +1341,50 @@ static void dispc_mgr_set_cpr_coef(enum omap_channel channel, coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) | FLD_VAL(coefs->bb, 9, 0); - dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r); - dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g); - dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b); + dispc_write_reg(dispc, DISPC_CPR_COEF_R(channel), coef_r); + dispc_write_reg(dispc, DISPC_CPR_COEF_G(channel), coef_g); + dispc_write_reg(dispc, DISPC_CPR_COEF_B(channel), coef_b); } -static void dispc_ovl_set_vid_color_conv(enum omap_plane_id plane, - bool enable) +static void dispc_ovl_set_vid_color_conv(struct dispc_device *dispc, + enum omap_plane_id plane, bool enable) { u32 val; BUG_ON(plane == OMAP_DSS_GFX); - val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); val = FLD_MOD(val, enable, 9, 9); - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val); } -static void dispc_ovl_enable_replication(enum omap_plane_id plane, - enum omap_overlay_caps caps, bool enable) +static void dispc_ovl_enable_replication(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + bool enable) { - static const unsigned shifts[] = { 5, 10, 10, 10 }; + static const unsigned int shifts[] = { 5, 10, 10, 10 }; int shift; if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) return; shift = shifts[plane]; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); } -static void dispc_mgr_set_size(enum omap_channel channel, u16 width, - u16 height) +static void dispc_mgr_set_size(struct dispc_device *dispc, + enum omap_channel channel, u16 width, u16 height) { u32 val; - val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) | - FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0); + val = FLD_VAL(height - 1, dispc->feat->mgr_height_start, 16) | + FLD_VAL(width - 1, dispc->feat->mgr_width_start, 0); - dispc_write_reg(DISPC_SIZE_MGR(channel), val); + dispc_write_reg(dispc, DISPC_SIZE_MGR(channel), val); } -static void dispc_init_fifos(void) +static void dispc_init_fifos(struct dispc_device *dispc) { u32 size; int fifo; @@ -1314,20 +1392,21 @@ static void dispc_init_fifos(void) u32 unit; int i; - unit = dispc.feat->buffer_size_unit; + unit = dispc->feat->buffer_size_unit; - dispc_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); + dispc_get_reg_field(dispc, FEAT_REG_FIFOSIZE, &start, &end); - for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { - size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); + for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) { + size = REG_GET(dispc, DISPC_OVL_FIFO_SIZE_STATUS(fifo), + start, end); size *= unit; - dispc.fifo_size[fifo] = size; + dispc->fifo_size[fifo] = size; /* * By default fifos are mapped directly to overlays, fifo 0 to * ovl 0, fifo 1 to ovl 1, etc. */ - dispc.fifo_assignment[fifo] = fifo; + dispc->fifo_assignment[fifo] = fifo; } /* @@ -1337,68 +1416,71 @@ static void dispc_init_fifos(void) * giving GFX plane a larger fifo. WB but should work fine with a * smaller fifo. */ - if (dispc.feat->gfx_fifo_workaround) { + if (dispc->feat->gfx_fifo_workaround) { u32 v; - v = dispc_read_reg(DISPC_GLOBAL_BUFFER); + v = dispc_read_reg(dispc, DISPC_GLOBAL_BUFFER); v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ - dispc_write_reg(DISPC_GLOBAL_BUFFER, v); + dispc_write_reg(dispc, DISPC_GLOBAL_BUFFER, v); - dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; - dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; + dispc->fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; + dispc->fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; } /* * Setup default fifo thresholds. */ - for (i = 0; i < dispc_get_num_ovls(); ++i) { + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) { u32 low, high; const bool use_fifomerge = false; const bool manual_update = false; - dispc_ovl_compute_fifo_thresholds(i, &low, &high, - use_fifomerge, manual_update); + dispc_ovl_compute_fifo_thresholds(dispc, i, &low, &high, + use_fifomerge, manual_update); - dispc_ovl_set_fifo_threshold(i, low, high); + dispc_ovl_set_fifo_threshold(dispc, i, low, high); } - if (dispc.feat->has_writeback) { + if (dispc->feat->has_writeback) { u32 low, high; const bool use_fifomerge = false; const bool manual_update = false; - dispc_ovl_compute_fifo_thresholds(OMAP_DSS_WB, &low, &high, - use_fifomerge, manual_update); + dispc_ovl_compute_fifo_thresholds(dispc, OMAP_DSS_WB, + &low, &high, use_fifomerge, + manual_update); - dispc_ovl_set_fifo_threshold(OMAP_DSS_WB, low, high); + dispc_ovl_set_fifo_threshold(dispc, OMAP_DSS_WB, low, high); } } -static u32 dispc_ovl_get_fifo_size(enum omap_plane_id plane) +static u32 dispc_ovl_get_fifo_size(struct dispc_device *dispc, + enum omap_plane_id plane) { int fifo; u32 size = 0; - for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { - if (dispc.fifo_assignment[fifo] == plane) - size += dispc.fifo_size[fifo]; + for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) { + if (dispc->fifo_assignment[fifo] == plane) + size += dispc->fifo_size[fifo]; } return size; } -void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low, - u32 high) +void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc, + enum omap_plane_id plane, + u32 low, u32 high) { u8 hi_start, hi_end, lo_start, lo_end; u32 unit; - unit = dispc.feat->buffer_size_unit; + unit = dispc->feat->buffer_size_unit; WARN_ON(low % unit != 0); WARN_ON(high % unit != 0); @@ -1406,18 +1488,20 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low, low /= unit; high /= unit; - dispc_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); - dispc_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); + dispc_get_reg_field(dispc, FEAT_REG_FIFOHIGHTHRESHOLD, + &hi_start, &hi_end); + dispc_get_reg_field(dispc, FEAT_REG_FIFOLOWTHRESHOLD, + &lo_start, &lo_end); DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n", plane, - REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), + REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), lo_start, lo_end) * unit, - REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), + REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), hi_start, hi_end) * unit, low * unit, high * unit); - dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), + dispc_write_reg(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), FLD_VAL(high, hi_start, hi_end) | FLD_VAL(low, lo_start, lo_end)); @@ -1426,42 +1510,43 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low, * large for the preload field, set the threshold to the maximum value * that can be held by the preload register */ - if (dispc_has_feature(FEAT_PRELOAD) && dispc.feat->set_max_preload && - plane != OMAP_DSS_WB) - dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu)); + if (dispc_has_feature(dispc, FEAT_PRELOAD) && + dispc->feat->set_max_preload && plane != OMAP_DSS_WB) + dispc_write_reg(dispc, DISPC_OVL_PRELOAD(plane), + min(high, 0xfffu)); } -void dispc_enable_fifomerge(bool enable) +void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable) { - if (!dispc_has_feature(FEAT_FIFO_MERGE)) { + if (!dispc_has_feature(dispc, FEAT_FIFO_MERGE)) { WARN_ON(enable); return; } DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); - REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); + REG_FLD_MOD(dispc, DISPC_CONFIG, enable ? 1 : 0, 14, 14); } -void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, - u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, - bool manual_update) +void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, + enum omap_plane_id plane, + u32 *fifo_low, u32 *fifo_high, + bool use_fifomerge, bool manual_update) { /* * All sizes are in bytes. Both the buffer and burst are made of * buffer_units, and the fifo thresholds must be buffer_unit aligned. */ - - unsigned buf_unit = dispc.feat->buffer_size_unit; - unsigned ovl_fifo_size, total_fifo_size, burst_size; + unsigned int buf_unit = dispc->feat->buffer_size_unit; + unsigned int ovl_fifo_size, total_fifo_size, burst_size; int i; - burst_size = dispc_ovl_get_burst_size(plane); - ovl_fifo_size = dispc_ovl_get_fifo_size(plane); + burst_size = dispc_ovl_get_burst_size(dispc, plane); + ovl_fifo_size = dispc_ovl_get_fifo_size(dispc, plane); if (use_fifomerge) { total_fifo_size = 0; - for (i = 0; i < dispc_get_num_ovls(); ++i) - total_fifo_size += dispc_ovl_get_fifo_size(i); + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) + total_fifo_size += dispc_ovl_get_fifo_size(dispc, i); } else { total_fifo_size = ovl_fifo_size; } @@ -1472,7 +1557,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, * combined fifo size */ - if (manual_update && dispc_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { + if (manual_update && dispc_has_feature(dispc, FEAT_OMAP3_DSI_FIFO_BUG)) { *fifo_low = ovl_fifo_size - burst_size * 2; *fifo_high = total_fifo_size - burst_size; } else if (plane == OMAP_DSS_WB) { @@ -1489,7 +1574,8 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, } } -static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable) +static void dispc_ovl_set_mflag(struct dispc_device *dispc, + enum omap_plane_id plane, bool enable) { int bit; @@ -1498,17 +1584,18 @@ static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable) else bit = 23; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); } -static void dispc_ovl_set_mflag_threshold(enum omap_plane_id plane, - int low, int high) +static void dispc_ovl_set_mflag_threshold(struct dispc_device *dispc, + enum omap_plane_id plane, + int low, int high) { - dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane), + dispc_write_reg(dispc, DISPC_OVL_MFLAG_THRESHOLD(plane), FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); } -static void dispc_init_mflag(void) +static void dispc_init_mflag(struct dispc_device *dispc) { int i; @@ -1522,16 +1609,16 @@ static void dispc_init_mflag(void) * * As a work-around, set force MFLAG to always on. */ - dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE, + dispc_write_reg(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, (1 << 0) | /* MFLAG_CTRL = force always on */ (0 << 2)); /* MFLAG_START = disable */ - for (i = 0; i < dispc_get_num_ovls(); ++i) { - u32 size = dispc_ovl_get_fifo_size(i); - u32 unit = dispc.feat->buffer_size_unit; + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) { + u32 size = dispc_ovl_get_fifo_size(dispc, i); + u32 unit = dispc->feat->buffer_size_unit; u32 low, high; - dispc_ovl_set_mflag(i, true); + dispc_ovl_set_mflag(dispc, i, true); /* * Simulation team suggests below thesholds: @@ -1542,15 +1629,15 @@ static void dispc_init_mflag(void) low = size * 4 / 8 / unit; high = size * 5 / 8 / unit; - dispc_ovl_set_mflag_threshold(i, low, high); + dispc_ovl_set_mflag_threshold(dispc, i, low, high); } - if (dispc.feat->has_writeback) { - u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB); - u32 unit = dispc.feat->buffer_size_unit; + if (dispc->feat->has_writeback) { + u32 size = dispc_ovl_get_fifo_size(dispc, OMAP_DSS_WB); + u32 unit = dispc->feat->buffer_size_unit; u32 low, high; - dispc_ovl_set_mflag(OMAP_DSS_WB, true); + dispc_ovl_set_mflag(dispc, OMAP_DSS_WB, true); /* * Simulation team suggests below thesholds: @@ -1561,98 +1648,112 @@ static void dispc_init_mflag(void) low = size * 4 / 8 / unit; high = size * 5 / 8 / unit; - dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high); + dispc_ovl_set_mflag_threshold(dispc, OMAP_DSS_WB, low, high); } } -static void dispc_ovl_set_fir(enum omap_plane_id plane, - int hinc, int vinc, - enum omap_color_component color_comp) +static void dispc_ovl_set_fir(struct dispc_device *dispc, + enum omap_plane_id plane, + int hinc, int vinc, + enum omap_color_component color_comp) { u32 val; if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { u8 hinc_start, hinc_end, vinc_start, vinc_end; - dispc_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end); - dispc_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end); + dispc_get_reg_field(dispc, FEAT_REG_FIRHINC, + &hinc_start, &hinc_end); + dispc_get_reg_field(dispc, FEAT_REG_FIRVINC, + &vinc_start, &vinc_end); val = FLD_VAL(vinc, vinc_start, vinc_end) | FLD_VAL(hinc, hinc_start, hinc_end); - dispc_write_reg(DISPC_OVL_FIR(plane), val); + dispc_write_reg(dispc, DISPC_OVL_FIR(plane), val); } else { val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0); - dispc_write_reg(DISPC_OVL_FIR2(plane), val); + dispc_write_reg(dispc, DISPC_OVL_FIR2(plane), val); } } -static void dispc_ovl_set_vid_accu0(enum omap_plane_id plane, int haccu, +static void dispc_ovl_set_vid_accu0(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, int vaccu) { u32 val; u8 hor_start, hor_end, vert_start, vert_end; - dispc_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); - dispc_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); + dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU, + &hor_start, &hor_end); + dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU, + &vert_start, &vert_end); val = FLD_VAL(vaccu, vert_start, vert_end) | FLD_VAL(haccu, hor_start, hor_end); - dispc_write_reg(DISPC_OVL_ACCU0(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU0(plane), val); } -static void dispc_ovl_set_vid_accu1(enum omap_plane_id plane, int haccu, +static void dispc_ovl_set_vid_accu1(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, int vaccu) { u32 val; u8 hor_start, hor_end, vert_start, vert_end; - dispc_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); - dispc_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); + dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU, + &hor_start, &hor_end); + dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU, + &vert_start, &vert_end); val = FLD_VAL(vaccu, vert_start, vert_end) | FLD_VAL(haccu, hor_start, hor_end); - dispc_write_reg(DISPC_OVL_ACCU1(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU1(plane), val); } -static void dispc_ovl_set_vid_accu2_0(enum omap_plane_id plane, int haccu, - int vaccu) +static void dispc_ovl_set_vid_accu2_0(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, + int vaccu) { u32 val; val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); - dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU2_0(plane), val); } -static void dispc_ovl_set_vid_accu2_1(enum omap_plane_id plane, int haccu, - int vaccu) +static void dispc_ovl_set_vid_accu2_1(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, + int vaccu) { u32 val; val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); - dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU2_1(plane), val); } -static void dispc_ovl_set_scale_param(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool five_taps, u8 rotation, - enum omap_color_component color_comp) +static void dispc_ovl_set_scale_param(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool five_taps, u8 rotation, + enum omap_color_component color_comp) { int fir_hinc, fir_vinc; fir_hinc = 1024 * orig_width / out_width; fir_vinc = 1024 * orig_height / out_height; - dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, - color_comp); - dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); + dispc_ovl_set_scale_coef(dispc, plane, fir_hinc, fir_vinc, five_taps, + color_comp); + dispc_ovl_set_fir(dispc, plane, fir_hinc, fir_vinc, color_comp); } -static void dispc_ovl_set_accu_uv(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, - bool ilace, u32 fourcc, u8 rotation) +static void dispc_ovl_set_accu_uv(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, u32 fourcc, u8 rotation) { int h_accu2_0, h_accu2_1; int v_accu2_0, v_accu2_1; @@ -1733,25 +1834,26 @@ static void dispc_ovl_set_accu_uv(enum omap_plane_id plane, v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024; v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024; - dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0); - dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1); + dispc_ovl_set_vid_accu2_0(dispc, plane, h_accu2_0, v_accu2_0); + dispc_ovl_set_vid_accu2_1(dispc, plane, h_accu2_1, v_accu2_1); } -static void dispc_ovl_set_scaling_common(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool ilace, bool five_taps, - bool fieldmode, u32 fourcc, - u8 rotation) +static void dispc_ovl_set_scaling_common(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, bool five_taps, + bool fieldmode, u32 fourcc, + u8 rotation) { int accu0 = 0; int accu1 = 0; u32 l; - dispc_ovl_set_scale_param(plane, orig_width, orig_height, - out_width, out_height, five_taps, - rotation, DISPC_COLOR_COMPONENT_RGB_Y); - l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height, + out_width, out_height, five_taps, + rotation, DISPC_COLOR_COMPONENT_RGB_Y); + l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); /* RESIZEENABLE and VERTICALTAPS */ l &= ~((0x3 << 5) | (0x1 << 21)); @@ -1760,19 +1862,19 @@ static void dispc_ovl_set_scaling_common(enum omap_plane_id plane, l |= five_taps ? (1 << 21) : 0; /* VRESIZECONF and HRESIZECONF */ - if (dispc_has_feature(FEAT_RESIZECONF)) { + if (dispc_has_feature(dispc, FEAT_RESIZECONF)) { l &= ~(0x3 << 7); l |= (orig_width <= out_width) ? 0 : (1 << 7); l |= (orig_height <= out_height) ? 0 : (1 << 8); } /* LINEBUFFERSPLIT */ - if (dispc_has_feature(FEAT_LINEBUFFERSPLIT)) { + if (dispc_has_feature(dispc, FEAT_LINEBUFFERSPLIT)) { l &= ~(0x1 << 22); l |= five_taps ? (1 << 22) : 0; } - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l); /* * field 0 = even field = bottom field @@ -1787,33 +1889,35 @@ static void dispc_ovl_set_scaling_common(enum omap_plane_id plane, } } - dispc_ovl_set_vid_accu0(plane, 0, accu0); - dispc_ovl_set_vid_accu1(plane, 0, accu1); + dispc_ovl_set_vid_accu0(dispc, plane, 0, accu0); + dispc_ovl_set_vid_accu1(dispc, plane, 0, accu1); } -static void dispc_ovl_set_scaling_uv(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool ilace, bool five_taps, - bool fieldmode, u32 fourcc, - u8 rotation) +static void dispc_ovl_set_scaling_uv(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, bool five_taps, + bool fieldmode, u32 fourcc, + u8 rotation) { int scale_x = out_width != orig_width; int scale_y = out_height != orig_height; bool chroma_upscale = plane != OMAP_DSS_WB; - if (!dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) + if (!dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) return; if (!format_is_yuv(fourcc)) { /* reset chroma resampling for RGB formats */ if (plane != OMAP_DSS_WB) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), + 0, 8, 8); return; } - dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width, - out_height, ilace, fourcc, rotation); + dispc_ovl_set_accu_uv(dispc, plane, orig_width, orig_height, out_width, + out_height, ilace, fourcc, rotation); switch (fourcc) { case DRM_FORMAT_NV12: @@ -1855,46 +1959,43 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane_id plane, if (out_height != orig_height) scale_y = true; - dispc_ovl_set_scale_param(plane, orig_width, orig_height, - out_width, out_height, five_taps, - rotation, DISPC_COLOR_COMPONENT_UV); + dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height, + out_width, out_height, five_taps, + rotation, DISPC_COLOR_COMPONENT_UV); if (plane != OMAP_DSS_WB) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), (scale_x || scale_y) ? 1 : 0, 8, 8); /* set H scaling */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); /* set V scaling */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); } -static void dispc_ovl_set_scaling(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool ilace, bool five_taps, - bool fieldmode, u32 fourcc, - u8 rotation) +static void dispc_ovl_set_scaling(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, bool five_taps, + bool fieldmode, u32 fourcc, + u8 rotation) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_ovl_set_scaling_common(plane, - orig_width, orig_height, - out_width, out_height, - ilace, five_taps, - fieldmode, fourcc, - rotation); + dispc_ovl_set_scaling_common(dispc, plane, orig_width, orig_height, + out_width, out_height, ilace, five_taps, + fieldmode, fourcc, rotation); - dispc_ovl_set_scaling_uv(plane, - orig_width, orig_height, - out_width, out_height, - ilace, five_taps, - fieldmode, fourcc, - rotation); + dispc_ovl_set_scaling_uv(dispc, plane, orig_width, orig_height, + out_width, out_height, ilace, five_taps, + fieldmode, fourcc, rotation); } -static void dispc_ovl_set_rotation_attrs(enum omap_plane_id plane, u8 rotation, - enum omap_dss_rotation_type rotation_type, u32 fourcc) +static void dispc_ovl_set_rotation_attrs(struct dispc_device *dispc, + enum omap_plane_id plane, u8 rotation, + enum omap_dss_rotation_type rotation_type, + u32 fourcc) { bool row_repeat = false; int vidrot = 0; @@ -1948,19 +2049,20 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane_id plane, u8 rotation, if (fourcc == DRM_FORMAT_NV12 && rotation_type != OMAP_DSS_ROT_TILER) vidrot = 1; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); - if (dispc_has_feature(FEAT_ROWREPEATENABLE)) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); + if (dispc_has_feature(dispc, FEAT_ROWREPEATENABLE)) + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), row_repeat ? 1 : 0, 18, 18); - if (dispc_ovl_color_mode_supported(plane, DRM_FORMAT_NV12)) { + if (dispc_ovl_color_mode_supported(dispc, plane, DRM_FORMAT_NV12)) { bool doublestride = fourcc == DRM_FORMAT_NV12 && rotation_type == OMAP_DSS_ROT_TILER && !drm_rotation_90_or_270(rotation); /* DOUBLESTRIDE */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), + doublestride, 22, 22); } } @@ -2006,8 +2108,8 @@ static s32 pixinc(int pixels, u8 ps) } static void calc_offset(u16 screen_width, u16 width, - u32 fourcc, bool fieldmode, - unsigned int field_offset, unsigned *offset0, unsigned *offset1, + u32 fourcc, bool fieldmode, unsigned int field_offset, + unsigned int *offset0, unsigned int *offset1, s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim, enum omap_dss_rotation_type rotation_type, u8 rotation) { @@ -2197,27 +2299,31 @@ static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width, return pclk; } -static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, - u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +static int dispc_ovl_calc_scaling_24xx(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, + int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, + bool mem_to_mem) { int error; u16 in_width, in_height; int min_factor = min(*decim_x, *decim_y); - const int maxsinglelinewidth = dispc.feat->max_line_width; + const int maxsinglelinewidth = dispc->feat->max_line_width; *five_taps = false; do { in_height = height / *decim_y; in_width = width / *decim_x; - *core_clk = dispc.feat->calc_core_clk(pclk, in_width, + *core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); error = (in_width > maxsinglelinewidth || !*core_clk || - *core_clk > dispc_core_clk_rate()); + *core_clk > dispc_core_clk_rate(dispc)); if (error) { if (*decim_x == *decim_y) { *decim_x = min_factor; @@ -2242,16 +2348,20 @@ static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, return 0; } -static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, - u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +static int dispc_ovl_calc_scaling_34xx(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, + int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, + bool mem_to_mem) { int error; u16 in_width, in_height; - const int maxsinglelinewidth = dispc.feat->max_line_width; + const int maxsinglelinewidth = dispc->feat->max_line_width; do { in_height = height / *decim_y; @@ -2268,7 +2378,7 @@ again: in_width, in_height, out_width, out_height, fourcc); else - *core_clk = dispc.feat->calc_core_clk(pclk, in_width, + *core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); @@ -2282,7 +2392,7 @@ again: error = (error || in_width > maxsinglelinewidth * 2 || (in_width > maxsinglelinewidth && *five_taps) || - !*core_clk || *core_clk > dispc_core_clk_rate()); + !*core_clk || *core_clk > dispc_core_clk_rate(dispc)); if (!error) { /* verify that we're inside the limits of scaler */ @@ -2326,24 +2436,28 @@ again: return 0; } -static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, - u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, + int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, + bool mem_to_mem) { u16 in_width, in_width_max; int decim_x_min = *decim_x; u16 in_height = height / *decim_y; - const int maxsinglelinewidth = dispc.feat->max_line_width; - const int maxdownscale = dispc.feat->max_downscale; + const int maxsinglelinewidth = dispc->feat->max_line_width; + const int maxdownscale = dispc->feat->max_downscale; if (mem_to_mem) { in_width_max = out_width * maxdownscale; } else { - in_width_max = dispc_core_clk_rate() / - DIV_ROUND_UP(pclk, out_width); + in_width_max = dispc_core_clk_rate(dispc) + / DIV_ROUND_UP(pclk, out_width); } *decim_x = DIV_ROUND_UP(width, in_width_max); @@ -2381,7 +2495,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, return -EINVAL; } - *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, + *core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); return 0; } @@ -2389,15 +2503,20 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, #define DIV_FRAC(dividend, divisor) \ ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100)) -static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, - enum omap_overlay_caps caps, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, u16 pos_x, - enum omap_dss_rotation_type rotation_type, bool mem_to_mem) -{ - const int maxdownscale = dispc.feat->max_downscale; +static int dispc_ovl_calc_scaling(struct dispc_device *dispc, + enum omap_plane_id plane, + unsigned long pclk, unsigned long lclk, + enum omap_overlay_caps caps, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, u16 pos_x, + enum omap_dss_rotation_type rotation_type, + bool mem_to_mem) +{ + int maxhdownscale = dispc->feat->max_downscale; + int maxvdownscale = dispc->feat->max_downscale; const int max_decim_limit = 16; unsigned long core_clk = 0; int decim_x, decim_y, ret; @@ -2405,6 +2524,20 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, if (width == out_width && height == out_height) return 0; + if (plane == OMAP_DSS_WB) { + switch (fourcc) { + case DRM_FORMAT_NV12: + maxhdownscale = maxvdownscale = 2; + break; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + maxhdownscale = 2; + maxvdownscale = 4; + break; + default: + break; + } + } if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) { DSSERR("cannot calculate scaling settings: pclk is zero\n"); return -EINVAL; @@ -2418,12 +2551,12 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, } else { *x_predecim = max_decim_limit; *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && - dispc_has_feature(FEAT_BURST_2D)) ? + dispc_has_feature(dispc, FEAT_BURST_2D)) ? 2 : max_decim_limit; } - decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); - decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); + decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxhdownscale); + decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxvdownscale); if (decim_x > *x_predecim || out_width > width * 8) return -EINVAL; @@ -2431,10 +2564,11 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, if (decim_y > *y_predecim || out_height > height * 8) return -EINVAL; - ret = dispc.feat->calc_scaling(pclk, lclk, vm, width, height, - out_width, out_height, fourcc, five_taps, - x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, - mem_to_mem); + ret = dispc->feat->calc_scaling(dispc, pclk, lclk, vm, width, height, + out_width, out_height, fourcc, + five_taps, x_predecim, y_predecim, + &decim_x, &decim_y, pos_x, &core_clk, + mem_to_mem); if (ret) return ret; @@ -2450,13 +2584,13 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y), *five_taps ? 5 : 3, - core_clk, dispc_core_clk_rate()); + core_clk, dispc_core_clk_rate(dispc)); - if (!core_clk || core_clk > dispc_core_clk_rate()) { + if (!core_clk || core_clk > dispc_core_clk_rate(dispc)) { DSSERR("failed to set up scaling, " "required core clk rate = %lu Hz, " "current core clk rate = %lu Hz\n", - core_clk, dispc_core_clk_rate()); + core_clk, dispc_core_clk_rate(dispc)); return -EINVAL; } @@ -2465,19 +2599,23 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, return 0; } -static int dispc_ovl_setup_common(enum omap_plane_id plane, - enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, - u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, - u16 out_width, u16 out_height, u32 fourcc, - u8 rotation, u8 zorder, u8 pre_mult_alpha, - u8 global_alpha, enum omap_dss_rotation_type rotation_type, - bool replication, const struct videomode *vm, - bool mem_to_mem) +static int dispc_ovl_setup_common(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + u32 paddr, u32 p_uv_addr, + u16 screen_width, int pos_x, int pos_y, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, u8 rotation, u8 zorder, + u8 pre_mult_alpha, u8 global_alpha, + enum omap_dss_rotation_type rotation_type, + bool replication, const struct videomode *vm, + bool mem_to_mem) { bool five_taps = true; bool fieldmode = false; int r, cconv = 0; - unsigned offset0, offset1; + unsigned int offset0, offset1; s32 row_inc; s32 pix_inc; u16 frame_width, frame_height; @@ -2486,8 +2624,12 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, u16 in_width = width; int x_predecim = 1, y_predecim = 1; bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED); - unsigned long pclk = dispc_plane_pclk_rate(plane); - unsigned long lclk = dispc_plane_lclk_rate(plane); + unsigned long pclk = dispc_plane_pclk_rate(dispc, plane); + unsigned long lclk = dispc_plane_lclk_rate(dispc, plane); + + /* when setting up WB, dispc_plane_pclk_rate() returns 0 */ + if (plane == OMAP_DSS_WB) + pclk = vm->pixelclock; if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) return -EINVAL; @@ -2500,27 +2642,28 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, out_width = out_width == 0 ? width : out_width; out_height = out_height == 0 ? height : out_height; - if (ilace && height == out_height) - fieldmode = true; + if (plane != OMAP_DSS_WB) { + if (ilace && height == out_height) + fieldmode = true; - if (ilace) { - if (fieldmode) - in_height /= 2; - pos_y /= 2; - out_height /= 2; + if (ilace) { + if (fieldmode) + in_height /= 2; + pos_y /= 2; + out_height /= 2; - DSSDBG("adjusting for ilace: height %d, pos_y %d, " - "out_height %d\n", in_height, pos_y, - out_height); + DSSDBG("adjusting for ilace: height %d, pos_y %d, out_height %d\n", + in_height, pos_y, out_height); + } } - if (!dispc_ovl_color_mode_supported(plane, fourcc)) + if (!dispc_ovl_color_mode_supported(dispc, plane, fourcc)) return -EINVAL; - r = dispc_ovl_calc_scaling(pclk, lclk, caps, vm, in_width, - in_height, out_width, out_height, fourcc, - &five_taps, &x_predecim, &y_predecim, pos_x, - rotation_type, mem_to_mem); + r = dispc_ovl_calc_scaling(dispc, plane, pclk, lclk, caps, vm, in_width, + in_height, out_width, out_height, fourcc, + &five_taps, &x_predecim, &y_predecim, pos_x, + rotation_type, mem_to_mem); if (r) return r; @@ -2582,60 +2725,62 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", offset0, offset1, row_inc, pix_inc); - dispc_ovl_set_color_mode(plane, fourcc); + dispc_ovl_set_color_mode(dispc, plane, fourcc); - dispc_ovl_configure_burst_type(plane, rotation_type); + dispc_ovl_configure_burst_type(dispc, plane, rotation_type); - if (dispc.feat->reverse_ilace_field_order) + if (dispc->feat->reverse_ilace_field_order) swap(offset0, offset1); - dispc_ovl_set_ba0(plane, paddr + offset0); - dispc_ovl_set_ba1(plane, paddr + offset1); + dispc_ovl_set_ba0(dispc, plane, paddr + offset0); + dispc_ovl_set_ba1(dispc, plane, paddr + offset1); if (fourcc == DRM_FORMAT_NV12) { - dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); - dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); + dispc_ovl_set_ba0_uv(dispc, plane, p_uv_addr + offset0); + dispc_ovl_set_ba1_uv(dispc, plane, p_uv_addr + offset1); } - if (dispc.feat->last_pixel_inc_missing) + if (dispc->feat->last_pixel_inc_missing) row_inc += pix_inc - 1; - dispc_ovl_set_row_inc(plane, row_inc); - dispc_ovl_set_pix_inc(plane, pix_inc); + dispc_ovl_set_row_inc(dispc, plane, row_inc); + dispc_ovl_set_pix_inc(dispc, plane, pix_inc); DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, in_height, out_width, out_height); - dispc_ovl_set_pos(plane, caps, pos_x, pos_y); + dispc_ovl_set_pos(dispc, plane, caps, pos_x, pos_y); - dispc_ovl_set_input_size(plane, in_width, in_height); + dispc_ovl_set_input_size(dispc, plane, in_width, in_height); if (caps & OMAP_DSS_OVL_CAP_SCALE) { - dispc_ovl_set_scaling(plane, in_width, in_height, out_width, - out_height, ilace, five_taps, fieldmode, - fourcc, rotation); - dispc_ovl_set_output_size(plane, out_width, out_height); - dispc_ovl_set_vid_color_conv(plane, cconv); + dispc_ovl_set_scaling(dispc, plane, in_width, in_height, + out_width, out_height, ilace, five_taps, + fieldmode, fourcc, rotation); + dispc_ovl_set_output_size(dispc, plane, out_width, out_height); + dispc_ovl_set_vid_color_conv(dispc, plane, cconv); } - dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, fourcc); + dispc_ovl_set_rotation_attrs(dispc, plane, rotation, rotation_type, + fourcc); - dispc_ovl_set_zorder(plane, caps, zorder); - dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); - dispc_ovl_setup_global_alpha(plane, caps, global_alpha); + dispc_ovl_set_zorder(dispc, plane, caps, zorder); + dispc_ovl_set_pre_mult_alpha(dispc, plane, caps, pre_mult_alpha); + dispc_ovl_setup_global_alpha(dispc, plane, caps, global_alpha); - dispc_ovl_enable_replication(plane, caps, replication); + dispc_ovl_enable_replication(dispc, plane, caps, replication); return 0; } -static int dispc_ovl_setup(enum omap_plane_id plane, - const struct omap_overlay_info *oi, - const struct videomode *vm, bool mem_to_mem, - enum omap_channel channel) +static int dispc_ovl_setup(struct dispc_device *dispc, + enum omap_plane_id plane, + const struct omap_overlay_info *oi, + const struct videomode *vm, bool mem_to_mem, + enum omap_channel channel) { int r; - enum omap_overlay_caps caps = dispc.feat->overlay_caps[plane]; + enum omap_overlay_caps caps = dispc->feat->overlay_caps[plane]; const bool replication = true; DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->" @@ -2644,9 +2789,9 @@ static int dispc_ovl_setup(enum omap_plane_id plane, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->fourcc, oi->rotation, channel, replication); - dispc_ovl_set_channel_out(plane, channel); + dispc_ovl_set_channel_out(dispc, plane, channel); - r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr, + r = dispc_ovl_setup_common(dispc, plane, caps, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->fourcc, oi->rotation, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, @@ -2655,8 +2800,10 @@ static int dispc_ovl_setup(enum omap_plane_id plane, return r; } -int dispc_wb_setup(const struct omap_dss_writeback_info *wi, - bool mem_to_mem, const struct videomode *vm) +static int dispc_wb_setup(struct dispc_device *dispc, + const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct videomode *vm, + enum dss_writeback_channel channel_in) { int r; u32 l; @@ -2670,15 +2817,20 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi, enum omap_overlay_caps caps = OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; + if (vm->flags & DISPLAY_FLAGS_INTERLACED) + in_height /= 2; + DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " "rot %d\n", wi->paddr, wi->p_uv_addr, in_width, in_height, wi->width, wi->height, wi->fourcc, wi->rotation); - r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, + r = dispc_ovl_setup_common(dispc, plane, caps, wi->paddr, wi->p_uv_addr, wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, wi->height, wi->fourcc, wi->rotation, zorder, wi->pre_mult_alpha, global_alpha, wi->rotation_type, replication, vm, mem_to_mem); + if (r) + return r; switch (wi->fourcc) { case DRM_FORMAT_RGB565: @@ -2697,132 +2849,162 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi, } /* setup extra DISPC_WB_ATTRIBUTES */ - l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ + l = FLD_MOD(l, channel_in, 18, 16); /* CHANNELIN */ l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ if (mem_to_mem) l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */ else l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */ - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l); if (mem_to_mem) { /* WBDELAYCOUNT */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0); } else { - int wbdelay; + u32 wbdelay; + + if (channel_in == DSS_WB_TV_MGR) + wbdelay = vm->vsync_len + vm->vback_porch; + else + wbdelay = vm->vfront_porch + vm->vsync_len + + vm->vback_porch; + + if (vm->flags & DISPLAY_FLAGS_INTERLACED) + wbdelay /= 2; - wbdelay = min(vm->vfront_porch + - vm->vsync_len + vm->vback_porch, (u32)255); + wbdelay = min(wbdelay, 255u); /* WBDELAYCOUNT */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); } - return r; + return 0; +} + +static bool dispc_has_writeback(struct dispc_device *dispc) +{ + return dispc->feat->has_writeback; } -static int dispc_ovl_enable(enum omap_plane_id plane, bool enable) +static int dispc_ovl_enable(struct dispc_device *dispc, + enum omap_plane_id plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); return 0; } -static enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel) +static enum omap_dss_output_id +dispc_mgr_get_supported_outputs(struct dispc_device *dispc, + enum omap_channel channel) { - return dss_get_supported_outputs(channel); + return dss_get_supported_outputs(dispc->dss, channel); } -static void dispc_lcd_enable_signal_polarity(bool act_high) +static void dispc_lcd_enable_signal_polarity(struct dispc_device *dispc, + bool act_high) { - if (!dispc_has_feature(FEAT_LCDENABLEPOL)) + if (!dispc_has_feature(dispc, FEAT_LCDENABLEPOL)) return; - REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); + REG_FLD_MOD(dispc, DISPC_CONTROL, act_high ? 1 : 0, 29, 29); } -void dispc_lcd_enable_signal(bool enable) +void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable) { - if (!dispc_has_feature(FEAT_LCDENABLESIGNAL)) + if (!dispc_has_feature(dispc, FEAT_LCDENABLESIGNAL)) return; - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); + REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 28, 28); } -void dispc_pck_free_enable(bool enable) +void dispc_pck_free_enable(struct dispc_device *dispc, bool enable) { - if (!dispc_has_feature(FEAT_PCKFREEENABLE)) + if (!dispc_has_feature(dispc, FEAT_PCKFREEENABLE)) return; - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); + REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 27, 27); } -static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_fifohandcheck(struct dispc_device *dispc, + enum omap_channel channel, + bool enable) { - mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); } -static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel) +static void dispc_mgr_set_lcd_type_tft(struct dispc_device *dispc, + enum omap_channel channel) { - mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STNTFT, 1); } -static void dispc_set_loadmode(enum omap_dss_load_mode mode) +static void dispc_set_loadmode(struct dispc_device *dispc, + enum omap_dss_load_mode mode) { - REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); + REG_FLD_MOD(dispc, DISPC_CONFIG, mode, 2, 1); } -static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) +static void dispc_mgr_set_default_color(struct dispc_device *dispc, + enum omap_channel channel, u32 color) { - dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); + dispc_write_reg(dispc, DISPC_DEFAULT_COLOR(channel), color); } -static void dispc_mgr_set_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type type, - u32 trans_key) +static void dispc_mgr_set_trans_key(struct dispc_device *dispc, + enum omap_channel ch, + enum omap_dss_trans_key_type type, + u32 trans_key) { - mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type); + mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKSELECTION, type); - dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); + dispc_write_reg(dispc, DISPC_TRANS_COLOR(ch), trans_key); } -static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) +static void dispc_mgr_enable_trans_key(struct dispc_device *dispc, + enum omap_channel ch, bool enable) { - mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable); + mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKENABLE, enable); } -static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, - bool enable) +static void dispc_mgr_enable_alpha_fixed_zorder(struct dispc_device *dispc, + enum omap_channel ch, + bool enable) { - if (!dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER)) + if (!dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER)) return; if (ch == OMAP_DSS_CHANNEL_LCD) - REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); + REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) - REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); + REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 19, 19); } -static void dispc_mgr_setup(enum omap_channel channel, - const struct omap_overlay_manager_info *info) +static void dispc_mgr_setup(struct dispc_device *dispc, + enum omap_channel channel, + const struct omap_overlay_manager_info *info) { - dispc_mgr_set_default_color(channel, info->default_color); - dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); - dispc_mgr_enable_trans_key(channel, info->trans_enabled); - dispc_mgr_enable_alpha_fixed_zorder(channel, + dispc_mgr_set_default_color(dispc, channel, info->default_color); + dispc_mgr_set_trans_key(dispc, channel, info->trans_key_type, + info->trans_key); + dispc_mgr_enable_trans_key(dispc, channel, info->trans_enabled); + dispc_mgr_enable_alpha_fixed_zorder(dispc, channel, info->partial_alpha_enabled); - if (dispc_has_feature(FEAT_CPR)) { - dispc_mgr_enable_cpr(channel, info->cpr_enable); - dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); + if (dispc_has_feature(dispc, FEAT_CPR)) { + dispc_mgr_enable_cpr(dispc, channel, info->cpr_enable); + dispc_mgr_set_cpr_coef(dispc, channel, &info->cpr_coefs); } } -static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) +static void dispc_mgr_set_tft_data_lines(struct dispc_device *dispc, + enum omap_channel channel, + u8 data_lines) { int code; @@ -2844,10 +3026,11 @@ static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_line return; } - mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_TFTDATALINES, code); } -static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) +static void dispc_mgr_set_io_pad_mode(struct dispc_device *dispc, + enum dss_io_pad_mode mode) { u32 l; int gpout0, gpout1; @@ -2870,68 +3053,74 @@ static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) return; } - l = dispc_read_reg(DISPC_CONTROL); + l = dispc_read_reg(dispc, DISPC_CONTROL); l = FLD_MOD(l, gpout0, 15, 15); l = FLD_MOD(l, gpout1, 16, 16); - dispc_write_reg(DISPC_CONTROL, l); + dispc_write_reg(dispc, DISPC_CONTROL, l); } -static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_stallmode(struct dispc_device *dispc, + enum omap_channel channel, bool enable) { - mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STALLMODE, enable); } -static void dispc_mgr_set_lcd_config(enum omap_channel channel, - const struct dss_lcd_mgr_config *config) +static void dispc_mgr_set_lcd_config(struct dispc_device *dispc, + enum omap_channel channel, + const struct dss_lcd_mgr_config *config) { - dispc_mgr_set_io_pad_mode(config->io_pad_mode); + dispc_mgr_set_io_pad_mode(dispc, config->io_pad_mode); - dispc_mgr_enable_stallmode(channel, config->stallmode); - dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck); + dispc_mgr_enable_stallmode(dispc, channel, config->stallmode); + dispc_mgr_enable_fifohandcheck(dispc, channel, config->fifohandcheck); - dispc_mgr_set_clock_div(channel, &config->clock_info); + dispc_mgr_set_clock_div(dispc, channel, &config->clock_info); - dispc_mgr_set_tft_data_lines(channel, config->video_port_width); + dispc_mgr_set_tft_data_lines(dispc, channel, config->video_port_width); - dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity); + dispc_lcd_enable_signal_polarity(dispc, config->lcden_sig_polarity); - dispc_mgr_set_lcd_type_tft(channel); + dispc_mgr_set_lcd_type_tft(dispc, channel); } -static bool _dispc_mgr_size_ok(u16 width, u16 height) +static bool _dispc_mgr_size_ok(struct dispc_device *dispc, + u16 width, u16 height) { - return width <= dispc.feat->mgr_width_max && - height <= dispc.feat->mgr_height_max; + return width <= dispc->feat->mgr_width_max && + height <= dispc->feat->mgr_height_max; } -static bool _dispc_lcd_timings_ok(int hsync_len, int hfp, int hbp, - int vsw, int vfp, int vbp) +static bool _dispc_lcd_timings_ok(struct dispc_device *dispc, + int hsync_len, int hfp, int hbp, + int vsw, int vfp, int vbp) { - if (hsync_len < 1 || hsync_len > dispc.feat->sw_max || - hfp < 1 || hfp > dispc.feat->hp_max || - hbp < 1 || hbp > dispc.feat->hp_max || - vsw < 1 || vsw > dispc.feat->sw_max || - vfp < 0 || vfp > dispc.feat->vp_max || - vbp < 0 || vbp > dispc.feat->vp_max) + if (hsync_len < 1 || hsync_len > dispc->feat->sw_max || + hfp < 1 || hfp > dispc->feat->hp_max || + hbp < 1 || hbp > dispc->feat->hp_max || + vsw < 1 || vsw > dispc->feat->sw_max || + vfp < 0 || vfp > dispc->feat->vp_max || + vbp < 0 || vbp > dispc->feat->vp_max) return false; return true; } -static bool _dispc_mgr_pclk_ok(enum omap_channel channel, - unsigned long pclk) +static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc, + enum omap_channel channel, + unsigned long pclk) { if (dss_mgr_is_lcd(channel)) - return pclk <= dispc.feat->max_lcd_pclk; + return pclk <= dispc->feat->max_lcd_pclk; else - return pclk <= dispc.feat->max_tv_pclk; + return pclk <= dispc->feat->max_tv_pclk; } -bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm) +bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel, + const struct videomode *vm) { - if (!_dispc_mgr_size_ok(vm->hactive, vm->vactive)) + if (!_dispc_mgr_size_ok(dispc, vm->hactive, vm->vactive)) return false; - if (!_dispc_mgr_pclk_ok(channel, vm->pixelclock)) + if (!_dispc_mgr_pclk_ok(dispc, channel, vm->pixelclock)) return false; if (dss_mgr_is_lcd(channel)) { @@ -2939,7 +3128,7 @@ bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm) if (vm->flags & DISPLAY_FLAGS_INTERLACED) return false; - if (!_dispc_lcd_timings_ok(vm->hsync_len, + if (!_dispc_lcd_timings_ok(dispc, vm->hsync_len, vm->hfront_porch, vm->hback_porch, vm->vsync_len, vm->vfront_porch, vm->vback_porch)) @@ -2949,21 +3138,22 @@ bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm) return true; } -static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, +static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc, + enum omap_channel channel, const struct videomode *vm) { u32 timing_h, timing_v, l; bool onoff, rf, ipc, vs, hs, de; - timing_h = FLD_VAL(vm->hsync_len - 1, dispc.feat->sw_start, 0) | - FLD_VAL(vm->hfront_porch - 1, dispc.feat->fp_start, 8) | - FLD_VAL(vm->hback_porch - 1, dispc.feat->bp_start, 20); - timing_v = FLD_VAL(vm->vsync_len - 1, dispc.feat->sw_start, 0) | - FLD_VAL(vm->vfront_porch, dispc.feat->fp_start, 8) | - FLD_VAL(vm->vback_porch, dispc.feat->bp_start, 20); + timing_h = FLD_VAL(vm->hsync_len - 1, dispc->feat->sw_start, 0) | + FLD_VAL(vm->hfront_porch - 1, dispc->feat->fp_start, 8) | + FLD_VAL(vm->hback_porch - 1, dispc->feat->bp_start, 20); + timing_v = FLD_VAL(vm->vsync_len - 1, dispc->feat->sw_start, 0) | + FLD_VAL(vm->vfront_porch, dispc->feat->fp_start, 8) | + FLD_VAL(vm->vback_porch, dispc->feat->bp_start, 20); - dispc_write_reg(DISPC_TIMING_H(channel), timing_h); - dispc_write_reg(DISPC_TIMING_V(channel), timing_v); + dispc_write_reg(dispc, DISPC_TIMING_H(channel), timing_h); + dispc_write_reg(dispc, DISPC_TIMING_V(channel), timing_v); if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) vs = false; @@ -3001,12 +3191,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, FLD_VAL(vs, 12, 12); /* always set ALIGN bit when available */ - if (dispc.feat->supports_sync_align) + if (dispc->feat->supports_sync_align) l |= (1 << 18); - dispc_write_reg(DISPC_POL_FREQ(channel), l); + dispc_write_reg(dispc, DISPC_POL_FREQ(channel), l); - if (dispc.syscon_pol) { + if (dispc->syscon_pol) { const int shifts[] = { [OMAP_DSS_CHANNEL_LCD] = 0, [OMAP_DSS_CHANNEL_LCD2] = 1, @@ -3021,8 +3211,8 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, mask <<= 16 + shifts[channel]; val <<= 16 + shifts[channel]; - regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset, - mask, val); + regmap_update_bits(dispc->syscon_pol, dispc->syscon_pol_offset, + mask, val); } } @@ -3037,22 +3227,23 @@ static int vm_flag_to_int(enum display_flags flags, enum display_flags high, } /* change name to mode? */ -static void dispc_mgr_set_timings(enum omap_channel channel, - const struct videomode *vm) +static void dispc_mgr_set_timings(struct dispc_device *dispc, + enum omap_channel channel, + const struct videomode *vm) { - unsigned xtot, ytot; + unsigned int xtot, ytot; unsigned long ht, vt; struct videomode t = *vm; DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive); - if (!dispc_mgr_timings_ok(channel, &t)) { + if (!dispc_mgr_timings_ok(dispc, channel, &t)) { BUG(); return; } if (dss_mgr_is_lcd(channel)) { - _dispc_mgr_set_lcd_timings(channel, &t); + _dispc_mgr_set_lcd_timings(dispc, channel, &t); xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch; ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch; @@ -3076,52 +3267,54 @@ static void dispc_mgr_set_timings(enum omap_channel channel, if (t.flags & DISPLAY_FLAGS_INTERLACED) t.vactive /= 2; - if (dispc.feat->supports_double_pixel) - REG_FLD_MOD(DISPC_CONTROL, + if (dispc->feat->supports_double_pixel) + REG_FLD_MOD(dispc, DISPC_CONTROL, !!(t.flags & DISPLAY_FLAGS_DOUBLECLK), 19, 17); } - dispc_mgr_set_size(channel, t.hactive, t.vactive); + dispc_mgr_set_size(dispc, channel, t.hactive, t.vactive); } -static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, - u16 pck_div) +static void dispc_mgr_set_lcd_divisor(struct dispc_device *dispc, + enum omap_channel channel, u16 lck_div, + u16 pck_div) { BUG_ON(lck_div < 1); BUG_ON(pck_div < 1); - dispc_write_reg(DISPC_DIVISORo(channel), + dispc_write_reg(dispc, DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); - if (!dispc_has_feature(FEAT_CORE_CLK_DIV) && + if (!dispc_has_feature(dispc, FEAT_CORE_CLK_DIV) && channel == OMAP_DSS_CHANNEL_LCD) - dispc.core_clk_rate = dispc_fclk_rate() / lck_div; + dispc->core_clk_rate = dispc_fclk_rate(dispc) / lck_div; } -static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, - int *pck_div) +static void dispc_mgr_get_lcd_divisor(struct dispc_device *dispc, + enum omap_channel channel, int *lck_div, + int *pck_div) { u32 l; - l = dispc_read_reg(DISPC_DIVISORo(channel)); + l = dispc_read_reg(dispc, DISPC_DIVISORo(channel)); *lck_div = FLD_GET(l, 23, 16); *pck_div = FLD_GET(l, 7, 0); } -static unsigned long dispc_fclk_rate(void) +static unsigned long dispc_fclk_rate(struct dispc_device *dispc) { unsigned long r; enum dss_clk_source src; - src = dss_get_dispc_clk_source(); + src = dss_get_dispc_clk_source(dispc->dss); if (src == DSS_CLK_SRC_FCK) { - r = dss_get_dispc_clk_rate(); + r = dss_get_dispc_clk_rate(dispc->dss); } else { struct dss_pll *pll; - unsigned clkout_idx; + unsigned int clkout_idx; - pll = dss_pll_find_by_src(src); + pll = dss_pll_find_by_src(dispc->dss, src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); r = pll->cinfo.clkout[clkout_idx]; @@ -3130,7 +3323,8 @@ static unsigned long dispc_fclk_rate(void) return r; } -static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) +static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc, + enum omap_channel channel) { int lcd; unsigned long r; @@ -3138,28 +3332,29 @@ static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) /* for TV, LCLK rate is the FCLK rate */ if (!dss_mgr_is_lcd(channel)) - return dispc_fclk_rate(); + return dispc_fclk_rate(dispc); - src = dss_get_lcd_clk_source(channel); + src = dss_get_lcd_clk_source(dispc->dss, channel); if (src == DSS_CLK_SRC_FCK) { - r = dss_get_dispc_clk_rate(); + r = dss_get_dispc_clk_rate(dispc->dss); } else { struct dss_pll *pll; - unsigned clkout_idx; + unsigned int clkout_idx; - pll = dss_pll_find_by_src(src); + pll = dss_pll_find_by_src(dispc->dss, src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); r = pll->cinfo.clkout[clkout_idx]; } - lcd = REG_GET(DISPC_DIVISORo(channel), 23, 16); + lcd = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16); return r / lcd; } -static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) +static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc, + enum omap_channel channel) { unsigned long r; @@ -3167,109 +3362,115 @@ static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) int pcd; u32 l; - l = dispc_read_reg(DISPC_DIVISORo(channel)); + l = dispc_read_reg(dispc, DISPC_DIVISORo(channel)); pcd = FLD_GET(l, 7, 0); - r = dispc_mgr_lclk_rate(channel); + r = dispc_mgr_lclk_rate(dispc, channel); return r / pcd; } else { - return dispc.tv_pclk_rate; + return dispc->tv_pclk_rate; } } -void dispc_set_tv_pclk(unsigned long pclk) +void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk) { - dispc.tv_pclk_rate = pclk; + dispc->tv_pclk_rate = pclk; } -static unsigned long dispc_core_clk_rate(void) +static unsigned long dispc_core_clk_rate(struct dispc_device *dispc) { - return dispc.core_clk_rate; + return dispc->core_clk_rate; } -static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane) +static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane) { enum omap_channel channel; if (plane == OMAP_DSS_WB) return 0; - channel = dispc_ovl_get_channel_out(plane); + channel = dispc_ovl_get_channel_out(dispc, plane); - return dispc_mgr_pclk_rate(channel); + return dispc_mgr_pclk_rate(dispc, channel); } -static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane) +static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane) { enum omap_channel channel; if (plane == OMAP_DSS_WB) return 0; - channel = dispc_ovl_get_channel_out(plane); + channel = dispc_ovl_get_channel_out(dispc, plane); - return dispc_mgr_lclk_rate(channel); + return dispc_mgr_lclk_rate(dispc, channel); } -static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) +static void dispc_dump_clocks_channel(struct dispc_device *dispc, + struct seq_file *s, + enum omap_channel channel) { int lcd, pcd; enum dss_clk_source lcd_clk_src; seq_printf(s, "- %s -\n", mgr_desc[channel].name); - lcd_clk_src = dss_get_lcd_clk_source(channel); + lcd_clk_src = dss_get_lcd_clk_source(dispc->dss, channel); seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name, dss_get_clk_source_name(lcd_clk_src)); - dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd); + dispc_mgr_get_lcd_divisor(dispc, channel, &lcd, &pcd); seq_printf(s, "lck\t\t%-16lulck div\t%u\n", - dispc_mgr_lclk_rate(channel), lcd); + dispc_mgr_lclk_rate(dispc, channel), lcd); seq_printf(s, "pck\t\t%-16lupck div\t%u\n", - dispc_mgr_pclk_rate(channel), pcd); + dispc_mgr_pclk_rate(dispc, channel), pcd); } -void dispc_dump_clocks(struct seq_file *s) +void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s) { + enum dss_clk_source dispc_clk_src; int lcd; u32 l; - enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); - if (dispc_runtime_get()) + if (dispc_runtime_get(dispc)) return; seq_printf(s, "- DISPC -\n"); + dispc_clk_src = dss_get_dispc_clk_source(dispc->dss); seq_printf(s, "dispc fclk source = %s\n", dss_get_clk_source_name(dispc_clk_src)); - seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); + seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate(dispc)); - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) { + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) { seq_printf(s, "- DISPC-CORE-CLK -\n"); - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(dispc, DISPC_DIVISOR); lcd = FLD_GET(l, 23, 16); seq_printf(s, "lck\t\t%-16lulck div\t%u\n", - (dispc_fclk_rate()/lcd), lcd); + (dispc_fclk_rate(dispc)/lcd), lcd); } - dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD); + dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD); - if (dispc_has_feature(FEAT_MGR_LCD2)) - dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD3); - dispc_runtime_put(); + dispc_runtime_put(dispc); } -static void dispc_dump_regs(struct seq_file *s) +static int dispc_dump_regs(struct seq_file *s, void *p) { + struct dispc_device *dispc = s->private; int i, j; const char *mgr_names[] = { [OMAP_DSS_CHANNEL_LCD] = "LCD", @@ -3286,186 +3487,190 @@ static void dispc_dump_regs(struct seq_file *s) }; const char **p_names; -#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) +#define DUMPREG(dispc, r) \ + seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(dispc, r)) - if (dispc_runtime_get()) - return; + if (dispc_runtime_get(dispc)) + return 0; /* DISPC common registers */ - DUMPREG(DISPC_REVISION); - DUMPREG(DISPC_SYSCONFIG); - DUMPREG(DISPC_SYSSTATUS); - DUMPREG(DISPC_IRQSTATUS); - DUMPREG(DISPC_IRQENABLE); - DUMPREG(DISPC_CONTROL); - DUMPREG(DISPC_CONFIG); - DUMPREG(DISPC_CAPABLE); - DUMPREG(DISPC_LINE_STATUS); - DUMPREG(DISPC_LINE_NUMBER); - if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) || - dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) - DUMPREG(DISPC_GLOBAL_ALPHA); - if (dispc_has_feature(FEAT_MGR_LCD2)) { - DUMPREG(DISPC_CONTROL2); - DUMPREG(DISPC_CONFIG2); + DUMPREG(dispc, DISPC_REVISION); + DUMPREG(dispc, DISPC_SYSCONFIG); + DUMPREG(dispc, DISPC_SYSSTATUS); + DUMPREG(dispc, DISPC_IRQSTATUS); + DUMPREG(dispc, DISPC_IRQENABLE); + DUMPREG(dispc, DISPC_CONTROL); + DUMPREG(dispc, DISPC_CONFIG); + DUMPREG(dispc, DISPC_CAPABLE); + DUMPREG(dispc, DISPC_LINE_STATUS); + DUMPREG(dispc, DISPC_LINE_NUMBER); + if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || + dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) + DUMPREG(dispc, DISPC_GLOBAL_ALPHA); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { + DUMPREG(dispc, DISPC_CONTROL2); + DUMPREG(dispc, DISPC_CONFIG2); } - if (dispc_has_feature(FEAT_MGR_LCD3)) { - DUMPREG(DISPC_CONTROL3); - DUMPREG(DISPC_CONFIG3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { + DUMPREG(dispc, DISPC_CONTROL3); + DUMPREG(dispc, DISPC_CONFIG3); } - if (dispc_has_feature(FEAT_MFLAG)) - DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE); + if (dispc_has_feature(dispc, FEAT_MFLAG)) + DUMPREG(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE); #undef DUMPREG #define DISPC_REG(i, name) name(i) -#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ +#define DUMPREG(dispc, i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \ - dispc_read_reg(DISPC_REG(i, r))) + dispc_read_reg(dispc, DISPC_REG(i, r))) p_names = mgr_names; /* DISPC channel specific registers */ - for (i = 0; i < dispc_get_num_mgrs(); i++) { - DUMPREG(i, DISPC_DEFAULT_COLOR); - DUMPREG(i, DISPC_TRANS_COLOR); - DUMPREG(i, DISPC_SIZE_MGR); + for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { + DUMPREG(dispc, i, DISPC_DEFAULT_COLOR); + DUMPREG(dispc, i, DISPC_TRANS_COLOR); + DUMPREG(dispc, i, DISPC_SIZE_MGR); if (i == OMAP_DSS_CHANNEL_DIGIT) continue; - DUMPREG(i, DISPC_TIMING_H); - DUMPREG(i, DISPC_TIMING_V); - DUMPREG(i, DISPC_POL_FREQ); - DUMPREG(i, DISPC_DIVISORo); + DUMPREG(dispc, i, DISPC_TIMING_H); + DUMPREG(dispc, i, DISPC_TIMING_V); + DUMPREG(dispc, i, DISPC_POL_FREQ); + DUMPREG(dispc, i, DISPC_DIVISORo); - DUMPREG(i, DISPC_DATA_CYCLE1); - DUMPREG(i, DISPC_DATA_CYCLE2); - DUMPREG(i, DISPC_DATA_CYCLE3); + DUMPREG(dispc, i, DISPC_DATA_CYCLE1); + DUMPREG(dispc, i, DISPC_DATA_CYCLE2); + DUMPREG(dispc, i, DISPC_DATA_CYCLE3); - if (dispc_has_feature(FEAT_CPR)) { - DUMPREG(i, DISPC_CPR_COEF_R); - DUMPREG(i, DISPC_CPR_COEF_G); - DUMPREG(i, DISPC_CPR_COEF_B); + if (dispc_has_feature(dispc, FEAT_CPR)) { + DUMPREG(dispc, i, DISPC_CPR_COEF_R); + DUMPREG(dispc, i, DISPC_CPR_COEF_G); + DUMPREG(dispc, i, DISPC_CPR_COEF_B); } } p_names = ovl_names; - for (i = 0; i < dispc_get_num_ovls(); i++) { - DUMPREG(i, DISPC_OVL_BA0); - DUMPREG(i, DISPC_OVL_BA1); - DUMPREG(i, DISPC_OVL_POSITION); - DUMPREG(i, DISPC_OVL_SIZE); - DUMPREG(i, DISPC_OVL_ATTRIBUTES); - DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD); - DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS); - DUMPREG(i, DISPC_OVL_ROW_INC); - DUMPREG(i, DISPC_OVL_PIXEL_INC); - - if (dispc_has_feature(FEAT_PRELOAD)) - DUMPREG(i, DISPC_OVL_PRELOAD); - if (dispc_has_feature(FEAT_MFLAG)) - DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) { + DUMPREG(dispc, i, DISPC_OVL_BA0); + DUMPREG(dispc, i, DISPC_OVL_BA1); + DUMPREG(dispc, i, DISPC_OVL_POSITION); + DUMPREG(dispc, i, DISPC_OVL_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES); + DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD); + DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS); + DUMPREG(dispc, i, DISPC_OVL_ROW_INC); + DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC); + + if (dispc_has_feature(dispc, FEAT_PRELOAD)) + DUMPREG(dispc, i, DISPC_OVL_PRELOAD); + if (dispc_has_feature(dispc, FEAT_MFLAG)) + DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD); if (i == OMAP_DSS_GFX) { - DUMPREG(i, DISPC_OVL_WINDOW_SKIP); - DUMPREG(i, DISPC_OVL_TABLE_BA); + DUMPREG(dispc, i, DISPC_OVL_WINDOW_SKIP); + DUMPREG(dispc, i, DISPC_OVL_TABLE_BA); continue; } - DUMPREG(i, DISPC_OVL_FIR); - DUMPREG(i, DISPC_OVL_PICTURE_SIZE); - DUMPREG(i, DISPC_OVL_ACCU0); - DUMPREG(i, DISPC_OVL_ACCU1); - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(i, DISPC_OVL_BA0_UV); - DUMPREG(i, DISPC_OVL_BA1_UV); - DUMPREG(i, DISPC_OVL_FIR2); - DUMPREG(i, DISPC_OVL_ACCU2_0); - DUMPREG(i, DISPC_OVL_ACCU2_1); + DUMPREG(dispc, i, DISPC_OVL_FIR); + DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ACCU0); + DUMPREG(dispc, i, DISPC_OVL_ACCU1); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + DUMPREG(dispc, i, DISPC_OVL_BA0_UV); + DUMPREG(dispc, i, DISPC_OVL_BA1_UV); + DUMPREG(dispc, i, DISPC_OVL_FIR2); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_0); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_1); } - if (dispc_has_feature(FEAT_ATTR2)) - DUMPREG(i, DISPC_OVL_ATTRIBUTES2); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2); } - if (dispc.feat->has_writeback) { + if (dispc->feat->has_writeback) { i = OMAP_DSS_WB; - DUMPREG(i, DISPC_OVL_BA0); - DUMPREG(i, DISPC_OVL_BA1); - DUMPREG(i, DISPC_OVL_SIZE); - DUMPREG(i, DISPC_OVL_ATTRIBUTES); - DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD); - DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS); - DUMPREG(i, DISPC_OVL_ROW_INC); - DUMPREG(i, DISPC_OVL_PIXEL_INC); - - if (dispc_has_feature(FEAT_MFLAG)) - DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD); - - DUMPREG(i, DISPC_OVL_FIR); - DUMPREG(i, DISPC_OVL_PICTURE_SIZE); - DUMPREG(i, DISPC_OVL_ACCU0); - DUMPREG(i, DISPC_OVL_ACCU1); - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(i, DISPC_OVL_BA0_UV); - DUMPREG(i, DISPC_OVL_BA1_UV); - DUMPREG(i, DISPC_OVL_FIR2); - DUMPREG(i, DISPC_OVL_ACCU2_0); - DUMPREG(i, DISPC_OVL_ACCU2_1); + DUMPREG(dispc, i, DISPC_OVL_BA0); + DUMPREG(dispc, i, DISPC_OVL_BA1); + DUMPREG(dispc, i, DISPC_OVL_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES); + DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD); + DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS); + DUMPREG(dispc, i, DISPC_OVL_ROW_INC); + DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC); + + if (dispc_has_feature(dispc, FEAT_MFLAG)) + DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD); + + DUMPREG(dispc, i, DISPC_OVL_FIR); + DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ACCU0); + DUMPREG(dispc, i, DISPC_OVL_ACCU1); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + DUMPREG(dispc, i, DISPC_OVL_BA0_UV); + DUMPREG(dispc, i, DISPC_OVL_BA1_UV); + DUMPREG(dispc, i, DISPC_OVL_FIR2); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_0); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_1); } - if (dispc_has_feature(FEAT_ATTR2)) - DUMPREG(i, DISPC_OVL_ATTRIBUTES2); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2); } #undef DISPC_REG #undef DUMPREG #define DISPC_REG(plane, name, i) name(plane, i) -#define DUMPREG(plane, name, i) \ +#define DUMPREG(dispc, plane, name, i) \ seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \ - dispc_read_reg(DISPC_REG(plane, name, i))) + dispc_read_reg(dispc, DISPC_REG(plane, name, i))) /* Video pipeline coefficient registers */ /* start from OMAP_DSS_VIDEO1 */ - for (i = 1; i < dispc_get_num_ovls(); i++) { + for (i = 1; i < dispc_get_num_ovls(dispc); i++) { for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_H, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H, j); for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV, j); for (j = 0; j < 5; j++) - DUMPREG(i, DISPC_OVL_CONV_COEF, j); + DUMPREG(dispc, i, DISPC_OVL_CONV_COEF, j); - if (dispc_has_feature(FEAT_FIR_COEF_V)) { + if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_V, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V, j); } - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H2, j); for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV2, j); for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V2, j); } } - dispc_runtime_put(); + dispc_runtime_put(dispc); #undef DISPC_REG #undef DUMPREG + + return 0; } /* calculate clock rates using dividers in cinfo */ -int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, - struct dispc_clock_info *cinfo) +int dispc_calc_clock_rates(struct dispc_device *dispc, + unsigned long dispc_fclk_rate, + struct dispc_clock_info *cinfo) { if (cinfo->lck_div > 255 || cinfo->lck_div == 0) return -EINVAL; @@ -3478,16 +3683,16 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, return 0; } -bool dispc_div_calc(unsigned long dispc_freq, - unsigned long pck_min, unsigned long pck_max, - dispc_div_calc_func func, void *data) +bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq, + unsigned long pck_min, unsigned long pck_max, + dispc_div_calc_func func, void *data) { int lckd, lckd_start, lckd_stop; int pckd, pckd_start, pckd_stop; unsigned long pck, lck; unsigned long lck_max; unsigned long pckd_hw_min, pckd_hw_max; - unsigned min_fck_per_pck; + unsigned int min_fck_per_pck; unsigned long fck; #ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK @@ -3496,10 +3701,10 @@ bool dispc_div_calc(unsigned long dispc_freq, min_fck_per_pck = 0; #endif - pckd_hw_min = dispc.feat->min_pcd; + pckd_hw_min = dispc->feat->min_pcd; pckd_hw_max = 255; - lck_max = dss_get_max_fck_rate(); + lck_max = dss_get_max_fck_rate(dispc->dss); pck_min = pck_min ? pck_min : 1; pck_max = pck_max ? pck_max : ULONG_MAX; @@ -3522,8 +3727,8 @@ bool dispc_div_calc(unsigned long dispc_freq, * also. Thus we need to use the calculated lck. For * OMAP4+ the DISPC fclk is a separate clock. */ - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) - fck = dispc_core_clk_rate(); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) + fck = dispc_core_clk_rate(dispc); else fck = lck; @@ -3538,24 +3743,27 @@ bool dispc_div_calc(unsigned long dispc_freq, return false; } -void dispc_mgr_set_clock_div(enum omap_channel channel, - const struct dispc_clock_info *cinfo) +void dispc_mgr_set_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + const struct dispc_clock_info *cinfo) { DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); - dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); + dispc_mgr_set_lcd_divisor(dispc, channel, cinfo->lck_div, + cinfo->pck_div); } -int dispc_mgr_get_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo) +int dispc_mgr_get_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + struct dispc_clock_info *cinfo) { unsigned long fck; - fck = dispc_fclk_rate(); + fck = dispc_fclk_rate(dispc); - cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0); + cinfo->lck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16); + cinfo->pck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 7, 0); cinfo->lck = fck / cinfo->lck_div; cinfo->pck = cinfo->lck / cinfo->pck_div; @@ -3563,53 +3771,56 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, return 0; } -static u32 dispc_read_irqstatus(void) +static u32 dispc_read_irqstatus(struct dispc_device *dispc) { - return dispc_read_reg(DISPC_IRQSTATUS); + return dispc_read_reg(dispc, DISPC_IRQSTATUS); } -static void dispc_clear_irqstatus(u32 mask) +static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask) { - dispc_write_reg(DISPC_IRQSTATUS, mask); + dispc_write_reg(dispc, DISPC_IRQSTATUS, mask); } -static void dispc_write_irqenable(u32 mask) +static void dispc_write_irqenable(struct dispc_device *dispc, u32 mask) { - u32 old_mask = dispc_read_reg(DISPC_IRQENABLE); + u32 old_mask = dispc_read_reg(dispc, DISPC_IRQENABLE); /* clear the irqstatus for newly enabled irqs */ - dispc_clear_irqstatus((mask ^ old_mask) & mask); + dispc_clear_irqstatus(dispc, (mask ^ old_mask) & mask); - dispc_write_reg(DISPC_IRQENABLE, mask); + dispc_write_reg(dispc, DISPC_IRQENABLE, mask); /* flush posted write */ - dispc_read_reg(DISPC_IRQENABLE); + dispc_read_reg(dispc, DISPC_IRQENABLE); } -void dispc_enable_sidle(void) +void dispc_enable_sidle(struct dispc_device *dispc) { - REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ + /* SIDLEMODE: smart idle */ + REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 2, 4, 3); } -void dispc_disable_sidle(void) +void dispc_disable_sidle(struct dispc_device *dispc) { - REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ + REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ } -static u32 dispc_mgr_gamma_size(enum omap_channel channel) +static u32 dispc_mgr_gamma_size(struct dispc_device *dispc, + enum omap_channel channel) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return 0; return gdesc->len; } -static void dispc_mgr_write_gamma_table(enum omap_channel channel) +static void dispc_mgr_write_gamma_table(struct dispc_device *dispc, + enum omap_channel channel) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; - u32 *table = dispc.gamma_table[channel]; + u32 *table = dispc->gamma_table[channel]; unsigned int i; DSSDBG("%s: channel %d\n", __func__, channel); @@ -3622,26 +3833,26 @@ static void dispc_mgr_write_gamma_table(enum omap_channel channel) else if (i == 0) v |= 1 << 31; - dispc_write_reg(gdesc->reg, v); + dispc_write_reg(dispc, gdesc->reg, v); } } -static void dispc_restore_gamma_tables(void) +static void dispc_restore_gamma_tables(struct dispc_device *dispc) { DSSDBG("%s()\n", __func__); - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return; - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD); + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD); - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT); + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_DIGIT); - if (dispc_has_feature(FEAT_MGR_LCD2)) - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD3); } static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { @@ -3649,18 +3860,19 @@ static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, }; -static void dispc_mgr_set_gamma(enum omap_channel channel, - const struct drm_color_lut *lut, - unsigned int length) +static void dispc_mgr_set_gamma(struct dispc_device *dispc, + enum omap_channel channel, + const struct drm_color_lut *lut, + unsigned int length) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; - u32 *table = dispc.gamma_table[channel]; + u32 *table = dispc->gamma_table[channel]; uint i; DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__, channel, length, gdesc->len); - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return; if (lut == NULL || length < 2) { @@ -3692,82 +3904,83 @@ static void dispc_mgr_set_gamma(enum omap_channel channel, } } - if (dispc.is_enabled) - dispc_mgr_write_gamma_table(channel); + if (dispc->is_enabled) + dispc_mgr_write_gamma_table(dispc, channel); } -static int dispc_init_gamma_tables(void) +static int dispc_init_gamma_tables(struct dispc_device *dispc) { int channel; - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return 0; - for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) { + for (channel = 0; channel < ARRAY_SIZE(dispc->gamma_table); channel++) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; u32 *gt; if (channel == OMAP_DSS_CHANNEL_LCD2 && - !dispc_has_feature(FEAT_MGR_LCD2)) + !dispc_has_feature(dispc, FEAT_MGR_LCD2)) continue; if (channel == OMAP_DSS_CHANNEL_LCD3 && - !dispc_has_feature(FEAT_MGR_LCD3)) + !dispc_has_feature(dispc, FEAT_MGR_LCD3)) continue; - gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len, - sizeof(u32), GFP_KERNEL); + gt = devm_kmalloc_array(&dispc->pdev->dev, gdesc->len, + sizeof(u32), GFP_KERNEL); if (!gt) return -ENOMEM; - dispc.gamma_table[channel] = gt; + dispc->gamma_table[channel] = gt; - dispc_mgr_set_gamma(channel, NULL, 0); + dispc_mgr_set_gamma(dispc, channel, NULL, 0); } return 0; } -static void _omap_dispc_initial_config(void) +static void _omap_dispc_initial_config(struct dispc_device *dispc) { u32 l; /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) { - l = dispc_read_reg(DISPC_DIVISOR); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) { + l = dispc_read_reg(dispc, DISPC_DIVISOR); /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ l = FLD_MOD(l, 1, 0, 0); l = FLD_MOD(l, 1, 23, 16); - dispc_write_reg(DISPC_DIVISOR, l); + dispc_write_reg(dispc, DISPC_DIVISOR, l); - dispc.core_clk_rate = dispc_fclk_rate(); + dispc->core_clk_rate = dispc_fclk_rate(dispc); } /* Use gamma table mode, instead of palette mode */ - if (dispc.feat->has_gamma_table) - REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3); + if (dispc->feat->has_gamma_table) + REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 3, 3); /* For older DSS versions (FEAT_FUNCGATED) this enables * func-clock auto-gating. For newer versions - * (dispc.feat->has_gamma_table) this enables tv-out gamma tables. + * (dispc->feat->has_gamma_table) this enables tv-out gamma tables. */ - if (dispc_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table) - REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); + if (dispc_has_feature(dispc, FEAT_FUNCGATED) || + dispc->feat->has_gamma_table) + REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 9, 9); - dispc_setup_color_conv_coef(); + dispc_setup_color_conv_coef(dispc); - dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); + dispc_set_loadmode(dispc, OMAP_DSS_LOAD_FRAME_ONLY); - dispc_init_fifos(); + dispc_init_fifos(dispc); - dispc_configure_burst_sizes(); + dispc_configure_burst_sizes(dispc); - dispc_ovl_enable_zorder_planes(); + dispc_ovl_enable_zorder_planes(dispc); - if (dispc.feat->mstandby_workaround) - REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0); + if (dispc->feat->mstandby_workaround) + REG_FLD_MOD(dispc, DISPC_MSTANDBY_CTRL, 1, 0, 0); - if (dispc_has_feature(FEAT_MFLAG)) - dispc_init_mflag(); + if (dispc_has_feature(dispc, FEAT_MFLAG)) + dispc_init_mflag(dispc); } static const enum dispc_feature_id omap2_dispc_features_list[] = { @@ -4286,49 +4499,52 @@ static const struct dispc_features omap54xx_dispc_feats = { static irqreturn_t dispc_irq_handler(int irq, void *arg) { - if (!dispc.is_enabled) + struct dispc_device *dispc = arg; + + if (!dispc->is_enabled) return IRQ_NONE; - return dispc.user_handler(irq, dispc.user_data); + return dispc->user_handler(irq, dispc->user_data); } -static int dispc_request_irq(irq_handler_t handler, void *dev_id) +static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler, + void *dev_id) { int r; - if (dispc.user_handler != NULL) + if (dispc->user_handler != NULL) return -EBUSY; - dispc.user_handler = handler; - dispc.user_data = dev_id; + dispc->user_handler = handler; + dispc->user_data = dev_id; /* ensure the dispc_irq_handler sees the values above */ smp_wmb(); - r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler, - IRQF_SHARED, "OMAP DISPC", &dispc); + r = devm_request_irq(&dispc->pdev->dev, dispc->irq, dispc_irq_handler, + IRQF_SHARED, "OMAP DISPC", dispc); if (r) { - dispc.user_handler = NULL; - dispc.user_data = NULL; + dispc->user_handler = NULL; + dispc->user_data = NULL; } return r; } -static void dispc_free_irq(void *dev_id) +static void dispc_free_irq(struct dispc_device *dispc, void *dev_id) { - devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc); + devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc); - dispc.user_handler = NULL; - dispc.user_data = NULL; + dispc->user_handler = NULL; + dispc->user_data = NULL; } -static u32 dispc_get_memory_bandwidth_limit(void) +static u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc) { u32 limit = 0; /* Optional maximum memory bandwidth */ - of_property_read_u32(dispc.pdev->dev.of_node, "max-memory-bandwidth", + of_property_read_u32(dispc->pdev->dev.of_node, "max-memory-bandwidth", &limit); return limit; @@ -4405,18 +4621,19 @@ static struct i734_buf { void *vaddr; } i734_buf; -static int dispc_errata_i734_wa_init(void) +static int dispc_errata_i734_wa_init(struct dispc_device *dispc) { - if (!dispc.feat->has_gamma_i734_bug) + if (!dispc->feat->has_gamma_i734_bug) return 0; i734_buf.size = i734.ovli.width * i734.ovli.height * color_mode_to_bpp(i734.ovli.fourcc) / 8; - i734_buf.vaddr = dma_alloc_writecombine(&dispc.pdev->dev, i734_buf.size, - &i734_buf.paddr, GFP_KERNEL); + i734_buf.vaddr = dma_alloc_writecombine(&dispc->pdev->dev, + i734_buf.size, &i734_buf.paddr, + GFP_KERNEL); if (!i734_buf.vaddr) { - dev_err(&dispc.pdev->dev, "%s: dma_alloc_writecombine failed", + dev_err(&dispc->pdev->dev, "%s: dma_alloc_writecombine failed", __func__); return -ENOMEM; } @@ -4424,72 +4641,73 @@ static int dispc_errata_i734_wa_init(void) return 0; } -static void dispc_errata_i734_wa_fini(void) +static void dispc_errata_i734_wa_fini(struct dispc_device *dispc) { - if (!dispc.feat->has_gamma_i734_bug) + if (!dispc->feat->has_gamma_i734_bug) return; - dma_free_writecombine(&dispc.pdev->dev, i734_buf.size, i734_buf.vaddr, + dma_free_writecombine(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr, i734_buf.paddr); } -static void dispc_errata_i734_wa(void) +static void dispc_errata_i734_wa(struct dispc_device *dispc) { - u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD); + u32 framedone_irq = dispc_mgr_get_framedone_irq(dispc, + OMAP_DSS_CHANNEL_LCD); struct omap_overlay_info ovli; struct dss_lcd_mgr_config lcd_conf; u32 gatestate; unsigned int count; - if (!dispc.feat->has_gamma_i734_bug) + if (!dispc->feat->has_gamma_i734_bug) return; - gatestate = REG_GET(DISPC_CONFIG, 8, 4); + gatestate = REG_GET(dispc, DISPC_CONFIG, 8, 4); ovli = i734.ovli; ovli.paddr = i734_buf.paddr; lcd_conf = i734.lcd_conf; /* Gate all LCD1 outputs */ - REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4); + REG_FLD_MOD(dispc, DISPC_CONFIG, 0x1f, 8, 4); /* Setup and enable GFX plane */ - dispc_ovl_setup(OMAP_DSS_GFX, &ovli, &i734.vm, false, - OMAP_DSS_CHANNEL_LCD); - dispc_ovl_enable(OMAP_DSS_GFX, true); + dispc_ovl_setup(dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false, + OMAP_DSS_CHANNEL_LCD); + dispc_ovl_enable(dispc, OMAP_DSS_GFX, true); /* Set up and enable display manager for LCD1 */ - dispc_mgr_setup(OMAP_DSS_CHANNEL_LCD, &i734.mgri); - dispc_calc_clock_rates(dss_get_dispc_clk_rate(), + dispc_mgr_setup(dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri); + dispc_calc_clock_rates(dispc, dss_get_dispc_clk_rate(dispc->dss), &lcd_conf.clock_info); - dispc_mgr_set_lcd_config(OMAP_DSS_CHANNEL_LCD, &lcd_conf); - dispc_mgr_set_timings(OMAP_DSS_CHANNEL_LCD, &i734.vm); + dispc_mgr_set_lcd_config(dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf); + dispc_mgr_set_timings(dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm); - dispc_clear_irqstatus(framedone_irq); + dispc_clear_irqstatus(dispc, framedone_irq); /* Enable and shut the channel to produce just one frame */ - dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, true); - dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, false); + dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, true); + dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, false); /* Busy wait for framedone. We can't fiddle with irq handlers * in PM resume. Typically the loop runs less than 5 times and * waits less than a micro second. */ count = 0; - while (!(dispc_read_irqstatus() & framedone_irq)) { + while (!(dispc_read_irqstatus(dispc) & framedone_irq)) { if (count++ > 10000) { - dev_err(&dispc.pdev->dev, "%s: framedone timeout\n", + dev_err(&dispc->pdev->dev, "%s: framedone timeout\n", __func__); break; } } - dispc_ovl_enable(OMAP_DSS_GFX, false); + dispc_ovl_enable(dispc, OMAP_DSS_GFX, false); /* Clear all irq bits before continuing */ - dispc_clear_irqstatus(0xffffffff); + dispc_clear_irqstatus(dispc, 0xffffffff); /* Restore the original state to LCD1 output gates */ - REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4); + REG_FLD_MOD(dispc, DISPC_CONFIG, gatestate, 8, 4); } static const struct dispc_ops dispc_ops = { @@ -4525,6 +4743,12 @@ static const struct dispc_ops dispc_ops = { .ovl_enable = dispc_ovl_enable, .ovl_setup = dispc_ovl_setup, .ovl_get_color_modes = dispc_ovl_get_color_modes, + + .wb_get_framedone_irq = dispc_wb_get_framedone_irq, + .wb_setup = dispc_wb_setup, + .has_writeback = dispc_has_writeback, + .wb_go_busy = dispc_wb_go_busy, + .wb_go = dispc_wb_go, }; /* DISPC HW IP initialisation */ @@ -4550,14 +4774,22 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); const struct soc_device_attribute *soc; + struct dss_device *dss = dss_get_device(master); + struct dispc_device *dispc; u32 rev; int r = 0; struct resource *dispc_mem; struct device_node *np = pdev->dev.of_node; - dispc.pdev = pdev; + dispc = kzalloc(sizeof(*dispc), GFP_KERNEL); + if (!dispc) + return -ENOMEM; + + dispc->pdev = pdev; + platform_set_drvdata(pdev, dispc); + dispc->dss = dss; - spin_lock_init(&dispc.control_lock); + spin_lock_init(&dispc->control_lock); /* * The OMAP3-based models can't be told apart using the compatible @@ -4565,76 +4797,92 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) */ soc = soc_device_match(dispc_soc_devices); if (soc) - dispc.feat = soc->data; + dispc->feat = soc->data; else - dispc.feat = of_match_device(dispc_of_match, &pdev->dev)->data; + dispc->feat = of_match_device(dispc_of_match, &pdev->dev)->data; - r = dispc_errata_i734_wa_init(); + r = dispc_errata_i734_wa_init(dispc); if (r) - return r; + goto err_free; - dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); - dispc.base = devm_ioremap_resource(&pdev->dev, dispc_mem); - if (IS_ERR(dispc.base)) - return PTR_ERR(dispc.base); + dispc_mem = platform_get_resource(dispc->pdev, IORESOURCE_MEM, 0); + dispc->base = devm_ioremap_resource(&pdev->dev, dispc_mem); + if (IS_ERR(dispc->base)) { + r = PTR_ERR(dispc->base); + goto err_free; + } - dispc.irq = platform_get_irq(dispc.pdev, 0); - if (dispc.irq < 0) { + dispc->irq = platform_get_irq(dispc->pdev, 0); + if (dispc->irq < 0) { DSSERR("platform_get_irq failed\n"); - return -ENODEV; + r = -ENODEV; + goto err_free; } if (np && of_property_read_bool(np, "syscon-pol")) { - dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol"); - if (IS_ERR(dispc.syscon_pol)) { + dispc->syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol"); + if (IS_ERR(dispc->syscon_pol)) { dev_err(&pdev->dev, "failed to get syscon-pol regmap\n"); - return PTR_ERR(dispc.syscon_pol); + r = PTR_ERR(dispc->syscon_pol); + goto err_free; } if (of_property_read_u32_index(np, "syscon-pol", 1, - &dispc.syscon_pol_offset)) { + &dispc->syscon_pol_offset)) { dev_err(&pdev->dev, "failed to get syscon-pol offset\n"); - return -EINVAL; + r = -EINVAL; + goto err_free; } } - r = dispc_init_gamma_tables(); + r = dispc_init_gamma_tables(dispc); if (r) - return r; + goto err_free; pm_runtime_enable(&pdev->dev); - r = dispc_runtime_get(); + r = dispc_runtime_get(dispc); if (r) goto err_runtime_get; - _omap_dispc_initial_config(); + _omap_dispc_initial_config(dispc); - rev = dispc_read_reg(DISPC_REVISION); + rev = dispc_read_reg(dispc, DISPC_REVISION); dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - dispc_runtime_put(); + dispc_runtime_put(dispc); - dispc_set_ops(&dispc_ops); + dss->dispc = dispc; + dss->dispc_ops = &dispc_ops; - dss_debugfs_create_file("dispc", dispc_dump_regs); + dispc->debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, + dispc); return 0; err_runtime_get: pm_runtime_disable(&pdev->dev); +err_free: + kfree(dispc); return r; } -static void dispc_unbind(struct device *dev, struct device *master, - void *data) +static void dispc_unbind(struct device *dev, struct device *master, void *data) { - dispc_set_ops(NULL); + struct dispc_device *dispc = dev_get_drvdata(dev); + struct dss_device *dss = dispc->dss; + + dss_debugfs_remove_file(dispc->debugfs); + + dss->dispc = NULL; + dss->dispc_ops = NULL; pm_runtime_disable(dev); - dispc_errata_i734_wa_fini(); + dispc_errata_i734_wa_fini(dispc); + + kfree(dispc); } static const struct component_ops dispc_component_ops = { @@ -4655,36 +4903,40 @@ static int dispc_remove(struct platform_device *pdev) static int dispc_runtime_suspend(struct device *dev) { - dispc.is_enabled = false; + struct dispc_device *dispc = dev_get_drvdata(dev); + + dispc->is_enabled = false; /* ensure the dispc_irq_handler sees the is_enabled value */ smp_wmb(); /* wait for current handler to finish before turning the DISPC off */ - synchronize_irq(dispc.irq); + synchronize_irq(dispc->irq); - dispc_save_context(); + dispc_save_context(dispc); return 0; } static int dispc_runtime_resume(struct device *dev) { + struct dispc_device *dispc = dev_get_drvdata(dev); + /* * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME) * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in * _omap_dispc_initial_config(). We can thus use it to detect if * we have lost register context. */ - if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { - _omap_dispc_initial_config(); + if (REG_GET(dispc, DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { + _omap_dispc_initial_config(dispc); - dispc_errata_i734_wa(); + dispc_errata_i734_wa(dispc); - dispc_restore_context(); + dispc_restore_context(dispc); - dispc_restore_gamma_tables(); + dispc_restore_gamma_tables(dispc); } - dispc.is_enabled = true; + dispc->is_enabled = true; /* ensure the dispc_irq_handler sees the is_enabled value */ smp_wmb(); diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 0c9480ba85c0..424143128cd4 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -28,12 +28,11 @@ #include "omapdss.h" -void omapdss_default_get_timings(struct omap_dss_device *dssdev, - struct videomode *vm) +static void omapdss_default_get_timings(struct omap_dss_device *dssdev, + struct videomode *vm) { *vm = dssdev->panel.vm; } -EXPORT_SYMBOL(omapdss_default_get_timings); static LIST_HEAD(panel_list); static DEFINE_MUTEX(panel_list_mutex); diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index ea44137ed08c..fb1c27f69e3a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -38,6 +38,7 @@ struct dpi_data { struct platform_device *pdev; enum dss_model dss_model; + struct dss_device *dss; struct regulator *vdds_dsi_reg; enum dss_clk_source clk_src; @@ -57,7 +58,8 @@ static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) return container_of(dssdev, struct dpi_data, output); } -static enum dss_clk_source dpi_get_clk_src_dra7xx(enum omap_channel channel) +static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi, + enum omap_channel channel) { /* * Possible clock sources: @@ -69,23 +71,23 @@ static enum dss_clk_source dpi_get_clk_src_dra7xx(enum omap_channel channel) switch (channel) { case OMAP_DSS_CHANNEL_LCD: { - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_1)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1)) return DSS_CLK_SRC_PLL1_1; break; } case OMAP_DSS_CHANNEL_LCD2: { - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_3)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3)) return DSS_CLK_SRC_PLL1_3; - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL2_3)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3)) return DSS_CLK_SRC_PLL2_3; break; } case OMAP_DSS_CHANNEL_LCD3: { - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL2_1)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1)) return DSS_CLK_SRC_PLL2_1; - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_3)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3)) return DSS_CLK_SRC_PLL1_3; break; } @@ -132,7 +134,7 @@ static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi) } case DSS_MODEL_DRA7: - return dpi_get_clk_src_dra7xx(channel); + return dpi_get_clk_src_dra7xx(dpi, channel); default: return DSS_CLK_SRC_FCK; @@ -141,7 +143,7 @@ static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi) struct dpi_clk_calc_ctx { struct dss_pll *pll; - unsigned clkout_idx; + unsigned int clkout_idx; /* inputs */ @@ -189,8 +191,9 @@ static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc, ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc; ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc; - return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->pll->dss->dispc, dispc, + ctx->pck_min, ctx->pck_max, + dpi_calc_dispc_cb, ctx); } @@ -206,7 +209,7 @@ static bool dpi_calc_pll_cb(int n, int m, unsigned long fint, ctx->pll_cinfo.clkdco = clkdco; return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, - ctx->pck_min, dss_get_max_fck_rate(), + ctx->pck_min, dss_get_max_fck_rate(ctx->pll->dss), dpi_calc_hsdiv_cb, ctx); } @@ -216,8 +219,9 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) ctx->fck = fck; - return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->pll->dss->dispc, fck, + ctx->pck_min, ctx->pck_max, + dpi_calc_dispc_cb, ctx); } static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck, @@ -255,7 +259,8 @@ static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck, } } -static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) +static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck, + struct dpi_clk_calc_ctx *ctx) { int i; @@ -276,7 +281,8 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) ctx->pck_min = 0; ctx->pck_max = pck + 1000 * i * i * i; - ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx); + ok = dss_div_calc(dpi->dss, pck, ctx->pck_min, + dpi_calc_dss_cb, ctx); if (ok) return ok; } @@ -302,7 +308,7 @@ static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, if (r) return r; - dss_select_lcd_clk_source(channel, dpi->clk_src); + dss_select_lcd_clk_source(dpi->dss, channel, dpi->clk_src); dpi->mgr_config.clock_info = ctx.dispc_cinfo; @@ -320,11 +326,11 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, int r; bool ok; - ok = dpi_dss_clk_calc(pck_req, &ctx); + ok = dpi_dss_clk_calc(dpi, pck_req, &ctx); if (!ok) return -EINVAL; - r = dss_set_fck_rate(ctx.fck); + r = dss_set_fck_rate(dpi->dss, ctx.fck); if (r) return r; @@ -339,8 +345,6 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, static int dpi_set_mode(struct dpi_data *dpi) { - struct omap_dss_device *out = &dpi->output; - enum omap_channel channel = out->dispc_channel; struct videomode *vm = &dpi->vm; int lck_div = 0, pck_div = 0; unsigned long fck = 0; @@ -348,8 +352,8 @@ static int dpi_set_mode(struct dpi_data *dpi) int r = 0; if (dpi->pll) - r = dpi_set_pll_clk(dpi, channel, vm->pixelclock, &fck, - &lck_div, &pck_div); + r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel, + vm->pixelclock, &fck, &lck_div, &pck_div); else r = dpi_set_dispc_clk(dpi, vm->pixelclock, &fck, &lck_div, &pck_div); @@ -365,16 +369,13 @@ static int dpi_set_mode(struct dpi_data *dpi) vm->pixelclock = pck; } - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&dpi->output, vm); return 0; } static void dpi_config_lcd_manager(struct dpi_data *dpi) { - struct omap_dss_device *out = &dpi->output; - enum omap_channel channel = out->dispc_channel; - dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dpi->mgr_config.stallmode = false; @@ -384,14 +385,13 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dpi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(channel, &dpi->mgr_config); + dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config); } static int dpi_display_enable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); struct omap_dss_device *out = &dpi->output; - enum omap_channel channel = out->dispc_channel; int r; mutex_lock(&dpi->lock); @@ -408,11 +408,11 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) goto err_reg_enable; } - r = dispc_runtime_get(); + r = dispc_runtime_get(dpi->dss->dispc); if (r) goto err_get_dispc; - r = dss_dpi_select_source(out->port_num, channel); + r = dss_dpi_select_source(dpi->dss, out->port_num, out->dispc_channel); if (r) goto err_src_sel; @@ -430,7 +430,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&dpi->output); if (r) goto err_mgr_enable; @@ -444,7 +444,7 @@ err_set_mode: dss_pll_disable(dpi->pll); err_pll_init: err_src_sel: - dispc_runtime_put(); + dispc_runtime_put(dpi->dss->dispc); err_get_dispc: if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); @@ -457,18 +457,18 @@ err_no_out_mgr: static void dpi_display_disable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - enum omap_channel channel = dpi->output.dispc_channel; mutex_lock(&dpi->lock); - dss_mgr_disable(channel); + dss_mgr_disable(&dpi->output); if (dpi->pll) { - dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel, + DSS_CLK_SRC_FCK); dss_pll_disable(dpi->pll); } - dispc_runtime_put(); + dispc_runtime_put(dpi->dss->dispc); if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); @@ -516,7 +516,7 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, if (vm->hactive % 8 != 0) return -EINVAL; - if (!dispc_mgr_timings_ok(channel, vm)) + if (!dispc_mgr_timings_ok(dpi->dss->dispc, channel, vm)) return -EINVAL; if (vm->pixelclock == 0) @@ -529,7 +529,7 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; } else { - ok = dpi_dss_clk_calc(vm->pixelclock, &ctx); + ok = dpi_dss_clk_calc(dpi, vm->pixelclock, &ctx); if (!ok) return -EINVAL; @@ -602,7 +602,7 @@ static void dpi_init_pll(struct dpi_data *dpi) dpi->clk_src = dpi_get_clk_src(dpi); - pll = dss_pll_find_by_src(dpi->clk_src); + pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); if (!pll) return; @@ -654,7 +654,6 @@ static int dpi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - enum omap_channel channel = dpi->output.dispc_channel; int r; r = dpi_init_regulator(dpi); @@ -663,7 +662,7 @@ static int dpi_connect(struct omap_dss_device *dssdev, dpi_init_pll(dpi); - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&dpi->output, dssdev); if (r) return r; @@ -671,7 +670,7 @@ static int dpi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&dpi->output, dssdev); return r; } @@ -682,7 +681,6 @@ static void dpi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - enum omap_channel channel = dpi->output.dispc_channel; WARN_ON(dst != dssdev->dst); @@ -691,7 +689,7 @@ static void dpi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&dpi->output, dssdev); } static const struct omapdss_dpi_ops dpi_ops = { @@ -748,8 +746,8 @@ static void dpi_uninit_output_port(struct device_node *port) omapdss_unregister_output(out); } -int dpi_init_port(struct platform_device *pdev, struct device_node *port, - enum dss_model dss_model) +int dpi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port, enum dss_model dss_model) { struct dpi_data *dpi; struct device_node *ep; @@ -776,6 +774,7 @@ int dpi_init_port(struct platform_device *pdev, struct device_node *port, dpi->pdev = pdev; dpi->dss_model = dss_model; + dpi->dss = dss; port->data = dpi; mutex_init(&dpi->lock); diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 80f1f3679a3c..d4a680629825 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -119,11 +119,11 @@ struct dsi_reg { u16 module; u16 idx; }; #define DSI_PLL_CONFIGURATION1 DSI_REG(DSI_PLL, 0x000C) #define DSI_PLL_CONFIGURATION2 DSI_REG(DSI_PLL, 0x0010) -#define REG_GET(dsidev, idx, start, end) \ - FLD_GET(dsi_read_reg(dsidev, idx), start, end) +#define REG_GET(dsi, idx, start, end) \ + FLD_GET(dsi_read_reg(dsi, idx), start, end) -#define REG_FLD_MOD(dsidev, idx, val, start, end) \ - dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end)) +#define REG_FLD_MOD(dsi, idx, val, start, end) \ + dsi_write_reg(dsi, idx, FLD_MOD(dsi_read_reg(dsi, idx), val, start, end)) /* Global interrupts */ #define DSI_IRQ_VC0 (1 << 0) @@ -213,13 +213,12 @@ struct dsi_reg { u16 module; u16 idx; }; DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5) typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); +struct dsi_data; -static int dsi_display_init_dispc(struct platform_device *dsidev, - enum omap_channel channel); -static void dsi_display_uninit_dispc(struct platform_device *dsidev, - enum omap_channel channel); +static int dsi_display_init_dispc(struct dsi_data *dsi); +static void dsi_display_uninit_dispc(struct dsi_data *dsi); -static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); +static int dsi_vc_send_null(struct dsi_data *dsi, int channel); /* DSI PLL HSDIV indices */ #define HSDIV_DISPC 0 @@ -269,10 +268,10 @@ enum dsi_vc_source { struct dsi_irq_stats { unsigned long last_reset; - unsigned irq_count; - unsigned dsi_irqs[32]; - unsigned vc_irqs[4][32]; - unsigned cio_irqs[32]; + unsigned int irq_count; + unsigned int dsi_irqs[32]; + unsigned int vc_irqs[4][32]; + unsigned int cio_irqs[32]; }; struct dsi_isr_tables { @@ -282,7 +281,7 @@ struct dsi_isr_tables { }; struct dsi_clk_calc_ctx { - struct platform_device *dsidev; + struct dsi_data *dsi; struct dss_pll *pll; /* inputs */ @@ -329,7 +328,7 @@ struct dsi_of_data { }; struct dsi_data { - struct platform_device *pdev; + struct device *dev; void __iomem *proto_base; void __iomem *phy_base; void __iomem *pll_base; @@ -343,6 +342,7 @@ struct dsi_data { struct clk *dss_clk; struct regmap *syscon; + struct dss_device *dss; struct dispc_clock_info user_dispc_cinfo; struct dss_pll_clock_info user_dsi_cinfo; @@ -373,7 +373,7 @@ struct dsi_data { int update_channel; #ifdef DSI_PERF_MEASURE - unsigned update_bytes; + unsigned int update_bytes; #endif bool te_enabled; @@ -400,19 +400,23 @@ struct dsi_data { #endif int debug_read; int debug_write; + struct { + struct dss_debugfs_entry *irqs; + struct dss_debugfs_entry *regs; + } debugfs; #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spinlock_t irq_stats_lock; struct dsi_irq_stats irq_stats; #endif - unsigned num_lanes_supported; - unsigned line_buffer_size; + unsigned int num_lanes_supported; + unsigned int line_buffer_size; struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; - unsigned num_lanes_used; + unsigned int num_lanes_used; - unsigned scp_clk_refcount; + unsigned int scp_clk_refcount; struct dss_lcd_mgr_config mgr_config; struct videomode vm; @@ -424,7 +428,7 @@ struct dsi_data { }; struct dsi_packet_sent_handler_data { - struct platform_device *dsidev; + struct dsi_data *dsi; struct completion *completion; }; @@ -433,17 +437,12 @@ static bool dsi_perf; module_param(dsi_perf, bool, 0644); #endif -static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev) +static inline struct dsi_data *to_dsi_data(struct omap_dss_device *dssdev) { - return dev_get_drvdata(&dsidev->dev); + return dev_get_drvdata(dssdev->dev); } -static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) -{ - return to_platform_device(dssdev->dev); -} - -static struct platform_device *dsi_get_dsidev_from_id(int module) +static struct dsi_data *dsi_get_dsi_from_id(int module) { struct omap_dss_device *out; enum omap_dss_output_id id; @@ -461,13 +460,12 @@ static struct platform_device *dsi_get_dsidev_from_id(int module) out = omap_dss_get_output(id); - return out ? to_platform_device(out->dev) : NULL; + return out ? to_dsi_data(out) : NULL; } -static inline void dsi_write_reg(struct platform_device *dsidev, - const struct dsi_reg idx, u32 val) +static inline void dsi_write_reg(struct dsi_data *dsi, + const struct dsi_reg idx, u32 val) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); void __iomem *base; switch(idx.module) { @@ -480,10 +478,8 @@ static inline void dsi_write_reg(struct platform_device *dsidev, __raw_writel(val, base + idx.idx); } -static inline u32 dsi_read_reg(struct platform_device *dsidev, - const struct dsi_reg idx) +static inline u32 dsi_read_reg(struct dsi_data *dsi, const struct dsi_reg idx) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); void __iomem *base; switch(idx.module) { @@ -498,24 +494,20 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev, static void dsi_bus_lock(struct omap_dss_device *dssdev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); down(&dsi->bus_lock); } static void dsi_bus_unlock(struct omap_dss_device *dssdev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); up(&dsi->bus_lock); } -static bool dsi_bus_is_locked(struct platform_device *dsidev) +static bool dsi_bus_is_locked(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->bus_lock.count == 0; } @@ -524,8 +516,9 @@ static void dsi_completion_handler(void *data, u32 mask) complete((struct completion *)data); } -static inline int wait_for_bit_change(struct platform_device *dsidev, - const struct dsi_reg idx, int bitnum, int value) +static inline bool wait_for_bit_change(struct dsi_data *dsi, + const struct dsi_reg idx, + int bitnum, int value) { unsigned long timeout; ktime_t wait; @@ -534,22 +527,22 @@ static inline int wait_for_bit_change(struct platform_device *dsidev, /* first busyloop to see if the bit changes right away */ t = 100; while (t-- > 0) { - if (REG_GET(dsidev, idx, bitnum, bitnum) == value) - return value; + if (REG_GET(dsi, idx, bitnum, bitnum) == value) + return true; } /* then loop for 500ms, sleeping for 1ms in between */ timeout = jiffies + msecs_to_jiffies(500); while (time_before(jiffies, timeout)) { - if (REG_GET(dsidev, idx, bitnum, bitnum) == value) - return value; + if (REG_GET(dsi, idx, bitnum, bitnum) == value) + return true; wait = ns_to_ktime(1000 * 1000); set_current_state(TASK_UNINTERRUPTIBLE); schedule_hrtimeout(&wait, HRTIMER_MODE_REL); } - return !value; + return false; } static u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) @@ -569,21 +562,18 @@ static u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) } #ifdef DSI_PERF_MEASURE -static void dsi_perf_mark_setup(struct platform_device *dsidev) +static void dsi_perf_mark_setup(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); dsi->perf_setup_time = ktime_get(); } -static void dsi_perf_mark_start(struct platform_device *dsidev) +static void dsi_perf_mark_start(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); dsi->perf_start_time = ktime_get(); } -static void dsi_perf_show(struct platform_device *dsidev, const char *name) +static void dsi_perf_show(struct dsi_data *dsi, const char *name) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); ktime_t t, setup_time, trans_time; u32 total_bytes; u32 setup_us, trans_us, total_us; @@ -617,16 +607,15 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_bytes * 1000 / total_us); } #else -static inline void dsi_perf_mark_setup(struct platform_device *dsidev) +static inline void dsi_perf_mark_setup(struct dsi_data *dsi) { } -static inline void dsi_perf_mark_start(struct platform_device *dsidev) +static inline void dsi_perf_mark_start(struct dsi_data *dsi) { } -static inline void dsi_perf_show(struct platform_device *dsidev, - const char *name) +static inline void dsi_perf_show(struct dsi_data *dsi, const char *name) { } #endif @@ -723,10 +712,9 @@ static void print_irq_status_cio(u32 status) } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus, - u32 *vcstatus, u32 ciostatus) +static void dsi_collect_irq_stats(struct dsi_data *dsi, u32 irqstatus, + u32 *vcstatus, u32 ciostatus) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; spin_lock(&dsi->irq_stats_lock); @@ -742,15 +730,14 @@ static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus, spin_unlock(&dsi->irq_stats_lock); } #else -#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus) +#define dsi_collect_irq_stats(dsi, irqstatus, vcstatus, ciostatus) #endif static int debug_irq; -static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus, - u32 *vcstatus, u32 ciostatus) +static void dsi_handle_irq_errors(struct dsi_data *dsi, u32 irqstatus, + u32 *vcstatus, u32 ciostatus) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; if (irqstatus & DSI_IRQ_ERROR_MASK) { @@ -782,7 +769,7 @@ static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus, } static void dsi_call_isrs(struct dsi_isr_data *isr_array, - unsigned isr_array_size, u32 irqstatus) + unsigned int isr_array_size, u32 irqstatus) { struct dsi_isr_data *isr_data; int i; @@ -819,20 +806,16 @@ static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables, static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) { - struct platform_device *dsidev; - struct dsi_data *dsi; + struct dsi_data *dsi = arg; u32 irqstatus, vcstatus[4], ciostatus; int i; - dsidev = (struct platform_device *) arg; - dsi = dsi_get_dsidrv_data(dsidev); - if (!dsi->is_enabled) return IRQ_NONE; spin_lock(&dsi->irq_lock); - irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS); + irqstatus = dsi_read_reg(dsi, DSI_IRQSTATUS); /* IRQ is not for us */ if (!irqstatus) { @@ -840,9 +823,9 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) return IRQ_NONE; } - dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); + dsi_write_reg(dsi, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); /* flush posted write */ - dsi_read_reg(dsidev, DSI_IRQSTATUS); + dsi_read_reg(dsi, DSI_IRQSTATUS); for (i = 0; i < 4; ++i) { if ((irqstatus & (1 << i)) == 0) { @@ -850,19 +833,19 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) continue; } - vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i)); + vcstatus[i] = dsi_read_reg(dsi, DSI_VC_IRQSTATUS(i)); - dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]); + dsi_write_reg(dsi, DSI_VC_IRQSTATUS(i), vcstatus[i]); /* flush posted write */ - dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i)); + dsi_read_reg(dsi, DSI_VC_IRQSTATUS(i)); } if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) { - ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS); + ciostatus = dsi_read_reg(dsi, DSI_COMPLEXIO_IRQ_STATUS); - dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus); + dsi_write_reg(dsi, DSI_COMPLEXIO_IRQ_STATUS, ciostatus); /* flush posted write */ - dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS); + dsi_read_reg(dsi, DSI_COMPLEXIO_IRQ_STATUS); } else { ciostatus = 0; } @@ -881,19 +864,20 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus); - dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus); + dsi_handle_irq_errors(dsi, irqstatus, vcstatus, ciostatus); - dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus); + dsi_collect_irq_stats(dsi, irqstatus, vcstatus, ciostatus); return IRQ_HANDLED; } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_configure_irqs(struct platform_device *dsidev, - struct dsi_isr_data *isr_array, - unsigned isr_array_size, u32 default_mask, - const struct dsi_reg enable_reg, - const struct dsi_reg status_reg) +static void _omap_dsi_configure_irqs(struct dsi_data *dsi, + struct dsi_isr_data *isr_array, + unsigned int isr_array_size, + u32 default_mask, + const struct dsi_reg enable_reg, + const struct dsi_reg status_reg) { struct dsi_isr_data *isr_data; u32 mask; @@ -911,54 +895,48 @@ static void _omap_dsi_configure_irqs(struct platform_device *dsidev, mask |= isr_data->mask; } - old_mask = dsi_read_reg(dsidev, enable_reg); + old_mask = dsi_read_reg(dsi, enable_reg); /* clear the irqstatus for newly enabled irqs */ - dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask); - dsi_write_reg(dsidev, enable_reg, mask); + dsi_write_reg(dsi, status_reg, (mask ^ old_mask) & mask); + dsi_write_reg(dsi, enable_reg, mask); /* flush posted writes */ - dsi_read_reg(dsidev, enable_reg); - dsi_read_reg(dsidev, status_reg); + dsi_read_reg(dsi, enable_reg); + dsi_read_reg(dsi, status_reg); } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs(struct platform_device *dsidev) +static void _omap_dsi_set_irqs(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 mask = DSI_IRQ_ERROR_MASK; #ifdef DSI_CATCH_MISSING_TE mask |= DSI_IRQ_TE_TRIGGER; #endif - _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table, + _omap_dsi_configure_irqs(dsi, dsi->isr_tables.isr_table, ARRAY_SIZE(dsi->isr_tables.isr_table), mask, DSI_IRQENABLE, DSI_IRQSTATUS); } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc) +static void _omap_dsi_set_irqs_vc(struct dsi_data *dsi, int vc) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc], + _omap_dsi_configure_irqs(dsi, dsi->isr_tables.isr_table_vc[vc], ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]), DSI_VC_IRQ_ERROR_MASK, DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc)); } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev) +static void _omap_dsi_set_irqs_cio(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio, + _omap_dsi_configure_irqs(dsi, dsi->isr_tables.isr_table_cio, ARRAY_SIZE(dsi->isr_tables.isr_table_cio), DSI_CIO_IRQ_ERROR_MASK, DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS); } -static void _dsi_initialize_irq(struct platform_device *dsidev) +static void _dsi_initialize_irq(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int vc; @@ -966,16 +944,16 @@ static void _dsi_initialize_irq(struct platform_device *dsidev) memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables)); - _omap_dsi_set_irqs(dsidev); + _omap_dsi_set_irqs(dsi); for (vc = 0; vc < 4; ++vc) - _omap_dsi_set_irqs_vc(dsidev, vc); - _omap_dsi_set_irqs_cio(dsidev); + _omap_dsi_set_irqs_vc(dsi, vc); + _omap_dsi_set_irqs_cio(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); } static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask, - struct dsi_isr_data *isr_array, unsigned isr_array_size) + struct dsi_isr_data *isr_array, unsigned int isr_array_size) { struct dsi_isr_data *isr_data; int free_idx; @@ -1009,7 +987,7 @@ static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask, } static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask, - struct dsi_isr_data *isr_array, unsigned isr_array_size) + struct dsi_isr_data *isr_array, unsigned int isr_array_size) { struct dsi_isr_data *isr_data; int i; @@ -1030,10 +1008,9 @@ static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask, return -EINVAL; } -static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr, - void *arg, u32 mask) +static int dsi_register_isr(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1043,17 +1020,16 @@ static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr, ARRAY_SIZE(dsi->isr_tables.isr_table)); if (r == 0) - _omap_dsi_set_irqs(dsidev); + _omap_dsi_set_irqs(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_unregister_isr(struct platform_device *dsidev, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_unregister_isr(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1063,17 +1039,16 @@ static int dsi_unregister_isr(struct platform_device *dsidev, ARRAY_SIZE(dsi->isr_tables.isr_table)); if (r == 0) - _omap_dsi_set_irqs(dsidev); + _omap_dsi_set_irqs(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_register_isr_vc(struct platform_device *dsidev, int channel, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_register_isr_vc(struct dsi_data *dsi, int channel, + omap_dsi_isr_t isr, void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1084,17 +1059,16 @@ static int dsi_register_isr_vc(struct platform_device *dsidev, int channel, ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel])); if (r == 0) - _omap_dsi_set_irqs_vc(dsidev, channel); + _omap_dsi_set_irqs_vc(dsi, channel); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_unregister_isr_vc(struct dsi_data *dsi, int channel, + omap_dsi_isr_t isr, void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1105,17 +1079,16 @@ static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel, ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel])); if (r == 0) - _omap_dsi_set_irqs_vc(dsidev, channel); + _omap_dsi_set_irqs_vc(dsi, channel); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_register_isr_cio(struct platform_device *dsidev, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_register_isr_cio(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1125,17 +1098,16 @@ static int dsi_register_isr_cio(struct platform_device *dsidev, ARRAY_SIZE(dsi->isr_tables.isr_table_cio)); if (r == 0) - _omap_dsi_set_irqs_cio(dsidev); + _omap_dsi_set_irqs_cio(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_unregister_isr_cio(struct platform_device *dsidev, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_unregister_isr_cio(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1145,18 +1117,18 @@ static int dsi_unregister_isr_cio(struct platform_device *dsidev, ARRAY_SIZE(dsi->isr_tables.isr_table_cio)); if (r == 0) - _omap_dsi_set_irqs_cio(dsidev); + _omap_dsi_set_irqs_cio(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static u32 dsi_get_errors(struct platform_device *dsidev) +static u32 dsi_get_errors(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; u32 e; + spin_lock_irqsave(&dsi->errors_lock, flags); e = dsi->errors; dsi->errors = 0; @@ -1164,38 +1136,35 @@ static u32 dsi_get_errors(struct platform_device *dsidev) return e; } -static int dsi_runtime_get(struct platform_device *dsidev) +static int dsi_runtime_get(struct dsi_data *dsi) { int r; - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DSSDBG("dsi_runtime_get\n"); - r = pm_runtime_get_sync(&dsi->pdev->dev); + r = pm_runtime_get_sync(dsi->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } -static void dsi_runtime_put(struct platform_device *dsidev) +static void dsi_runtime_put(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; DSSDBG("dsi_runtime_put\n"); - r = pm_runtime_put_sync(&dsi->pdev->dev); + r = pm_runtime_put_sync(dsi->dev); WARN_ON(r < 0 && r != -ENOSYS); } -static int dsi_regulator_init(struct platform_device *dsidev) +static int dsi_regulator_init(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct regulator *vdds_dsi; if (dsi->vdds_dsi_reg != NULL) return 0; - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd"); + vdds_dsi = devm_regulator_get(dsi->dev, "vdd"); if (IS_ERR(vdds_dsi)) { if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) @@ -1208,16 +1177,15 @@ static int dsi_regulator_init(struct platform_device *dsidev) return 0; } -static void _dsi_print_reset_status(struct platform_device *dsidev) +static void _dsi_print_reset_status(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 l; int b0, b1, b2; /* A dummy read using the SCP interface to any DSIPHY register is * required after DSIPHY reset to complete the reset of the DSI complex * I/O. */ - l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); + l = dsi_read_reg(dsi, DSI_DSIPHY_CFG5); if (dsi->data->quirks & DSI_QUIRK_REVERSE_TXCLKESC) { b0 = 28; @@ -1230,7 +1198,7 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) } #define DSI_FLD_GET(fld, start, end)\ - FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end) + FLD_GET(dsi_read_reg(dsi, DSI_##fld), start, end) pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n", DSI_FLD_GET(PLL_STATUS, 0, 0), @@ -1245,53 +1213,48 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) #undef DSI_FLD_GET } -static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) +static inline int dsi_if_enable(struct dsi_data *dsi, bool enable) { DSSDBG("dsi_if_enable(%d)\n", enable); enable = enable ? 1 : 0; - REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */ + REG_FLD_MOD(dsi, DSI_CTRL, enable, 0, 0); /* IF_EN */ - if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) { - DSSERR("Failed to set dsi_if_enable to %d\n", enable); - return -EIO; + if (!wait_for_bit_change(dsi, DSI_CTRL, 0, enable)) { + DSSERR("Failed to set dsi_if_enable to %d\n", enable); + return -EIO; } return 0; } -static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) +static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->pll.cinfo.clkout[HSDIV_DISPC]; } -static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev) +static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->pll.cinfo.clkout[HSDIV_DSI]; } -static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev) +static unsigned long dsi_get_txbyteclkhs(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->pll.cinfo.clkdco / 16; } -static unsigned long dsi_fclk_rate(struct platform_device *dsidev) +static unsigned long dsi_fclk_rate(struct dsi_data *dsi) { unsigned long r; - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + enum dss_clk_source source; - if (dss_get_dsi_clk_source(dsi->module_id) == DSS_CLK_SRC_FCK) { + source = dss_get_dsi_clk_source(dsi->dss, dsi->module_id); + if (source == DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ r = clk_get_rate(dsi->dss_clk); } else { /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ - r = dsi_get_pll_hsdiv_dsi_rate(dsidev); + r = dsi_get_pll_hsdiv_dsi_rate(dsi); } return r; @@ -1301,7 +1264,7 @@ static int dsi_lp_clock_calc(unsigned long dsi_fclk, unsigned long lp_clk_min, unsigned long lp_clk_max, struct dsi_lp_clock_info *lp_cinfo) { - unsigned lp_clk_div; + unsigned int lp_clk_div; unsigned long lp_clk; lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2); @@ -1316,13 +1279,12 @@ static int dsi_lp_clock_calc(unsigned long dsi_fclk, return 0; } -static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) +static int dsi_set_lp_clk_divisor(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long dsi_fclk; - unsigned lp_clk_div; + unsigned int lp_clk_div; unsigned long lp_clk; - unsigned lpdiv_max = dsi->data->max_pll_lpdiv; + unsigned int lpdiv_max = dsi->data->max_pll_lpdiv; lp_clk_div = dsi->user_lp_cinfo.lp_clk_div; @@ -1330,7 +1292,7 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) if (lp_clk_div == 0 || lp_clk_div > lpdiv_max) return -EINVAL; - dsi_fclk = dsi_fclk_rate(dsidev); + dsi_fclk = dsi_fclk_rate(dsi); lp_clk = dsi_fclk / 2 / lp_clk_div; @@ -1339,29 +1301,25 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) dsi->current_lp_cinfo.lp_clk_div = lp_clk_div; /* LP_CLK_DIVISOR */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, lp_clk_div, 12, 0); /* LP_RX_SYNCHRO_ENABLE */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21); return 0; } -static void dsi_enable_scp_clk(struct platform_device *dsidev) +static void dsi_enable_scp_clk(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->scp_clk_refcount++ == 0) - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */ + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */ } -static void dsi_disable_scp_clk(struct platform_device *dsidev) +static void dsi_disable_scp_clk(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - WARN_ON(dsi->scp_clk_refcount == 0); if (--dsi->scp_clk_refcount == 0) - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */ + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */ } enum dsi_pll_power_state { @@ -1371,10 +1329,8 @@ enum dsi_pll_power_state { DSI_PLL_POWER_ON_DIV = 0x3, }; -static int dsi_pll_power(struct platform_device *dsidev, - enum dsi_pll_power_state state) +static int dsi_pll_power(struct dsi_data *dsi, enum dsi_pll_power_state state) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int t = 0; /* DSI-PLL power command 0x3 is not working */ @@ -1383,10 +1339,10 @@ static int dsi_pll_power(struct platform_device *dsidev, state = DSI_PLL_POWER_ON_ALL; /* PLL_PWR_CMD */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_STATUS */ - while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) { + while (FLD_GET(dsi_read_reg(dsi, DSI_CLK_CTRL), 29, 28) != state) { if (++t > 1000) { DSSERR("Failed to set DSI PLL power mode to %d\n", state); @@ -1413,23 +1369,22 @@ static void dsi_pll_calc_dsi_fck(struct dsi_data *dsi, static int dsi_pll_enable(struct dss_pll *pll) { struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); - struct platform_device *dsidev = dsi->pdev; int r = 0; DSSDBG("PLL init\n"); - r = dsi_regulator_init(dsidev); + r = dsi_regulator_init(dsi); if (r) return r; - r = dsi_runtime_get(dsidev); + r = dsi_runtime_get(dsi); if (r) return r; /* * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. */ - dsi_enable_scp_clk(dsidev); + dsi_enable_scp_clk(dsi); if (!dsi->vdds_dsi_enabled) { r = regulator_enable(dsi->vdds_dsi_reg); @@ -1439,20 +1394,20 @@ static int dsi_pll_enable(struct dss_pll *pll) } /* XXX PLL does not come out of reset without this... */ - dispc_pck_free_enable(1); + dispc_pck_free_enable(dsi->dss->dispc, 1); - if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) { + if (!wait_for_bit_change(dsi, DSI_PLL_STATUS, 0, 1)) { DSSERR("PLL not coming out of reset.\n"); r = -ENODEV; - dispc_pck_free_enable(0); + dispc_pck_free_enable(dsi->dss->dispc, 0); goto err1; } /* XXX ... but if left on, we get problems when planes do not * fill the whole display. No idea about this */ - dispc_pck_free_enable(0); + dispc_pck_free_enable(dsi->dss->dispc, 0); - r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL); + r = dsi_pll_power(dsi, DSI_PLL_POWER_ON_ALL); if (r) goto err1; @@ -1466,24 +1421,22 @@ err1: dsi->vdds_dsi_enabled = false; } err0: - dsi_disable_scp_clk(dsidev); - dsi_runtime_put(dsidev); + dsi_disable_scp_clk(dsi); + dsi_runtime_put(dsi); return r; } -static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) +static void dsi_pll_uninit(struct dsi_data *dsi, bool disconnect_lanes) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - dsi_pll_power(dsidev, DSI_PLL_POWER_OFF); + dsi_pll_power(dsi, DSI_PLL_POWER_OFF); if (disconnect_lanes) { WARN_ON(!dsi->vdds_dsi_enabled); regulator_disable(dsi->vdds_dsi_reg); dsi->vdds_dsi_enabled = false; } - dsi_disable_scp_clk(dsidev); - dsi_runtime_put(dsidev); + dsi_disable_scp_clk(dsi); + dsi_runtime_put(dsi); DSSDBG("PLL uninit done\n"); } @@ -1491,24 +1444,21 @@ static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes static void dsi_pll_disable(struct dss_pll *pll) { struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); - struct platform_device *dsidev = dsi->pdev; - dsi_pll_uninit(dsidev, true); + dsi_pll_uninit(dsi, true); } -static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, - struct seq_file *s) +static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo; enum dss_clk_source dispc_clk_src, dsi_clk_src; int dsi_module = dsi->module_id; struct dss_pll *pll = &dsi->pll; - dispc_clk_src = dss_get_dispc_clk_source(); - dsi_clk_src = dss_get_dsi_clk_source(dsi_module); + dispc_clk_src = dss_get_dispc_clk_source(dsi->dss); + dsi_clk_src = dss_get_dsi_clk_source(dsi->dss, dsi_module); - if (dsi_runtime_get(dsidev)) + if (dsi_runtime_get(dsi)) return; seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); @@ -1543,35 +1493,33 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "dsi fclk source = %s\n", dss_get_clk_source_name(dsi_clk_src)); - seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev)); + seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsi)); seq_printf(s, "DDR_CLK\t\t%lu\n", cinfo->clkdco / 4); - seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev)); + seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsi)); seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk); - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); } void dsi_dump_clocks(struct seq_file *s) { - struct platform_device *dsidev; + struct dsi_data *dsi; int i; for (i = 0; i < MAX_NUM_DSI; i++) { - dsidev = dsi_get_dsidev_from_id(i); - if (dsidev) - dsi_dump_dsidev_clocks(dsidev, s); + dsi = dsi_get_dsi_from_id(i); + if (dsi) + dsi_dump_dsi_clocks(dsi, s); } } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, - struct seq_file *s) +static void dsi_dump_dsi_irqs(struct dsi_data *dsi, struct seq_file *s) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; struct dsi_irq_stats stats; @@ -1657,29 +1605,30 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, #undef PIS } -static void dsi1_dump_irqs(struct seq_file *s) +static int dsi1_dump_irqs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(0); + struct dsi_data *dsi = dsi_get_dsi_from_id(0); - dsi_dump_dsidev_irqs(dsidev, s); + dsi_dump_dsi_irqs(dsi, s); + return 0; } -static void dsi2_dump_irqs(struct seq_file *s) +static int dsi2_dump_irqs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(1); + struct dsi_data *dsi = dsi_get_dsi_from_id(1); - dsi_dump_dsidev_irqs(dsidev, s); + dsi_dump_dsi_irqs(dsi, s); + return 0; } #endif -static void dsi_dump_dsidev_regs(struct platform_device *dsidev, - struct seq_file *s) +static void dsi_dump_dsi_regs(struct dsi_data *dsi, struct seq_file *s) { -#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r)) +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsi, r)) - if (dsi_runtime_get(dsidev)) + if (dsi_runtime_get(dsi)) return; - dsi_enable_scp_clk(dsidev); + dsi_enable_scp_clk(dsi); DUMPREG(DSI_REVISION); DUMPREG(DSI_SYSCONFIG); @@ -1751,23 +1700,25 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, DUMPREG(DSI_PLL_CONFIGURATION1); DUMPREG(DSI_PLL_CONFIGURATION2); - dsi_disable_scp_clk(dsidev); - dsi_runtime_put(dsidev); + dsi_disable_scp_clk(dsi); + dsi_runtime_put(dsi); #undef DUMPREG } -static void dsi1_dump_regs(struct seq_file *s) +static int dsi1_dump_regs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(0); + struct dsi_data *dsi = dsi_get_dsi_from_id(0); - dsi_dump_dsidev_regs(dsidev, s); + dsi_dump_dsi_regs(dsi, s); + return 0; } -static void dsi2_dump_regs(struct seq_file *s) +static int dsi2_dump_regs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(1); + struct dsi_data *dsi = dsi_get_dsi_from_id(1); - dsi_dump_dsidev_regs(dsidev, s); + dsi_dump_dsi_regs(dsi, s); + return 0; } enum dsi_cio_power_state { @@ -1776,16 +1727,15 @@ enum dsi_cio_power_state { DSI_COMPLEXIO_POWER_ULPS = 0x2, }; -static int dsi_cio_power(struct platform_device *dsidev, - enum dsi_cio_power_state state) +static int dsi_cio_power(struct dsi_data *dsi, enum dsi_cio_power_state state) { int t = 0; /* PWR_CMD */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27); + REG_FLD_MOD(dsi, DSI_COMPLEXIO_CFG1, state, 28, 27); /* PWR_STATUS */ - while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1), + while (FLD_GET(dsi_read_reg(dsi, DSI_COMPLEXIO_CFG1), 26, 25) != state) { if (++t > 1000) { DSSERR("failed to set complexio power state to " @@ -1798,9 +1748,8 @@ static int dsi_cio_power(struct platform_device *dsidev, return 0; } -static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) +static unsigned int dsi_get_line_buf_size(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int val; /* line buffer on OMAP3 is 1024 x 24bits */ @@ -1810,7 +1759,7 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) if (!(dsi->data->quirks & DSI_QUIRK_GNQ)) return 1023 * 3; - val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */ + val = REG_GET(dsi, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */ switch (val) { case 1: @@ -1833,9 +1782,8 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) } } -static int dsi_set_lane_config(struct platform_device *dsidev) +static int dsi_set_lane_config(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); static const u8 offsets[] = { 0, 4, 8, 12, 16 }; static const enum dsi_lane_function functions[] = { DSI_LANE_CLK, @@ -1847,12 +1795,12 @@ static int dsi_set_lane_config(struct platform_device *dsidev) u32 r; int i; - r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); + r = dsi_read_reg(dsi, DSI_COMPLEXIO_CFG1); for (i = 0; i < dsi->num_lanes_used; ++i) { - unsigned offset = offsets[i]; - unsigned polarity, lane_number; - unsigned t; + unsigned int offset = offsets[i]; + unsigned int polarity, lane_number; + unsigned int t; for (t = 0; t < dsi->num_lanes_supported; ++t) if (dsi->lanes[t].function == functions[i]) @@ -1870,37 +1818,34 @@ static int dsi_set_lane_config(struct platform_device *dsidev) /* clear the unused lanes */ for (; i < dsi->num_lanes_supported; ++i) { - unsigned offset = offsets[i]; + unsigned int offset = offsets[i]; r = FLD_MOD(r, 0, offset + 2, offset); r = FLD_MOD(r, 0, offset + 3, offset + 3); } - dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); + dsi_write_reg(dsi, DSI_COMPLEXIO_CFG1, r); return 0; } -static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) +static inline unsigned int ns2ddr(struct dsi_data *dsi, unsigned int ns) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - /* convert time in ns to ddr ticks, rounding up */ unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4; + return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000; } -static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr) +static inline unsigned int ddr2ns(struct dsi_data *dsi, unsigned int ddr) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4; + return ddr * 1000 * 1000 / (ddr_clk / 1000); } -static void dsi_cio_timings(struct platform_device *dsidev) +static void dsi_cio_timings(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit; u32 tlpx_half, tclk_trail, tclk_zero; @@ -1911,54 +1856,54 @@ static void dsi_cio_timings(struct platform_device *dsidev) /* 1 * DDR_CLK = 2 * UI */ /* min 40ns + 4*UI max 85ns + 6*UI */ - ths_prepare = ns2ddr(dsidev, 70) + 2; + ths_prepare = ns2ddr(dsi, 70) + 2; /* min 145ns + 10*UI */ - ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2; + ths_prepare_ths_zero = ns2ddr(dsi, 175) + 2; /* min max(8*UI, 60ns+4*UI) */ - ths_trail = ns2ddr(dsidev, 60) + 5; + ths_trail = ns2ddr(dsi, 60) + 5; /* min 100ns */ - ths_exit = ns2ddr(dsidev, 145); + ths_exit = ns2ddr(dsi, 145); /* tlpx min 50n */ - tlpx_half = ns2ddr(dsidev, 25); + tlpx_half = ns2ddr(dsi, 25); /* min 60ns */ - tclk_trail = ns2ddr(dsidev, 60) + 2; + tclk_trail = ns2ddr(dsi, 60) + 2; /* min 38ns, max 95ns */ - tclk_prepare = ns2ddr(dsidev, 65); + tclk_prepare = ns2ddr(dsi, 65); /* min tclk-prepare + tclk-zero = 300ns */ - tclk_zero = ns2ddr(dsidev, 260); + tclk_zero = ns2ddr(dsi, 260); DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n", - ths_prepare, ddr2ns(dsidev, ths_prepare), - ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero)); + ths_prepare, ddr2ns(dsi, ths_prepare), + ths_prepare_ths_zero, ddr2ns(dsi, ths_prepare_ths_zero)); DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n", - ths_trail, ddr2ns(dsidev, ths_trail), - ths_exit, ddr2ns(dsidev, ths_exit)); + ths_trail, ddr2ns(dsi, ths_trail), + ths_exit, ddr2ns(dsi, ths_exit)); DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), " "tclk_zero %u (%uns)\n", - tlpx_half, ddr2ns(dsidev, tlpx_half), - tclk_trail, ddr2ns(dsidev, tclk_trail), - tclk_zero, ddr2ns(dsidev, tclk_zero)); + tlpx_half, ddr2ns(dsi, tlpx_half), + tclk_trail, ddr2ns(dsi, tclk_trail), + tclk_zero, ddr2ns(dsi, tclk_zero)); DSSDBG("tclk_prepare %u (%uns)\n", - tclk_prepare, ddr2ns(dsidev, tclk_prepare)); + tclk_prepare, ddr2ns(dsi, tclk_prepare)); /* program timings */ - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG0); r = FLD_MOD(r, ths_prepare, 31, 24); r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16); r = FLD_MOD(r, ths_trail, 15, 8); r = FLD_MOD(r, ths_exit, 7, 0); - dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); + dsi_write_reg(dsi, DSI_DSIPHY_CFG0, r); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); r = FLD_MOD(r, tlpx_half, 20, 16); r = FLD_MOD(r, tclk_trail, 15, 8); r = FLD_MOD(r, tclk_zero, 7, 0); @@ -1969,18 +1914,18 @@ static void dsi_cio_timings(struct platform_device *dsidev) r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ } - dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); + dsi_write_reg(dsi, DSI_DSIPHY_CFG1, r); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG2); r = FLD_MOD(r, tclk_prepare, 7, 0); - dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); + dsi_write_reg(dsi, DSI_DSIPHY_CFG2, r); } /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ -static void dsi_cio_enable_lane_override(struct platform_device *dsidev, - unsigned mask_p, unsigned mask_n) +static void dsi_cio_enable_lane_override(struct dsi_data *dsi, + unsigned int mask_p, + unsigned int mask_n) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; u32 l; u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26; @@ -1988,7 +1933,7 @@ static void dsi_cio_enable_lane_override(struct platform_device *dsidev, l = 0; for (i = 0; i < dsi->num_lanes_supported; ++i) { - unsigned p = dsi->lanes[i].polarity; + unsigned int p = dsi->lanes[i].polarity; if (mask_p & (1 << i)) l |= 1 << (i * 2 + (p ? 0 : 1)); @@ -2009,26 +1954,25 @@ static void dsi_cio_enable_lane_override(struct platform_device *dsidev, /* Set the lane override configuration */ /* REGLPTXSCPDAT4TO0DXDY */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17); + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, l, lptxscp_start, 17); /* Enable lane override */ /* ENLPTXSCPDAT */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27); + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, 1, 27, 27); } -static void dsi_cio_disable_lane_override(struct platform_device *dsidev) +static void dsi_cio_disable_lane_override(struct dsi_data *dsi) { /* Disable lane override */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */ + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */ /* Reset the lane override configuration */ /* REGLPTXSCPDAT4TO0DXDY */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, 0, 22, 17); } -static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) +static int dsi_cio_wait_tx_clk_esc_reset(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int t, i; bool in_use[DSI_MAX_NR_LANES]; static const u8 offsets_old[] = { 28, 27, 26 }; @@ -2048,7 +1992,7 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) u32 l; int ok; - l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); + l = dsi_read_reg(dsi, DSI_DSIPHY_CFG5); ok = 0; for (i = 0; i < dsi->num_lanes_supported; ++i) { @@ -2075,10 +2019,9 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) } /* return bitmask of enabled lanes, lane0 being the lsb */ -static unsigned dsi_get_lane_mask(struct platform_device *dsidev) +static unsigned int dsi_get_lane_mask(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - unsigned mask = 0; + unsigned int mask = 0; int i; for (i = 0; i < dsi->num_lanes_supported; ++i) { @@ -2166,45 +2109,44 @@ static void dsi_disable_pads(struct dsi_data *dsi) dsi_omap5_mux_pads(dsi, 0); } -static int dsi_cio_init(struct platform_device *dsidev) +static int dsi_cio_init(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; u32 l; DSSDBG("DSI CIO init starts"); - r = dsi_enable_pads(dsi, dsi_get_lane_mask(dsidev)); + r = dsi_enable_pads(dsi, dsi_get_lane_mask(dsi)); if (r) return r; - dsi_enable_scp_clk(dsidev); + dsi_enable_scp_clk(dsi); /* A dummy read using the SCP interface to any DSIPHY register is * required after DSIPHY reset to complete the reset of the DSI complex * I/O. */ - dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); + dsi_read_reg(dsi, DSI_DSIPHY_CFG5); - if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) { + if (!wait_for_bit_change(dsi, DSI_DSIPHY_CFG5, 30, 1)) { DSSERR("CIO SCP Clock domain not coming out of reset.\n"); r = -EIO; goto err_scp_clk_dom; } - r = dsi_set_lane_config(dsidev); + r = dsi_set_lane_config(dsi); if (r) goto err_scp_clk_dom; /* set TX STOP MODE timer to maximum for this operation */ - l = dsi_read_reg(dsidev, DSI_TIMING1); + l = dsi_read_reg(dsi, DSI_TIMING1); l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */ l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */ l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */ - dsi_write_reg(dsidev, DSI_TIMING1, l); + dsi_write_reg(dsi, DSI_TIMING1, l); if (dsi->ulps_enabled) { - unsigned mask_p; + unsigned int mask_p; int i; DSSDBG("manual ulps exit\n"); @@ -2226,24 +2168,24 @@ static int dsi_cio_init(struct platform_device *dsidev) mask_p |= 1 << i; } - dsi_cio_enable_lane_override(dsidev, mask_p, 0); + dsi_cio_enable_lane_override(dsi, mask_p, 0); } - r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); + r = dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_ON); if (r) goto err_cio_pwr; - if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) { + if (!wait_for_bit_change(dsi, DSI_COMPLEXIO_CFG1, 29, 1)) { DSSERR("CIO PWR clock domain not coming out of reset.\n"); r = -ENODEV; goto err_cio_pwr_dom; } - dsi_if_enable(dsidev, true); - dsi_if_enable(dsidev, false); - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ + dsi_if_enable(dsi, true); + dsi_if_enable(dsi, false); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ - r = dsi_cio_wait_tx_clk_esc_reset(dsidev); + r = dsi_cio_wait_tx_clk_esc_reset(dsi); if (r) goto err_tx_clk_esc_rst; @@ -2255,17 +2197,17 @@ static int dsi_cio_init(struct platform_device *dsidev) /* Disable the override. The lanes should be set to Mark-11 * state by the HW */ - dsi_cio_disable_lane_override(dsidev); + dsi_cio_disable_lane_override(dsi); } /* FORCE_TX_STOP_MODE_IO */ - REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15); + REG_FLD_MOD(dsi, DSI_TIMING1, 0, 15, 15); - dsi_cio_timings(dsidev); + dsi_cio_timings(dsi); if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* DDR_CLK_ALWAYS_ON */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, + REG_FLD_MOD(dsi, DSI_CLK_CTRL, dsi->vm_timings.ddr_clk_always_on, 13, 13); } @@ -2276,35 +2218,32 @@ static int dsi_cio_init(struct platform_device *dsidev) return 0; err_tx_clk_esc_rst: - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */ + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */ err_cio_pwr_dom: - dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); + dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_OFF); err_cio_pwr: if (dsi->ulps_enabled) - dsi_cio_disable_lane_override(dsidev); + dsi_cio_disable_lane_override(dsi); err_scp_clk_dom: - dsi_disable_scp_clk(dsidev); + dsi_disable_scp_clk(dsi); dsi_disable_pads(dsi); return r; } -static void dsi_cio_uninit(struct platform_device *dsidev) +static void dsi_cio_uninit(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - /* DDR_CLK_ALWAYS_ON */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 13, 13); - dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); - dsi_disable_scp_clk(dsidev); + dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_OFF); + dsi_disable_scp_clk(dsi); dsi_disable_pads(dsi); } -static void dsi_config_tx_fifo(struct platform_device *dsidev, - enum fifo_size size1, enum fifo_size size2, - enum fifo_size size3, enum fifo_size size4) +static void dsi_config_tx_fifo(struct dsi_data *dsi, + enum fifo_size size1, enum fifo_size size2, + enum fifo_size size3, enum fifo_size size4) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r = 0; int add = 0; int i; @@ -2330,14 +2269,13 @@ static void dsi_config_tx_fifo(struct platform_device *dsidev, add += size; } - dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r); + dsi_write_reg(dsi, DSI_TX_FIFO_VC_SIZE, r); } -static void dsi_config_rx_fifo(struct platform_device *dsidev, +static void dsi_config_rx_fifo(struct dsi_data *dsi, enum fifo_size size1, enum fifo_size size2, enum fifo_size size3, enum fifo_size size4) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r = 0; int add = 0; int i; @@ -2363,18 +2301,18 @@ static void dsi_config_rx_fifo(struct platform_device *dsidev, add += size; } - dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r); + dsi_write_reg(dsi, DSI_RX_FIFO_VC_SIZE, r); } -static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev) +static int dsi_force_tx_stop_mode_io(struct dsi_data *dsi) { u32 r; - r = dsi_read_reg(dsidev, DSI_TIMING1); + r = dsi_read_reg(dsi, DSI_TIMING1); r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ - dsi_write_reg(dsidev, DSI_TIMING1, r); + dsi_write_reg(dsi, DSI_TIMING1, r); - if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) { + if (!wait_for_bit_change(dsi, DSI_TIMING1, 15, 0)) { DSSERR("TX_STOP bit not going down\n"); return -EIO; } @@ -2382,29 +2320,28 @@ static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev) return 0; } -static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel) +static bool dsi_vc_is_enabled(struct dsi_data *dsi, int channel) { - return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0); + return REG_GET(dsi, DSI_VC_CTRL(channel), 0, 0); } static void dsi_packet_sent_handler_vp(void *data, u32 mask) { struct dsi_packet_sent_handler_data *vp_data = (struct dsi_packet_sent_handler_data *) data; - struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev); + struct dsi_data *dsi = vp_data->dsi; const int channel = dsi->update_channel; u8 bit = dsi->te_enabled ? 30 : 31; - if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0) + if (REG_GET(dsi, DSI_VC_TE(channel), bit, bit) == 0) complete(vp_data->completion); } -static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel) +static int dsi_sync_vc_vp(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); struct dsi_packet_sent_handler_data vp_data = { - .dsidev = dsidev, + .dsi = dsi, .completion = &completion }; int r = 0; @@ -2412,13 +2349,13 @@ static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel) bit = dsi->te_enabled ? 30 : 31; - r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp, + r = dsi_register_isr_vc(dsi, channel, dsi_packet_sent_handler_vp, &vp_data, DSI_VC_IRQ_PACKET_SENT); if (r) goto err0; /* Wait for completion only if TE_EN/TE_START is still set */ - if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) { + if (REG_GET(dsi, DSI_VC_TE(channel), bit, bit)) { if (wait_for_completion_timeout(&completion, msecs_to_jiffies(10)) == 0) { DSSERR("Failed to complete previous frame transfer\n"); @@ -2427,12 +2364,12 @@ static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel) } } - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_vp, &vp_data, DSI_VC_IRQ_PACKET_SENT); return 0; err1: - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_vp, &vp_data, DSI_VC_IRQ_PACKET_SENT); err0: return r; @@ -2442,29 +2379,29 @@ static void dsi_packet_sent_handler_l4(void *data, u32 mask) { struct dsi_packet_sent_handler_data *l4_data = (struct dsi_packet_sent_handler_data *) data; - struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev); + struct dsi_data *dsi = l4_data->dsi; const int channel = dsi->update_channel; - if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0) + if (REG_GET(dsi, DSI_VC_CTRL(channel), 5, 5) == 0) complete(l4_data->completion); } -static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel) +static int dsi_sync_vc_l4(struct dsi_data *dsi, int channel) { DECLARE_COMPLETION_ONSTACK(completion); struct dsi_packet_sent_handler_data l4_data = { - .dsidev = dsidev, + .dsi = dsi, .completion = &completion }; int r = 0; - r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4, + r = dsi_register_isr_vc(dsi, channel, dsi_packet_sent_handler_l4, &l4_data, DSI_VC_IRQ_PACKET_SENT); if (r) goto err0; /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 5, 5)) { if (wait_for_completion_timeout(&completion, msecs_to_jiffies(10)) == 0) { DSSERR("Failed to complete previous l4 transfer\n"); @@ -2473,66 +2410,61 @@ static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel) } } - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_l4, &l4_data, DSI_VC_IRQ_PACKET_SENT); return 0; err1: - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_l4, &l4_data, DSI_VC_IRQ_PACKET_SENT); err0: return r; } -static int dsi_sync_vc(struct platform_device *dsidev, int channel) +static int dsi_sync_vc(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); WARN_ON(in_interrupt()); - if (!dsi_vc_is_enabled(dsidev, channel)) + if (!dsi_vc_is_enabled(dsi, channel)) return 0; switch (dsi->vc[channel].source) { case DSI_VC_SOURCE_VP: - return dsi_sync_vc_vp(dsidev, channel); + return dsi_sync_vc_vp(dsi, channel); case DSI_VC_SOURCE_L4: - return dsi_sync_vc_l4(dsidev, channel); + return dsi_sync_vc_l4(dsi, channel); default: BUG(); return -EINVAL; } } -static int dsi_vc_enable(struct platform_device *dsidev, int channel, - bool enable) +static int dsi_vc_enable(struct dsi_data *dsi, int channel, bool enable) { DSSDBG("dsi_vc_enable channel %d, enable %d\n", channel, enable); enable = enable ? 1 : 0; - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), enable, 0, 0); - if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), - 0, enable) != enable) { - DSSERR("Failed to set dsi_vc_enable to %d\n", enable); - return -EIO; + if (!wait_for_bit_change(dsi, DSI_VC_CTRL(channel), 0, enable)) { + DSSERR("Failed to set dsi_vc_enable to %d\n", enable); + return -EIO; } return 0; } -static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) +static void dsi_vc_initial_config(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; DSSDBG("Initial config of virtual channel %d", channel); - r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); + r = dsi_read_reg(dsi, DSI_VC_CTRL(channel)); if (FLD_GET(r, 15, 15)) /* VC_BUSY */ DSSERR("VC(%d) busy when trying to configure it!\n", @@ -2551,41 +2483,39 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ - dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); + dsi_write_reg(dsi, DSI_VC_CTRL(channel), r); dsi->vc[channel].source = DSI_VC_SOURCE_L4; } -static int dsi_vc_config_source(struct platform_device *dsidev, int channel, - enum dsi_vc_source source) +static int dsi_vc_config_source(struct dsi_data *dsi, int channel, + enum dsi_vc_source source) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->vc[channel].source == source) return 0; DSSDBG("Source config of virtual channel %d", channel); - dsi_sync_vc(dsidev, channel); + dsi_sync_vc(dsi, channel); - dsi_vc_enable(dsidev, channel, 0); + dsi_vc_enable(dsi, channel, 0); /* VC_BUSY */ - if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) { + if (!wait_for_bit_change(dsi, DSI_VC_CTRL(channel), 15, 0)) { DSSERR("vc(%d) busy when trying to config for VP\n", channel); return -EIO; } /* SOURCE, 0 = L4, 1 = video port */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), source, 1, 1); /* DCS_CMD_ENABLE */ if (dsi->data->quirks & DSI_QUIRK_DCS_CMD_CONFIG_VC) { bool enable = source == DSI_VC_SOURCE_VP; - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), enable, 30, 30); } - dsi_vc_enable(dsidev, channel, 1); + dsi_vc_enable(dsi, channel, 1); dsi->vc[channel].source = source; @@ -2595,33 +2525,32 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel, static void dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); - dsi_vc_enable(dsidev, channel, 0); - dsi_if_enable(dsidev, 0); + dsi_vc_enable(dsi, channel, 0); + dsi_if_enable(dsi, 0); - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), enable, 9, 9); - dsi_vc_enable(dsidev, channel, 1); - dsi_if_enable(dsidev, 1); + dsi_vc_enable(dsi, channel, 1); + dsi_if_enable(dsi, 1); - dsi_force_tx_stop_mode_io(dsidev); + dsi_force_tx_stop_mode_io(dsi); /* start the DDR clock by sending a NULL packet */ if (dsi->vm_timings.ddr_clk_always_on && enable) - dsi_vc_send_null(dssdev, channel); + dsi_vc_send_null(dsi, channel); } -static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel) +static void dsi_vc_flush_long_data(struct dsi_data *dsi, int channel) { - while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + while (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { u32 val; - val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n", (val >> 0) & 0xff, (val >> 8) & 0xff, @@ -2667,14 +2596,13 @@ static void dsi_show_rx_ack_with_err(u16 err) DSSERR("\t\tDSI Protocol Violation\n"); } -static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, - int channel) +static u16 dsi_vc_flush_receive_data(struct dsi_data *dsi, int channel) { /* RX_FIFO_NOT_EMPTY */ - while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + while (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { u32 val; u8 dt; - val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); DSSERR("\trawval %#08x\n", val); dt = FLD_GET(val, 5, 0); if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) { @@ -2689,7 +2617,7 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) { DSSERR("\tDCS long response, len %d\n", FLD_GET(val, 23, 8)); - dsi_vc_flush_long_data(dsidev, channel); + dsi_vc_flush_long_data(dsi, channel); } else { DSSERR("\tunknown datatype 0x%02x\n", dt); } @@ -2697,47 +2625,45 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, return 0; } -static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) +static int dsi_vc_send_bta(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->debug_write || dsi->debug_read) DSSDBG("dsi_vc_send_bta %d\n", channel); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { DSSERR("rx fifo not empty when sending BTA, dumping data:\n"); - dsi_vc_flush_receive_data(dsidev, channel); + dsi_vc_flush_receive_data(dsi, channel); } - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ /* flush posted write */ - dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); + dsi_read_reg(dsi, DSI_VC_CTRL(channel)); return 0; } static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = to_dsi_data(dssdev); DECLARE_COMPLETION_ONSTACK(completion); int r = 0; u32 err; - r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler, + r = dsi_register_isr_vc(dsi, channel, dsi_completion_handler, &completion, DSI_VC_IRQ_BTA); if (r) goto err0; - r = dsi_register_isr(dsidev, dsi_completion_handler, &completion, + r = dsi_register_isr(dsi, dsi_completion_handler, &completion, DSI_IRQ_ERROR_MASK); if (r) goto err1; - r = dsi_vc_send_bta(dsidev, channel); + r = dsi_vc_send_bta(dsi, channel); if (r) goto err2; @@ -2748,41 +2674,40 @@ static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel) goto err2; } - err = dsi_get_errors(dsidev); + err = dsi_get_errors(dsi); if (err) { DSSERR("Error while sending BTA: %x\n", err); r = -EIO; goto err2; } err2: - dsi_unregister_isr(dsidev, dsi_completion_handler, &completion, + dsi_unregister_isr(dsi, dsi_completion_handler, &completion, DSI_IRQ_ERROR_MASK); err1: - dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler, + dsi_unregister_isr_vc(dsi, channel, dsi_completion_handler, &completion, DSI_VC_IRQ_BTA); err0: return r; } -static inline void dsi_vc_write_long_header(struct platform_device *dsidev, - int channel, u8 data_type, u16 len, u8 ecc) +static inline void dsi_vc_write_long_header(struct dsi_data *dsi, int channel, + u8 data_type, u16 len, u8 ecc) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 val; u8 data_id; - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); data_id = data_type | dsi->vc[channel].vc_id << 6; val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) | FLD_VAL(ecc, 31, 24); - dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val); + dsi_write_reg(dsi, DSI_VC_LONG_PACKET_HEADER(channel), val); } -static inline void dsi_vc_write_long_payload(struct platform_device *dsidev, - int channel, u8 b1, u8 b2, u8 b3, u8 b4) +static inline void dsi_vc_write_long_payload(struct dsi_data *dsi, int channel, + u8 b1, u8 b2, u8 b3, u8 b4) { u32 val; @@ -2791,14 +2716,13 @@ static inline void dsi_vc_write_long_payload(struct platform_device *dsidev, /* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n", b1, b2, b3, b4, val); */ - dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val); + dsi_write_reg(dsi, DSI_VC_LONG_PACKET_PAYLOAD(channel), val); } -static int dsi_vc_send_long(struct platform_device *dsidev, int channel, - u8 data_type, u8 *data, u16 len, u8 ecc) +static int dsi_vc_send_long(struct dsi_data *dsi, int channel, u8 data_type, + u8 *data, u16 len, u8 ecc) { /*u32 val; */ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; u8 *p; int r = 0; @@ -2813,9 +2737,9 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, return -EINVAL; } - dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); + dsi_vc_config_source(dsi, channel, DSI_VC_SOURCE_L4); - dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc); + dsi_vc_write_long_header(dsi, channel, data_type, len, ecc); p = data; for (i = 0; i < len >> 2; i++) { @@ -2827,7 +2751,7 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, b3 = *p++; b4 = *p++; - dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4); + dsi_vc_write_long_payload(dsi, channel, b1, b2, b3, b4); } i = len % 4; @@ -2852,29 +2776,28 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, break; } - dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0); + dsi_vc_write_long_payload(dsi, channel, b1, b2, b3, 0); } return r; } -static int dsi_vc_send_short(struct platform_device *dsidev, int channel, - u8 data_type, u16 data, u8 ecc) +static int dsi_vc_send_short(struct dsi_data *dsi, int channel, u8 data_type, + u16 data, u8 ecc) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; u8 data_id; - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); if (dsi->debug_write) DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n", channel, data_type, data & 0xff, (data >> 8) & 0xff); - dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); + dsi_vc_config_source(dsi, channel, DSI_VC_SOURCE_L4); - if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) { + if (FLD_GET(dsi_read_reg(dsi, DSI_VC_CTRL(channel)), 16, 16)) { DSSERR("ERROR FIFO FULL, aborting transfer\n"); return -EINVAL; } @@ -2883,41 +2806,39 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel, r = (data_id << 0) | (data << 8) | (ecc << 24); - dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r); + dsi_write_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel), r); return 0; } -static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) +static int dsi_vc_send_null(struct dsi_data *dsi, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - - return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL, - 0, 0); + return dsi_vc_send_long(dsi, channel, MIPI_DSI_NULL_PACKET, NULL, 0, 0); } -static int dsi_vc_write_nosync_common(struct platform_device *dsidev, - int channel, u8 *data, int len, enum dss_dsi_content_type type) +static int dsi_vc_write_nosync_common(struct dsi_data *dsi, int channel, + u8 *data, int len, + enum dss_dsi_content_type type) { int r; if (len == 0) { BUG_ON(type == DSS_DSI_CONTENT_DCS); - r = dsi_vc_send_short(dsidev, channel, + r = dsi_vc_send_short(dsi, channel, MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0); } else if (len == 1) { - r = dsi_vc_send_short(dsidev, channel, + r = dsi_vc_send_short(dsi, channel, type == DSS_DSI_CONTENT_GENERIC ? MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM : MIPI_DSI_DCS_SHORT_WRITE, data[0], 0); } else if (len == 2) { - r = dsi_vc_send_short(dsidev, channel, + r = dsi_vc_send_short(dsi, channel, type == DSS_DSI_CONTENT_GENERIC ? MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM : MIPI_DSI_DCS_SHORT_WRITE_PARAM, data[0] | (data[1] << 8), 0); } else { - r = dsi_vc_send_long(dsidev, channel, + r = dsi_vc_send_long(dsi, channel, type == DSS_DSI_CONTENT_GENERIC ? MIPI_DSI_GENERIC_LONG_WRITE : MIPI_DSI_DCS_LONG_WRITE, data, len, 0); @@ -2929,28 +2850,29 @@ static int dsi_vc_write_nosync_common(struct platform_device *dsidev, static int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = to_dsi_data(dssdev); - return dsi_vc_write_nosync_common(dsidev, channel, data, len, + return dsi_vc_write_nosync_common(dsi, channel, data, len, DSS_DSI_CONTENT_DCS); } static int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = to_dsi_data(dssdev); - return dsi_vc_write_nosync_common(dsidev, channel, data, len, + return dsi_vc_write_nosync_common(dsi, channel, data, len, DSS_DSI_CONTENT_GENERIC); } -static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, - u8 *data, int len, enum dss_dsi_content_type type) +static int dsi_vc_write_common(struct omap_dss_device *dssdev, + int channel, u8 *data, int len, + enum dss_dsi_content_type type) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r; - r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type); + r = dsi_vc_write_nosync_common(dsi, channel, data, len, type); if (r) goto err; @@ -2959,9 +2881,9 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, goto err; /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { DSSERR("rx fifo not empty after write, dumping data:\n"); - dsi_vc_flush_receive_data(dsidev, channel); + dsi_vc_flush_receive_data(dsi, channel); r = -EIO; goto err; } @@ -2987,17 +2909,16 @@ static int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 DSS_DSI_CONTENT_GENERIC); } -static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, - int channel, u8 dcs_cmd) +static int dsi_vc_dcs_send_read_request(struct dsi_data *dsi, int channel, + u8 dcs_cmd) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; if (dsi->debug_read) DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n", channel, dcs_cmd); - r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0); + r = dsi_vc_send_short(dsi, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0); if (r) { DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)" " failed\n", channel, dcs_cmd); @@ -3007,10 +2928,9 @@ static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, return 0; } -static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, - int channel, u8 *reqdata, int reqlen) +static int dsi_vc_generic_send_read_request(struct dsi_data *dsi, int channel, + u8 *reqdata, int reqlen) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 data; u8 data_type; int r; @@ -3033,7 +2953,7 @@ static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, return -EINVAL; } - r = dsi_vc_send_short(dsidev, channel, data_type, data, 0); + r = dsi_vc_send_short(dsi, channel, data_type, data, 0); if (r) { DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)" " failed\n", channel, reqlen); @@ -3043,22 +2963,21 @@ static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, return 0; } -static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, - u8 *buf, int buflen, enum dss_dsi_content_type type) +static int dsi_vc_read_rx_fifo(struct dsi_data *dsi, int channel, u8 *buf, + int buflen, enum dss_dsi_content_type type) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 val; u8 dt; int r; /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20) == 0) { DSSERR("RX fifo empty when trying to read.\n"); r = -EIO; goto err; } - val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); if (dsi->debug_read) DSSDBG("\theader: %08x\n", val); dt = FLD_GET(val, 5, 0); @@ -3121,7 +3040,7 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, /* two byte checksum ends the packet, not included in len */ for (w = 0; w < len + 2;) { int b; - val = dsi_read_reg(dsidev, + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); if (dsi->debug_read) DSSDBG("\t\t%02x %02x %02x %02x\n", @@ -3155,10 +3074,10 @@ err: static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, u8 *buf, int buflen) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r; - r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd); + r = dsi_vc_dcs_send_read_request(dsi, channel, dcs_cmd); if (r) goto err; @@ -3166,7 +3085,7 @@ static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_c if (r) goto err; - r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, + r = dsi_vc_read_rx_fifo(dsi, channel, buf, buflen, DSS_DSI_CONTENT_DCS); if (r < 0) goto err; @@ -3185,10 +3104,10 @@ err: static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, u8 *reqdata, int reqlen, u8 *buf, int buflen) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r; - r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen); + r = dsi_vc_generic_send_read_request(dsi, channel, reqdata, reqlen); if (r) return r; @@ -3196,7 +3115,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, if (r) return r; - r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, + r = dsi_vc_read_rx_fifo(dsi, channel, buf, buflen, DSS_DSI_CONTENT_GENERIC); if (r < 0) return r; @@ -3212,22 +3131,21 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, static int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, u16 len) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = to_dsi_data(dssdev); - return dsi_vc_send_short(dsidev, channel, + return dsi_vc_send_short(dsi, channel, MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); } -static int dsi_enter_ulps(struct platform_device *dsidev) +static int dsi_enter_ulps(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); int r, i; - unsigned mask; + unsigned int mask; DSSDBG("Entering ULPS"); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); WARN_ON(dsi->ulps_enabled); @@ -3235,35 +3153,35 @@ static int dsi_enter_ulps(struct platform_device *dsidev) return 0; /* DDR_CLK_ALWAYS_ON */ - if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { - dsi_if_enable(dsidev, 0); - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); - dsi_if_enable(dsidev, 1); + if (REG_GET(dsi, DSI_CLK_CTRL, 13, 13)) { + dsi_if_enable(dsi, 0); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 13, 13); + dsi_if_enable(dsi, 1); } - dsi_sync_vc(dsidev, 0); - dsi_sync_vc(dsidev, 1); - dsi_sync_vc(dsidev, 2); - dsi_sync_vc(dsidev, 3); + dsi_sync_vc(dsi, 0); + dsi_sync_vc(dsi, 1); + dsi_sync_vc(dsi, 2); + dsi_sync_vc(dsi, 3); - dsi_force_tx_stop_mode_io(dsidev); + dsi_force_tx_stop_mode_io(dsi); - dsi_vc_enable(dsidev, 0, false); - dsi_vc_enable(dsidev, 1, false); - dsi_vc_enable(dsidev, 2, false); - dsi_vc_enable(dsidev, 3, false); + dsi_vc_enable(dsi, 0, false); + dsi_vc_enable(dsi, 1, false); + dsi_vc_enable(dsi, 2, false); + dsi_vc_enable(dsi, 3, false); - if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */ + if (REG_GET(dsi, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */ DSSERR("HS busy when enabling ULPS\n"); return -EIO; } - if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */ + if (REG_GET(dsi, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */ DSSERR("LP busy when enabling ULPS\n"); return -EIO; } - r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion, + r = dsi_register_isr_cio(dsi, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); if (r) return r; @@ -3277,10 +3195,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) } /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ /* LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5); + REG_FLD_MOD(dsi, DSI_COMPLEXIO_CFG2, mask, 9, 5); /* flush posted write and wait for SCP interface to finish the write */ - dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); + dsi_read_reg(dsi, DSI_COMPLEXIO_CFG2); if (wait_for_completion_timeout(&completion, msecs_to_jiffies(1000)) == 0) { @@ -3289,31 +3207,31 @@ static int dsi_enter_ulps(struct platform_device *dsidev) goto err; } - dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, + dsi_unregister_isr_cio(dsi, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); /* Reset LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5); + REG_FLD_MOD(dsi, DSI_COMPLEXIO_CFG2, 0, 9, 5); /* flush posted write and wait for SCP interface to finish the write */ - dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); + dsi_read_reg(dsi, DSI_COMPLEXIO_CFG2); - dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); + dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_ULPS); - dsi_if_enable(dsidev, false); + dsi_if_enable(dsi, false); dsi->ulps_enabled = true; return 0; err: - dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, + dsi_unregister_isr_cio(dsi, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); return r; } -static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) +static void dsi_set_lp_rx_timeout(struct dsi_data *dsi, unsigned int ticks, + bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3322,14 +3240,14 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ - fck = dsi_fclk_rate(dsidev); + fck = dsi_fclk_rate(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING2); + r = dsi_read_reg(dsi, DSI_TIMING2); r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ - dsi_write_reg(dsidev, DSI_TIMING2, r); + dsi_write_reg(dsi, DSI_TIMING2, r); total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); @@ -3339,8 +3257,8 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, - bool x8, bool x16) +static void dsi_set_ta_timeout(struct dsi_data *dsi, unsigned int ticks, + bool x8, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3349,14 +3267,14 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ - fck = dsi_fclk_rate(dsidev); + fck = dsi_fclk_rate(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING1); + r = dsi_read_reg(dsi, DSI_TIMING1); r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */ r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ - dsi_write_reg(dsidev, DSI_TIMING1, r); + dsi_write_reg(dsi, DSI_TIMING1, r); total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1); @@ -3366,8 +3284,8 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_stop_state_counter(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) +static void dsi_set_stop_state_counter(struct dsi_data *dsi, unsigned int ticks, + bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3376,14 +3294,14 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ - fck = dsi_fclk_rate(dsidev); + fck = dsi_fclk_rate(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING1); + r = dsi_read_reg(dsi, DSI_TIMING1); r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ - dsi_write_reg(dsidev, DSI_TIMING1, r); + dsi_write_reg(dsi, DSI_TIMING1, r); total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); @@ -3393,8 +3311,8 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) +static void dsi_set_hs_tx_timeout(struct dsi_data *dsi, unsigned int ticks, + bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3403,14 +3321,14 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, BUG_ON(ticks > 0x1fff); /* ticks in TxByteClkHS */ - fck = dsi_get_txbyteclkhs(dsidev); + fck = dsi_get_txbyteclkhs(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING2); + r = dsi_read_reg(dsi, DSI_TIMING2); r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ - dsi_write_reg(dsidev, DSI_TIMING2, r); + dsi_write_reg(dsi, DSI_TIMING2, r); total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); @@ -3420,9 +3338,8 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) +static void dsi_config_vp_num_line_buffers(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int num_line_buffers; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { @@ -3442,12 +3359,11 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) } /* LINE_BUFFER */ - REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); + REG_FLD_MOD(dsi, DSI_CTRL, num_line_buffers, 13, 12); } -static void dsi_config_vp_sync_events(struct platform_device *dsidev) +static void dsi_config_vp_sync_events(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); bool sync_end; u32 r; @@ -3456,7 +3372,7 @@ static void dsi_config_vp_sync_events(struct platform_device *dsidev) else sync_end = false; - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */ r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ @@ -3464,12 +3380,11 @@ static void dsi_config_vp_sync_events(struct platform_device *dsidev) r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */ r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */ - dsi_write_reg(dsidev, DSI_CTRL, r); + dsi_write_reg(dsi, DSI_CTRL, r); } -static void dsi_config_blanking_modes(struct platform_device *dsidev) +static void dsi_config_blanking_modes(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int blanking_mode = dsi->vm_timings.blanking_mode; int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode; int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode; @@ -3480,12 +3395,12 @@ static void dsi_config_blanking_modes(struct platform_device *dsidev) * 0 = TX FIFO packets sent or LPS in corresponding blanking periods * 1 = Long blanking packets are sent in corresponding blanking periods */ - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */ r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */ r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */ r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */ - dsi_write_reg(dsidev, DSI_CTRL, r); + dsi_write_reg(dsi, DSI_CTRL, r); } /* @@ -3550,9 +3465,8 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, return max(lp_inter, 0); } -static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) +static void dsi_config_cmd_mode_interleaving(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int blanking_mode; int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div; @@ -3569,33 +3483,33 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) int bl_interleave_hs = 0, bl_interleave_lp = 0; u32 r; - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); blanking_mode = FLD_GET(r, 20, 20); hfp_blanking_mode = FLD_GET(r, 21, 21); hbp_blanking_mode = FLD_GET(r, 22, 22); hsa_blanking_mode = FLD_GET(r, 23, 23); - r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + r = dsi_read_reg(dsi, DSI_VM_TIMING1); hbp = FLD_GET(r, 11, 0); hfp = FLD_GET(r, 23, 12); hsa = FLD_GET(r, 31, 24); - r = dsi_read_reg(dsidev, DSI_CLK_TIMING); + r = dsi_read_reg(dsi, DSI_CLK_TIMING); ddr_clk_post = FLD_GET(r, 7, 0); ddr_clk_pre = FLD_GET(r, 15, 8); - r = dsi_read_reg(dsidev, DSI_VM_TIMING7); + r = dsi_read_reg(dsi, DSI_VM_TIMING7); exit_hs_mode_lat = FLD_GET(r, 15, 0); enter_hs_mode_lat = FLD_GET(r, 31, 16); - r = dsi_read_reg(dsidev, DSI_CLK_CTRL); + r = dsi_read_reg(dsi, DSI_CLK_CTRL); lp_clk_div = FLD_GET(r, 12, 0); ddr_alwon = FLD_GET(r, 13, 13); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG0); ths_exit = FLD_GET(r, 7, 0); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); tclk_trail = FLD_GET(r, 15, 8); exiths_clk = ths_exit + tclk_trail; @@ -3649,45 +3563,44 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp, bl_interleave_lp); - r = dsi_read_reg(dsidev, DSI_VM_TIMING4); + r = dsi_read_reg(dsi, DSI_VM_TIMING4); r = FLD_MOD(r, hsa_interleave_hs, 23, 16); r = FLD_MOD(r, hfp_interleave_hs, 15, 8); r = FLD_MOD(r, hbp_interleave_hs, 7, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING4, r); + dsi_write_reg(dsi, DSI_VM_TIMING4, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING5); + r = dsi_read_reg(dsi, DSI_VM_TIMING5); r = FLD_MOD(r, hsa_interleave_lp, 23, 16); r = FLD_MOD(r, hfp_interleave_lp, 15, 8); r = FLD_MOD(r, hbp_interleave_lp, 7, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING5, r); + dsi_write_reg(dsi, DSI_VM_TIMING5, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING6); + r = dsi_read_reg(dsi, DSI_VM_TIMING6); r = FLD_MOD(r, bl_interleave_hs, 31, 15); r = FLD_MOD(r, bl_interleave_lp, 16, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING6, r); + dsi_write_reg(dsi, DSI_VM_TIMING6, r); } -static int dsi_proto_config(struct platform_device *dsidev) +static int dsi_proto_config(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; int buswidth = 0; - dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32, + dsi_config_tx_fifo(dsi, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32); - dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32, + dsi_config_rx_fifo(dsi, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ - dsi_set_stop_state_counter(dsidev, 0x1000, false, false); - dsi_set_ta_timeout(dsidev, 0x1fff, true, true); - dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); - dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); + dsi_set_stop_state_counter(dsi, 0x1000, false, false); + dsi_set_ta_timeout(dsi, 0x1fff, true, true); + dsi_set_lp_rx_timeout(dsi, 0x1fff, true, true); + dsi_set_hs_tx_timeout(dsi, 0x1fff, true, true); switch (dsi_get_pixel_size(dsi->pix_fmt)) { case 16: @@ -3704,7 +3617,7 @@ static int dsi_proto_config(struct platform_device *dsidev) return -EINVAL; } - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */ r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */ r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */ @@ -3719,56 +3632,55 @@ static int dsi_proto_config(struct platform_device *dsidev) r = FLD_MOD(r, 0, 25, 25); } - dsi_write_reg(dsidev, DSI_CTRL, r); + dsi_write_reg(dsi, DSI_CTRL, r); - dsi_config_vp_num_line_buffers(dsidev); + dsi_config_vp_num_line_buffers(dsi); if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_config_vp_sync_events(dsidev); - dsi_config_blanking_modes(dsidev); - dsi_config_cmd_mode_interleaving(dsidev); + dsi_config_vp_sync_events(dsi); + dsi_config_blanking_modes(dsi); + dsi_config_cmd_mode_interleaving(dsi); } - dsi_vc_initial_config(dsidev, 0); - dsi_vc_initial_config(dsidev, 1); - dsi_vc_initial_config(dsidev, 2); - dsi_vc_initial_config(dsidev, 3); + dsi_vc_initial_config(dsi, 0); + dsi_vc_initial_config(dsi, 1); + dsi_vc_initial_config(dsi, 2); + dsi_vc_initial_config(dsi, 3); return 0; } -static void dsi_proto_timings(struct platform_device *dsidev) +static void dsi_proto_timings(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; - unsigned tclk_pre, tclk_post; - unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; - unsigned ths_trail, ths_exit; - unsigned ddr_clk_pre, ddr_clk_post; - unsigned enter_hs_mode_lat, exit_hs_mode_lat; - unsigned ths_eot; + unsigned int tlpx, tclk_zero, tclk_prepare, tclk_trail; + unsigned int tclk_pre, tclk_post; + unsigned int ths_prepare, ths_prepare_ths_zero, ths_zero; + unsigned int ths_trail, ths_exit; + unsigned int ddr_clk_pre, ddr_clk_post; + unsigned int enter_hs_mode_lat, exit_hs_mode_lat; + unsigned int ths_eot; int ndl = dsi->num_lanes_used - 1; u32 r; - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG0); ths_prepare = FLD_GET(r, 31, 24); ths_prepare_ths_zero = FLD_GET(r, 23, 16); ths_zero = ths_prepare_ths_zero - ths_prepare; ths_trail = FLD_GET(r, 15, 8); ths_exit = FLD_GET(r, 7, 0); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); tlpx = FLD_GET(r, 20, 16) * 2; tclk_trail = FLD_GET(r, 15, 8); tclk_zero = FLD_GET(r, 7, 0); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG2); tclk_prepare = FLD_GET(r, 7, 0); /* min 8*UI */ tclk_pre = 20; /* min 60ns + 52*UI */ - tclk_post = ns2ddr(dsidev, 60) + 26; + tclk_post = ns2ddr(dsi, 60) + 26; ths_eot = DIV_ROUND_UP(4, ndl); @@ -3779,10 +3691,10 @@ static void dsi_proto_timings(struct platform_device *dsidev) BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255); BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255); - r = dsi_read_reg(dsidev, DSI_CLK_TIMING); + r = dsi_read_reg(dsi, DSI_CLK_TIMING); r = FLD_MOD(r, ddr_clk_pre, 15, 8); r = FLD_MOD(r, ddr_clk_post, 7, 0); - dsi_write_reg(dsidev, DSI_CLK_TIMING, r); + dsi_write_reg(dsi, DSI_CLK_TIMING, r); DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n", ddr_clk_pre, @@ -3796,7 +3708,7 @@ static void dsi_proto_timings(struct platform_device *dsidev) r = FLD_VAL(enter_hs_mode_lat, 31, 16) | FLD_VAL(exit_hs_mode_lat, 15, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING7, r); + dsi_write_reg(dsi, DSI_VM_TIMING7, r); DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", enter_hs_mode_lat, exit_hs_mode_lat); @@ -3830,31 +3742,30 @@ static void dsi_proto_timings(struct platform_device *dsidev) DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp, vsa, vm->vactive); - r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + r = dsi_read_reg(dsi, DSI_VM_TIMING1); r = FLD_MOD(r, hbp, 11, 0); /* HBP */ r = FLD_MOD(r, hfp, 23, 12); /* HFP */ r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */ - dsi_write_reg(dsidev, DSI_VM_TIMING1, r); + dsi_write_reg(dsi, DSI_VM_TIMING1, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING2); + r = dsi_read_reg(dsi, DSI_VM_TIMING2); r = FLD_MOD(r, vbp, 7, 0); /* VBP */ r = FLD_MOD(r, vfp, 15, 8); /* VFP */ r = FLD_MOD(r, vsa, 23, 16); /* VSA */ r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */ - dsi_write_reg(dsidev, DSI_VM_TIMING2, r); + dsi_write_reg(dsi, DSI_VM_TIMING2, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING3); + r = dsi_read_reg(dsi, DSI_VM_TIMING3); r = FLD_MOD(r, vm->vactive, 14, 0); /* VACT */ r = FLD_MOD(r, tl, 31, 16); /* TL */ - dsi_write_reg(dsidev, DSI_VM_TIMING3, r); + dsi_write_reg(dsi, DSI_VM_TIMING3, r); } } static int dsi_configure_pins(struct omap_dss_device *dssdev, const struct omap_dsi_pin_config *pin_cfg) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int num_pins; const int *pins; struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; @@ -3919,9 +3830,7 @@ static int dsi_configure_pins(struct omap_dss_device *dssdev, static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - enum omap_channel dispc_channel = dssdev->dispc_channel; + struct dsi_data *dsi = to_dsi_data(dssdev); int bpp = dsi_get_pixel_size(dsi->pix_fmt); struct omap_dss_device *out = &dsi->output; u8 data_type; @@ -3933,7 +3842,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) return -ENODEV; } - r = dsi_display_init_dispc(dsidev, dispc_channel); + r = dsi_display_init_dispc(dsi); if (r) goto err_init_dispc; @@ -3956,22 +3865,22 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) goto err_pix_fmt; } - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsi, false); + dsi_vc_enable(dsi, channel, false); /* MODE, 1 = video mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), 1, 4, 4); word_count = DIV_ROUND_UP(dsi->vm.hactive * bpp, 8); - dsi_vc_write_long_header(dsidev, channel, data_type, + dsi_vc_write_long_header(dsi, channel, data_type, word_count, 0); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsi, channel, true); + dsi_if_enable(dsi, true); } - r = dss_mgr_enable(dispc_channel); + r = dss_mgr_enable(&dsi->output); if (r) goto err_mgr_enable; @@ -3979,57 +3888,53 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) err_mgr_enable: if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsi, false); + dsi_vc_enable(dsi, channel, false); } err_pix_fmt: - dsi_display_uninit_dispc(dsidev, dispc_channel); + dsi_display_uninit_dispc(dsi); err_init_dispc: return r; } static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - enum omap_channel dispc_channel = dssdev->dispc_channel; + struct dsi_data *dsi = to_dsi_data(dssdev); if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsi, false); + dsi_vc_enable(dsi, channel, false); /* MODE, 0 = command mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), 0, 4, 4); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsi, channel, true); + dsi_if_enable(dsi, true); } - dss_mgr_disable(dispc_channel); + dss_mgr_disable(&dsi->output); - dsi_display_uninit_dispc(dsidev, dispc_channel); + dsi_display_uninit_dispc(dsi); } -static void dsi_update_screen_dispc(struct platform_device *dsidev) +static void dsi_update_screen_dispc(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - enum omap_channel dispc_channel = dsi->output.dispc_channel; - unsigned bytespp; - unsigned bytespl; - unsigned bytespf; - unsigned total_len; - unsigned packet_payload; - unsigned packet_len; + unsigned int bytespp; + unsigned int bytespl; + unsigned int bytespf; + unsigned int total_len; + unsigned int packet_payload; + unsigned int packet_len; u32 l; int r; const unsigned channel = dsi->update_channel; - const unsigned line_buf_size = dsi->line_buffer_size; + const unsigned int line_buf_size = dsi->line_buffer_size; u16 w = dsi->vm.hactive; u16 h = dsi->vm.vactive; DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); - dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); + dsi_vc_config_source(dsi, channel, DSI_VC_SOURCE_VP); bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8; bytespl = w * bytespp; @@ -4050,16 +3955,16 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) total_len += (bytespf % packet_payload) + 1; l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ - dsi_write_reg(dsidev, DSI_VC_TE(channel), l); + dsi_write_reg(dsi, DSI_VC_TE(channel), l); - dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE, + dsi_vc_write_long_header(dsi, channel, MIPI_DSI_DCS_LONG_WRITE, packet_len, 0); if (dsi->te_enabled) l = FLD_MOD(l, 1, 30, 30); /* TE_EN */ else l = FLD_MOD(l, 1, 31, 31); /* TE_START */ - dsi_write_reg(dsidev, DSI_VC_TE(channel), l); + dsi_write_reg(dsi, DSI_VC_TE(channel), l); /* We put SIDLEMODE to no-idle for the duration of the transfer, * because DSS interrupts are not capable of waking up the CPU and the @@ -4067,24 +3972,24 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) * the same goes for any DSS interrupts, but for some reason I have not * seen the problem anywhere else than here. */ - dispc_disable_sidle(); + dispc_disable_sidle(dsi->dss->dispc); - dsi_perf_mark_start(dsidev); + dsi_perf_mark_start(dsi); r = schedule_delayed_work(&dsi->framedone_timeout_work, msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_mgr_set_timings(dispc_channel, &dsi->vm); + dss_mgr_set_timings(&dsi->output, &dsi->vm); - dss_mgr_start_update(dispc_channel); + dss_mgr_start_update(&dsi->output); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait * for TE is longer than the timer allows */ - REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */ + REG_FLD_MOD(dsi, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */ - dsi_vc_send_bta(dsidev, channel); + dsi_vc_send_bta(dsi, channel); #ifdef DSI_CATCH_MISSING_TE mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250)); @@ -4099,22 +4004,20 @@ static void dsi_te_timeout(struct timer_list *unused) } #endif -static void dsi_handle_framedone(struct platform_device *dsidev, int error) +static void dsi_handle_framedone(struct dsi_data *dsi, int error) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - /* SIDLEMODE back to smart-idle */ - dispc_enable_sidle(); + dispc_enable_sidle(dsi->dss->dispc); if (dsi->te_enabled) { /* enable LP_RX_TO again after the TE */ - REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ + REG_FLD_MOD(dsi, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ } dsi->framedone_callback(error, dsi->framedone_data); if (!error) - dsi_perf_show(dsidev, "DISPC"); + dsi_perf_show(dsi, "DISPC"); } static void dsi_framedone_timeout_work_callback(struct work_struct *work) @@ -4130,13 +4033,12 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) DSSERR("Framedone not received for 250ms!\n"); - dsi_handle_framedone(dsi->pdev, -ETIMEDOUT); + dsi_handle_framedone(dsi, -ETIMEDOUT); } static void dsi_framedone_irq_callback(void *data) { - struct platform_device *dsidev = (struct platform_device *) data; - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = data; /* Note: We get FRAMEDONE when DISPC has finished sending pixels and * turns itself off. However, DSI still has the pixels in its buffers, @@ -4145,17 +4047,16 @@ static void dsi_framedone_irq_callback(void *data) cancel_delayed_work(&dsi->framedone_timeout_work); - dsi_handle_framedone(dsidev, 0); + dsi_handle_framedone(dsi, 0); } static int dsi_update(struct omap_dss_device *dssdev, int channel, void (*callback)(int, void *), void *data) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); u16 dw, dh; - dsi_perf_mark_setup(dsidev); + dsi_perf_mark_setup(dsi); dsi->update_channel = channel; @@ -4169,26 +4070,25 @@ static int dsi_update(struct omap_dss_device *dssdev, int channel, dsi->update_bytes = dw * dh * dsi_get_pixel_size(dsi->pix_fmt) / 8; #endif - dsi_update_screen_dispc(dsidev); + dsi_update_screen_dispc(dsi); return 0; } /* Display funcs */ -static int dsi_configure_dispc_clocks(struct platform_device *dsidev) +static int dsi_configure_dispc_clocks(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dispc_clock_info dispc_cinfo; int r; unsigned long fck; - fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); + fck = dsi_get_pll_hsdiv_dispc_rate(dsi); dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div; dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div; - r = dispc_calc_clock_rates(fck, &dispc_cinfo); + r = dispc_calc_clock_rates(dsi->dss->dispc, fck, &dispc_cinfo); if (r) { DSSERR("Failed to calc dispc clocks\n"); return r; @@ -4199,19 +4099,18 @@ static int dsi_configure_dispc_clocks(struct platform_device *dsidev) return 0; } -static int dsi_display_init_dispc(struct platform_device *dsidev, - enum omap_channel channel) +static int dsi_display_init_dispc(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + enum omap_channel channel = dsi->output.dispc_channel; int r; - dss_select_lcd_clk_source(channel, dsi->module_id == 0 ? + dss_select_lcd_clk_source(dsi->dss, channel, dsi->module_id == 0 ? DSS_CLK_SRC_PLL1_1 : DSS_CLK_SRC_PLL2_1); if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { - r = dss_mgr_register_framedone_handler(channel, - dsi_framedone_irq_callback, dsidev); + r = dss_mgr_register_framedone_handler(&dsi->output, + dsi_framedone_irq_callback, dsi); if (r) { DSSERR("can't register FRAMEDONE handler\n"); goto err; @@ -4240,9 +4139,9 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dsi->vm.flags &= ~DISPLAY_FLAGS_SYNC_POSEDGE; dsi->vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE; - dss_mgr_set_timings(channel, &dsi->vm); + dss_mgr_set_timings(&dsi->output, &dsi->vm); - r = dsi_configure_dispc_clocks(dsidev); + r = dsi_configure_dispc_clocks(dsi); if (r) goto err1; @@ -4251,33 +4150,31 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dsi_get_pixel_size(dsi->pix_fmt); dsi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(channel, &dsi->mgr_config); + dss_mgr_set_lcd_config(&dsi->output, &dsi->mgr_config); return 0; err1: if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) - dss_mgr_unregister_framedone_handler(channel, - dsi_framedone_irq_callback, dsidev); + dss_mgr_unregister_framedone_handler(&dsi->output, + dsi_framedone_irq_callback, dsi); err: - dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); return r; } -static void dsi_display_uninit_dispc(struct platform_device *dsidev, - enum omap_channel channel) +static void dsi_display_uninit_dispc(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + enum omap_channel channel = dsi->output.dispc_channel; if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) - dss_mgr_unregister_framedone_handler(channel, - dsi_framedone_irq_callback, dsidev); + dss_mgr_unregister_framedone_handler(&dsi->output, + dsi_framedone_irq_callback, dsi); - dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); } -static int dsi_configure_dsi_clocks(struct platform_device *dsidev) +static int dsi_configure_dsi_clocks(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll_clock_info cinfo; int r; @@ -4292,99 +4189,95 @@ static int dsi_configure_dsi_clocks(struct platform_device *dsidev) return 0; } -static int dsi_display_init_dsi(struct platform_device *dsidev) +static int dsi_display_init_dsi(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; r = dss_pll_enable(&dsi->pll); if (r) goto err0; - r = dsi_configure_dsi_clocks(dsidev); + r = dsi_configure_dsi_clocks(dsi); if (r) goto err1; - dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ? - DSS_CLK_SRC_PLL1_2 : - DSS_CLK_SRC_PLL2_2); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, + dsi->module_id == 0 ? + DSS_CLK_SRC_PLL1_2 : DSS_CLK_SRC_PLL2_2); DSSDBG("PLL OK\n"); - r = dsi_cio_init(dsidev); + r = dsi_cio_init(dsi); if (r) goto err2; - _dsi_print_reset_status(dsidev); + _dsi_print_reset_status(dsi); - dsi_proto_timings(dsidev); - dsi_set_lp_clk_divisor(dsidev); + dsi_proto_timings(dsi); + dsi_set_lp_clk_divisor(dsi); if (1) - _dsi_print_reset_status(dsidev); + _dsi_print_reset_status(dsi); - r = dsi_proto_config(dsidev); + r = dsi_proto_config(dsi); if (r) goto err3; /* enable interface */ - dsi_vc_enable(dsidev, 0, 1); - dsi_vc_enable(dsidev, 1, 1); - dsi_vc_enable(dsidev, 2, 1); - dsi_vc_enable(dsidev, 3, 1); - dsi_if_enable(dsidev, 1); - dsi_force_tx_stop_mode_io(dsidev); + dsi_vc_enable(dsi, 0, 1); + dsi_vc_enable(dsi, 1, 1); + dsi_vc_enable(dsi, 2, 1); + dsi_vc_enable(dsi, 3, 1); + dsi_if_enable(dsi, 1); + dsi_force_tx_stop_mode_io(dsi); return 0; err3: - dsi_cio_uninit(dsidev); + dsi_cio_uninit(dsi); err2: - dss_select_dsi_clk_source(dsi->module_id, DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); err1: dss_pll_disable(&dsi->pll); err0: return r; } -static void dsi_display_uninit_dsi(struct platform_device *dsidev, - bool disconnect_lanes, bool enter_ulps) +static void dsi_display_uninit_dsi(struct dsi_data *dsi, bool disconnect_lanes, + bool enter_ulps) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (enter_ulps && !dsi->ulps_enabled) - dsi_enter_ulps(dsidev); + dsi_enter_ulps(dsi); /* disable interface */ - dsi_if_enable(dsidev, 0); - dsi_vc_enable(dsidev, 0, 0); - dsi_vc_enable(dsidev, 1, 0); - dsi_vc_enable(dsidev, 2, 0); - dsi_vc_enable(dsidev, 3, 0); + dsi_if_enable(dsi, 0); + dsi_vc_enable(dsi, 0, 0); + dsi_vc_enable(dsi, 1, 0); + dsi_vc_enable(dsi, 2, 0); + dsi_vc_enable(dsi, 3, 0); - dss_select_dsi_clk_source(dsi->module_id, DSS_CLK_SRC_FCK); - dsi_cio_uninit(dsidev); - dsi_pll_uninit(dsidev, disconnect_lanes); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); + dsi_cio_uninit(dsi); + dsi_pll_uninit(dsi, disconnect_lanes); } static int dsi_display_enable(struct omap_dss_device *dssdev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r = 0; DSSDBG("dsi_display_enable\n"); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); mutex_lock(&dsi->lock); - r = dsi_runtime_get(dsidev); + r = dsi_runtime_get(dsi); if (r) goto err_get_dsi; - _dsi_initialize_irq(dsidev); + _dsi_initialize_irq(dsi); - r = dsi_display_init_dsi(dsidev); + r = dsi_display_init_dsi(dsi); if (r) goto err_init_dsi; @@ -4393,7 +4286,7 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) return 0; err_init_dsi: - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); err_get_dsi: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); @@ -4403,31 +4296,29 @@ err_get_dsi: static void dsi_display_disable(struct omap_dss_device *dssdev, bool disconnect_lanes, bool enter_ulps) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); DSSDBG("dsi_display_disable\n"); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); mutex_lock(&dsi->lock); - dsi_sync_vc(dsidev, 0); - dsi_sync_vc(dsidev, 1); - dsi_sync_vc(dsidev, 2); - dsi_sync_vc(dsidev, 3); + dsi_sync_vc(dsi, 0); + dsi_sync_vc(dsi, 1); + dsi_sync_vc(dsi, 2); + dsi_sync_vc(dsi, 3); - dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps); + dsi_display_uninit_dsi(dsi, disconnect_lanes, enter_ulps); - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); mutex_unlock(&dsi->lock); } static int dsi_enable_te(struct omap_dss_device *dssdev, bool enable) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); dsi->te_enabled = enable; return 0; @@ -4548,15 +4439,16 @@ static bool dsi_cm_calc_hsdiv_cb(int m_dispc, unsigned long dispc, ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc; ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc; - return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, - dsi_cm_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->dsi->dss->dispc, dispc, + ctx->req_pck_min, ctx->req_pck_max, + dsi_cm_calc_dispc_cb, ctx); } static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint, unsigned long clkdco, void *data) { struct dsi_clk_calc_ctx *ctx = data; - struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); + struct dsi_data *dsi = ctx->dsi; ctx->dsi_cinfo.n = n; ctx->dsi_cinfo.m = m; @@ -4592,7 +4484,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi, txbyteclk = pck * bitspp / 8 / ndl; memset(ctx, 0, sizeof(*ctx)); - ctx->dsidev = dsi->pdev; + ctx->dsi = dsi; ctx->pll = &dsi->pll; ctx->config = cfg; ctx->req_pck_min = pck; @@ -4609,7 +4501,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi, static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) { - struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); + struct dsi_data *dsi = ctx->dsi; const struct omap_dss_dsi_config *cfg = ctx->config; int bitspp = dsi_get_pixel_size(cfg->pixel_format); int ndl = dsi->num_lanes_used - 1; @@ -4848,15 +4740,16 @@ static bool dsi_vm_calc_hsdiv_cb(int m_dispc, unsigned long dispc, else pck_max = ctx->req_pck_max; - return dispc_div_calc(dispc, ctx->req_pck_min, pck_max, - dsi_vm_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->dsi->dss->dispc, dispc, + ctx->req_pck_min, pck_max, + dsi_vm_calc_dispc_cb, ctx); } static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint, unsigned long clkdco, void *data) { struct dsi_clk_calc_ctx *ctx = data; - struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); + struct dsi_data *dsi = ctx->dsi; ctx->dsi_cinfo.n = n; ctx->dsi_cinfo.m = m; @@ -4883,7 +4776,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi, clkin = clk_get_rate(dsi->pll.clkin); memset(ctx, 0, sizeof(*ctx)); - ctx->dsidev = dsi->pdev; + ctx->dsi = dsi; ctx->pll = &dsi->pll; ctx->config = cfg; @@ -4913,8 +4806,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi, static int dsi_set_config(struct omap_dss_device *dssdev, const struct omap_dss_dsi_config *config) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); struct dsi_clk_calc_ctx ctx; bool ok; int r; @@ -5001,8 +4893,7 @@ static enum omap_channel dsi_get_channel(struct dsi_data *dsi) static int dsi_request_vc(struct omap_dss_device *dssdev, int *channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int i; for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { @@ -5019,8 +4910,7 @@ static int dsi_request_vc(struct omap_dss_device *dssdev, int *channel) static int dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); if (vc_id < 0 || vc_id > 3) { DSSERR("VC ID out of range\n"); @@ -5045,8 +4935,7 @@ static int dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id) static void dsi_release_vc(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); if ((channel >= 0 && channel <= 3) && dsi->vc[channel].dssdev == dssdev) { @@ -5056,12 +4945,11 @@ static void dsi_release_vc(struct omap_dss_device *dssdev, int channel) } -static int dsi_get_clocks(struct platform_device *dsidev) +static int dsi_get_clocks(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct clk *clk; - clk = devm_clk_get(&dsidev->dev, "fck"); + clk = devm_clk_get(dsi->dev, "fck"); if (IS_ERR(clk)) { DSSERR("can't get fck\n"); return PTR_ERR(clk); @@ -5075,15 +4963,14 @@ static int dsi_get_clocks(struct platform_device *dsidev) static int dsi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - enum omap_channel dispc_channel = dssdev->dispc_channel; + struct dsi_data *dsi = to_dsi_data(dssdev); int r; - r = dsi_regulator_init(dsidev); + r = dsi_regulator_init(dsi); if (r) return r; - r = dss_mgr_connect(dispc_channel, dssdev); + r = dss_mgr_connect(&dsi->output, dssdev); if (r) return r; @@ -5091,7 +4978,7 @@ static int dsi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dssdev->name); - dss_mgr_disconnect(dispc_channel, dssdev); + dss_mgr_disconnect(&dsi->output, dssdev); return r; } @@ -5101,7 +4988,7 @@ static int dsi_connect(struct omap_dss_device *dssdev, static void dsi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel dispc_channel = dssdev->dispc_channel; + struct dsi_data *dsi = to_dsi_data(dssdev); WARN_ON(dst != dssdev->dst); @@ -5110,7 +4997,7 @@ static void dsi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(dispc_channel, dssdev); + dss_mgr_disconnect(&dsi->output, dssdev); } static const struct omapdss_dsi_ops dsi_ops = { @@ -5152,12 +5039,11 @@ static const struct omapdss_dsi_ops dsi_ops = { .set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size, }; -static void dsi_init_output(struct platform_device *dsidev) +static void dsi_init_output(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_device *out = &dsi->output; - out->dev = &dsidev->dev; + out->dev = dsi->dev; out->id = dsi->module_id == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; @@ -5170,18 +5056,16 @@ static void dsi_init_output(struct platform_device *dsidev) omapdss_register_output(out); } -static void dsi_uninit_output(struct platform_device *dsidev) +static void dsi_uninit_output(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_device *out = &dsi->output; omapdss_unregister_output(out); } -static int dsi_probe_of(struct platform_device *pdev) +static int dsi_probe_of(struct dsi_data *dsi) { - struct device_node *node = pdev->dev.of_node; - struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct device_node *node = dsi->dev->of_node; struct property *prop; u32 lane_arr[10]; int len, num_pins; @@ -5195,7 +5079,7 @@ static int dsi_probe_of(struct platform_device *pdev) prop = of_find_property(ep, "lanes", &len); if (prop == NULL) { - dev_err(&pdev->dev, "failed to find lane data\n"); + dev_err(dsi->dev, "failed to find lane data\n"); r = -EINVAL; goto err; } @@ -5204,14 +5088,14 @@ static int dsi_probe_of(struct platform_device *pdev) if (num_pins < 4 || num_pins % 2 != 0 || num_pins > dsi->num_lanes_supported * 2) { - dev_err(&pdev->dev, "bad number of lanes\n"); + dev_err(dsi->dev, "bad number of lanes\n"); r = -EINVAL; goto err; } r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins); if (r) { - dev_err(&pdev->dev, "failed to read lane data\n"); + dev_err(dsi->dev, "failed to read lane data\n"); goto err; } @@ -5221,7 +5105,7 @@ static int dsi_probe_of(struct platform_device *pdev) r = dsi_configure_pins(&dsi->output, &pin_cfg); if (r) { - dev_err(&pdev->dev, "failed to configure pins"); + dev_err(dsi->dev, "failed to configure pins"); goto err; } @@ -5321,14 +5205,13 @@ static const struct dss_pll_hw dss_omap5_dsi_pll_hw = { .has_refsel = true, }; -static int dsi_init_pll_data(struct platform_device *dsidev) +static int dsi_init_pll_data(struct dss_device *dss, struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll *pll = &dsi->pll; struct clk *clk; int r; - clk = devm_clk_get(&dsidev->dev, "sys_clk"); + clk = devm_clk_get(dsi->dev, "sys_clk"); if (IS_ERR(clk)) { DSSERR("can't get sys_clk\n"); return PTR_ERR(clk); @@ -5341,7 +5224,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev) pll->hw = dsi->data->pll_hw; pll->ops = &dsi_pll_ops; - r = dss_pll_register(pll); + r = dss_pll_register(dss, pll); if (r) return r; @@ -5413,9 +5296,11 @@ static const struct soc_device_attribute dsi_soc_devices[] = { { .machine = "AM35*", .data = &dsi_of_data_omap34xx }, { /* sentinel */ } }; + static int dsi_bind(struct device *dev, struct device *master, void *data) { - struct platform_device *dsidev = to_platform_device(dev); + struct platform_device *pdev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); const struct soc_device_attribute *soc; const struct dsi_module_id_data *d; u32 rev; @@ -5424,12 +5309,13 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) struct resource *dsi_mem; struct resource *res; - dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL); + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); if (!dsi) return -ENOMEM; - dsi->pdev = dsidev; - dev_set_drvdata(&dsidev->dev, dsi); + dsi->dss = dss; + dsi->dev = dev; + dev_set_drvdata(dev, dsi); spin_lock_init(&dsi->irq_lock); spin_lock_init(&dsi->errors_lock); @@ -5450,29 +5336,29 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) timer_setup(&dsi->te_timer, dsi_te_timeout, 0); #endif - dsi_mem = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "proto"); - dsi->proto_base = devm_ioremap_resource(&dsidev->dev, dsi_mem); + dsi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "proto"); + dsi->proto_base = devm_ioremap_resource(dev, dsi_mem); if (IS_ERR(dsi->proto_base)) return PTR_ERR(dsi->proto_base); - res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "phy"); - dsi->phy_base = devm_ioremap_resource(&dsidev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); + dsi->phy_base = devm_ioremap_resource(dev, res); if (IS_ERR(dsi->phy_base)) return PTR_ERR(dsi->phy_base); - res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "pll"); - dsi->pll_base = devm_ioremap_resource(&dsidev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); + dsi->pll_base = devm_ioremap_resource(dev, res); if (IS_ERR(dsi->pll_base)) return PTR_ERR(dsi->pll_base); - dsi->irq = platform_get_irq(dsi->pdev, 0); + dsi->irq = platform_get_irq(pdev, 0); if (dsi->irq < 0) { DSSERR("platform_get_irq failed\n"); return -ENODEV; } - r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler, - IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); + r = devm_request_irq(dev, dsi->irq, omap_dsi_irq_handler, + IRQF_SHARED, dev_name(dev), dsi); if (r < 0) { DSSERR("request_irq failed\n"); return r; @@ -5520,83 +5406,92 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) dsi->vc[i].vc_id = 0; } - r = dsi_get_clocks(dsidev); + r = dsi_get_clocks(dsi); if (r) return r; - dsi_init_pll_data(dsidev); + dsi_init_pll_data(dss, dsi); - pm_runtime_enable(&dsidev->dev); + pm_runtime_enable(dev); - r = dsi_runtime_get(dsidev); + r = dsi_runtime_get(dsi); if (r) goto err_runtime_get; - rev = dsi_read_reg(dsidev, DSI_REVISION); - dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", + rev = dsi_read_reg(dsi, DSI_REVISION); + dev_dbg(dev, "OMAP DSI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); /* DSI on OMAP3 doesn't have register DSI_GNQ, set number * of data to 3 by default */ if (dsi->data->quirks & DSI_QUIRK_GNQ) /* NB_DATA_LANES */ - dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); + dsi->num_lanes_supported = 1 + REG_GET(dsi, DSI_GNQ, 11, 9); else dsi->num_lanes_supported = 3; - dsi->line_buffer_size = dsi_get_line_buf_size(dsidev); + dsi->line_buffer_size = dsi_get_line_buf_size(dsi); - dsi_init_output(dsidev); + dsi_init_output(dsi); - r = dsi_probe_of(dsidev); + r = dsi_probe_of(dsi); if (r) { DSSERR("Invalid DSI DT data\n"); goto err_probe_of; } - r = of_platform_populate(dsidev->dev.of_node, NULL, NULL, &dsidev->dev); + r = of_platform_populate(dev->of_node, NULL, NULL, dev); if (r) DSSERR("Failed to populate DSI child devices: %d\n", r); - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); if (dsi->module_id == 0) - dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs); - else if (dsi->module_id == 1) - dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs); - + dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi1_regs", + dsi1_dump_regs, + &dsi); + else + dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi2_regs", + dsi2_dump_regs, + &dsi); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS if (dsi->module_id == 0) - dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs); - else if (dsi->module_id == 1) - dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); + dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi1_irqs", + dsi1_dump_irqs, + &dsi); + else + dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi2_irqs", + dsi2_dump_irqs, + &dsi); #endif return 0; err_probe_of: - dsi_uninit_output(dsidev); - dsi_runtime_put(dsidev); + dsi_uninit_output(dsi); + dsi_runtime_put(dsi); err_runtime_get: - pm_runtime_disable(&dsidev->dev); + pm_runtime_disable(dev); return r; } static void dsi_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *dsidev = to_platform_device(dev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = dev_get_drvdata(dev); - of_platform_depopulate(&dsidev->dev); + dss_debugfs_remove_file(dsi->debugfs.irqs); + dss_debugfs_remove_file(dsi->debugfs.regs); + + of_platform_depopulate(dev); WARN_ON(dsi->scp_clk_refcount > 0); dss_pll_unregister(&dsi->pll); - dsi_uninit_output(dsidev); + dsi_uninit_output(dsi); - pm_runtime_disable(&dsidev->dev); + pm_runtime_disable(dev); if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) { regulator_disable(dsi->vdds_dsi_reg); @@ -5622,8 +5517,7 @@ static int dsi_remove(struct platform_device *pdev) static int dsi_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct dsi_data *dsi = dev_get_drvdata(dev); dsi->is_enabled = false; /* ensure the irq handler sees the is_enabled value */ @@ -5631,18 +5525,17 @@ static int dsi_runtime_suspend(struct device *dev) /* wait for current handler to finish before turning the DSI off */ synchronize_irq(dsi->irq); - dispc_runtime_put(); + dispc_runtime_put(dsi->dss->dispc); return 0; } static int dsi_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct dsi_data *dsi = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(dsi->dss->dispc); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c index 967d9e1b34e5..4602a79c6c44 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ b/drivers/gpu/drm/omapdrm/dss/dss-of.c @@ -44,7 +44,6 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port) return NULL; } -EXPORT_SYMBOL_GPL(dss_of_port_get_parent_device); u32 dss_of_port_get_port_number(struct device_node *port) { @@ -57,7 +56,6 @@ u32 dss_of_port_get_port_number(struct device_node *port) return reg; } -EXPORT_SYMBOL_GPL(dss_of_port_get_port_number); struct omap_dss_device * omapdss_of_find_source_for_first_ep(struct device_node *node) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 04300b2da1b1..0b908e9de792 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -48,8 +48,6 @@ #include "omapdss.h" #include "dss.h" -#define DSS_SZ_REGS SZ_512 - struct dss_reg { u16 idx; }; @@ -64,16 +62,19 @@ struct dss_reg { #define DSS_PLL_CONTROL DSS_REG(0x0048) #define DSS_SDI_STATUS DSS_REG(0x005C) -#define REG_GET(idx, start, end) \ - FLD_GET(dss_read_reg(idx), start, end) +#define REG_GET(dss, idx, start, end) \ + FLD_GET(dss_read_reg(dss, idx), start, end) -#define REG_FLD_MOD(idx, val, start, end) \ - dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) +#define REG_FLD_MOD(dss, idx, val, start, end) \ + dss_write_reg(dss, idx, \ + FLD_MOD(dss_read_reg(dss, idx), val, start, end)) struct dss_ops { - int (*dpi_select_source)(int port, enum omap_channel channel); - int (*select_lcd_source)(enum omap_channel channel, - enum dss_clk_source clk_src); + int (*dpi_select_source)(struct dss_device *dss, int port, + enum omap_channel channel); + int (*select_lcd_source)(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src); }; struct dss_features { @@ -90,33 +91,6 @@ struct dss_features { bool has_lcd_clk_src; }; -static struct { - struct platform_device *pdev; - void __iomem *base; - struct regmap *syscon_pll_ctrl; - u32 syscon_pll_ctrl_offset; - - struct clk *parent_clk; - struct clk *dss_clk; - unsigned long dss_clk_rate; - - unsigned long cache_req_pck; - unsigned long cache_prate; - struct dispc_clock_info cache_dispc_cinfo; - - enum dss_clk_source dsi_clk_source[MAX_NUM_DSI]; - enum dss_clk_source dispc_clk_source; - enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; - - bool ctx_valid; - u32 ctx[DSS_SZ_REGS / sizeof(u32)]; - - const struct dss_features *feat; - - struct dss_pll *video1_pll; - struct dss_pll *video2_pll; -} dss; - static const char * const dss_generic_clk_source_names[] = { [DSS_CLK_SRC_FCK] = "FCK", [DSS_CLK_SRC_PLL1_1] = "PLL1:1", @@ -128,49 +102,50 @@ static const char * const dss_generic_clk_source_names[] = { [DSS_CLK_SRC_HDMI_PLL] = "HDMI PLL", }; -static inline void dss_write_reg(const struct dss_reg idx, u32 val) +static inline void dss_write_reg(struct dss_device *dss, + const struct dss_reg idx, u32 val) { - __raw_writel(val, dss.base + idx.idx); + __raw_writel(val, dss->base + idx.idx); } -static inline u32 dss_read_reg(const struct dss_reg idx) +static inline u32 dss_read_reg(struct dss_device *dss, const struct dss_reg idx) { - return __raw_readl(dss.base + idx.idx); + return __raw_readl(dss->base + idx.idx); } -#define SR(reg) \ - dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg) -#define RR(reg) \ - dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)]) +#define SR(dss, reg) \ + dss->ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(dss, DSS_##reg) +#define RR(dss, reg) \ + dss_write_reg(dss, DSS_##reg, dss->ctx[(DSS_##reg).idx / sizeof(u32)]) -static void dss_save_context(void) +static void dss_save_context(struct dss_device *dss) { DSSDBG("dss_save_context\n"); - SR(CONTROL); + SR(dss, CONTROL); - if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { - SR(SDI_CONTROL); - SR(PLL_CONTROL); + if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { + SR(dss, SDI_CONTROL); + SR(dss, PLL_CONTROL); } - dss.ctx_valid = true; + dss->ctx_valid = true; DSSDBG("context saved\n"); } -static void dss_restore_context(void) +static void dss_restore_context(struct dss_device *dss) { DSSDBG("dss_restore_context\n"); - if (!dss.ctx_valid) + if (!dss->ctx_valid) return; - RR(CONTROL); + RR(dss, CONTROL); - if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { - RR(SDI_CONTROL); - RR(PLL_CONTROL); + if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { + RR(dss, SDI_CONTROL); + RR(dss, PLL_CONTROL); } DSSDBG("context restored\n"); @@ -179,17 +154,17 @@ static void dss_restore_context(void) #undef SR #undef RR -void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) +void dss_ctrl_pll_enable(struct dss_pll *pll, bool enable) { - unsigned shift; - unsigned val; + unsigned int shift; + unsigned int val; - if (!dss.syscon_pll_ctrl) + if (!pll->dss->syscon_pll_ctrl) return; val = !enable; - switch (pll_id) { + switch (pll->id) { case DSS_PLL_VIDEO1: shift = 0; break; @@ -200,20 +175,22 @@ void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) shift = 2; break; default: - DSSERR("illegal DSS PLL ID %d\n", pll_id); + DSSERR("illegal DSS PLL ID %d\n", pll->id); return; } - regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset, - 1 << shift, val << shift); + regmap_update_bits(pll->dss->syscon_pll_ctrl, + pll->dss->syscon_pll_ctrl_offset, + 1 << shift, val << shift); } -static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, - enum omap_channel channel) +static int dss_ctrl_pll_set_control_mux(struct dss_device *dss, + enum dss_clk_source clk_src, + enum omap_channel channel) { - unsigned shift, val; + unsigned int shift, val; - if (!dss.syscon_pll_ctrl) + if (!dss->syscon_pll_ctrl) return -EINVAL; switch (channel) { @@ -268,47 +245,47 @@ static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, return -EINVAL; } - regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset, + regmap_update_bits(dss->syscon_pll_ctrl, dss->syscon_pll_ctrl_offset, 0x3 << shift, val << shift); return 0; } -void dss_sdi_init(int datapairs) +void dss_sdi_init(struct dss_device *dss, int datapairs) { u32 l; BUG_ON(datapairs > 3 || datapairs < 1); - l = dss_read_reg(DSS_SDI_CONTROL); + l = dss_read_reg(dss, DSS_SDI_CONTROL); l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */ l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */ l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */ - dss_write_reg(DSS_SDI_CONTROL, l); + dss_write_reg(dss, DSS_SDI_CONTROL, l); - l = dss_read_reg(DSS_PLL_CONTROL); + l = dss_read_reg(dss, DSS_PLL_CONTROL); l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */ l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */ l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */ - dss_write_reg(DSS_PLL_CONTROL, l); + dss_write_reg(dss, DSS_PLL_CONTROL, l); } -int dss_sdi_enable(void) +int dss_sdi_enable(struct dss_device *dss) { unsigned long timeout; - dispc_pck_free_enable(1); + dispc_pck_free_enable(dss->dispc, 1); /* Reset SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */ udelay(1); /* wait 2x PCLK */ /* Lock SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */ /* Waiting for PLL lock request to complete */ timeout = jiffies + msecs_to_jiffies(500); - while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) { + while (dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 6)) { if (time_after_eq(jiffies, timeout)) { DSSERR("PLL lock request timed out\n"); goto err1; @@ -316,22 +293,22 @@ int dss_sdi_enable(void) } /* Clearing PLL_GO bit */ - REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28); + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 28, 28); /* Waiting for PLL to lock */ timeout = jiffies + msecs_to_jiffies(500); - while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) { + while (!(dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 5))) { if (time_after_eq(jiffies, timeout)) { DSSERR("PLL lock timed out\n"); goto err1; } } - dispc_lcd_enable_signal(1); + dispc_lcd_enable_signal(dss->dispc, 1); /* Waiting for SDI reset to complete */ timeout = jiffies + msecs_to_jiffies(500); - while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) { + while (!(dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 2))) { if (time_after_eq(jiffies, timeout)) { DSSERR("SDI reset timed out\n"); goto err2; @@ -341,24 +318,24 @@ int dss_sdi_enable(void) return 0; err2: - dispc_lcd_enable_signal(0); + dispc_lcd_enable_signal(dss->dispc, 0); err1: /* Reset SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ - dispc_pck_free_enable(0); + dispc_pck_free_enable(dss->dispc, 0); return -ETIMEDOUT; } -void dss_sdi_disable(void) +void dss_sdi_disable(struct dss_device *dss) { - dispc_lcd_enable_signal(0); + dispc_lcd_enable_signal(dss->dispc, 0); - dispc_pck_free_enable(0); + dispc_pck_free_enable(dss->dispc, 0); /* Reset SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ } const char *dss_get_clk_source_name(enum dss_clk_source clk_src) @@ -366,48 +343,61 @@ const char *dss_get_clk_source_name(enum dss_clk_source clk_src) return dss_generic_clk_source_names[clk_src]; } -#if defined(CONFIG_OMAP2_DSS_DEBUGFS) -static void dss_dump_clocks(struct seq_file *s) +static void dss_dump_clocks(struct dss_device *dss, struct seq_file *s) { const char *fclk_name; unsigned long fclk_rate; - if (dss_runtime_get()) + if (dss_runtime_get(dss)) return; seq_printf(s, "- DSS -\n"); fclk_name = dss_get_clk_source_name(DSS_CLK_SRC_FCK); - fclk_rate = clk_get_rate(dss.dss_clk); + fclk_rate = clk_get_rate(dss->dss_clk); seq_printf(s, "%s = %lu\n", fclk_name, fclk_rate); - dss_runtime_put(); + dss_runtime_put(dss); } -#endif -static void dss_dump_regs(struct seq_file *s) +static int dss_dump_regs(struct seq_file *s, void *p) { -#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) + struct dss_device *dss = s->private; - if (dss_runtime_get()) - return; +#define DUMPREG(dss, r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(dss, r)) + + if (dss_runtime_get(dss)) + return 0; - DUMPREG(DSS_REVISION); - DUMPREG(DSS_SYSCONFIG); - DUMPREG(DSS_SYSSTATUS); - DUMPREG(DSS_CONTROL); + DUMPREG(dss, DSS_REVISION); + DUMPREG(dss, DSS_SYSCONFIG); + DUMPREG(dss, DSS_SYSSTATUS); + DUMPREG(dss, DSS_CONTROL); - if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { - DUMPREG(DSS_SDI_CONTROL); - DUMPREG(DSS_PLL_CONTROL); - DUMPREG(DSS_SDI_STATUS); + if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { + DUMPREG(dss, DSS_SDI_CONTROL); + DUMPREG(dss, DSS_PLL_CONTROL); + DUMPREG(dss, DSS_SDI_STATUS); } - dss_runtime_put(); + dss_runtime_put(dss); #undef DUMPREG + return 0; +} + +static int dss_debug_dump_clocks(struct seq_file *s, void *p) +{ + struct dss_device *dss = s->private; + + dss_dump_clocks(dss, s); + dispc_dump_clocks(dss->dispc, s); +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_dump_clocks(s); +#endif + return 0; } static int dss_get_channel_index(enum omap_channel channel) @@ -425,7 +415,8 @@ static int dss_get_channel_index(enum omap_channel channel) } } -static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) +static void dss_select_dispc_clk_source(struct dss_device *dss, + enum dss_clk_source clk_src) { int b; @@ -433,7 +424,7 @@ static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) * We always use PRCM clock as the DISPC func clock, except on DSS3, * where we don't have separate DISPC and LCD clock sources. */ - if (WARN_ON(dss.feat->has_lcd_clk_src && clk_src != DSS_CLK_SRC_FCK)) + if (WARN_ON(dss->feat->has_lcd_clk_src && clk_src != DSS_CLK_SRC_FCK)) return; switch (clk_src) { @@ -451,15 +442,15 @@ static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) return; } - REG_FLD_MOD(DSS_CONTROL, b, /* DISPC_CLK_SWITCH */ - dss.feat->dispc_clk_switch.start, - dss.feat->dispc_clk_switch.end); + REG_FLD_MOD(dss, DSS_CONTROL, b, /* DISPC_CLK_SWITCH */ + dss->feat->dispc_clk_switch.start, + dss->feat->dispc_clk_switch.end); - dss.dispc_clk_source = clk_src; + dss->dispc_clk_source = clk_src; } -void dss_select_dsi_clk_source(int dsi_module, - enum dss_clk_source clk_src) +void dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module, + enum dss_clk_source clk_src) { int b, pos; @@ -481,13 +472,14 @@ void dss_select_dsi_clk_source(int dsi_module, } pos = dsi_module == 0 ? 1 : 10; - REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */ + REG_FLD_MOD(dss, DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */ - dss.dsi_clk_source[dsi_module] = clk_src; + dss->dsi_clk_source[dsi_module] = clk_src; } -static int dss_lcd_clk_mux_dra7(enum omap_channel channel, - enum dss_clk_source clk_src) +static int dss_lcd_clk_mux_dra7(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { const u8 ctrl_bits[] = { [OMAP_DSS_CHANNEL_LCD] = 0, @@ -500,21 +492,22 @@ static int dss_lcd_clk_mux_dra7(enum omap_channel channel, if (clk_src == DSS_CLK_SRC_FCK) { /* LCDx_CLK_SWITCH */ - REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit); return -EINVAL; } - r = dss_ctrl_pll_set_control_mux(clk_src, channel); + r = dss_ctrl_pll_set_control_mux(dss, clk_src, channel); if (r) return r; - REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit); return 0; } -static int dss_lcd_clk_mux_omap5(enum omap_channel channel, - enum dss_clk_source clk_src) +static int dss_lcd_clk_mux_omap5(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { const u8 ctrl_bits[] = { [OMAP_DSS_CHANNEL_LCD] = 0, @@ -531,20 +524,21 @@ static int dss_lcd_clk_mux_omap5(enum omap_channel channel, if (clk_src == DSS_CLK_SRC_FCK) { /* LCDx_CLK_SWITCH */ - REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit); return -EINVAL; } if (WARN_ON(allowed_plls[channel] != clk_src)) return -EINVAL; - REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit); return 0; } -static int dss_lcd_clk_mux_omap4(enum omap_channel channel, - enum dss_clk_source clk_src) +static int dss_lcd_clk_mux_omap4(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { const u8 ctrl_bits[] = { [OMAP_DSS_CHANNEL_LCD] = 0, @@ -559,87 +553,90 @@ static int dss_lcd_clk_mux_omap4(enum omap_channel channel, if (clk_src == DSS_CLK_SRC_FCK) { /* LCDx_CLK_SWITCH */ - REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit); return 0; } if (WARN_ON(allowed_plls[channel] != clk_src)) return -EINVAL; - REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit); return 0; } -void dss_select_lcd_clk_source(enum omap_channel channel, - enum dss_clk_source clk_src) +void dss_select_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { int idx = dss_get_channel_index(channel); int r; - if (!dss.feat->has_lcd_clk_src) { - dss_select_dispc_clk_source(clk_src); - dss.lcd_clk_source[idx] = clk_src; + if (!dss->feat->has_lcd_clk_src) { + dss_select_dispc_clk_source(dss, clk_src); + dss->lcd_clk_source[idx] = clk_src; return; } - r = dss.feat->ops->select_lcd_source(channel, clk_src); + r = dss->feat->ops->select_lcd_source(dss, channel, clk_src); if (r) return; - dss.lcd_clk_source[idx] = clk_src; + dss->lcd_clk_source[idx] = clk_src; } -enum dss_clk_source dss_get_dispc_clk_source(void) +enum dss_clk_source dss_get_dispc_clk_source(struct dss_device *dss) { - return dss.dispc_clk_source; + return dss->dispc_clk_source; } -enum dss_clk_source dss_get_dsi_clk_source(int dsi_module) +enum dss_clk_source dss_get_dsi_clk_source(struct dss_device *dss, + int dsi_module) { - return dss.dsi_clk_source[dsi_module]; + return dss->dsi_clk_source[dsi_module]; } -enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) +enum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel) { - if (dss.feat->has_lcd_clk_src) { + if (dss->feat->has_lcd_clk_src) { int idx = dss_get_channel_index(channel); - return dss.lcd_clk_source[idx]; + return dss->lcd_clk_source[idx]; } else { /* LCD_CLK source is the same as DISPC_FCLK source for * OMAP2 and OMAP3 */ - return dss.dispc_clk_source; + return dss->dispc_clk_source; } } -bool dss_div_calc(unsigned long pck, unsigned long fck_min, - dss_div_calc_func func, void *data) +bool dss_div_calc(struct dss_device *dss, unsigned long pck, + unsigned long fck_min, dss_div_calc_func func, void *data) { int fckd, fckd_start, fckd_stop; unsigned long fck; unsigned long fck_hw_max; unsigned long fckd_hw_max; unsigned long prate; - unsigned m; + unsigned int m; - fck_hw_max = dss.feat->fck_freq_max; + fck_hw_max = dss->feat->fck_freq_max; - if (dss.parent_clk == NULL) { - unsigned pckd; + if (dss->parent_clk == NULL) { + unsigned int pckd; pckd = fck_hw_max / pck; fck = pck * pckd; - fck = clk_round_rate(dss.dss_clk, fck); + fck = clk_round_rate(dss->dss_clk, fck); return func(fck, data); } - fckd_hw_max = dss.feat->fck_div_max; + fckd_hw_max = dss->feat->fck_div_max; - m = dss.feat->dss_fck_multiplier; - prate = clk_get_rate(dss.parent_clk); + m = dss->feat->dss_fck_multiplier; + prate = clk_get_rate(dss->parent_clk); fck_min = fck_min ? fck_min : 1; @@ -656,67 +653,68 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, return false; } -int dss_set_fck_rate(unsigned long rate) +int dss_set_fck_rate(struct dss_device *dss, unsigned long rate) { int r; DSSDBG("set fck to %lu\n", rate); - r = clk_set_rate(dss.dss_clk, rate); + r = clk_set_rate(dss->dss_clk, rate); if (r) return r; - dss.dss_clk_rate = clk_get_rate(dss.dss_clk); + dss->dss_clk_rate = clk_get_rate(dss->dss_clk); - WARN_ONCE(dss.dss_clk_rate != rate, - "clk rate mismatch: %lu != %lu", dss.dss_clk_rate, - rate); + WARN_ONCE(dss->dss_clk_rate != rate, "clk rate mismatch: %lu != %lu", + dss->dss_clk_rate, rate); return 0; } -unsigned long dss_get_dispc_clk_rate(void) +unsigned long dss_get_dispc_clk_rate(struct dss_device *dss) { - return dss.dss_clk_rate; + return dss->dss_clk_rate; } -unsigned long dss_get_max_fck_rate(void) +unsigned long dss_get_max_fck_rate(struct dss_device *dss) { - return dss.feat->fck_freq_max; + return dss->feat->fck_freq_max; } -enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel) +enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss, + enum omap_channel channel) { - return dss.feat->outputs[channel]; + return dss->feat->outputs[channel]; } -static int dss_setup_default_clock(void) +static int dss_setup_default_clock(struct dss_device *dss) { unsigned long max_dss_fck, prate; unsigned long fck; - unsigned fck_div; + unsigned int fck_div; int r; - max_dss_fck = dss.feat->fck_freq_max; + max_dss_fck = dss->feat->fck_freq_max; - if (dss.parent_clk == NULL) { - fck = clk_round_rate(dss.dss_clk, max_dss_fck); + if (dss->parent_clk == NULL) { + fck = clk_round_rate(dss->dss_clk, max_dss_fck); } else { - prate = clk_get_rate(dss.parent_clk); + prate = clk_get_rate(dss->parent_clk); - fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, + fck_div = DIV_ROUND_UP(prate * dss->feat->dss_fck_multiplier, max_dss_fck); - fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier; + fck = DIV_ROUND_UP(prate, fck_div) + * dss->feat->dss_fck_multiplier; } - r = dss_set_fck_rate(fck); + r = dss_set_fck_rate(dss, fck); if (r) return r; return 0; } -void dss_set_venc_output(enum omap_dss_venc_type type) +void dss_set_venc_output(struct dss_device *dss, enum omap_dss_venc_type type) { int l = 0; @@ -728,19 +726,21 @@ void dss_set_venc_output(enum omap_dss_venc_type type) BUG(); /* venc out selection. 0 = comp, 1 = svideo */ - REG_FLD_MOD(DSS_CONTROL, l, 6, 6); + REG_FLD_MOD(dss, DSS_CONTROL, l, 6, 6); } -void dss_set_dac_pwrdn_bgz(bool enable) +void dss_set_dac_pwrdn_bgz(struct dss_device *dss, bool enable) { - REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ + /* DAC Power-Down Control */ + REG_FLD_MOD(dss, DSS_CONTROL, enable, 5, 5); } -void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) +void dss_select_hdmi_venc_clk_source(struct dss_device *dss, + enum dss_hdmi_venc_clk_source_select src) { enum omap_dss_output_id outputs; - outputs = dss.feat->outputs[OMAP_DSS_CHANNEL_DIGIT]; + outputs = dss->feat->outputs[OMAP_DSS_CHANNEL_DIGIT]; /* Complain about invalid selections */ WARN_ON((src == DSS_VENC_TV_CLK) && !(outputs & OMAP_DSS_OUTPUT_VENC)); @@ -749,24 +749,12 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) /* Select only if we have options */ if ((outputs & OMAP_DSS_OUTPUT_VENC) && (outputs & OMAP_DSS_OUTPUT_HDMI)) - REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ -} - -enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) -{ - enum omap_dss_output_id outputs; - - outputs = dss.feat->outputs[OMAP_DSS_CHANNEL_DIGIT]; - if ((outputs & OMAP_DSS_OUTPUT_HDMI) == 0) - return DSS_VENC_TV_CLK; - - if ((outputs & OMAP_DSS_OUTPUT_VENC) == 0) - return DSS_HDMI_M_PCLK; - - return REG_GET(DSS_CONTROL, 15, 15); + /* VENC_HDMI_SWITCH */ + REG_FLD_MOD(dss, DSS_CONTROL, src, 15, 15); } -static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel) +static int dss_dpi_select_source_omap2_omap3(struct dss_device *dss, int port, + enum omap_channel channel) { if (channel != OMAP_DSS_CHANNEL_LCD) return -EINVAL; @@ -774,7 +762,8 @@ static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel return 0; } -static int dss_dpi_select_source_omap4(int port, enum omap_channel channel) +static int dss_dpi_select_source_omap4(struct dss_device *dss, int port, + enum omap_channel channel) { int val; @@ -789,12 +778,13 @@ static int dss_dpi_select_source_omap4(int port, enum omap_channel channel) return -EINVAL; } - REG_FLD_MOD(DSS_CONTROL, val, 17, 17); + REG_FLD_MOD(dss, DSS_CONTROL, val, 17, 17); return 0; } -static int dss_dpi_select_source_omap5(int port, enum omap_channel channel) +static int dss_dpi_select_source_omap5(struct dss_device *dss, int port, + enum omap_channel channel) { int val; @@ -815,16 +805,17 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel) return -EINVAL; } - REG_FLD_MOD(DSS_CONTROL, val, 17, 16); + REG_FLD_MOD(dss, DSS_CONTROL, val, 17, 16); return 0; } -static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel) +static int dss_dpi_select_source_dra7xx(struct dss_device *dss, int port, + enum omap_channel channel) { switch (port) { case 0: - return dss_dpi_select_source_omap5(port, channel); + return dss_dpi_select_source_omap5(dss, port, channel); case 1: if (channel != OMAP_DSS_CHANNEL_LCD2) return -EINVAL; @@ -840,135 +831,153 @@ static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel) return 0; } -int dss_dpi_select_source(int port, enum omap_channel channel) +int dss_dpi_select_source(struct dss_device *dss, int port, + enum omap_channel channel) { - return dss.feat->ops->dpi_select_source(port, channel); + return dss->feat->ops->dpi_select_source(dss, port, channel); } -static int dss_get_clocks(void) +static int dss_get_clocks(struct dss_device *dss) { struct clk *clk; - clk = devm_clk_get(&dss.pdev->dev, "fck"); + clk = devm_clk_get(&dss->pdev->dev, "fck"); if (IS_ERR(clk)) { DSSERR("can't get clock fck\n"); return PTR_ERR(clk); } - dss.dss_clk = clk; + dss->dss_clk = clk; - if (dss.feat->parent_clk_name) { - clk = clk_get(NULL, dss.feat->parent_clk_name); + if (dss->feat->parent_clk_name) { + clk = clk_get(NULL, dss->feat->parent_clk_name); if (IS_ERR(clk)) { - DSSERR("Failed to get %s\n", dss.feat->parent_clk_name); + DSSERR("Failed to get %s\n", + dss->feat->parent_clk_name); return PTR_ERR(clk); } } else { clk = NULL; } - dss.parent_clk = clk; + dss->parent_clk = clk; return 0; } -static void dss_put_clocks(void) +static void dss_put_clocks(struct dss_device *dss) { - if (dss.parent_clk) - clk_put(dss.parent_clk); + if (dss->parent_clk) + clk_put(dss->parent_clk); } -int dss_runtime_get(void) +int dss_runtime_get(struct dss_device *dss) { int r; DSSDBG("dss_runtime_get\n"); - r = pm_runtime_get_sync(&dss.pdev->dev); + r = pm_runtime_get_sync(&dss->pdev->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } -void dss_runtime_put(void) +void dss_runtime_put(struct dss_device *dss) { int r; DSSDBG("dss_runtime_put\n"); - r = pm_runtime_put_sync(&dss.pdev->dev); + r = pm_runtime_put_sync(&dss->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY); } -/* DEBUGFS */ -#if defined(CONFIG_OMAP2_DSS_DEBUGFS) -static void dss_debug_dump_clocks(struct seq_file *s) +struct dss_device *dss_get_device(struct device *dev) { - dss_dump_clocks(s); - dispc_dump_clocks(s); -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_dump_clocks(s); -#endif + return dev_get_drvdata(dev); } -static int dss_debug_show(struct seq_file *s, void *unused) +/* DEBUGFS */ +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) +static int dss_initialize_debugfs(struct dss_device *dss) { - void (*func)(struct seq_file *) = s->private; + struct dentry *dir; + + dir = debugfs_create_dir("omapdss", NULL); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + dss->debugfs.root = dir; - func(s); return 0; } +static void dss_uninitialize_debugfs(struct dss_device *dss) +{ + debugfs_remove_recursive(dss->debugfs.root); +} + +struct dss_debugfs_entry { + struct dentry *dentry; + int (*show_fn)(struct seq_file *s, void *data); + void *data; +}; + static int dss_debug_open(struct inode *inode, struct file *file) { - return single_open(file, dss_debug_show, inode->i_private); + struct dss_debugfs_entry *entry = inode->i_private; + + return single_open(file, entry->show_fn, entry->data); } static const struct file_operations dss_debug_fops = { - .open = dss_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, + .open = dss_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; -static struct dentry *dss_debugfs_dir; - -static int dss_initialize_debugfs(void) +struct dss_debugfs_entry * +dss_debugfs_create_file(struct dss_device *dss, const char *name, + int (*show_fn)(struct seq_file *s, void *data), + void *data) { - dss_debugfs_dir = debugfs_create_dir("omapdss", NULL); - if (IS_ERR(dss_debugfs_dir)) { - int err = PTR_ERR(dss_debugfs_dir); + struct dss_debugfs_entry *entry; + struct dentry *d; - dss_debugfs_dir = NULL; - return err; - } + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return ERR_PTR(-ENOMEM); - debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, - &dss_debug_dump_clocks, &dss_debug_fops); + entry->show_fn = show_fn; + entry->data = data; - return 0; -} + d = debugfs_create_file(name, 0444, dss->debugfs.root, entry, + &dss_debug_fops); + if (IS_ERR(d)) { + kfree(entry); + return ERR_PTR(PTR_ERR(d)); + } -static void dss_uninitialize_debugfs(void) -{ - if (dss_debugfs_dir) - debugfs_remove_recursive(dss_debugfs_dir); + entry->dentry = d; + return entry; } -int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) +void dss_debugfs_remove_file(struct dss_debugfs_entry *entry) { - struct dentry *d; - - d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, - write, &dss_debug_fops); + if (IS_ERR_OR_NULL(entry)) + return; - return PTR_ERR_OR_ZERO(d); + debugfs_remove(entry->dentry); + kfree(entry); } + #else /* CONFIG_OMAP2_DSS_DEBUGFS */ -static inline int dss_initialize_debugfs(void) +static inline int dss_initialize_debugfs(struct dss_device *dss) { return 0; } -static inline void dss_uninitialize_debugfs(void) +static inline void dss_uninitialize_debugfs(struct dss_device *dss) { } #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ @@ -1169,23 +1178,24 @@ static const struct dss_features dra7xx_dss_feats = { .has_lcd_clk_src = true, }; -static int dss_init_ports(struct platform_device *pdev) +static int dss_init_ports(struct dss_device *dss) { + struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; int i; - for (i = 0; i < dss.feat->num_ports; i++) { + for (i = 0; i < dss->feat->num_ports; i++) { port = of_graph_get_port_by_id(parent, i); if (!port) continue; - switch (dss.feat->ports[i]) { + switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - dpi_init_port(pdev, port, dss.feat->model); + dpi_init_port(dss, pdev, port, dss->feat->model); break; case OMAP_DISPLAY_TYPE_SDI: - sdi_init_port(pdev, port); + sdi_init_port(dss, pdev, port); break; default: break; @@ -1195,18 +1205,19 @@ static int dss_init_ports(struct platform_device *pdev) return 0; } -static void dss_uninit_ports(struct platform_device *pdev) +static void dss_uninit_ports(struct dss_device *dss) { + struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; int i; - for (i = 0; i < dss.feat->num_ports; i++) { + for (i = 0; i < dss->feat->num_ports; i++) { port = of_graph_get_port_by_id(parent, i); if (!port) continue; - switch (dss.feat->ports[i]) { + switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: dpi_uninit_port(port); break; @@ -1219,8 +1230,9 @@ static void dss_uninit_ports(struct platform_device *pdev) } } -static int dss_video_pll_probe(struct platform_device *pdev) +static int dss_video_pll_probe(struct dss_device *dss) { + struct platform_device *pdev = dss->pdev; struct device_node *np = pdev->dev.of_node; struct regulator *pll_regulator; int r; @@ -1229,16 +1241,16 @@ static int dss_video_pll_probe(struct platform_device *pdev) return 0; if (of_property_read_bool(np, "syscon-pll-ctrl")) { - dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np, + dss->syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np, "syscon-pll-ctrl"); - if (IS_ERR(dss.syscon_pll_ctrl)) { + if (IS_ERR(dss->syscon_pll_ctrl)) { dev_err(&pdev->dev, "failed to get syscon-pll-ctrl regmap\n"); - return PTR_ERR(dss.syscon_pll_ctrl); + return PTR_ERR(dss->syscon_pll_ctrl); } if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1, - &dss.syscon_pll_ctrl_offset)) { + &dss->syscon_pll_ctrl_offset)) { dev_err(&pdev->dev, "failed to get syscon-pll-ctrl offset\n"); return -EINVAL; @@ -1264,16 +1276,18 @@ static int dss_video_pll_probe(struct platform_device *pdev) } if (of_property_match_string(np, "reg-names", "pll1") >= 0) { - dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator); - if (IS_ERR(dss.video1_pll)) - return PTR_ERR(dss.video1_pll); + dss->video1_pll = dss_video_pll_init(dss, pdev, 0, + pll_regulator); + if (IS_ERR(dss->video1_pll)) + return PTR_ERR(dss->video1_pll); } if (of_property_match_string(np, "reg-names", "pll2") >= 0) { - dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator); - if (IS_ERR(dss.video2_pll)) { - dss_video_pll_uninit(dss.video1_pll); - return PTR_ERR(dss.video2_pll); + dss->video2_pll = dss_video_pll_init(dss, pdev, 1, + pll_regulator); + if (IS_ERR(dss->video2_pll)) { + dss_video_pll_uninit(dss->video1_pll); + return PTR_ERR(dss->video2_pll); } } @@ -1300,109 +1314,26 @@ static const struct soc_device_attribute dss_soc_devices[] = { static int dss_bind(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct resource *dss_mem; - u32 rev; + struct dss_device *dss = dev_get_drvdata(dev); int r; - dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); - dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); - if (IS_ERR(dss.base)) - return PTR_ERR(dss.base); - - r = dss_get_clocks(); + r = component_bind_all(dev, NULL); if (r) return r; - r = dss_setup_default_clock(); - if (r) - goto err_setup_clocks; - - r = dss_video_pll_probe(pdev); - if (r) - goto err_pll_init; - - r = dss_init_ports(pdev); - if (r) - goto err_init_ports; - - pm_runtime_enable(&pdev->dev); - - r = dss_runtime_get(); - if (r) - goto err_runtime_get; - - dss.dss_clk_rate = clk_get_rate(dss.dss_clk); - - /* Select DPLL */ - REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); - - dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); - -#ifdef CONFIG_OMAP2_DSS_VENC - REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ - REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ - REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ -#endif - dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; - dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; - dss.dispc_clk_source = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; - - rev = dss_read_reg(DSS_REVISION); - pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - - dss_runtime_put(); - - r = component_bind_all(&pdev->dev, NULL); - if (r) - goto err_component; - - dss_debugfs_create_file("dss", dss_dump_regs); - pm_set_vt_switch(0); omapdss_gather_components(dev); - omapdss_set_is_initialized(true); + omapdss_set_dss(dss); return 0; - -err_component: -err_runtime_get: - pm_runtime_disable(&pdev->dev); - dss_uninit_ports(pdev); -err_init_ports: - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); - - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); -err_pll_init: -err_setup_clocks: - dss_put_clocks(); - return r; } static void dss_unbind(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - - omapdss_set_is_initialized(false); + omapdss_set_dss(NULL); - component_unbind_all(&pdev->dev, NULL); - - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); - - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); - - dss_uninit_ports(pdev); - - pm_runtime_disable(&pdev->dev); - - dss_put_clocks(); + component_unbind_all(dev, NULL); } static const struct component_master_ops dss_component_ops = { @@ -1434,18 +1365,60 @@ static int dss_add_child_component(struct device *dev, void *data) return 0; } +static int dss_probe_hardware(struct dss_device *dss) +{ + u32 rev; + int r; + + r = dss_runtime_get(dss); + if (r) + return r; + + dss->dss_clk_rate = clk_get_rate(dss->dss_clk); + + /* Select DPLL */ + REG_FLD_MOD(dss, DSS_CONTROL, 0, 0, 0); + + dss_select_dispc_clk_source(dss, DSS_CLK_SRC_FCK); + +#ifdef CONFIG_OMAP2_DSS_VENC + REG_FLD_MOD(dss, DSS_CONTROL, 1, 4, 4); /* venc dac demen */ + REG_FLD_MOD(dss, DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ + REG_FLD_MOD(dss, DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ +#endif + dss->dsi_clk_source[0] = DSS_CLK_SRC_FCK; + dss->dsi_clk_source[1] = DSS_CLK_SRC_FCK; + dss->dispc_clk_source = DSS_CLK_SRC_FCK; + dss->lcd_clk_source[0] = DSS_CLK_SRC_FCK; + dss->lcd_clk_source[1] = DSS_CLK_SRC_FCK; + + rev = dss_read_reg(dss, DSS_REVISION); + pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + + dss_runtime_put(dss); + + return 0; +} + static int dss_probe(struct platform_device *pdev) { const struct soc_device_attribute *soc; struct component_match *match = NULL; + struct resource *dss_mem; + struct dss_device *dss; int r; - dss.pdev = pdev; + dss = kzalloc(sizeof(*dss), GFP_KERNEL); + if (!dss) + return -ENOMEM; + + dss->pdev = pdev; + platform_set_drvdata(pdev, dss); r = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (r) { dev_err(&pdev->dev, "Failed to set the DMA mask\n"); - return r; + goto err_free_dss; } /* @@ -1454,31 +1427,108 @@ static int dss_probe(struct platform_device *pdev) */ soc = soc_device_match(dss_soc_devices); if (soc) - dss.feat = soc->data; + dss->feat = soc->data; else - dss.feat = of_match_device(dss_of_match, &pdev->dev)->data; + dss->feat = of_match_device(dss_of_match, &pdev->dev)->data; + + /* Map I/O registers, get and setup clocks. */ + dss_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dss->base = devm_ioremap_resource(&pdev->dev, dss_mem); + if (IS_ERR(dss->base)) { + r = PTR_ERR(dss->base); + goto err_free_dss; + } - r = dss_initialize_debugfs(); + r = dss_get_clocks(dss); if (r) - return r; + goto err_free_dss; + + r = dss_setup_default_clock(dss); + if (r) + goto err_put_clocks; - /* add all the child devices as components */ + /* Setup the video PLLs and the DPI and SDI ports. */ + r = dss_video_pll_probe(dss); + if (r) + goto err_put_clocks; + + r = dss_init_ports(dss); + if (r) + goto err_uninit_plls; + + /* Enable runtime PM and probe the hardware. */ + pm_runtime_enable(&pdev->dev); + + r = dss_probe_hardware(dss); + if (r) + goto err_pm_runtime_disable; + + /* Initialize debugfs. */ + r = dss_initialize_debugfs(dss); + if (r) + goto err_pm_runtime_disable; + + dss->debugfs.clk = dss_debugfs_create_file(dss, "clk", + dss_debug_dump_clocks, dss); + dss->debugfs.dss = dss_debugfs_create_file(dss, "dss", dss_dump_regs, + dss); + + /* Add all the child devices as components. */ device_for_each_child(&pdev->dev, &match, dss_add_child_component); r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); - if (r) { - dss_uninitialize_debugfs(); - return r; - } + if (r) + goto err_uninit_debugfs; return 0; + +err_uninit_debugfs: + dss_debugfs_remove_file(dss->debugfs.clk); + dss_debugfs_remove_file(dss->debugfs.dss); + dss_uninitialize_debugfs(dss); + +err_pm_runtime_disable: + pm_runtime_disable(&pdev->dev); + dss_uninit_ports(dss); + +err_uninit_plls: + if (dss->video1_pll) + dss_video_pll_uninit(dss->video1_pll); + if (dss->video2_pll) + dss_video_pll_uninit(dss->video2_pll); + +err_put_clocks: + dss_put_clocks(dss); + +err_free_dss: + kfree(dss); + + return r; } static int dss_remove(struct platform_device *pdev) { + struct dss_device *dss = platform_get_drvdata(pdev); + component_master_del(&pdev->dev, &dss_component_ops); - dss_uninitialize_debugfs(); + dss_debugfs_remove_file(dss->debugfs.clk); + dss_debugfs_remove_file(dss->debugfs.dss); + dss_uninitialize_debugfs(dss); + + pm_runtime_disable(&pdev->dev); + + dss_uninit_ports(dss); + + if (dss->video1_pll) + dss_video_pll_uninit(dss->video1_pll); + + if (dss->video2_pll) + dss_video_pll_uninit(dss->video2_pll); + + dss_put_clocks(dss); + + kfree(dss); return 0; } @@ -1500,7 +1550,9 @@ static void dss_shutdown(struct platform_device *pdev) static int dss_runtime_suspend(struct device *dev) { - dss_save_context(); + struct dss_device *dss = dev_get_drvdata(dev); + + dss_save_context(dss); dss_set_min_bus_tput(dev, 0); pinctrl_pm_select_sleep_state(dev); @@ -1510,6 +1562,7 @@ static int dss_runtime_suspend(struct device *dev) static int dss_runtime_resume(struct device *dev) { + struct dss_device *dss = dev_get_drvdata(dev); int r; pinctrl_pm_select_default_state(dev); @@ -1525,7 +1578,7 @@ static int dss_runtime_resume(struct device *dev) if (r) return r; - dss_restore_context(); + dss_restore_context(dss); return 0; } diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 6374e57ed9da..847c78ade024 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -25,6 +25,11 @@ #include "omapdss.h" +struct dispc_device; +struct dss_debugfs_entry; +struct platform_device; +struct seq_file; + #define MAX_DSS_LCD_MANAGERS 3 #define MAX_NUM_DSI 2 @@ -97,17 +102,6 @@ enum dss_dsi_content_type { DSS_DSI_CONTENT_GENERIC, }; -enum dss_writeback_channel { - DSS_WB_LCD1_MGR = 0, - DSS_WB_LCD2_MGR = 1, - DSS_WB_TV_MGR = 2, - DSS_WB_OVL0 = 3, - DSS_WB_OVL1 = 4, - DSS_WB_OVL2 = 5, - DSS_WB_OVL3 = 6, - DSS_WB_LCD3_MGR = 7, -}; - enum dss_clk_source { DSS_CLK_SRC_FCK = 0, @@ -167,10 +161,10 @@ struct dss_pll_ops { struct dss_pll_hw { enum dss_pll_type type; - unsigned n_max; - unsigned m_min; - unsigned m_max; - unsigned mX_max; + unsigned int n_max; + unsigned int m_min; + unsigned int m_max; + unsigned int mX_max; unsigned long fint_min, fint_max; unsigned long clkdco_min, clkdco_low, clkdco_max; @@ -191,6 +185,7 @@ struct dss_pll_hw { struct dss_pll { const char *name; enum dss_pll_id id; + struct dss_device *dss; struct clk *clkin; struct regulator *regulator; @@ -232,8 +227,44 @@ struct dss_lcd_mgr_config { int lcden_sig_polarity; }; -struct seq_file; -struct platform_device; +#define DSS_SZ_REGS SZ_512 + +struct dss_device { + struct platform_device *pdev; + void __iomem *base; + struct regmap *syscon_pll_ctrl; + u32 syscon_pll_ctrl_offset; + + struct clk *parent_clk; + struct clk *dss_clk; + unsigned long dss_clk_rate; + + unsigned long cache_req_pck; + unsigned long cache_prate; + struct dispc_clock_info cache_dispc_cinfo; + + enum dss_clk_source dsi_clk_source[MAX_NUM_DSI]; + enum dss_clk_source dispc_clk_source; + enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; + + bool ctx_valid; + u32 ctx[DSS_SZ_REGS / sizeof(u32)]; + + const struct dss_features *feat; + + struct { + struct dentry *root; + struct dss_debugfs_entry *clk; + struct dss_debugfs_entry *dss; + } debugfs; + + struct dss_pll *plls[4]; + struct dss_pll *video1_pll; + struct dss_pll *video2_pll; + + struct dispc_device *dispc; + const struct dispc_ops *dispc_ops; +}; /* core */ static inline int dss_set_min_bus_tput(struct device *dev, unsigned long tput) @@ -253,61 +284,81 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) /* DSS */ #if defined(CONFIG_OMAP2_DSS_DEBUGFS) -int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); +struct dss_debugfs_entry * +dss_debugfs_create_file(struct dss_device *dss, const char *name, + int (*show_fn)(struct seq_file *s, void *data), + void *data); +void dss_debugfs_remove_file(struct dss_debugfs_entry *entry); #else -static inline int dss_debugfs_create_file(const char *name, - void (*write)(struct seq_file *)) +static inline struct dss_debugfs_entry * +dss_debugfs_create_file(struct dss_device *dss, const char *name, + int (*show_fn)(struct seq_file *s, void *data), + void *data) +{ + return NULL; +} + +static inline void dss_debugfs_remove_file(struct dss_debugfs_entry *entry) { - return 0; } #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ -int dss_runtime_get(void); -void dss_runtime_put(void); +struct dss_device *dss_get_device(struct device *dev); -unsigned long dss_get_dispc_clk_rate(void); -unsigned long dss_get_max_fck_rate(void); -enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel); -int dss_dpi_select_source(int port, enum omap_channel channel); -void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); -enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); +int dss_runtime_get(struct dss_device *dss); +void dss_runtime_put(struct dss_device *dss); + +unsigned long dss_get_dispc_clk_rate(struct dss_device *dss); +unsigned long dss_get_max_fck_rate(struct dss_device *dss); +enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss, + enum omap_channel channel); +int dss_dpi_select_source(struct dss_device *dss, int port, + enum omap_channel channel); +void dss_select_hdmi_venc_clk_source(struct dss_device *dss, + enum dss_hdmi_venc_clk_source_select src); const char *dss_get_clk_source_name(enum dss_clk_source clk_src); /* DSS VIDEO PLL */ -struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, - struct regulator *regulator); +struct dss_pll *dss_video_pll_init(struct dss_device *dss, + struct platform_device *pdev, int id, + struct regulator *regulator); void dss_video_pll_uninit(struct dss_pll *pll); -void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable); +void dss_ctrl_pll_enable(struct dss_pll *pll, bool enable); -void dss_sdi_init(int datapairs); -int dss_sdi_enable(void); -void dss_sdi_disable(void); +void dss_sdi_init(struct dss_device *dss, int datapairs); +int dss_sdi_enable(struct dss_device *dss); +void dss_sdi_disable(struct dss_device *dss); -void dss_select_dsi_clk_source(int dsi_module, - enum dss_clk_source clk_src); -void dss_select_lcd_clk_source(enum omap_channel channel, - enum dss_clk_source clk_src); -enum dss_clk_source dss_get_dispc_clk_source(void); -enum dss_clk_source dss_get_dsi_clk_source(int dsi_module); -enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel); +void dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module, + enum dss_clk_source clk_src); +void dss_select_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src); +enum dss_clk_source dss_get_dispc_clk_source(struct dss_device *dss); +enum dss_clk_source dss_get_dsi_clk_source(struct dss_device *dss, + int dsi_module); +enum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel); -void dss_set_venc_output(enum omap_dss_venc_type type); -void dss_set_dac_pwrdn_bgz(bool enable); +void dss_set_venc_output(struct dss_device *dss, enum omap_dss_venc_type type); +void dss_set_dac_pwrdn_bgz(struct dss_device *dss, bool enable); -int dss_set_fck_rate(unsigned long rate); +int dss_set_fck_rate(struct dss_device *dss, unsigned long rate); typedef bool (*dss_div_calc_func)(unsigned long fck, void *data); -bool dss_div_calc(unsigned long pck, unsigned long fck_min, - dss_div_calc_func func, void *data); +bool dss_div_calc(struct dss_device *dss, unsigned long pck, + unsigned long fck_min, dss_div_calc_func func, void *data); /* SDI */ #ifdef CONFIG_OMAP2_DSS_SDI -int sdi_init_port(struct platform_device *pdev, struct device_node *port); +int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port); void sdi_uninit_port(struct device_node *port); #else -static inline int sdi_init_port(struct platform_device *pdev, - struct device_node *port) +static inline int sdi_init_port(struct dss_device *dss, + struct platform_device *pdev, + struct device_node *port) { return 0; } @@ -320,9 +371,6 @@ static inline void sdi_uninit_port(struct device_node *port) #ifdef CONFIG_OMAP2_DSS_DSI -struct dentry; -struct file_operations; - void dsi_dump_clocks(struct seq_file *s); void dsi_irq_handler(void); @@ -331,12 +379,14 @@ void dsi_irq_handler(void); /* DPI */ #ifdef CONFIG_OMAP2_DSS_DPI -int dpi_init_port(struct platform_device *pdev, struct device_node *port, - enum dss_model dss_model); +int dpi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port, enum dss_model dss_model); void dpi_uninit_port(struct device_node *port); #else -static inline int dpi_init_port(struct platform_device *pdev, - struct device_node *port, enum dss_model dss_model) +static inline int dpi_init_port(struct dss_device *dss, + struct platform_device *pdev, + struct device_node *port, + enum dss_model dss_model) { return 0; } @@ -346,51 +396,49 @@ static inline void dpi_uninit_port(struct device_node *port) #endif /* DISPC */ -void dispc_dump_clocks(struct seq_file *s); +void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s); -int dispc_runtime_get(void); -void dispc_runtime_put(void); +int dispc_runtime_get(struct dispc_device *dispc); +void dispc_runtime_put(struct dispc_device *dispc); -void dispc_enable_sidle(void); -void dispc_disable_sidle(void); +void dispc_enable_sidle(struct dispc_device *dispc); +void dispc_disable_sidle(struct dispc_device *dispc); -void dispc_lcd_enable_signal(bool enable); -void dispc_pck_free_enable(bool enable); -void dispc_enable_fifomerge(bool enable); -void dispc_enable_gamma_table(bool enable); +void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable); +void dispc_pck_free_enable(struct dispc_device *dispc, bool enable); +void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable); typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, unsigned long pck, void *data); -bool dispc_div_calc(unsigned long dispc, - unsigned long pck_min, unsigned long pck_max, - dispc_div_calc_func func, void *data); - -bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm); -int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, - struct dispc_clock_info *cinfo); - - -void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low, - u32 high); -void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, - u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, - bool manual_update); - -void dispc_mgr_set_clock_div(enum omap_channel channel, - const struct dispc_clock_info *cinfo); -int dispc_mgr_get_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo); -void dispc_set_tv_pclk(unsigned long pclk); - -u32 dispc_wb_get_framedone_irq(void); -bool dispc_wb_go_busy(void); -void dispc_wb_go(void); -void dispc_wb_set_channel_in(enum dss_writeback_channel channel); -int dispc_wb_setup(const struct omap_dss_writeback_info *wi, - bool mem_to_mem, const struct videomode *vm); +bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq, + unsigned long pck_min, unsigned long pck_max, + dispc_div_calc_func func, void *data); + +bool dispc_mgr_timings_ok(struct dispc_device *dispc, + enum omap_channel channel, + const struct videomode *vm); +int dispc_calc_clock_rates(struct dispc_device *dispc, + unsigned long dispc_fclk_rate, + struct dispc_clock_info *cinfo); + + +void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc, + enum omap_plane_id plane, u32 low, u32 high); +void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, + enum omap_plane_id plane, + u32 *fifo_low, u32 *fifo_high, + bool use_fifomerge, bool manual_update); + +void dispc_mgr_set_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + const struct dispc_clock_info *cinfo); +int dispc_mgr_get_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + struct dispc_clock_info *cinfo); +void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr) +static inline void dss_collect_irq_stats(u32 irqstatus, unsigned int *irq_arr) { int b; for (b = 0; b < 32; ++b) { @@ -406,11 +454,12 @@ typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint, typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc, void *data); -int dss_pll_register(struct dss_pll *pll); +int dss_pll_register(struct dss_device *dss, struct dss_pll *pll); void dss_pll_unregister(struct dss_pll *pll); -struct dss_pll *dss_pll_find(const char *name); -struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src); -unsigned dss_pll_get_clkout_idx_for_src(enum dss_clk_source src); +struct dss_pll *dss_pll_find(struct dss_device *dss, const char *name); +struct dss_pll *dss_pll_find_by_src(struct dss_device *dss, + enum dss_clk_source src); +unsigned int dss_pll_get_clkout_idx_for_src(enum dss_clk_source src); int dss_pll_enable(struct dss_pll *pll); void dss_pll_disable(struct dss_pll *pll); int dss_pll_set_config(struct dss_pll *pll, diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index c2609c448ddc..3aeb4cabd59f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -29,6 +29,8 @@ #include "omapdss.h" #include "dss.h" +struct dss_device; + /* HDMI Wrapper */ #define HDMI_WP_REVISION 0x0 @@ -324,8 +326,8 @@ phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp); /* HDMI PLL funcs */ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); -int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, - struct hdmi_wp_data *wp); +int hdmi_pll_init(struct dss_device *dss, struct platform_device *pdev, + struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); void hdmi_pll_uninit(struct hdmi_pll_data *hpll); /* HDMI PHY funcs */ @@ -357,6 +359,9 @@ static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg) struct omap_hdmi { struct mutex lock; struct platform_device *pdev; + struct dss_device *dss; + + struct dss_debugfs_entry *debugfs; struct hdmi_wp_data wp; struct hdmi_pll_data pll; @@ -384,4 +389,6 @@ struct omap_hdmi { bool display_enabled; }; +#define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output) + #endif diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index bf914f2ac99e..97c88861d67a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -45,15 +45,13 @@ #include "dss.h" #include "hdmi.h" -static struct omap_hdmi hdmi; - -static int hdmi_runtime_get(void) +static int hdmi_runtime_get(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_get\n"); - r = pm_runtime_get_sync(&hdmi.pdev->dev); + r = pm_runtime_get_sync(&hdmi->pdev->dev); WARN_ON(r < 0); if (r < 0) return r; @@ -61,13 +59,13 @@ static int hdmi_runtime_get(void) return 0; } -static void hdmi_runtime_put(void) +static void hdmi_runtime_put(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_put\n"); - r = pm_runtime_put_sync(&hdmi.pdev->dev); + r = pm_runtime_put_sync(&hdmi->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } @@ -110,14 +108,14 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int hdmi_init_regulator(void) +static int hdmi_init_regulator(struct omap_hdmi *hdmi) { struct regulator *reg; - if (hdmi.vdda_reg != NULL) + if (hdmi->vdda_reg != NULL) return 0; - reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); + reg = devm_regulator_get(&hdmi->pdev->dev, "vdda"); if (IS_ERR(reg)) { if (PTR_ERR(reg) != -EPROBE_DEFER) @@ -125,64 +123,63 @@ static int hdmi_init_regulator(void) return PTR_ERR(reg); } - hdmi.vdda_reg = reg; + hdmi->vdda_reg = reg; return 0; } -static int hdmi_power_on_core(struct omap_dss_device *dssdev) +static int hdmi_power_on_core(struct omap_hdmi *hdmi) { int r; - if (hdmi.core.core_pwr_cnt++) + if (hdmi->core.core_pwr_cnt++) return 0; - r = regulator_enable(hdmi.vdda_reg); + r = regulator_enable(hdmi->vdda_reg); if (r) goto err_reg_enable; - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); if (r) goto err_runtime_get; - hdmi4_core_powerdown_disable(&hdmi.core); + hdmi4_core_powerdown_disable(&hdmi->core); /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK); - hdmi.core_enabled = true; + hdmi->core_enabled = true; return 0; err_runtime_get: - regulator_disable(hdmi.vdda_reg); + regulator_disable(hdmi->vdda_reg); err_reg_enable: - hdmi.core.core_pwr_cnt--; + hdmi->core.core_pwr_cnt--; return r; } -static void hdmi_power_off_core(struct omap_dss_device *dssdev) +static void hdmi_power_off_core(struct omap_hdmi *hdmi) { - if (--hdmi.core.core_pwr_cnt) + if (--hdmi->core.core_pwr_cnt) return; - hdmi.core_enabled = false; + hdmi->core_enabled = false; - hdmi_runtime_put(); - regulator_disable(hdmi.vdda_reg); + hdmi_runtime_put(hdmi); + regulator_disable(hdmi->vdda_reg); } -static int hdmi_power_on_full(struct omap_dss_device *dssdev) +static int hdmi_power_on_full(struct omap_hdmi *hdmi) { int r; struct videomode *vm; - enum omap_channel channel = dssdev->dispc_channel; - struct hdmi_wp_data *wp = &hdmi.wp; + struct hdmi_wp_data *wp = &hdmi->wp; struct dss_pll_clock_info hdmi_cinfo = { 0 }; - unsigned pc; + unsigned int pc; - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) return r; @@ -190,7 +187,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi_wp_clear_irqenable(wp, ~HDMI_IRQ_CORE); hdmi_wp_set_irqstatus(wp, ~HDMI_IRQ_CORE); - vm = &hdmi.cfg.vm; + vm = &hdmi->cfg.vm; DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive, vm->vactive); @@ -202,22 +199,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) /* DSS_HDMI_TCLK is bitclk / 10 */ pc *= 10; - dss_pll_calc_b(&hdmi.pll.pll, clk_get_rate(hdmi.pll.pll.clkin), + dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin), pc, &hdmi_cinfo); - r = dss_pll_enable(&hdmi.pll.pll); + r = dss_pll_enable(&hdmi->pll.pll); if (r) { DSSERR("Failed to enable PLL\n"); goto err_pll_enable; } - r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo); + r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo); if (r) { DSSERR("Failed to configure PLL\n"); goto err_pll_cfg; } - r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco, + r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco, hdmi_cinfo.clkout[0]); if (r) { DSSDBG("Failed to configure PHY\n"); @@ -228,16 +225,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) if (r) goto err_phy_pwr; - hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); + hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg); /* tv size */ - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&hdmi->output, vm); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&hdmi->output); if (r) goto err_mgr_enable; - r = hdmi_wp_video_start(&hdmi.wp); + r = hdmi_wp_video_start(&hdmi->wp); if (r) goto err_vid_enable; @@ -247,39 +244,39 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) return 0; err_vid_enable: - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi->output); err_mgr_enable: - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: err_pll_cfg: - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); err_pll_enable: - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); return -EIO; } -static void hdmi_power_off_full(struct omap_dss_device *dssdev) +static void hdmi_power_off_full(struct omap_hdmi *hdmi) { - enum omap_channel channel = dssdev->dispc_channel; - - hdmi_wp_clear_irqenable(&hdmi.wp, ~HDMI_IRQ_CORE); + hdmi_wp_clear_irqenable(&hdmi->wp, ~HDMI_IRQ_CORE); - hdmi_wp_video_stop(&hdmi.wp); + hdmi_wp_video_stop(&hdmi->wp); - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi->output); - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); } static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - if (!dispc_mgr_timings_ok(dssdev->dispc_channel, vm)) + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm)) return -EINVAL; return 0; @@ -288,52 +285,59 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, static void hdmi_display_set_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + mutex_lock(&hdmi->lock); - hdmi.cfg.vm = *vm; + hdmi->cfg.vm = *vm; - dispc_set_tv_pclk(vm->pixelclock); + dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } static void hdmi_display_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - *vm = hdmi.cfg.vm; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + *vm = hdmi->cfg.vm; } -static void hdmi_dump_regs(struct seq_file *s) +static int hdmi_dump_regs(struct seq_file *s, void *p) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = s->private; - if (hdmi_runtime_get()) { - mutex_unlock(&hdmi.lock); - return; + mutex_lock(&hdmi->lock); + + if (hdmi_runtime_get(hdmi)) { + mutex_unlock(&hdmi->lock); + return 0; } - hdmi_wp_dump(&hdmi.wp, s); - hdmi_pll_dump(&hdmi.pll, s); - hdmi_phy_dump(&hdmi.phy, s); - hdmi4_core_dump(&hdmi.core, s); + hdmi_wp_dump(&hdmi->wp, s); + hdmi_pll_dump(&hdmi->pll, s); + hdmi_phy_dump(&hdmi->phy, s); + hdmi4_core_dump(&hdmi->core, s); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); + return 0; } -static int read_edid(u8 *buf, int len) +static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) { int r; - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); BUG_ON(r); - r = hdmi4_read_edid(&hdmi.core, buf, len); + r = hdmi4_read_edid(&hdmi->core, buf, len); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); return r; } @@ -352,112 +356,117 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) static int hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &hdmi.output; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - if (!out->dispc_channel_connected) { + if (!dssdev->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - r = hdmi_power_on_full(dssdev); + r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - if (hdmi.audio_configured) { - r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config, - hdmi.cfg.vm.pixelclock); + if (hdmi->audio_configured) { + r = hdmi4_audio_config(&hdmi->core, &hdmi->wp, + &hdmi->audio_config, + hdmi->cfg.vm.pixelclock); if (r) { DSSERR("Error restoring audio configuration: %d", r); - hdmi.audio_abort_cb(&hdmi.pdev->dev); - hdmi.audio_configured = false; + hdmi->audio_abort_cb(&hdmi->pdev->dev); + hdmi->audio_configured = false; } } - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - if (hdmi.audio_configured && hdmi.audio_playing) - hdmi_start_audio_stream(&hdmi); - hdmi.display_enabled = true; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + if (hdmi->audio_configured && hdmi->audio_playing) + hdmi_start_audio_stream(hdmi); + hdmi->display_enabled = true; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; DSSDBG("Enter hdmi_display_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - hdmi_stop_audio_stream(&hdmi); - hdmi.display_enabled = false; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + hdmi_stop_audio_stream(hdmi); + hdmi->display_enabled = false; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - hdmi_power_off_full(dssdev); + hdmi_power_off_full(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } -int hdmi4_core_enable(struct omap_dss_device *dssdev) +int hdmi4_core_enable(struct hdmi_core_data *core) { + struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); int r = 0; DSSDBG("ENTER omapdss_hdmi4_core_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } -void hdmi4_core_disable(struct omap_dss_device *dssdev) +void hdmi4_core_disable(struct hdmi_core_data *core) { + struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); + DSSDBG("Enter omapdss_hdmi4_core_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); int r; - r = hdmi_init_regulator(); + r = hdmi_init_regulator(hdmi); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&hdmi->output, dssdev); if (r) return r; @@ -465,7 +474,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); return r; } @@ -475,7 +484,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); WARN_ON(dst != dssdev->dst); @@ -484,51 +493,58 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *edid, int len) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); bool need_enable; int r; - need_enable = hdmi.core_enabled == false; + need_enable = hdmi->core_enabled == false; if (need_enable) { - r = hdmi4_core_enable(dssdev); + r = hdmi4_core_enable(&hdmi->core); if (r) return r; } - r = read_edid(edid, len); + r = read_edid(hdmi, edid, len); if (r >= 256) - hdmi4_cec_set_phys_addr(&hdmi.core, + hdmi4_cec_set_phys_addr(&hdmi->core, cec_get_edid_phys_addr(edid, r, NULL)); else - hdmi4_cec_set_phys_addr(&hdmi.core, CEC_PHYS_ADDR_INVALID); + hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); if (need_enable) - hdmi4_core_disable(dssdev); + hdmi4_core_disable(&hdmi->core); return r; } static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) { - hdmi4_cec_set_phys_addr(&hdmi.core, CEC_PHYS_ADDR_INVALID); + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); } static int hdmi_set_infoframe(struct omap_dss_device *dssdev, const struct hdmi_avi_infoframe *avi) { - hdmi.cfg.infoframe = *avi; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.infoframe = *avi; return 0; } static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) { - hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; return 0; } @@ -549,11 +565,11 @@ static const struct omapdss_hdmi_ops hdmi_ops = { .set_hdmi_mode = hdmi_set_hdmi_mode, }; -static void hdmi_init_output(struct platform_device *pdev) +static void hdmi_init_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; - out->dev = &pdev->dev; + out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; out->output_type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; @@ -564,15 +580,16 @@ static void hdmi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void hdmi_uninit_output(struct platform_device *pdev) +static void hdmi_uninit_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; omapdss_unregister_output(out); } -static int hdmi_probe_of(struct platform_device *pdev) +static int hdmi_probe_of(struct omap_hdmi *hdmi) { + struct platform_device *pdev = hdmi->pdev; struct device_node *node = pdev->dev.of_node; struct device_node *ep; int r; @@ -581,7 +598,7 @@ static int hdmi_probe_of(struct platform_device *pdev) if (!ep) return 0; - r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy); + r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy); if (r) goto err; @@ -598,21 +615,16 @@ static int hdmi_audio_startup(struct device *dev, void (*abort_cb)(struct device *dev)) { struct omap_hdmi *hd = dev_get_drvdata(dev); - int ret = 0; mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; - } + WARN_ON(hd->audio_abort_cb != NULL); hd->audio_abort_cb = abort_cb; -out: mutex_unlock(&hd->lock); - return ret; + return 0; } static int hdmi_audio_shutdown(struct device *dev) @@ -633,12 +645,14 @@ static int hdmi_audio_start(struct device *dev) struct omap_hdmi *hd = dev_get_drvdata(dev); unsigned long flags; - WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); - spin_lock_irqsave(&hd->audio_playing_lock, flags); - if (hd->display_enabled) + if (hd->display_enabled) { + if (!hdmi_mode_has_audio(&hd->cfg)) + DSSERR("%s: Video mode does not support audio\n", + __func__); hdmi_start_audio_stream(hd); + } hd->audio_playing = true; spin_unlock_irqrestore(&hd->audio_playing_lock, flags); @@ -669,17 +683,15 @@ static int hdmi_audio_config(struct device *dev, mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; + if (hd->display_enabled) { + ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio, + hd->cfg.vm.pixelclock); + if (ret) + goto out; } - ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio, - hd->cfg.vm.pixelclock); - if (!ret) { - hd->audio_configured = true; - hd->audio_config = *dss_audio; - } + hd->audio_configured = true; + hd->audio_config = *dss_audio; out: mutex_unlock(&hd->lock); @@ -694,21 +706,21 @@ static const struct omap_hdmi_audio_ops hdmi_audio_ops = { .audio_config = hdmi_audio_config, }; -static int hdmi_audio_register(struct device *dev) +static int hdmi_audio_register(struct omap_hdmi *hdmi) { struct omap_hdmi_audio_pdata pdata = { - .dev = dev, + .dev = &hdmi->pdev->dev, .version = 4, - .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), + .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp), .ops = &hdmi_audio_ops, }; - hdmi.audio_pdev = platform_device_register_data( - dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, + hdmi->audio_pdev = platform_device_register_data( + &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (IS_ERR(hdmi.audio_pdev)) - return PTR_ERR(hdmi.audio_pdev); + if (IS_ERR(hdmi->audio_pdev)) + return PTR_ERR(hdmi->audio_pdev); return 0; } @@ -717,88 +729,103 @@ static int hdmi_audio_register(struct device *dev) static int hdmi4_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); + struct omap_hdmi *hdmi; int r; int irq; - hdmi.pdev = pdev; - dev_set_drvdata(&pdev->dev, &hdmi); + hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->pdev = pdev; + hdmi->dss = dss; + dev_set_drvdata(&pdev->dev, hdmi); - mutex_init(&hdmi.lock); - spin_lock_init(&hdmi.audio_playing_lock); + mutex_init(&hdmi->lock); + spin_lock_init(&hdmi->audio_playing_lock); - r = hdmi_probe_of(pdev); + r = hdmi_probe_of(hdmi); if (r) - return r; + goto err_free; - r = hdmi_wp_init(pdev, &hdmi.wp, 4); + r = hdmi_wp_init(pdev, &hdmi->wp, 4); if (r) - return r; + goto err_free; - r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); + r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp); if (r) - return r; + goto err_free; - r = hdmi_phy_init(pdev, &hdmi.phy, 4); + r = hdmi_phy_init(pdev, &hdmi->phy, 4); if (r) - goto err; + goto err_pll; - r = hdmi4_core_init(pdev, &hdmi.core); + r = hdmi4_core_init(pdev, &hdmi->core); if (r) - goto err; + goto err_pll; - r = hdmi4_cec_init(pdev, &hdmi.core, &hdmi.wp); + r = hdmi4_cec_init(pdev, &hdmi->core, &hdmi->wp); if (r) - goto err; + goto err_pll; irq = platform_get_irq(pdev, 0); if (irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err; + goto err_pll; } r = devm_request_threaded_irq(&pdev->dev, irq, NULL, hdmi_irq_handler, - IRQF_ONESHOT, "OMAP HDMI", &hdmi); + IRQF_ONESHOT, "OMAP HDMI", hdmi); if (r) { DSSERR("HDMI IRQ request failed\n"); - goto err; + goto err_pll; } pm_runtime_enable(&pdev->dev); - hdmi_init_output(pdev); + hdmi_init_output(hdmi); - r = hdmi_audio_register(&pdev->dev); + r = hdmi_audio_register(hdmi); if (r) { DSSERR("Registering HDMI audio failed\n"); - hdmi_uninit_output(pdev); + hdmi_uninit_output(hdmi); pm_runtime_disable(&pdev->dev); return r; } - dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, + hdmi); return 0; -err: - hdmi_pll_uninit(&hdmi.pll); + +err_pll: + hdmi_pll_uninit(&hdmi->pll); +err_free: + kfree(hdmi); return r; } static void hdmi4_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dss_debugfs_remove_file(hdmi->debugfs); - if (hdmi.audio_pdev) - platform_device_unregister(hdmi.audio_pdev); + if (hdmi->audio_pdev) + platform_device_unregister(hdmi->audio_pdev); - hdmi_uninit_output(pdev); + hdmi_uninit_output(hdmi); - hdmi4_cec_uninit(&hdmi.core); + hdmi4_cec_uninit(&hdmi->core); - hdmi_pll_uninit(&hdmi.pll); + hdmi_pll_uninit(&hdmi->pll); - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); + + kfree(hdmi); } static const struct component_ops hdmi4_component_ops = { @@ -819,16 +846,19 @@ static int hdmi4_remove(struct platform_device *pdev) static int hdmi_runtime_suspend(struct device *dev) { - dispc_runtime_put(); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dispc_runtime_put(hdmi->dss->dispc); return 0; } static int hdmi_runtime_resume(struct device *dev) { + struct omap_hdmi *hdmi = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(hdmi->dss->dispc); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c index 23db74ae1826..340383150fb9 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c @@ -175,10 +175,10 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) REG_FLD_MOD(core->base, HDMI_CORE_SYS_INTR_UNMASK4, 0, 3, 3); hdmi_wp_clear_irqenable(core->wp, HDMI_IRQ_CORE); hdmi_wp_set_irqstatus(core->wp, HDMI_IRQ_CORE); - hdmi4_core_disable(NULL); + hdmi4_core_disable(core); return 0; } - err = hdmi4_core_enable(NULL); + err = hdmi4_core_enable(core); if (err) return err; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h index b6ab579e44d2..337a317c1a27 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h @@ -266,8 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s); int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core); -int hdmi4_core_enable(struct omap_dss_device *dssdev); -void hdmi4_core_disable(struct omap_dss_device *dssdev); +int hdmi4_core_enable(struct hdmi_core_data *core); +void hdmi4_core_disable(struct hdmi_core_data *core); void hdmi4_core_powerdown_disable(struct hdmi_core_data *core); int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 689cda41858b..d28da9ac3e90 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -46,15 +46,13 @@ #include "hdmi5_core.h" #include "dss.h" -static struct omap_hdmi hdmi; - -static int hdmi_runtime_get(void) +static int hdmi_runtime_get(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_get\n"); - r = pm_runtime_get_sync(&hdmi.pdev->dev); + r = pm_runtime_get_sync(&hdmi->pdev->dev); WARN_ON(r < 0); if (r < 0) return r; @@ -62,19 +60,20 @@ static int hdmi_runtime_get(void) return 0; } -static void hdmi_runtime_put(void) +static void hdmi_runtime_put(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_put\n"); - r = pm_runtime_put_sync(&hdmi.pdev->dev); + r = pm_runtime_put_sync(&hdmi->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } static irqreturn_t hdmi_irq_handler(int irq, void *data) { - struct hdmi_wp_data *wp = data; + struct omap_hdmi *hdmi = data; + struct hdmi_wp_data *wp = &hdmi->wp; u32 irqstatus; irqstatus = hdmi_wp_get_irqstatus(wp); @@ -97,17 +96,17 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data) * setting the PHY to LDOON. To ignore those, we force the RXDET * line to 0 until the PHY power state has been changed. */ - v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL); + v = hdmi_read_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL); v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */ v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */ - hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v); + hdmi_write_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v); hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); - REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15); + REG_FLD_MOD(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15); } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); @@ -118,70 +117,69 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int hdmi_init_regulator(void) +static int hdmi_init_regulator(struct omap_hdmi *hdmi) { struct regulator *reg; - if (hdmi.vdda_reg != NULL) + if (hdmi->vdda_reg != NULL) return 0; - reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); + reg = devm_regulator_get(&hdmi->pdev->dev, "vdda"); if (IS_ERR(reg)) { DSSERR("can't get VDDA regulator\n"); return PTR_ERR(reg); } - hdmi.vdda_reg = reg; + hdmi->vdda_reg = reg; return 0; } -static int hdmi_power_on_core(struct omap_dss_device *dssdev) +static int hdmi_power_on_core(struct omap_hdmi *hdmi) { int r; - r = regulator_enable(hdmi.vdda_reg); + r = regulator_enable(hdmi->vdda_reg); if (r) return r; - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); if (r) goto err_runtime_get; /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK); - hdmi.core_enabled = true; + hdmi->core_enabled = true; return 0; err_runtime_get: - regulator_disable(hdmi.vdda_reg); + regulator_disable(hdmi->vdda_reg); return r; } -static void hdmi_power_off_core(struct omap_dss_device *dssdev) +static void hdmi_power_off_core(struct omap_hdmi *hdmi) { - hdmi.core_enabled = false; + hdmi->core_enabled = false; - hdmi_runtime_put(); - regulator_disable(hdmi.vdda_reg); + hdmi_runtime_put(hdmi); + regulator_disable(hdmi->vdda_reg); } -static int hdmi_power_on_full(struct omap_dss_device *dssdev) +static int hdmi_power_on_full(struct omap_hdmi *hdmi) { int r; struct videomode *vm; - enum omap_channel channel = dssdev->dispc_channel; struct dss_pll_clock_info hdmi_cinfo = { 0 }; - unsigned pc; + unsigned int pc; - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) return r; - vm = &hdmi.cfg.vm; + vm = &hdmi->cfg.vm; DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive, vm->vactive); @@ -193,89 +191,89 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) /* DSS_HDMI_TCLK is bitclk / 10 */ pc *= 10; - dss_pll_calc_b(&hdmi.pll.pll, clk_get_rate(hdmi.pll.pll.clkin), + dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin), pc, &hdmi_cinfo); /* disable and clear irqs */ - hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); - hdmi_wp_set_irqstatus(&hdmi.wp, - hdmi_wp_get_irqstatus(&hdmi.wp)); + hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff); + hdmi_wp_set_irqstatus(&hdmi->wp, + hdmi_wp_get_irqstatus(&hdmi->wp)); - r = dss_pll_enable(&hdmi.pll.pll); + r = dss_pll_enable(&hdmi->pll.pll); if (r) { DSSERR("Failed to enable PLL\n"); goto err_pll_enable; } - r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo); + r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo); if (r) { DSSERR("Failed to configure PLL\n"); goto err_pll_cfg; } - r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco, + r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco, hdmi_cinfo.clkout[0]); if (r) { DSSDBG("Failed to start PHY\n"); goto err_phy_cfg; } - r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON); + r = hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_LDOON); if (r) goto err_phy_pwr; - hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); + hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg); /* tv size */ - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&hdmi->output, vm); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&hdmi->output); if (r) goto err_mgr_enable; - r = hdmi_wp_video_start(&hdmi.wp); + r = hdmi_wp_video_start(&hdmi->wp); if (r) goto err_vid_enable; - hdmi_wp_set_irqenable(&hdmi.wp, + hdmi_wp_set_irqenable(&hdmi->wp, HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); return 0; err_vid_enable: - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi->output); err_mgr_enable: - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: err_pll_cfg: - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); err_pll_enable: - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); return -EIO; } -static void hdmi_power_off_full(struct omap_dss_device *dssdev) +static void hdmi_power_off_full(struct omap_hdmi *hdmi) { - enum omap_channel channel = dssdev->dispc_channel; - - hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); + hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff); - hdmi_wp_video_stop(&hdmi.wp); + hdmi_wp_video_stop(&hdmi->wp); - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi->output); - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); } static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - if (!dispc_mgr_timings_ok(dssdev->dispc_channel, vm)) + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm)) return -EINVAL; return 0; @@ -284,66 +282,73 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, static void hdmi_display_set_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - hdmi.cfg.vm = *vm; + mutex_lock(&hdmi->lock); - dispc_set_tv_pclk(vm->pixelclock); + hdmi->cfg.vm = *vm; - mutex_unlock(&hdmi.lock); + dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); + + mutex_unlock(&hdmi->lock); } static void hdmi_display_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - *vm = hdmi.cfg.vm; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + *vm = hdmi->cfg.vm; } -static void hdmi_dump_regs(struct seq_file *s) +static int hdmi_dump_regs(struct seq_file *s, void *p) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = s->private; - if (hdmi_runtime_get()) { - mutex_unlock(&hdmi.lock); - return; + mutex_lock(&hdmi->lock); + + if (hdmi_runtime_get(hdmi)) { + mutex_unlock(&hdmi->lock); + return 0; } - hdmi_wp_dump(&hdmi.wp, s); - hdmi_pll_dump(&hdmi.pll, s); - hdmi_phy_dump(&hdmi.phy, s); - hdmi5_core_dump(&hdmi.core, s); + hdmi_wp_dump(&hdmi->wp, s); + hdmi_pll_dump(&hdmi->pll, s); + hdmi_phy_dump(&hdmi->phy, s); + hdmi5_core_dump(&hdmi->core, s); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); + return 0; } -static int read_edid(u8 *buf, int len) +static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) { int r; int idlemode; - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); BUG_ON(r); - idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); + idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); /* No-idle mode */ - REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); - r = hdmi5_read_edid(&hdmi.core, buf, len); + r = hdmi5_read_edid(&hdmi->core, buf, len); - REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); return r; } static void hdmi_start_audio_stream(struct omap_hdmi *hd) { - REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); hdmi_wp_audio_enable(&hd->wp, true); hdmi_wp_audio_core_req_enable(&hd->wp, true); } @@ -357,112 +362,114 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) static int hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &hdmi.output; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - if (!out->dispc_channel_connected) { + if (!dssdev->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - r = hdmi_power_on_full(dssdev); + r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - if (hdmi.audio_configured) { - r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config, - hdmi.cfg.vm.pixelclock); + if (hdmi->audio_configured) { + r = hdmi5_audio_config(&hdmi->core, &hdmi->wp, + &hdmi->audio_config, + hdmi->cfg.vm.pixelclock); if (r) { DSSERR("Error restoring audio configuration: %d", r); - hdmi.audio_abort_cb(&hdmi.pdev->dev); - hdmi.audio_configured = false; + hdmi->audio_abort_cb(&hdmi->pdev->dev); + hdmi->audio_configured = false; } } - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - if (hdmi.audio_configured && hdmi.audio_playing) - hdmi_start_audio_stream(&hdmi); - hdmi.display_enabled = true; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + if (hdmi->audio_configured && hdmi->audio_playing) + hdmi_start_audio_stream(hdmi); + hdmi->display_enabled = true; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; DSSDBG("Enter hdmi_display_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - hdmi_stop_audio_stream(&hdmi); - hdmi.display_enabled = false; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + hdmi_stop_audio_stream(hdmi); + hdmi->display_enabled = false; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - hdmi_power_off_full(dssdev); + hdmi_power_off_full(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } -static int hdmi_core_enable(struct omap_dss_device *dssdev) +static int hdmi_core_enable(struct omap_hdmi *hdmi) { int r = 0; DSSDBG("ENTER omapdss_hdmi_core_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } -static void hdmi_core_disable(struct omap_dss_device *dssdev) +static void hdmi_core_disable(struct omap_hdmi *hdmi) { DSSDBG("Enter omapdss_hdmi_core_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); int r; - r = hdmi_init_regulator(); + r = hdmi_init_regulator(hdmi); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&hdmi->output, dssdev); if (r) return r; @@ -470,7 +477,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); return r; } @@ -480,7 +487,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); WARN_ON(dst != dssdev->dst); @@ -489,27 +496,28 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *edid, int len) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); bool need_enable; int r; - need_enable = hdmi.core_enabled == false; + need_enable = hdmi->core_enabled == false; if (need_enable) { - r = hdmi_core_enable(dssdev); + r = hdmi_core_enable(hdmi); if (r) return r; } - r = read_edid(edid, len); + r = read_edid(hdmi, edid, len); if (need_enable) - hdmi_core_disable(dssdev); + hdmi_core_disable(hdmi); return r; } @@ -517,14 +525,18 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, static int hdmi_set_infoframe(struct omap_dss_device *dssdev, const struct hdmi_avi_infoframe *avi) { - hdmi.cfg.infoframe = *avi; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.infoframe = *avi; return 0; } static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) { - hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; return 0; } @@ -544,11 +556,11 @@ static const struct omapdss_hdmi_ops hdmi_ops = { .set_hdmi_mode = hdmi_set_hdmi_mode, }; -static void hdmi_init_output(struct platform_device *pdev) +static void hdmi_init_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; - out->dev = &pdev->dev; + out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; out->output_type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; @@ -559,15 +571,16 @@ static void hdmi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void hdmi_uninit_output(struct platform_device *pdev) +static void hdmi_uninit_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; omapdss_unregister_output(out); } -static int hdmi_probe_of(struct platform_device *pdev) +static int hdmi_probe_of(struct omap_hdmi *hdmi) { + struct platform_device *pdev = hdmi->pdev; struct device_node *node = pdev->dev.of_node; struct device_node *ep; int r; @@ -576,7 +589,7 @@ static int hdmi_probe_of(struct platform_device *pdev) if (!ep) return 0; - r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy); + r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy); if (r) goto err; @@ -593,21 +606,16 @@ static int hdmi_audio_startup(struct device *dev, void (*abort_cb)(struct device *dev)) { struct omap_hdmi *hd = dev_get_drvdata(dev); - int ret = 0; mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; - } + WARN_ON(hd->audio_abort_cb != NULL); hd->audio_abort_cb = abort_cb; -out: mutex_unlock(&hd->lock); - return ret; + return 0; } static int hdmi_audio_shutdown(struct device *dev) @@ -628,12 +636,14 @@ static int hdmi_audio_start(struct device *dev) struct omap_hdmi *hd = dev_get_drvdata(dev); unsigned long flags; - WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); - spin_lock_irqsave(&hd->audio_playing_lock, flags); - if (hd->display_enabled) + if (hd->display_enabled) { + if (!hdmi_mode_has_audio(&hd->cfg)) + DSSERR("%s: Video mode does not support audio\n", + __func__); hdmi_start_audio_stream(hd); + } hd->audio_playing = true; spin_unlock_irqrestore(&hd->audio_playing_lock, flags); @@ -645,7 +655,8 @@ static void hdmi_audio_stop(struct device *dev) struct omap_hdmi *hd = dev_get_drvdata(dev); unsigned long flags; - WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); + if (!hdmi_mode_has_audio(&hd->cfg)) + DSSERR("%s: Video mode does not support audio\n", __func__); spin_lock_irqsave(&hd->audio_playing_lock, flags); @@ -664,18 +675,15 @@ static int hdmi_audio_config(struct device *dev, mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; + if (hd->display_enabled) { + ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio, + hd->cfg.vm.pixelclock); + if (ret) + goto out; } - ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio, - hd->cfg.vm.pixelclock); - - if (!ret) { - hd->audio_configured = true; - hd->audio_config = *dss_audio; - } + hd->audio_configured = true; + hd->audio_config = *dss_audio; out: mutex_unlock(&hd->lock); @@ -690,26 +698,26 @@ static const struct omap_hdmi_audio_ops hdmi_audio_ops = { .audio_config = hdmi_audio_config, }; -static int hdmi_audio_register(struct device *dev) +static int hdmi_audio_register(struct omap_hdmi *hdmi) { struct omap_hdmi_audio_pdata pdata = { - .dev = dev, + .dev = &hdmi->pdev->dev, .version = 5, - .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), + .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp), .ops = &hdmi_audio_ops, }; - hdmi.audio_pdev = platform_device_register_data( - dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, + hdmi->audio_pdev = platform_device_register_data( + &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (IS_ERR(hdmi.audio_pdev)) - return PTR_ERR(hdmi.audio_pdev); + if (IS_ERR(hdmi->audio_pdev)) + return PTR_ERR(hdmi->audio_pdev); - hdmi_runtime_get(); - hdmi.wp_idlemode = - REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); - hdmi_runtime_put(); + hdmi_runtime_get(hdmi); + hdmi->wp_idlemode = + REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); + hdmi_runtime_put(hdmi); return 0; } @@ -718,82 +726,97 @@ static int hdmi_audio_register(struct device *dev) static int hdmi5_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); + struct omap_hdmi *hdmi; int r; int irq; - hdmi.pdev = pdev; - dev_set_drvdata(&pdev->dev, &hdmi); + hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; - mutex_init(&hdmi.lock); - spin_lock_init(&hdmi.audio_playing_lock); + hdmi->pdev = pdev; + hdmi->dss = dss; + dev_set_drvdata(&pdev->dev, hdmi); - r = hdmi_probe_of(pdev); + mutex_init(&hdmi->lock); + spin_lock_init(&hdmi->audio_playing_lock); + + r = hdmi_probe_of(hdmi); if (r) - return r; + goto err_free; - r = hdmi_wp_init(pdev, &hdmi.wp, 5); + r = hdmi_wp_init(pdev, &hdmi->wp, 5); if (r) - return r; + goto err_free; - r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); + r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp); if (r) - return r; + goto err_free; - r = hdmi_phy_init(pdev, &hdmi.phy, 5); + r = hdmi_phy_init(pdev, &hdmi->phy, 5); if (r) - goto err; + goto err_pll; - r = hdmi5_core_init(pdev, &hdmi.core); + r = hdmi5_core_init(pdev, &hdmi->core); if (r) - goto err; + goto err_pll; irq = platform_get_irq(pdev, 0); if (irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err; + goto err_pll; } r = devm_request_threaded_irq(&pdev->dev, irq, NULL, hdmi_irq_handler, - IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); + IRQF_ONESHOT, "OMAP HDMI", hdmi); if (r) { DSSERR("HDMI IRQ request failed\n"); - goto err; + goto err_pll; } pm_runtime_enable(&pdev->dev); - hdmi_init_output(pdev); + hdmi_init_output(hdmi); - r = hdmi_audio_register(&pdev->dev); + r = hdmi_audio_register(hdmi); if (r) { DSSERR("Registering HDMI audio failed %d\n", r); - hdmi_uninit_output(pdev); + hdmi_uninit_output(hdmi); pm_runtime_disable(&pdev->dev); return r; } - dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, + hdmi); return 0; -err: - hdmi_pll_uninit(&hdmi.pll); + +err_pll: + hdmi_pll_uninit(&hdmi->pll); +err_free: + kfree(hdmi); return r; } static void hdmi5_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dss_debugfs_remove_file(hdmi->debugfs); - if (hdmi.audio_pdev) - platform_device_unregister(hdmi.audio_pdev); + if (hdmi->audio_pdev) + platform_device_unregister(hdmi->audio_pdev); - hdmi_uninit_output(pdev); + hdmi_uninit_output(hdmi); - hdmi_pll_uninit(&hdmi.pll); + hdmi_pll_uninit(&hdmi->pll); - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); + + kfree(hdmi); } static const struct component_ops hdmi5_component_ops = { @@ -814,16 +837,19 @@ static int hdmi5_remove(struct platform_device *pdev) static int hdmi_runtime_suspend(struct device *dev) { - dispc_runtime_put(); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dispc_runtime_put(hdmi->dss->dispc); return 0; } static int hdmi_runtime_resume(struct device *dev) { + struct omap_hdmi *hdmi = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(hdmi->dss->dispc); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index 09759f8ea7bc..2282e48574c6 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -50,14 +50,14 @@ static void hdmi_core_ddc_init(struct hdmi_core_data *core) { void __iomem *base = core->base; const unsigned long long iclk = 266000000; /* DSS L3 ICLK */ - const unsigned ss_scl_high = 4600; /* ns */ - const unsigned ss_scl_low = 5400; /* ns */ - const unsigned fs_scl_high = 600; /* ns */ - const unsigned fs_scl_low = 1300; /* ns */ - const unsigned sda_hold = 1000; /* ns */ - const unsigned sfr_div = 10; + const unsigned int ss_scl_high = 4600; /* ns */ + const unsigned int ss_scl_low = 5400; /* ns */ + const unsigned int fs_scl_high = 600; /* ns */ + const unsigned int fs_scl_low = 1300; /* ns */ + const unsigned int sda_hold = 1000; /* ns */ + const unsigned int sfr_div = 10; unsigned long long sfr; - unsigned v; + unsigned int v; sfr = iclk / sfr_div; /* SFR_DIV */ sfr /= 1000; /* SFR clock in kHz */ @@ -430,11 +430,11 @@ static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core, void __iomem *base = core->base; u8 data[HDMI_INFOFRAME_SIZE(AVI)]; u8 *ptr; - unsigned y, a, b, s; - unsigned c, m, r; - unsigned itc, ec, q, sc; - unsigned vic; - unsigned yq, cn, pr; + unsigned int y, a, b, s; + unsigned int c, m, r; + unsigned int itc, ec, q, sc; + unsigned int vic; + unsigned int yq, cn, pr; hdmi_avi_infoframe_pack(frame, data, sizeof(data)); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c index 5c14ed851609..9915923a53bd 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c @@ -99,7 +99,7 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy) u16 lane_cfg = 0; int i; - unsigned lane_cfg_val; + unsigned int lane_cfg_val; u16 pol_val = 0; for (i = 0; i < 4; ++i) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c index 08885d7de1e8..e7be3707d147 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -48,7 +48,7 @@ static int hdmi_pll_enable(struct dss_pll *dsspll) r = pm_runtime_get_sync(&pll->pdev->dev); WARN_ON(r < 0); - dss_ctrl_pll_enable(DSS_PLL_HDMI, true); + dss_ctrl_pll_enable(dsspll, true); r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); if (r) @@ -65,7 +65,7 @@ static void hdmi_pll_disable(struct dss_pll *dsspll) hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); - dss_ctrl_pll_enable(DSS_PLL_HDMI, false); + dss_ctrl_pll_enable(dsspll, false); r = pm_runtime_put_sync(&pll->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); @@ -128,7 +128,8 @@ static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { .has_refsel = true, }; -static int hdmi_init_pll_data(struct platform_device *pdev, +static int hdmi_init_pll_data(struct dss_device *dss, + struct platform_device *pdev, struct hdmi_pll_data *hpll) { struct dss_pll *pll = &hpll->pll; @@ -153,15 +154,15 @@ static int hdmi_init_pll_data(struct platform_device *pdev, pll->ops = &hdmi_pll_ops; - r = dss_pll_register(pll); + r = dss_pll_register(dss, pll); if (r) return r; return 0; } -int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, - struct hdmi_wp_data *wp) +int hdmi_pll_init(struct dss_device *dss, struct platform_device *pdev, + struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) { int r; struct resource *res; @@ -174,7 +175,7 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, if (IS_ERR(pll->base)) return PTR_ERR(pll->base); - r = hdmi_init_pll_data(pdev, pll); + r = hdmi_init_pll_data(dss, pdev, pll); if (r) { DSSERR("failed to init HDMI PLL\n"); return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c index 806e5fdcfe52..53bc5f78050c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c @@ -168,7 +168,7 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp, { u32 timing_h = 0; u32 timing_v = 0; - unsigned hsync_len_offset = 1; + unsigned int hsync_len_offset = 1; DSSDBG("Enter hdmi_wp_video_config_timing\n"); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index f8f83e826a56..14d74adb13fb 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -59,7 +59,11 @@ #define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) #define DISPC_IRQ_FRAMEDONE3 (1 << 30) +struct dss_device; +struct omap_drm_private; struct omap_dss_device; +struct dispc_device; +struct dss_device; struct dss_lcd_mgr_config; struct snd_aes_iec958; struct snd_cea_861_aud_if; @@ -159,21 +163,6 @@ enum omap_overlay_caps { OMAP_DSS_OVL_CAP_REPLICATION = 1 << 5, }; -enum omap_dss_clk_source { - OMAP_DSS_CLK_SRC_FCK = 0, /* OMAP2/3: DSS1_ALWON_FCLK - * OMAP4: DSS_FCLK */ - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, /* OMAP3: DSI1_PLL_FCLK - * OMAP4: PLL1_CLK1 */ - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, /* OMAP3: DSI2_PLL_FCLK - * OMAP4: PLL1_CLK2 */ - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC, /* OMAP4: PLL2_CLK1 */ - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */ -}; - -enum omap_hdmi_flags { - OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0, -}; - enum omap_dss_output_id { OMAP_DSS_OUTPUT_DPI = 1 << 0, OMAP_DSS_OUTPUT_DBI = 1 << 1, @@ -198,8 +187,8 @@ enum omap_dss_dsi_trans_mode { struct omap_dss_dsi_videomode_timings { unsigned long hsclk; - unsigned ndl; - unsigned bitspp; + unsigned int ndl; + unsigned int bitspp; /* pixels */ u16 hact; @@ -585,7 +574,12 @@ struct omap_dss_driver { const struct hdmi_avi_infoframe *avi); }; -bool omapdss_is_initialized(void); +struct dss_device *omapdss_get_dss(void); +void omapdss_set_dss(struct dss_device *dss); +static inline bool omapdss_is_initialized(void) +{ + return !!omapdss_get_dss(); +} int omapdss_register_display(struct omap_dss_device *dssdev); void omapdss_unregister_display(struct omap_dss_device *dssdev); @@ -609,9 +603,6 @@ int omapdss_output_unset_device(struct omap_dss_device *out); struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev); -void omapdss_default_get_timings(struct omap_dss_device *dssdev, - struct videomode *vm); - typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask); int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask); @@ -632,97 +623,139 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) struct omap_dss_device * omapdss_of_find_source_for_first_ep(struct device_node *node); -void omapdss_set_is_initialized(bool set); - struct device_node *dss_of_port_get_parent_device(struct device_node *port); u32 dss_of_port_get_port_number(struct device_node *port); +enum dss_writeback_channel { + DSS_WB_LCD1_MGR = 0, + DSS_WB_LCD2_MGR = 1, + DSS_WB_TV_MGR = 2, + DSS_WB_OVL0 = 3, + DSS_WB_OVL1 = 4, + DSS_WB_OVL2 = 5, + DSS_WB_OVL3 = 6, + DSS_WB_LCD3_MGR = 7, +}; + struct dss_mgr_ops { - int (*connect)(enum omap_channel channel, - struct omap_dss_device *dst); - void (*disconnect)(enum omap_channel channel, - struct omap_dss_device *dst); - - void (*start_update)(enum omap_channel channel); - int (*enable)(enum omap_channel channel); - void (*disable)(enum omap_channel channel); - void (*set_timings)(enum omap_channel channel, - const struct videomode *vm); - void (*set_lcd_config)(enum omap_channel channel, - const struct dss_lcd_mgr_config *config); - int (*register_framedone_handler)(enum omap_channel channel, + int (*connect)(struct omap_drm_private *priv, + enum omap_channel channel, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_drm_private *priv, + enum omap_channel channel, + struct omap_dss_device *dst); + + void (*start_update)(struct omap_drm_private *priv, + enum omap_channel channel); + int (*enable)(struct omap_drm_private *priv, + enum omap_channel channel); + void (*disable)(struct omap_drm_private *priv, + enum omap_channel channel); + void (*set_timings)(struct omap_drm_private *priv, + enum omap_channel channel, + const struct videomode *vm); + void (*set_lcd_config)(struct omap_drm_private *priv, + enum omap_channel channel, + const struct dss_lcd_mgr_config *config); + int (*register_framedone_handler)(struct omap_drm_private *priv, + enum omap_channel channel, void (*handler)(void *), void *data); - void (*unregister_framedone_handler)(enum omap_channel channel, + void (*unregister_framedone_handler)(struct omap_drm_private *priv, + enum omap_channel channel, void (*handler)(void *), void *data); }; -int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops); +int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops, + struct omap_drm_private *priv); void dss_uninstall_mgr_ops(void); -int dss_mgr_connect(enum omap_channel channel, - struct omap_dss_device *dst); -void dss_mgr_disconnect(enum omap_channel channel, - struct omap_dss_device *dst); -void dss_mgr_set_timings(enum omap_channel channel, +int dss_mgr_connect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); +void dss_mgr_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); +void dss_mgr_set_timings(struct omap_dss_device *dssdev, const struct videomode *vm); -void dss_mgr_set_lcd_config(enum omap_channel channel, +void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, const struct dss_lcd_mgr_config *config); -int dss_mgr_enable(enum omap_channel channel); -void dss_mgr_disable(enum omap_channel channel); -void dss_mgr_start_update(enum omap_channel channel); -int dss_mgr_register_framedone_handler(enum omap_channel channel, +int dss_mgr_enable(struct omap_dss_device *dssdev); +void dss_mgr_disable(struct omap_dss_device *dssdev); +void dss_mgr_start_update(struct omap_dss_device *dssdev); +int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data); -void dss_mgr_unregister_framedone_handler(enum omap_channel channel, +void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data); /* dispc ops */ struct dispc_ops { - u32 (*read_irqstatus)(void); - void (*clear_irqstatus)(u32 mask); - void (*write_irqenable)(u32 mask); - - int (*request_irq)(irq_handler_t handler, void *dev_id); - void (*free_irq)(void *dev_id); - - int (*runtime_get)(void); - void (*runtime_put)(void); - - int (*get_num_ovls)(void); - int (*get_num_mgrs)(void); - - u32 (*get_memory_bandwidth_limit)(void); - - void (*mgr_enable)(enum omap_channel channel, bool enable); - bool (*mgr_is_enabled)(enum omap_channel channel); - u32 (*mgr_get_vsync_irq)(enum omap_channel channel); - u32 (*mgr_get_framedone_irq)(enum omap_channel channel); - u32 (*mgr_get_sync_lost_irq)(enum omap_channel channel); - bool (*mgr_go_busy)(enum omap_channel channel); - void (*mgr_go)(enum omap_channel channel); - void (*mgr_set_lcd_config)(enum omap_channel channel, - const struct dss_lcd_mgr_config *config); - void (*mgr_set_timings)(enum omap_channel channel, - const struct videomode *vm); - void (*mgr_setup)(enum omap_channel channel, - const struct omap_overlay_manager_info *info); - enum omap_dss_output_id (*mgr_get_supported_outputs)(enum omap_channel channel); - u32 (*mgr_gamma_size)(enum omap_channel channel); - void (*mgr_set_gamma)(enum omap_channel channel, - const struct drm_color_lut *lut, - unsigned int length); - - int (*ovl_enable)(enum omap_plane_id plane, bool enable); - int (*ovl_setup)(enum omap_plane_id plane, + u32 (*read_irqstatus)(struct dispc_device *dispc); + void (*clear_irqstatus)(struct dispc_device *dispc, u32 mask); + void (*write_irqenable)(struct dispc_device *dispc, u32 mask); + + int (*request_irq)(struct dispc_device *dispc, irq_handler_t handler, + void *dev_id); + void (*free_irq)(struct dispc_device *dispc, void *dev_id); + + int (*runtime_get)(struct dispc_device *dispc); + void (*runtime_put)(struct dispc_device *dispc); + + int (*get_num_ovls)(struct dispc_device *dispc); + int (*get_num_mgrs)(struct dispc_device *dispc); + + u32 (*get_memory_bandwidth_limit)(struct dispc_device *dispc); + + void (*mgr_enable)(struct dispc_device *dispc, + enum omap_channel channel, bool enable); + bool (*mgr_is_enabled)(struct dispc_device *dispc, + enum omap_channel channel); + u32 (*mgr_get_vsync_irq)(struct dispc_device *dispc, + enum omap_channel channel); + u32 (*mgr_get_framedone_irq)(struct dispc_device *dispc, + enum omap_channel channel); + u32 (*mgr_get_sync_lost_irq)(struct dispc_device *dispc, + enum omap_channel channel); + bool (*mgr_go_busy)(struct dispc_device *dispc, + enum omap_channel channel); + void (*mgr_go)(struct dispc_device *dispc, enum omap_channel channel); + void (*mgr_set_lcd_config)(struct dispc_device *dispc, + enum omap_channel channel, + const struct dss_lcd_mgr_config *config); + void (*mgr_set_timings)(struct dispc_device *dispc, + enum omap_channel channel, + const struct videomode *vm); + void (*mgr_setup)(struct dispc_device *dispc, enum omap_channel channel, + const struct omap_overlay_manager_info *info); + enum omap_dss_output_id (*mgr_get_supported_outputs)( + struct dispc_device *dispc, enum omap_channel channel); + u32 (*mgr_gamma_size)(struct dispc_device *dispc, + enum omap_channel channel); + void (*mgr_set_gamma)(struct dispc_device *dispc, + enum omap_channel channel, + const struct drm_color_lut *lut, + unsigned int length); + + int (*ovl_enable)(struct dispc_device *dispc, enum omap_plane_id plane, + bool enable); + int (*ovl_setup)(struct dispc_device *dispc, enum omap_plane_id plane, const struct omap_overlay_info *oi, - const struct videomode *vm, bool mem_to_mem, - enum omap_channel channel); + const struct videomode *vm, bool mem_to_mem, + enum omap_channel channel); + + const u32 *(*ovl_get_color_modes)(struct dispc_device *dispc, + enum omap_plane_id plane); - const u32 *(*ovl_get_color_modes)(enum omap_plane_id plane); + u32 (*wb_get_framedone_irq)(struct dispc_device *dispc); + int (*wb_setup)(struct dispc_device *dispc, + const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct videomode *vm, + enum dss_writeback_channel channel_in); + bool (*has_writeback)(struct dispc_device *dispc); + bool (*wb_go_busy)(struct dispc_device *dispc); + void (*wb_go)(struct dispc_device *dispc); }; -void dispc_set_ops(const struct dispc_ops *o); -const struct dispc_ops *dispc_get_ops(void); +struct dispc_device *dispc_get_dispc(struct dss_device *dss); +const struct dispc_ops *dispc_get_ops(struct dss_device *dss); bool omapdss_component_is_display(struct device_node *node); bool omapdss_component_is_output(struct device_node *node); diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index b9afd80ae385..96b9d4cd505f 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -156,7 +156,6 @@ struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *po return NULL; } -EXPORT_SYMBOL(omap_dss_find_output_by_port_node); struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) { @@ -171,13 +170,16 @@ struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device EXPORT_SYMBOL(omapdss_find_output_from_display); static const struct dss_mgr_ops *dss_mgr_ops; +static struct omap_drm_private *dss_mgr_ops_priv; -int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) +int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops, + struct omap_drm_private *priv) { if (dss_mgr_ops) return -EBUSY; dss_mgr_ops = mgr_ops; + dss_mgr_ops_priv = priv; return 0; } @@ -186,64 +188,71 @@ EXPORT_SYMBOL(dss_install_mgr_ops); void dss_uninstall_mgr_ops(void) { dss_mgr_ops = NULL; + dss_mgr_ops_priv = NULL; } EXPORT_SYMBOL(dss_uninstall_mgr_ops); -int dss_mgr_connect(enum omap_channel channel, - struct omap_dss_device *dst) +int dss_mgr_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - return dss_mgr_ops->connect(channel, dst); + return dss_mgr_ops->connect(dss_mgr_ops_priv, + dssdev->dispc_channel, dst); } EXPORT_SYMBOL(dss_mgr_connect); -void dss_mgr_disconnect(enum omap_channel channel, - struct omap_dss_device *dst) +void dss_mgr_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) { - dss_mgr_ops->disconnect(channel, dst); + dss_mgr_ops->disconnect(dss_mgr_ops_priv, dssdev->dispc_channel, dst); } EXPORT_SYMBOL(dss_mgr_disconnect); -void dss_mgr_set_timings(enum omap_channel channel, const struct videomode *vm) +void dss_mgr_set_timings(struct omap_dss_device *dssdev, + const struct videomode *vm) { - dss_mgr_ops->set_timings(channel, vm); + dss_mgr_ops->set_timings(dss_mgr_ops_priv, dssdev->dispc_channel, vm); } EXPORT_SYMBOL(dss_mgr_set_timings); -void dss_mgr_set_lcd_config(enum omap_channel channel, +void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, const struct dss_lcd_mgr_config *config) { - dss_mgr_ops->set_lcd_config(channel, config); + dss_mgr_ops->set_lcd_config(dss_mgr_ops_priv, + dssdev->dispc_channel, config); } EXPORT_SYMBOL(dss_mgr_set_lcd_config); -int dss_mgr_enable(enum omap_channel channel) +int dss_mgr_enable(struct omap_dss_device *dssdev) { - return dss_mgr_ops->enable(channel); + return dss_mgr_ops->enable(dss_mgr_ops_priv, dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_enable); -void dss_mgr_disable(enum omap_channel channel) +void dss_mgr_disable(struct omap_dss_device *dssdev) { - dss_mgr_ops->disable(channel); + dss_mgr_ops->disable(dss_mgr_ops_priv, dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_disable); -void dss_mgr_start_update(enum omap_channel channel) +void dss_mgr_start_update(struct omap_dss_device *dssdev) { - dss_mgr_ops->start_update(channel); + dss_mgr_ops->start_update(dss_mgr_ops_priv, dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_start_update); -int dss_mgr_register_framedone_handler(enum omap_channel channel, +int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data) { - return dss_mgr_ops->register_framedone_handler(channel, handler, data); + return dss_mgr_ops->register_framedone_handler(dss_mgr_ops_priv, + dssdev->dispc_channel, + handler, data); } EXPORT_SYMBOL(dss_mgr_register_framedone_handler); -void dss_mgr_unregister_framedone_handler(enum omap_channel channel, +void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data) { - dss_mgr_ops->unregister_framedone_handler(channel, handler, data); + dss_mgr_ops->unregister_framedone_handler(dss_mgr_ops_priv, + dssdev->dispc_channel, + handler, data); } EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index 058714b1eb56..078b0e8216c3 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -35,15 +35,14 @@ #define PLL_SSC_CONFIGURATION2 0x001C #define PLL_CONFIGURATION4 0x0020 -static struct dss_pll *dss_plls[4]; - -int dss_pll_register(struct dss_pll *pll) +int dss_pll_register(struct dss_device *dss, struct dss_pll *pll) { int i; - for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { - if (!dss_plls[i]) { - dss_plls[i] = pll; + for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) { + if (!dss->plls[i]) { + dss->plls[i] = pll; + pll->dss = dss; return 0; } } @@ -53,29 +52,32 @@ int dss_pll_register(struct dss_pll *pll) void dss_pll_unregister(struct dss_pll *pll) { + struct dss_device *dss = pll->dss; int i; - for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { - if (dss_plls[i] == pll) { - dss_plls[i] = NULL; + for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) { + if (dss->plls[i] == pll) { + dss->plls[i] = NULL; + pll->dss = NULL; return; } } } -struct dss_pll *dss_pll_find(const char *name) +struct dss_pll *dss_pll_find(struct dss_device *dss, const char *name) { int i; - for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { - if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0) - return dss_plls[i]; + for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) { + if (dss->plls[i] && strcmp(dss->plls[i]->name, name) == 0) + return dss->plls[i]; } return NULL; } -struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src) +struct dss_pll *dss_pll_find_by_src(struct dss_device *dss, + enum dss_clk_source src) { struct dss_pll *pll; @@ -85,27 +87,27 @@ struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src) return NULL; case DSS_CLK_SRC_HDMI_PLL: - return dss_pll_find("hdmi"); + return dss_pll_find(dss, "hdmi"); case DSS_CLK_SRC_PLL1_1: case DSS_CLK_SRC_PLL1_2: case DSS_CLK_SRC_PLL1_3: - pll = dss_pll_find("dsi0"); + pll = dss_pll_find(dss, "dsi0"); if (!pll) - pll = dss_pll_find("video0"); + pll = dss_pll_find(dss, "video0"); return pll; case DSS_CLK_SRC_PLL2_1: case DSS_CLK_SRC_PLL2_2: case DSS_CLK_SRC_PLL2_3: - pll = dss_pll_find("dsi1"); + pll = dss_pll_find(dss, "dsi1"); if (!pll) - pll = dss_pll_find("video1"); + pll = dss_pll_find(dss, "video1"); return pll; } } -unsigned dss_pll_get_clkout_idx_for_src(enum dss_clk_source src) +unsigned int dss_pll_get_clkout_idx_for_src(enum dss_clk_source src) { switch (src) { case DSS_CLK_SRC_HDMI_PLL: @@ -277,7 +279,7 @@ bool dss_pll_calc_b(const struct dss_pll *pll, unsigned long clkin, unsigned long fint, clkdco, clkout; unsigned long target_clkdco; unsigned long min_dco; - unsigned n, m, mf, m2, sd; + unsigned int n, m, mf, m2, sd; const struct dss_pll_hw *hw = pll->hw; DSSDBG("clkin %lu, target clkout %lu\n", clkin, target_clkout); diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index d8ab31f3a813..68a40ae26f5b 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -29,8 +29,9 @@ #include "omapdss.h" #include "dss.h" -static struct { +struct sdi_device { struct platform_device *pdev; + struct dss_device *dss; bool update_enabled; struct regulator *vdds_sdi_reg; @@ -40,11 +41,12 @@ static struct { int datapairs; struct omap_dss_device output; +}; - bool port_initialized; -} sdi; +#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output) struct sdi_clk_calc_ctx { + struct sdi_device *sdi; unsigned long pck_min, pck_max; unsigned long fck; @@ -70,16 +72,17 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) ctx->fck = fck; - return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->sdi->dss->dispc, fck, + ctx->pck_min, ctx->pck_max, + dpi_calc_dispc_cb, ctx); } -static int sdi_calc_clock_div(unsigned long pclk, - unsigned long *fck, - struct dispc_clock_info *dispc_cinfo) +static int sdi_calc_clock_div(struct sdi_device *sdi, unsigned long pclk, + unsigned long *fck, + struct dispc_clock_info *dispc_cinfo) { int i; - struct sdi_clk_calc_ctx ctx; + struct sdi_clk_calc_ctx ctx = { .sdi = sdi }; /* * DSS fclk gives us very few possibilities, so finding a good pixel @@ -98,7 +101,8 @@ static int sdi_calc_clock_div(unsigned long pclk, ctx.pck_min = 0; ctx.pck_max = pclk + 1000 * i * i * i; - ok = dss_div_calc(pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx); + ok = dss_div_calc(sdi->dss, pclk, ctx.pck_min, + dpi_calc_dss_cb, &ctx); if (ok) { *fck = ctx.fck; *dispc_cinfo = ctx.dispc_cinfo; @@ -109,52 +113,49 @@ static int sdi_calc_clock_div(unsigned long pclk, return -EINVAL; } -static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) +static void sdi_config_lcd_manager(struct sdi_device *sdi) { - enum omap_channel channel = dssdev->dispc_channel; + sdi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; - sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; + sdi->mgr_config.stallmode = false; + sdi->mgr_config.fifohandcheck = false; - sdi.mgr_config.stallmode = false; - sdi.mgr_config.fifohandcheck = false; + sdi->mgr_config.video_port_width = 24; + sdi->mgr_config.lcden_sig_polarity = 1; - sdi.mgr_config.video_port_width = 24; - sdi.mgr_config.lcden_sig_polarity = 1; - - dss_mgr_set_lcd_config(channel, &sdi.mgr_config); + dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config); } static int sdi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &sdi.output; - enum omap_channel channel = dssdev->dispc_channel; - struct videomode *vm = &sdi.vm; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + struct videomode *vm = &sdi->vm; unsigned long fck; struct dispc_clock_info dispc_cinfo; unsigned long pck; int r; - if (!out->dispc_channel_connected) { + if (!sdi->output.dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } - r = regulator_enable(sdi.vdds_sdi_reg); + r = regulator_enable(sdi->vdds_sdi_reg); if (r) goto err_reg_enable; - r = dispc_runtime_get(); + r = dispc_runtime_get(sdi->dss->dispc); if (r) goto err_get_dispc; /* 15.5.9.1.2 */ vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE | DISPLAY_FLAGS_SYNC_POSEDGE; - r = sdi_calc_clock_div(vm->pixelclock, &fck, &dispc_cinfo); + r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo); if (r) goto err_calc_clock_div; - sdi.mgr_config.clock_info = dispc_cinfo; + sdi->mgr_config.clock_info = dispc_cinfo; pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; @@ -166,13 +167,13 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) } - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&sdi->output, vm); - r = dss_set_fck_rate(fck); + r = dss_set_fck_rate(sdi->dss, fck); if (r) goto err_set_dss_clock_div; - sdi_config_lcd_manager(dssdev); + sdi_config_lcd_manager(sdi); /* * LCLK and PCLK divisors are located in shadow registers, and we @@ -185,63 +186,69 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(channel, &sdi.mgr_config.clock_info); + dispc_mgr_set_clock_div(sdi->dss->dispc, sdi->output.dispc_channel, + &sdi->mgr_config.clock_info); - dss_sdi_init(sdi.datapairs); - r = dss_sdi_enable(); + dss_sdi_init(sdi->dss, sdi->datapairs); + r = dss_sdi_enable(sdi->dss); if (r) goto err_sdi_enable; mdelay(2); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&sdi->output); if (r) goto err_mgr_enable; return 0; err_mgr_enable: - dss_sdi_disable(); + dss_sdi_disable(sdi->dss); err_sdi_enable: err_set_dss_clock_div: err_calc_clock_div: - dispc_runtime_put(); + dispc_runtime_put(sdi->dss->dispc); err_get_dispc: - regulator_disable(sdi.vdds_sdi_reg); + regulator_disable(sdi->vdds_sdi_reg); err_reg_enable: return r; } static void sdi_display_disable(struct omap_dss_device *dssdev) { - enum omap_channel channel = dssdev->dispc_channel; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); - dss_mgr_disable(channel); + dss_mgr_disable(&sdi->output); - dss_sdi_disable(); + dss_sdi_disable(sdi->dss); - dispc_runtime_put(); + dispc_runtime_put(sdi->dss->dispc); - regulator_disable(sdi.vdds_sdi_reg); + regulator_disable(sdi->vdds_sdi_reg); } static void sdi_set_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - sdi.vm = *vm; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + + sdi->vm = *vm; } static void sdi_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - *vm = sdi.vm; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + + *vm = sdi->vm; } static int sdi_check_timings(struct omap_dss_device *dssdev, struct videomode *vm) { + struct sdi_device *sdi = dssdev_to_sdi(dssdev); enum omap_channel channel = dssdev->dispc_channel; - if (!dispc_mgr_timings_ok(channel, vm)) + if (!dispc_mgr_timings_ok(sdi->dss->dispc, channel, vm)) return -EINVAL; if (vm->pixelclock == 0) @@ -250,21 +257,21 @@ static int sdi_check_timings(struct omap_dss_device *dssdev, return 0; } -static int sdi_init_regulator(void) +static int sdi_init_regulator(struct sdi_device *sdi) { struct regulator *vdds_sdi; - if (sdi.vdds_sdi_reg) + if (sdi->vdds_sdi_reg) return 0; - vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi"); + vdds_sdi = devm_regulator_get(&sdi->pdev->dev, "vdds_sdi"); if (IS_ERR(vdds_sdi)) { if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER) DSSERR("can't get VDDS_SDI regulator\n"); return PTR_ERR(vdds_sdi); } - sdi.vdds_sdi_reg = vdds_sdi; + sdi->vdds_sdi_reg = vdds_sdi; return 0; } @@ -272,14 +279,14 @@ static int sdi_init_regulator(void) static int sdi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); int r; - r = sdi_init_regulator(); + r = sdi_init_regulator(sdi); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&sdi->output, dssdev); if (r) return r; @@ -287,7 +294,7 @@ static int sdi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&sdi->output, dssdev); return r; } @@ -297,7 +304,7 @@ static int sdi_connect(struct omap_dss_device *dssdev, static void sdi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); WARN_ON(dst != dssdev->dst); @@ -306,7 +313,7 @@ static void sdi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&sdi->output, dssdev); } static const struct omapdss_sdi_ops sdi_ops = { @@ -321,11 +328,11 @@ static const struct omapdss_sdi_ops sdi_ops = { .get_timings = sdi_get_timings, }; -static void sdi_init_output(struct platform_device *pdev) +static void sdi_init_output(struct sdi_device *sdi) { - struct omap_dss_device *out = &sdi.output; + struct omap_dss_device *out = &sdi->output; - out->dev = &pdev->dev; + out->dev = &sdi->pdev->dev; out->id = OMAP_DSS_OUTPUT_SDI; out->output_type = OMAP_DISPLAY_TYPE_SDI; out->name = "sdi.0"; @@ -338,22 +345,28 @@ static void sdi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void sdi_uninit_output(struct platform_device *pdev) +static void sdi_uninit_output(struct sdi_device *sdi) { - struct omap_dss_device *out = &sdi.output; - - omapdss_unregister_output(out); + omapdss_unregister_output(&sdi->output); } -int sdi_init_port(struct platform_device *pdev, struct device_node *port) +int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port) { + struct sdi_device *sdi; struct device_node *ep; u32 datapairs; int r; + sdi = kzalloc(sizeof(*sdi), GFP_KERNEL); + if (!sdi) + return -ENOMEM; + ep = of_get_next_child(port, NULL); - if (!ep) - return 0; + if (!ep) { + r = 0; + goto err_free; + } r = of_property_read_u32(ep, "datapairs", &datapairs); if (r) { @@ -361,28 +374,33 @@ int sdi_init_port(struct platform_device *pdev, struct device_node *port) goto err_datapairs; } - sdi.datapairs = datapairs; + sdi->datapairs = datapairs; + sdi->dss = dss; of_node_put(ep); - sdi.pdev = pdev; - - sdi_init_output(pdev); + sdi->pdev = pdev; + port->data = sdi; - sdi.port_initialized = true; + sdi_init_output(sdi); return 0; err_datapairs: of_node_put(ep); +err_free: + kfree(sdi); return r; } void sdi_uninit_port(struct device_node *port) { - if (!sdi.port_initialized) + struct sdi_device *sdi = port->data; + + if (!sdi) return; - sdi_uninit_output(sdi.pdev); + sdi_uninit_output(sdi); + kfree(sdi); } diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 6de9d734ddb9..24d1ced210bd 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -319,12 +319,15 @@ static enum venc_videomode venc_get_videomode(const struct videomode *vm) return VENC_MODE_UNKNOWN; } -static struct { +struct venc_device { struct platform_device *pdev; void __iomem *base; struct mutex venc_lock; u32 wss_data; struct regulator *vdda_dac_reg; + struct dss_device *dss; + + struct dss_debugfs_entry *debugfs; struct clk *tv_dac_clk; @@ -334,81 +337,87 @@ static struct { bool requires_tv_dac_clk; struct omap_dss_device output; -} venc; +}; + +#define dssdev_to_venc(dssdev) container_of(dssdev, struct venc_device, output) -static inline void venc_write_reg(int idx, u32 val) +static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val) { - __raw_writel(val, venc.base + idx); + __raw_writel(val, venc->base + idx); } -static inline u32 venc_read_reg(int idx) +static inline u32 venc_read_reg(struct venc_device *venc, int idx) { - u32 l = __raw_readl(venc.base + idx); + u32 l = __raw_readl(venc->base + idx); return l; } -static void venc_write_config(const struct venc_config *config) +static void venc_write_config(struct venc_device *venc, + const struct venc_config *config) { DSSDBG("write venc conf\n"); - venc_write_reg(VENC_LLEN, config->llen); - venc_write_reg(VENC_FLENS, config->flens); - venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr); - venc_write_reg(VENC_C_PHASE, config->c_phase); - venc_write_reg(VENC_GAIN_U, config->gain_u); - venc_write_reg(VENC_GAIN_V, config->gain_v); - venc_write_reg(VENC_GAIN_Y, config->gain_y); - venc_write_reg(VENC_BLACK_LEVEL, config->black_level); - venc_write_reg(VENC_BLANK_LEVEL, config->blank_level); - venc_write_reg(VENC_M_CONTROL, config->m_control); - venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | - venc.wss_data); - venc_write_reg(VENC_S_CARR, config->s_carr); - venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl); - venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid); - venc_write_reg(VENC_FLEN__FAL, config->flen__fal); - venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset); - venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x); - venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x); - venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x); - venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y, + venc_write_reg(venc, VENC_LLEN, config->llen); + venc_write_reg(venc, VENC_FLENS, config->flens); + venc_write_reg(venc, VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr); + venc_write_reg(venc, VENC_C_PHASE, config->c_phase); + venc_write_reg(venc, VENC_GAIN_U, config->gain_u); + venc_write_reg(venc, VENC_GAIN_V, config->gain_v); + venc_write_reg(venc, VENC_GAIN_Y, config->gain_y); + venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level); + venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level); + venc_write_reg(venc, VENC_M_CONTROL, config->m_control); + venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | + venc->wss_data); + venc_write_reg(venc, VENC_S_CARR, config->s_carr); + venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl); + venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid); + venc_write_reg(venc, VENC_FLEN__FAL, config->flen__fal); + venc_write_reg(venc, VENC_LAL__PHASE_RESET, config->lal__phase_reset); + venc_write_reg(venc, VENC_HS_INT_START_STOP_X, + config->hs_int_start_stop_x); + venc_write_reg(venc, VENC_HS_EXT_START_STOP_X, + config->hs_ext_start_stop_x); + venc_write_reg(venc, VENC_VS_INT_START_X, config->vs_int_start_x); + venc_write_reg(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y, config->vs_int_stop_x__vs_int_start_y); - venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X, + venc_write_reg(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X, config->vs_int_stop_y__vs_ext_start_x); - venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y, + venc_write_reg(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y, config->vs_ext_stop_x__vs_ext_start_y); - venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y); - venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x); - venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y); - venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y, + venc_write_reg(venc, VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y); + venc_write_reg(venc, VENC_AVID_START_STOP_X, config->avid_start_stop_x); + venc_write_reg(venc, VENC_AVID_START_STOP_Y, config->avid_start_stop_y); + venc_write_reg(venc, VENC_FID_INT_START_X__FID_INT_START_Y, config->fid_int_start_x__fid_int_start_y); - venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X, + venc_write_reg(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X, config->fid_int_offset_y__fid_ext_start_x); - venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y, + venc_write_reg(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y, config->fid_ext_start_y__fid_ext_offset_y); - venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C)); - venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl); - venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl); - venc_write_reg(VENC_X_COLOR, config->x_color); - venc_write_reg(VENC_LINE21, config->line21); - venc_write_reg(VENC_LN_SEL, config->ln_sel); - venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger); - venc_write_reg(VENC_TVDETGP_INT_START_STOP_X, + venc_write_reg(venc, VENC_DAC_B__DAC_C, + venc_read_reg(venc, VENC_DAC_B__DAC_C)); + venc_write_reg(venc, VENC_VIDOUT_CTRL, config->vidout_ctrl); + venc_write_reg(venc, VENC_HFLTR_CTRL, config->hfltr_ctrl); + venc_write_reg(venc, VENC_X_COLOR, config->x_color); + venc_write_reg(venc, VENC_LINE21, config->line21); + venc_write_reg(venc, VENC_LN_SEL, config->ln_sel); + venc_write_reg(venc, VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger); + venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_X, config->tvdetgp_int_start_stop_x); - venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y, + venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_Y, config->tvdetgp_int_start_stop_y); - venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl); - venc_write_reg(VENC_F_CONTROL, config->f_control); - venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl); + venc_write_reg(venc, VENC_GEN_CTRL, config->gen_ctrl); + venc_write_reg(venc, VENC_F_CONTROL, config->f_control); + venc_write_reg(venc, VENC_SYNC_CTRL, config->sync_ctrl); } -static void venc_reset(void) +static void venc_reset(struct venc_device *venc) { int t = 1000; - venc_write_reg(VENC_F_CONTROL, 1<<8); - while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) { + venc_write_reg(venc, VENC_F_CONTROL, 1<<8); + while (venc_read_reg(venc, VENC_F_CONTROL) & (1<<8)) { if (--t == 0) { DSSERR("Failed to reset venc\n"); return; @@ -422,24 +431,24 @@ static void venc_reset(void) #endif } -static int venc_runtime_get(void) +static int venc_runtime_get(struct venc_device *venc) { int r; DSSDBG("venc_runtime_get\n"); - r = pm_runtime_get_sync(&venc.pdev->dev); + r = pm_runtime_get_sync(&venc->pdev->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } -static void venc_runtime_put(void) +static void venc_runtime_put(struct venc_device *venc) { int r; DSSDBG("venc_runtime_put\n"); - r = pm_runtime_put_sync(&venc.pdev->dev); + r = pm_runtime_put_sync(&venc->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } @@ -455,119 +464,119 @@ static const struct venc_config *venc_timings_to_config(struct videomode *vm) } } -static int venc_power_on(struct omap_dss_device *dssdev) +static int venc_power_on(struct venc_device *venc) { - enum omap_channel channel = dssdev->dispc_channel; u32 l; int r; - r = venc_runtime_get(); + r = venc_runtime_get(venc); if (r) goto err0; - venc_reset(); - venc_write_config(venc_timings_to_config(&venc.vm)); + venc_reset(venc); + venc_write_config(venc, venc_timings_to_config(&venc->vm)); - dss_set_venc_output(venc.type); - dss_set_dac_pwrdn_bgz(1); + dss_set_venc_output(venc->dss, venc->type); + dss_set_dac_pwrdn_bgz(venc->dss, 1); l = 0; - if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) + if (venc->type == OMAP_DSS_VENC_TYPE_COMPOSITE) l |= 1 << 1; else /* S-Video */ l |= (1 << 0) | (1 << 2); - if (venc.invert_polarity == false) + if (venc->invert_polarity == false) l |= 1 << 3; - venc_write_reg(VENC_OUTPUT_CONTROL, l); + venc_write_reg(venc, VENC_OUTPUT_CONTROL, l); - dss_mgr_set_timings(channel, &venc.vm); + dss_mgr_set_timings(&venc->output, &venc->vm); - r = regulator_enable(venc.vdda_dac_reg); + r = regulator_enable(venc->vdda_dac_reg); if (r) goto err1; - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&venc->output); if (r) goto err2; return 0; err2: - regulator_disable(venc.vdda_dac_reg); + regulator_disable(venc->vdda_dac_reg); err1: - venc_write_reg(VENC_OUTPUT_CONTROL, 0); - dss_set_dac_pwrdn_bgz(0); + venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0); + dss_set_dac_pwrdn_bgz(venc->dss, 0); - venc_runtime_put(); + venc_runtime_put(venc); err0: return r; } -static void venc_power_off(struct omap_dss_device *dssdev) +static void venc_power_off(struct venc_device *venc) { - enum omap_channel channel = dssdev->dispc_channel; + venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0); + dss_set_dac_pwrdn_bgz(venc->dss, 0); - venc_write_reg(VENC_OUTPUT_CONTROL, 0); - dss_set_dac_pwrdn_bgz(0); + dss_mgr_disable(&venc->output); - dss_mgr_disable(channel); + regulator_disable(venc->vdda_dac_reg); - regulator_disable(venc.vdda_dac_reg); - - venc_runtime_put(); + venc_runtime_put(venc); } static int venc_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &venc.output; + struct venc_device *venc = dssdev_to_venc(dssdev); int r; DSSDBG("venc_display_enable\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); - if (!out->dispc_channel_connected) { + if (!dssdev->dispc_channel_connected) { DSSERR("Failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - r = venc_power_on(dssdev); + r = venc_power_on(venc); if (r) goto err0; - venc.wss_data = 0; + venc->wss_data = 0; - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); return 0; err0: - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); return r; } static void venc_display_disable(struct omap_dss_device *dssdev) { + struct venc_device *venc = dssdev_to_venc(dssdev); + DSSDBG("venc_display_disable\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); - venc_power_off(dssdev); + venc_power_off(venc); - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); } static void venc_set_timings(struct omap_dss_device *dssdev, struct videomode *vm) { + struct venc_device *venc = dssdev_to_venc(dssdev); struct videomode actual_vm; DSSDBG("venc_set_timings\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); switch (venc_get_videomode(vm)) { default: @@ -581,14 +590,14 @@ static void venc_set_timings(struct omap_dss_device *dssdev, } /* Reset WSS data when the TV standard changes. */ - if (memcmp(&venc.vm, &actual_vm, sizeof(actual_vm))) - venc.wss_data = 0; + if (memcmp(&venc->vm, &actual_vm, sizeof(actual_vm))) + venc->wss_data = 0; - venc.vm = actual_vm; + venc->vm = actual_vm; - dispc_set_tv_pclk(13500000); + dispc_set_tv_pclk(venc->dss->dispc, 13500000); - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); } static int venc_check_timings(struct omap_dss_device *dssdev, @@ -608,127 +617,136 @@ static int venc_check_timings(struct omap_dss_device *dssdev, static void venc_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - mutex_lock(&venc.venc_lock); + struct venc_device *venc = dssdev_to_venc(dssdev); - *vm = venc.vm; + mutex_lock(&venc->venc_lock); - mutex_unlock(&venc.venc_lock); + *vm = venc->vm; + + mutex_unlock(&venc->venc_lock); } static u32 venc_get_wss(struct omap_dss_device *dssdev) { + struct venc_device *venc = dssdev_to_venc(dssdev); + /* Invert due to VENC_L21_WC_CTL:INV=1 */ - return (venc.wss_data >> 8) ^ 0xfffff; + return (venc->wss_data >> 8) ^ 0xfffff; } static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) { + struct venc_device *venc = dssdev_to_venc(dssdev); const struct venc_config *config; int r; DSSDBG("venc_set_wss\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); - config = venc_timings_to_config(&venc.vm); + config = venc_timings_to_config(&venc->vm); /* Invert due to VENC_L21_WC_CTL:INV=1 */ - venc.wss_data = (wss ^ 0xfffff) << 8; + venc->wss_data = (wss ^ 0xfffff) << 8; - r = venc_runtime_get(); + r = venc_runtime_get(venc); if (r) goto err; - venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | - venc.wss_data); + venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | + venc->wss_data); - venc_runtime_put(); + venc_runtime_put(venc); err: - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); return r; } -static int venc_init_regulator(void) +static int venc_init_regulator(struct venc_device *venc) { struct regulator *vdda_dac; - if (venc.vdda_dac_reg != NULL) + if (venc->vdda_dac_reg != NULL) return 0; - vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda"); + vdda_dac = devm_regulator_get(&venc->pdev->dev, "vdda"); if (IS_ERR(vdda_dac)) { if (PTR_ERR(vdda_dac) != -EPROBE_DEFER) DSSERR("can't get VDDA_DAC regulator\n"); return PTR_ERR(vdda_dac); } - venc.vdda_dac_reg = vdda_dac; + venc->vdda_dac_reg = vdda_dac; return 0; } -static void venc_dump_regs(struct seq_file *s) +static int venc_dump_regs(struct seq_file *s, void *p) { -#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) + struct venc_device *venc = s->private; - if (venc_runtime_get()) - return; +#define DUMPREG(venc, r) \ + seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(venc, r)) + + if (venc_runtime_get(venc)) + return 0; - DUMPREG(VENC_F_CONTROL); - DUMPREG(VENC_VIDOUT_CTRL); - DUMPREG(VENC_SYNC_CTRL); - DUMPREG(VENC_LLEN); - DUMPREG(VENC_FLENS); - DUMPREG(VENC_HFLTR_CTRL); - DUMPREG(VENC_CC_CARR_WSS_CARR); - DUMPREG(VENC_C_PHASE); - DUMPREG(VENC_GAIN_U); - DUMPREG(VENC_GAIN_V); - DUMPREG(VENC_GAIN_Y); - DUMPREG(VENC_BLACK_LEVEL); - DUMPREG(VENC_BLANK_LEVEL); - DUMPREG(VENC_X_COLOR); - DUMPREG(VENC_M_CONTROL); - DUMPREG(VENC_BSTAMP_WSS_DATA); - DUMPREG(VENC_S_CARR); - DUMPREG(VENC_LINE21); - DUMPREG(VENC_LN_SEL); - DUMPREG(VENC_L21__WC_CTL); - DUMPREG(VENC_HTRIGGER_VTRIGGER); - DUMPREG(VENC_SAVID__EAVID); - DUMPREG(VENC_FLEN__FAL); - DUMPREG(VENC_LAL__PHASE_RESET); - DUMPREG(VENC_HS_INT_START_STOP_X); - DUMPREG(VENC_HS_EXT_START_STOP_X); - DUMPREG(VENC_VS_INT_START_X); - DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y); - DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X); - DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y); - DUMPREG(VENC_VS_EXT_STOP_Y); - DUMPREG(VENC_AVID_START_STOP_X); - DUMPREG(VENC_AVID_START_STOP_Y); - DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y); - DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X); - DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y); - DUMPREG(VENC_TVDETGP_INT_START_STOP_X); - DUMPREG(VENC_TVDETGP_INT_START_STOP_Y); - DUMPREG(VENC_GEN_CTRL); - DUMPREG(VENC_OUTPUT_CONTROL); - DUMPREG(VENC_OUTPUT_TEST); - - venc_runtime_put(); + DUMPREG(venc, VENC_F_CONTROL); + DUMPREG(venc, VENC_VIDOUT_CTRL); + DUMPREG(venc, VENC_SYNC_CTRL); + DUMPREG(venc, VENC_LLEN); + DUMPREG(venc, VENC_FLENS); + DUMPREG(venc, VENC_HFLTR_CTRL); + DUMPREG(venc, VENC_CC_CARR_WSS_CARR); + DUMPREG(venc, VENC_C_PHASE); + DUMPREG(venc, VENC_GAIN_U); + DUMPREG(venc, VENC_GAIN_V); + DUMPREG(venc, VENC_GAIN_Y); + DUMPREG(venc, VENC_BLACK_LEVEL); + DUMPREG(venc, VENC_BLANK_LEVEL); + DUMPREG(venc, VENC_X_COLOR); + DUMPREG(venc, VENC_M_CONTROL); + DUMPREG(venc, VENC_BSTAMP_WSS_DATA); + DUMPREG(venc, VENC_S_CARR); + DUMPREG(venc, VENC_LINE21); + DUMPREG(venc, VENC_LN_SEL); + DUMPREG(venc, VENC_L21__WC_CTL); + DUMPREG(venc, VENC_HTRIGGER_VTRIGGER); + DUMPREG(venc, VENC_SAVID__EAVID); + DUMPREG(venc, VENC_FLEN__FAL); + DUMPREG(venc, VENC_LAL__PHASE_RESET); + DUMPREG(venc, VENC_HS_INT_START_STOP_X); + DUMPREG(venc, VENC_HS_EXT_START_STOP_X); + DUMPREG(venc, VENC_VS_INT_START_X); + DUMPREG(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y); + DUMPREG(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X); + DUMPREG(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y); + DUMPREG(venc, VENC_VS_EXT_STOP_Y); + DUMPREG(venc, VENC_AVID_START_STOP_X); + DUMPREG(venc, VENC_AVID_START_STOP_Y); + DUMPREG(venc, VENC_FID_INT_START_X__FID_INT_START_Y); + DUMPREG(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X); + DUMPREG(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y); + DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_X); + DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_Y); + DUMPREG(venc, VENC_GEN_CTRL); + DUMPREG(venc, VENC_OUTPUT_CONTROL); + DUMPREG(venc, VENC_OUTPUT_TEST); + + venc_runtime_put(venc); #undef DUMPREG + return 0; } -static int venc_get_clocks(struct platform_device *pdev) +static int venc_get_clocks(struct venc_device *venc) { struct clk *clk; - if (venc.requires_tv_dac_clk) { - clk = devm_clk_get(&pdev->dev, "tv_dac_clk"); + if (venc->requires_tv_dac_clk) { + clk = devm_clk_get(&venc->pdev->dev, "tv_dac_clk"); if (IS_ERR(clk)) { DSSERR("can't get tv_dac_clk\n"); return PTR_ERR(clk); @@ -737,7 +755,7 @@ static int venc_get_clocks(struct platform_device *pdev) clk = NULL; } - venc.tv_dac_clk = clk; + venc->tv_dac_clk = clk; return 0; } @@ -745,14 +763,14 @@ static int venc_get_clocks(struct platform_device *pdev) static int venc_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct venc_device *venc = dssdev_to_venc(dssdev); int r; - r = venc_init_regulator(); + r = venc_init_regulator(venc); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&venc->output, dssdev); if (r) return r; @@ -760,7 +778,7 @@ static int venc_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&venc->output, dssdev); return r; } @@ -770,7 +788,7 @@ static int venc_connect(struct omap_dss_device *dssdev, static void venc_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; + struct venc_device *venc = dssdev_to_venc(dssdev); WARN_ON(dst != dssdev->dst); @@ -779,7 +797,7 @@ static void venc_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&venc->output, dssdev); } static const struct omapdss_atv_ops venc_ops = { @@ -797,11 +815,11 @@ static const struct omapdss_atv_ops venc_ops = { .get_wss = venc_get_wss, }; -static void venc_init_output(struct platform_device *pdev) +static void venc_init_output(struct venc_device *venc) { - struct omap_dss_device *out = &venc.output; + struct omap_dss_device *out = &venc->output; - out->dev = &pdev->dev; + out->dev = &venc->pdev->dev; out->id = OMAP_DSS_OUTPUT_VENC; out->output_type = OMAP_DISPLAY_TYPE_VENC; out->name = "venc.0"; @@ -812,16 +830,14 @@ static void venc_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void venc_uninit_output(struct platform_device *pdev) +static void venc_uninit_output(struct venc_device *venc) { - struct omap_dss_device *out = &venc.output; - - omapdss_unregister_output(out); + omapdss_unregister_output(&venc->output); } -static int venc_probe_of(struct platform_device *pdev) +static int venc_probe_of(struct venc_device *venc) { - struct device_node *node = pdev->dev.of_node; + struct device_node *node = venc->pdev->dev.of_node; struct device_node *ep; u32 channels; int r; @@ -830,24 +846,25 @@ static int venc_probe_of(struct platform_device *pdev) if (!ep) return 0; - venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity"); + venc->invert_polarity = of_property_read_bool(ep, "ti,invert-polarity"); r = of_property_read_u32(ep, "ti,channels", &channels); if (r) { - dev_err(&pdev->dev, + dev_err(&venc->pdev->dev, "failed to read property 'ti,channels': %d\n", r); goto err; } switch (channels) { case 1: - venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE; + venc->type = OMAP_DSS_VENC_TYPE_COMPOSITE; break; case 2: - venc.type = OMAP_DSS_VENC_TYPE_SVIDEO; + venc->type = OMAP_DSS_VENC_TYPE_SVIDEO; break; default: - dev_err(&pdev->dev, "bad channel propert '%d'\n", channels); + dev_err(&venc->pdev->dev, "bad channel propert '%d'\n", + channels); r = -EINVAL; goto err; } @@ -871,65 +888,82 @@ static const struct soc_device_attribute venc_soc_devices[] = { static int venc_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); + struct venc_device *venc; u8 rev_id; struct resource *venc_mem; int r; - venc.pdev = pdev; + venc = kzalloc(sizeof(*venc), GFP_KERNEL); + if (!venc) + return -ENOMEM; + + venc->pdev = pdev; + venc->dss = dss; + dev_set_drvdata(dev, venc); /* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */ if (soc_device_match(venc_soc_devices)) - venc.requires_tv_dac_clk = true; + venc->requires_tv_dac_clk = true; - mutex_init(&venc.venc_lock); + mutex_init(&venc->venc_lock); - venc.wss_data = 0; + venc->wss_data = 0; - venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); - venc.base = devm_ioremap_resource(&pdev->dev, venc_mem); - if (IS_ERR(venc.base)) - return PTR_ERR(venc.base); + venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0); + venc->base = devm_ioremap_resource(&pdev->dev, venc_mem); + if (IS_ERR(venc->base)) { + r = PTR_ERR(venc->base); + goto err_free; + } - r = venc_get_clocks(pdev); + r = venc_get_clocks(venc); if (r) - return r; + goto err_free; pm_runtime_enable(&pdev->dev); - r = venc_runtime_get(); + r = venc_runtime_get(venc); if (r) goto err_runtime_get; - rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); + rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff); dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); - venc_runtime_put(); + venc_runtime_put(venc); - r = venc_probe_of(pdev); + r = venc_probe_of(venc); if (r) { DSSERR("Invalid DT data\n"); goto err_probe_of; } - dss_debugfs_create_file("venc", venc_dump_regs); + venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs, + venc); - venc_init_output(pdev); + venc_init_output(venc); return 0; err_probe_of: err_runtime_get: pm_runtime_disable(&pdev->dev); +err_free: + kfree(venc); return r; } static void venc_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct venc_device *venc = dev_get_drvdata(dev); - venc_uninit_output(pdev); + dss_debugfs_remove_file(venc->debugfs); - pm_runtime_disable(&pdev->dev); + venc_uninit_output(venc); + + pm_runtime_disable(dev); + + kfree(venc); } static const struct component_ops venc_component_ops = { @@ -950,24 +984,27 @@ static int venc_remove(struct platform_device *pdev) static int venc_runtime_suspend(struct device *dev) { - if (venc.tv_dac_clk) - clk_disable_unprepare(venc.tv_dac_clk); + struct venc_device *venc = dev_get_drvdata(dev); + + if (venc->tv_dac_clk) + clk_disable_unprepare(venc->tv_dac_clk); - dispc_runtime_put(); + dispc_runtime_put(venc->dss->dispc); return 0; } static int venc_runtime_resume(struct device *dev) { + struct venc_device *venc = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(venc->dss->dispc); if (r < 0) return r; - if (venc.tv_dac_clk) - clk_prepare_enable(venc.tv_dac_clk); + if (venc->tv_dac_clk) + clk_prepare_enable(venc->tv_dac_clk); return 0; } diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index bbedac797927..585ed94ccf17 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -64,11 +64,11 @@ static int dss_video_pll_enable(struct dss_pll *pll) struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll); int r; - r = dss_runtime_get(); + r = dss_runtime_get(pll->dss); if (r) return r; - dss_ctrl_pll_enable(pll->id, true); + dss_ctrl_pll_enable(pll, true); dss_dpll_enable_scp_clk(vpll); @@ -82,8 +82,8 @@ static int dss_video_pll_enable(struct dss_pll *pll) err_reset: dss_dpll_disable_scp_clk(vpll); - dss_ctrl_pll_enable(pll->id, false); - dss_runtime_put(); + dss_ctrl_pll_enable(pll, false); + dss_runtime_put(pll->dss); return r; } @@ -96,9 +96,9 @@ static void dss_video_pll_disable(struct dss_pll *pll) dss_dpll_disable_scp_clk(vpll); - dss_ctrl_pll_enable(pll->id, false); + dss_ctrl_pll_enable(pll, false); - dss_runtime_put(); + dss_runtime_put(pll->dss); } static const struct dss_pll_ops dss_pll_ops = { @@ -136,8 +136,9 @@ static const struct dss_pll_hw dss_dra7_video_pll_hw = { .errata_i886 = true, }; -struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, - struct regulator *regulator) +struct dss_pll *dss_video_pll_init(struct dss_device *dss, + struct platform_device *pdev, int id, + struct regulator *regulator) { const char * const reg_name[] = { "pll1", "pll2" }; const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" }; @@ -190,7 +191,7 @@ struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, pll->hw = &dss_dra7_video_pll_hw; pll->ops = &dss_pll_ops; - r = dss_pll_register(pll); + r = dss_pll_register(dss, pll); if (r) return ERR_PTR(r); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 1b8154e58d18..6c4d40b824e4 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -113,15 +113,17 @@ static struct omap_crtc *omap_crtcs[8]; static struct omap_dss_device *omap_crtc_output[8]; /* we can probably ignore these until we support command-mode panels: */ -static int omap_crtc_dss_connect(enum omap_channel channel, +static int omap_crtc_dss_connect(struct omap_drm_private *priv, + enum omap_channel channel, struct omap_dss_device *dst) { - const struct dispc_ops *dispc_ops = dispc_get_ops(); + const struct dispc_ops *dispc_ops = priv->dispc_ops; + struct dispc_device *dispc = priv->dispc; if (omap_crtc_output[channel]) return -EINVAL; - if ((dispc_ops->mgr_get_supported_outputs(channel) & dst->id) == 0) + if (!(dispc_ops->mgr_get_supported_outputs(dispc, channel) & dst->id)) return -EINVAL; omap_crtc_output[channel] = dst; @@ -130,14 +132,16 @@ static int omap_crtc_dss_connect(enum omap_channel channel, return 0; } -static void omap_crtc_dss_disconnect(enum omap_channel channel, +static void omap_crtc_dss_disconnect(struct omap_drm_private *priv, + enum omap_channel channel, struct omap_dss_device *dst) { omap_crtc_output[channel] = NULL; dst->dispc_channel_connected = false; } -static void omap_crtc_dss_start_update(enum omap_channel channel) +static void omap_crtc_dss_start_update(struct omap_drm_private *priv, + enum omap_channel channel) { } @@ -156,7 +160,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) return; if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { - priv->dispc_ops->mgr_enable(channel, enable); + priv->dispc_ops->mgr_enable(priv->dispc, channel, enable); omap_crtc->enabled = enable; return; } @@ -169,8 +173,9 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) omap_crtc->ignore_digit_sync_lost = true; } - framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel); - vsync_irq = priv->dispc_ops->mgr_get_vsync_irq(channel); + framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(priv->dispc, + channel); + vsync_irq = priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, channel); if (enable) { wait = omap_irq_wait_init(dev, vsync_irq, 1); @@ -190,7 +195,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) wait = omap_irq_wait_init(dev, vsync_irq, 2); } - priv->dispc_ops->mgr_enable(channel, enable); + priv->dispc_ops->mgr_enable(priv->dispc, channel, enable); omap_crtc->enabled = enable; ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); @@ -207,25 +212,28 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) } -static int omap_crtc_dss_enable(enum omap_channel channel) +static int omap_crtc_dss_enable(struct omap_drm_private *priv, + enum omap_channel channel) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; - struct omap_drm_private *priv = omap_crtc->base.dev->dev_private; - priv->dispc_ops->mgr_set_timings(omap_crtc->channel, &omap_crtc->vm); + priv->dispc_ops->mgr_set_timings(priv->dispc, omap_crtc->channel, + &omap_crtc->vm); omap_crtc_set_enabled(&omap_crtc->base, true); return 0; } -static void omap_crtc_dss_disable(enum omap_channel channel) +static void omap_crtc_dss_disable(struct omap_drm_private *priv, + enum omap_channel channel) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; omap_crtc_set_enabled(&omap_crtc->base, false); } -static void omap_crtc_dss_set_timings(enum omap_channel channel, +static void omap_crtc_dss_set_timings(struct omap_drm_private *priv, + enum omap_channel channel, const struct videomode *vm) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; @@ -233,25 +241,26 @@ static void omap_crtc_dss_set_timings(enum omap_channel channel, omap_crtc->vm = *vm; } -static void omap_crtc_dss_set_lcd_config(enum omap_channel channel, +static void omap_crtc_dss_set_lcd_config(struct omap_drm_private *priv, + enum omap_channel channel, const struct dss_lcd_mgr_config *config) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; - struct omap_drm_private *priv = omap_crtc->base.dev->dev_private; DBG("%s", omap_crtc->name); - priv->dispc_ops->mgr_set_lcd_config(omap_crtc->channel, config); + priv->dispc_ops->mgr_set_lcd_config(priv->dispc, omap_crtc->channel, + config); } static int omap_crtc_dss_register_framedone( - enum omap_channel channel, + struct omap_drm_private *priv, enum omap_channel channel, void (*handler)(void *), void *data) { return 0; } static void omap_crtc_dss_unregister_framedone( - enum omap_channel channel, + struct omap_drm_private *priv, enum omap_channel channel, void (*handler)(void *), void *data) { } @@ -272,7 +281,7 @@ static const struct dss_mgr_ops mgr_ops = { * Setup, Flush and Page Flip */ -void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus) +void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); @@ -297,7 +306,7 @@ void omap_crtc_vblank_irq(struct drm_crtc *crtc) * If the dispc is busy we're racing the flush operation. Try again on * the next vblank interrupt. */ - if (priv->dispc_ops->mgr_go_busy(omap_crtc->channel)) { + if (priv->dispc_ops->mgr_go_busy(priv->dispc, omap_crtc->channel)) { spin_unlock(&crtc->dev->event_lock); return; } @@ -334,7 +343,7 @@ static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc) info.partial_alpha_enabled = false; info.cpr_enable = false; - priv->dispc_ops->mgr_setup(omap_crtc->channel, &info); + priv->dispc_ops->mgr_setup(priv->dispc, omap_crtc->channel, &info); } /* ----------------------------------------------------------------------------- @@ -492,7 +501,7 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc, struct drm_plane_state *pri_state; if (state->color_mgmt_changed && state->gamma_lut) { - uint length = state->gamma_lut->length / + unsigned int length = state->gamma_lut->length / sizeof(struct drm_color_lut); if (length < 2) @@ -526,7 +535,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, if (crtc->state->color_mgmt_changed) { struct drm_color_lut *lut = NULL; - uint length = 0; + unsigned int length = 0; if (crtc->state->gamma_lut) { lut = (struct drm_color_lut *) @@ -534,7 +543,8 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, length = crtc->state->gamma_lut->length / sizeof(*lut); } - priv->dispc_ops->mgr_set_gamma(omap_crtc->channel, lut, length); + priv->dispc_ops->mgr_set_gamma(priv->dispc, omap_crtc->channel, + lut, length); } omap_crtc_write_crtc_properties(crtc); @@ -549,7 +559,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, WARN_ON(ret != 0); spin_lock_irq(&crtc->dev->event_lock); - priv->dispc_ops->mgr_go(omap_crtc->channel); + priv->dispc_ops->mgr_go(priv->dispc, omap_crtc->channel); omap_crtc_arm_event(crtc); spin_unlock_irq(&crtc->dev->event_lock); } @@ -557,7 +567,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, - uint64_t val) + u64 val) { struct omap_drm_private *priv = crtc->dev->dev_private; struct drm_plane_state *plane_state; @@ -585,7 +595,7 @@ static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, static int omap_crtc_atomic_get_property(struct drm_crtc *crtc, const struct drm_crtc_state *state, struct drm_property *property, - uint64_t *val) + u64 *val) { struct omap_drm_private *priv = crtc->dev->dev_private; struct omap_crtc_state *omap_state = to_omap_crtc_state(state); @@ -669,11 +679,11 @@ static const char *channel_names[] = { [OMAP_DSS_CHANNEL_LCD3] = "lcd3", }; -void omap_crtc_pre_init(void) +void omap_crtc_pre_init(struct omap_drm_private *priv) { memset(omap_crtcs, 0, sizeof(omap_crtcs)); - dss_install_mgr_ops(&mgr_ops); + dss_install_mgr_ops(&mgr_ops, priv); } void omap_crtc_pre_uninit(void) @@ -731,8 +741,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, * extracted with dispc_mgr_gamma_size(). If it returns 0 * gamma table is not supprted. */ - if (priv->dispc_ops->mgr_gamma_size(channel)) { - uint gamma_lut_size = 256; + if (priv->dispc_ops->mgr_gamma_size(priv->dispc, channel)) { + unsigned int gamma_lut_size = 256; drm_crtc_enable_color_mgmt(crtc, 0, false, gamma_lut_size); drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h index ad7b007c6174..eaab2d7f0324 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.h +++ b/drivers/gpu/drm/omapdrm/omap_crtc.h @@ -32,12 +32,12 @@ struct videomode; struct videomode *omap_crtc_timings(struct drm_crtc *crtc); enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); -void omap_crtc_pre_init(void); +void omap_crtc_pre_init(struct omap_drm_private *priv); void omap_crtc_pre_uninit(void); struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_plane *plane, struct omap_dss_device *dssdev); int omap_crtc_wait_pending(struct drm_crtc *crtc); -void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus); +void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus); void omap_crtc_vblank_irq(struct drm_crtc *crtc); #endif /* __OMAPDRM_CRTC_H__ */ diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_priv.h b/drivers/gpu/drm/omapdrm/omap_dmm_priv.h index 600064d5c25b..c2785cc98dc9 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_priv.h +++ b/drivers/gpu/drm/omapdrm/omap_dmm_priv.h @@ -102,10 +102,10 @@ struct pat_ctrl { }; struct pat { - uint32_t next_pa; + u32 next_pa; struct pat_area area; struct pat_ctrl ctrl; - uint32_t data_pa; + u32 data_pa; }; #define DMM_FIXED_RETRY_COUNT 1000 @@ -129,7 +129,7 @@ struct dmm_txn { void *engine_handle; struct tcm *tcm; - uint8_t *current_va; + u8 *current_va; dma_addr_t current_pa; struct pat *last_pat; @@ -140,7 +140,7 @@ struct refill_engine { struct dmm *dmm; struct tcm *tcm; - uint8_t *refill_va; + u8 *refill_va; dma_addr_t refill_pa; /* only one trans per engine for now */ @@ -154,7 +154,7 @@ struct refill_engine { }; struct dmm_platform_data { - uint32_t cpu_cache_flags; + u32 cpu_cache_flags; }; struct dmm { diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 4be0c94673f5..f9fa1c90b35c 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -58,11 +58,11 @@ static DEFINE_SPINLOCK(list_lock); } static const struct { - uint32_t x_shft; /* unused X-bits (as part of bpp) */ - uint32_t y_shft; /* unused Y-bits (as part of bpp) */ - uint32_t cpp; /* bytes/chars per pixel */ - uint32_t slot_w; /* width of each slot (in pixels) */ - uint32_t slot_h; /* height of each slot (in pixels) */ + u32 x_shft; /* unused X-bits (as part of bpp) */ + u32 y_shft; /* unused Y-bits (as part of bpp) */ + u32 cpp; /* bytes/chars per pixel */ + u32 slot_w; /* width of each slot (in pixels) */ + u32 slot_h; /* height of each slot (in pixels) */ } geom[TILFMT_NFORMATS] = { [TILFMT_8BIT] = GEOM(0, 0, 1), [TILFMT_16BIT] = GEOM(0, 1, 2), @@ -72,7 +72,7 @@ static const struct { /* lookup table for registers w/ per-engine instances */ -static const uint32_t reg[][4] = { +static const u32 reg[][4] = { [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1, DMM_PAT_STATUS__2, DMM_PAT_STATUS__3}, [PAT_DESCR] = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1, @@ -111,10 +111,10 @@ static void *alloc_dma(struct dmm_txn *txn, size_t sz, dma_addr_t *pa) } /* check status and spin until wait_mask comes true */ -static int wait_status(struct refill_engine *engine, uint32_t wait_mask) +static int wait_status(struct refill_engine *engine, u32 wait_mask) { struct dmm *dmm = engine->dmm; - uint32_t r = 0, err, i; + u32 r = 0, err, i; i = DMM_FIXED_RETRY_COUNT; while (true) { @@ -158,7 +158,7 @@ static void release_engine(struct refill_engine *engine) static irqreturn_t omap_dmm_irq_handler(int irq, void *arg) { struct dmm *dmm = arg; - uint32_t status = dmm_read(dmm, DMM_PAT_IRQSTATUS); + u32 status = dmm_read(dmm, DMM_PAT_IRQSTATUS); int i; /* ack IRQ */ @@ -226,10 +226,10 @@ static struct dmm_txn *dmm_txn_init(struct dmm *dmm, struct tcm *tcm) * corresponding slot is cleared (ie. dummy_pa is programmed) */ static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area, - struct page **pages, uint32_t npages, uint32_t roll) + struct page **pages, u32 npages, u32 roll) { dma_addr_t pat_pa = 0, data_pa = 0; - uint32_t *data; + u32 *data; struct pat *pat; struct refill_engine *engine = txn->engine_handle; int columns = (1 + area->x1 - area->x0); @@ -239,7 +239,7 @@ static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area, pat = alloc_dma(txn, sizeof(*pat), &pat_pa); if (txn->last_pat) - txn->last_pat->next_pa = (uint32_t)pat_pa; + txn->last_pat->next_pa = (u32)pat_pa; pat->area = *area; @@ -330,7 +330,7 @@ cleanup: * DMM programming */ static int fill(struct tcm_area *area, struct page **pages, - uint32_t npages, uint32_t roll, bool wait) + u32 npages, u32 roll, bool wait) { int ret = 0; struct tcm_area slice, area_s; @@ -378,7 +378,7 @@ static int fill(struct tcm_area *area, struct page **pages, /* note: slots for which pages[i] == NULL are filled w/ dummy page */ int tiler_pin(struct tiler_block *block, struct page **pages, - uint32_t npages, uint32_t roll, bool wait) + u32 npages, u32 roll, bool wait) { int ret; @@ -398,8 +398,8 @@ int tiler_unpin(struct tiler_block *block) /* * Reserve/release */ -struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, - uint16_t h, uint16_t align) +struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, u16 w, + u16 h, u16 align) { struct tiler_block *block = kzalloc(sizeof(*block), GFP_KERNEL); u32 min_align = 128; @@ -542,8 +542,8 @@ dma_addr_t tiler_ssptr(struct tiler_block *block) block->area.p0.y * geom[block->fmt].slot_h); } -dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, - uint32_t x, uint32_t y) +dma_addr_t tiler_tsptr(struct tiler_block *block, u32 orient, + u32 x, u32 y) { struct tcm_pt *p = &block->area.p0; BUG_ON(!validfmt(block->fmt)); @@ -553,14 +553,14 @@ dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, (p->y * geom[block->fmt].slot_h) + y); } -void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h) +void tiler_align(enum tiler_fmt fmt, u16 *w, u16 *h) { BUG_ON(!validfmt(fmt)); *w = round_up(*w, geom[fmt].slot_w); *h = round_up(*h, geom[fmt].slot_h); } -uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient) +u32 tiler_stride(enum tiler_fmt fmt, u32 orient) { BUG_ON(!validfmt(fmt)); @@ -570,19 +570,19 @@ uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient) return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft); } -size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h) +size_t tiler_size(enum tiler_fmt fmt, u16 w, u16 h) { tiler_align(fmt, &w, &h); return geom[fmt].cpp * w * h; } -size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h) +size_t tiler_vsize(enum tiler_fmt fmt, u16 w, u16 h) { BUG_ON(!validfmt(fmt)); return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h; } -uint32_t tiler_get_cpu_cache_flags(void) +u32 tiler_get_cpu_cache_flags(void) { return omap_dmm->plat_data->cpu_cache_flags; } diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h index cc78ba4fe6ab..835e6654fa82 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h @@ -88,30 +88,30 @@ int tiler_map_show(struct seq_file *s, void *arg); /* pin/unpin */ int tiler_pin(struct tiler_block *block, struct page **pages, - uint32_t npages, uint32_t roll, bool wait); + u32 npages, u32 roll, bool wait); int tiler_unpin(struct tiler_block *block); /* reserve/release */ -struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, uint16_t h, - uint16_t align); +struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, u16 w, u16 h, + u16 align); struct tiler_block *tiler_reserve_1d(size_t size); int tiler_release(struct tiler_block *block); /* utilities */ dma_addr_t tiler_ssptr(struct tiler_block *block); -dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, - uint32_t x, uint32_t y); -uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient); -size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h); -size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h); -void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h); -uint32_t tiler_get_cpu_cache_flags(void); +dma_addr_t tiler_tsptr(struct tiler_block *block, u32 orient, + u32 x, u32 y); +u32 tiler_stride(enum tiler_fmt fmt, u32 orient); +size_t tiler_size(enum tiler_fmt fmt, u16 w, u16 h); +size_t tiler_vsize(enum tiler_fmt fmt, u16 w, u16 h); +void tiler_align(enum tiler_fmt fmt, u16 *w, u16 *h); +u32 tiler_get_cpu_cache_flags(void); bool dmm_is_available(void); extern struct platform_driver omap_dmm_driver; /* GEM bo flags -> tiler fmt */ -static inline enum tiler_fmt gem2fmt(uint32_t flags) +static inline enum tiler_fmt gem2fmt(u32 flags) { switch (flags & OMAP_BO_TILED) { case OMAP_BO_TILED_8: diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index dd68b2556f5b..3632854c2b91 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -69,7 +69,7 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) struct drm_device *dev = old_state->dev; struct omap_drm_private *priv = dev->dev_private; - priv->dispc_ops->runtime_get(); + priv->dispc_ops->runtime_get(priv->dispc); /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); @@ -113,7 +113,7 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_cleanup_planes(dev, old_state); - priv->dispc_ops->runtime_put(); + priv->dispc_ops->runtime_put(priv->dispc); } static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs = { @@ -191,7 +191,7 @@ cleanup: static int omap_modeset_init_properties(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - unsigned int num_planes = priv->dispc_ops->get_num_ovls(); + unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc); priv->zorder_prop = drm_property_create_range(dev, 0, "zorder", 0, num_planes - 1); @@ -205,8 +205,8 @@ static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; - int num_ovls = priv->dispc_ops->get_num_ovls(); - int num_mgrs = priv->dispc_ops->get_num_mgrs(); + int num_ovls = priv->dispc_ops->get_num_ovls(priv->dispc); + int num_mgrs = priv->dispc_ops->get_num_mgrs(priv->dispc); int num_crtcs, crtc_idx, plane_idx; int ret; u32 plane_crtc_mask; @@ -310,11 +310,14 @@ static int omap_modeset_init(struct drm_device *dev) dev->mode_config.min_width = 8; dev->mode_config.min_height = 2; - /* note: eventually will need some cpu_is_omapXYZ() type stuff here - * to fill in these limits properly on different OMAP generations.. + /* + * Note: these values are used for multiple independent things: + * connector mode filtering, buffer sizes, crtc sizes... + * Use big enough values here to cover all use cases, and do more + * specific checking in the respective code paths. */ - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; dev->mode_config.funcs = &omap_mode_config_funcs; dev->mode_config.helper_private = &omap_mode_config_helper_funcs; @@ -510,40 +513,26 @@ static const struct soc_device_attribute omapdrm_soc_devices[] = { { /* sentinel */ } }; -static int pdev_probe(struct platform_device *pdev) +static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) { const struct soc_device_attribute *soc; - struct omap_drm_private *priv; struct drm_device *ddev; unsigned int i; int ret; - DBG("%s", pdev->name); + DBG("%s", dev_name(dev)); - if (omapdss_is_initialized() == false) - return -EPROBE_DEFER; + priv->dev = dev; + priv->dss = omapdss_get_dss(); + priv->dispc = dispc_get_dispc(priv->dss); + priv->dispc_ops = dispc_get_ops(priv->dss); - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, "Failed to set the DMA mask\n"); - return ret; - } - - omap_crtc_pre_init(); + omap_crtc_pre_init(priv); ret = omap_connect_dssdevs(); if (ret) goto err_crtc_uninit; - /* Allocate and initialize the driver private structure. */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_disconnect_dssdevs; - } - - priv->dispc_ops = dispc_get_ops(); - soc = soc_device_match(omapdrm_soc_devices); priv->omaprev = soc ? (unsigned int)soc->data : 0; priv->wq = alloc_ordered_workqueue("omapdrm", 0); @@ -552,39 +541,39 @@ static int pdev_probe(struct platform_device *pdev) INIT_LIST_HEAD(&priv->obj_list); /* Allocate and initialize the DRM device. */ - ddev = drm_dev_alloc(&omap_drm_driver, &pdev->dev); + ddev = drm_dev_alloc(&omap_drm_driver, priv->dev); if (IS_ERR(ddev)) { ret = PTR_ERR(ddev); - goto err_free_priv; + goto err_destroy_wq; } + priv->ddev = ddev; ddev->dev_private = priv; - platform_set_drvdata(pdev, ddev); /* Get memory bandwidth limits */ if (priv->dispc_ops->get_memory_bandwidth_limit) priv->max_bandwidth = - priv->dispc_ops->get_memory_bandwidth_limit(); + priv->dispc_ops->get_memory_bandwidth_limit(priv->dispc); omap_gem_init(ddev); ret = omap_modeset_init(ddev); if (ret) { - dev_err(&pdev->dev, "omap_modeset_init failed: ret=%d\n", ret); + dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret); goto err_free_drm_dev; } /* Initialize vblank handling, start with all CRTCs disabled. */ ret = drm_vblank_init(ddev, priv->num_crtcs); if (ret) { - dev_err(&pdev->dev, "could not init vblank\n"); + dev_err(priv->dev, "could not init vblank\n"); goto err_cleanup_modeset; } for (i = 0; i < priv->num_crtcs; i++) drm_crtc_vblank_off(priv->crtcs[i]); - priv->fbdev = omap_fbdev_init(ddev); + omap_fbdev_init(ddev); drm_kms_helper_poll_init(ddev); omap_modeset_enable_external_hpd(); @@ -602,28 +591,25 @@ static int pdev_probe(struct platform_device *pdev) err_cleanup_helpers: omap_modeset_disable_external_hpd(); drm_kms_helper_poll_fini(ddev); - if (priv->fbdev) - omap_fbdev_free(ddev); + + omap_fbdev_fini(ddev); err_cleanup_modeset: drm_mode_config_cleanup(ddev); omap_drm_irq_uninstall(ddev); err_free_drm_dev: omap_gem_deinit(ddev); drm_dev_unref(ddev); -err_free_priv: +err_destroy_wq: destroy_workqueue(priv->wq); - kfree(priv); -err_disconnect_dssdevs: omap_disconnect_dssdevs(); err_crtc_uninit: omap_crtc_pre_uninit(); return ret; } -static int pdev_remove(struct platform_device *pdev) +static void omapdrm_cleanup(struct omap_drm_private *priv) { - struct drm_device *ddev = platform_get_drvdata(pdev); - struct omap_drm_private *priv = ddev->dev_private; + struct drm_device *ddev = priv->ddev; DBG(""); @@ -632,8 +618,7 @@ static int pdev_remove(struct platform_device *pdev) omap_modeset_disable_external_hpd(); drm_kms_helper_poll_fini(ddev); - if (priv->fbdev) - omap_fbdev_free(ddev); + omap_fbdev_fini(ddev); drm_atomic_helper_shutdown(ddev); @@ -645,10 +630,45 @@ static int pdev_remove(struct platform_device *pdev) drm_dev_unref(ddev); destroy_workqueue(priv->wq); - kfree(priv); omap_disconnect_dssdevs(); omap_crtc_pre_uninit(); +} + +static int pdev_probe(struct platform_device *pdev) +{ + struct omap_drm_private *priv; + int ret; + + if (omapdss_is_initialized() == false) + return -EPROBE_DEFER; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "Failed to set the DMA mask\n"); + return ret; + } + + /* Allocate and initialize the driver private structure. */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + ret = omapdrm_init(priv, &pdev->dev); + if (ret < 0) + kfree(priv); + + return ret; +} + +static int pdev_remove(struct platform_device *pdev) +{ + struct omap_drm_private *priv = platform_get_drvdata(pdev); + + omapdrm_cleanup(priv); + kfree(priv); return 0; } @@ -692,7 +712,8 @@ static int omap_drm_resume_all_displays(void) static int omap_drm_suspend(struct device *dev) { - struct drm_device *drm_dev = dev_get_drvdata(dev); + struct omap_drm_private *priv = dev_get_drvdata(dev); + struct drm_device *drm_dev = priv->ddev; drm_kms_helper_poll_disable(drm_dev); @@ -705,7 +726,8 @@ static int omap_drm_suspend(struct device *dev) static int omap_drm_resume(struct device *dev) { - struct drm_device *drm_dev = dev_get_drvdata(dev); + struct omap_drm_private *priv = dev_get_drvdata(dev); + struct drm_device *drm_dev = priv->ddev; drm_modeset_lock_all(drm_dev); omap_drm_resume_all_displays(); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 0ac97fe09f9b..6eaee4df4559 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -46,8 +46,12 @@ struct omap_drm_usergart; struct omap_drm_private { - uint32_t omaprev; + struct drm_device *ddev; + struct device *dev; + u32 omaprev; + struct dss_device *dss; + struct dispc_device *dispc; const struct dispc_ops *dispc_ops; unsigned int num_crtcs; @@ -81,7 +85,7 @@ struct omap_drm_private { /* irq handling: */ spinlock_t wait_lock; /* protects the wait_list */ struct list_head wait_list; /* list of omap_irq_wait */ - uint32_t irq_mask; /* enabled irqs in addition to wait_list */ + u32 irq_mask; /* enabled irqs in addition to wait_list */ /* memory bandwidth limit if it is needed on the platform */ unsigned int max_bandwidth; diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index b2539a90e1a4..5fd22ca73913 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -52,8 +52,8 @@ static const u32 formats[] = { /* per-plane info for the fb: */ struct plane { struct drm_gem_object *bo; - uint32_t pitch; - uint32_t offset; + u32 pitch; + u32 offset; dma_addr_t dma_addr; }; @@ -100,10 +100,10 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .destroy = omap_framebuffer_destroy, }; -static uint32_t get_linear_addr(struct plane *plane, +static u32 get_linear_addr(struct plane *plane, const struct drm_format_info *format, int n, int x, int y) { - uint32_t offset; + u32 offset; offset = plane->offset + (x * format->cpp[n] / (n == 0 ? 1 : format->hsub)) @@ -121,9 +121,9 @@ bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb) } /* Note: DRM rotates counter-clockwise, TILER & DSS rotates clockwise */ -static uint32_t drm_rotation_to_tiler(unsigned int drm_rot) +static u32 drm_rotation_to_tiler(unsigned int drm_rot) { - uint32_t orient; + u32 orient; switch (drm_rot & DRM_MODE_ROTATE_MASK) { default: @@ -158,7 +158,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); const struct drm_format_info *format = omap_fb->format; struct plane *plane = &omap_fb->planes[0]; - uint32_t x, y, orient = 0; + u32 x, y, orient = 0; info->fourcc = fb->format->format; @@ -177,8 +177,8 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, y = state->src_y >> 16; if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) { - uint32_t w = state->src_w >> 16; - uint32_t h = state->src_h >> 16; + u32 w = state->src_w >> 16; + u32 h = state->src_h >> 16; orient = drm_rotation_to_tiler(state->rotation); diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index fb309d19ca1b..0f66c74a54b0 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -80,15 +80,21 @@ fallback: static struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, + + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcmap = drm_fb_helper_setcmap, + .fb_blank = drm_fb_helper_blank, + .fb_pan_display = omap_fbdev_pan_display, + .fb_debug_enter = drm_fb_helper_debug_enter, + .fb_debug_leave = drm_fb_helper_debug_leave, + .fb_ioctl = drm_fb_helper_ioctl, .fb_read = drm_fb_helper_sys_read, .fb_write = drm_fb_helper_sys_write, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - - .fb_pan_display = omap_fbdev_pan_display, }; static int omap_fbdev_create(struct drm_fb_helper *helper, @@ -188,7 +194,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, dev->mode_config.fb_base = dma_addr; - fbi->screen_base = omap_gem_vaddr(fbdev->bo); + fbi->screen_buffer = omap_gem_vaddr(fbdev->bo); fbi->screen_size = fbdev->bo->size; fbi->fix.smem_start = dma_addr; fbi->fix.smem_len = fbdev->bo->size; @@ -236,13 +242,16 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi) } /* initialize fbdev helper */ -struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) +void omap_fbdev_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_fbdev *fbdev = NULL; struct drm_fb_helper *helper; int ret = 0; + if (!priv->num_crtcs || !priv->num_connectors) + return; + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); if (!fbdev) goto fail; @@ -254,10 +263,8 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs); ret = drm_fb_helper_init(dev, helper, priv->num_connectors); - if (ret) { - dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret); + if (ret) goto fail; - } ret = drm_fb_helper_single_add_all_connectors(helper); if (ret) @@ -269,7 +276,7 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) priv->fbdev = helper; - return helper; + return; fini: drm_fb_helper_fini(helper); @@ -277,12 +284,9 @@ fail: kfree(fbdev); dev_warn(dev->dev, "omap_fbdev_init failed\n"); - /* well, limp along without an fbdev.. maybe X11 will work? */ - - return NULL; } -void omap_fbdev_free(struct drm_device *dev) +void omap_fbdev_fini(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct drm_fb_helper *helper = priv->fbdev; @@ -290,14 +294,18 @@ void omap_fbdev_free(struct drm_device *dev) DBG(); + if (!helper) + return; + drm_fb_helper_unregister_fbi(helper); drm_fb_helper_fini(helper); - fbdev = to_omap_fbdev(priv->fbdev); + fbdev = to_omap_fbdev(helper); /* unpin the GEM object pinned in omap_fbdev_create() */ - omap_gem_unpin(fbdev->bo); + if (fbdev->bo) + omap_gem_unpin(fbdev->bo); /* this will free the backing object */ if (fbdev->fb) diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.h b/drivers/gpu/drm/omapdrm/omap_fbdev.h index 1f5ba0996a1a..7dfd843f73f1 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.h +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.h @@ -24,14 +24,13 @@ struct drm_device; struct drm_fb_helper; #ifdef CONFIG_DRM_FBDEV_EMULATION -struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); -void omap_fbdev_free(struct drm_device *dev); +void omap_fbdev_init(struct drm_device *dev); +void omap_fbdev_fini(struct drm_device *dev); #else -static inline struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) +static inline void omap_fbdev_init(struct drm_device *dev) { - return NULL; } -static inline void omap_fbdev_free(struct drm_device *dev) +static inline void omap_fbdev_fini(struct drm_device *dev) { } #endif diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 443469d4fa46..0faf042b82e1 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -39,13 +39,13 @@ struct omap_gem_object { struct list_head mm_list; - uint32_t flags; + u32 flags; /** width/height for tiled formats (rounded up to slot boundaries) */ - uint16_t width, height; + u16 width, height; /** roll applied when mapping to DMM */ - uint32_t roll; + u32 roll; /** * dma_addr contains the buffer DMA address. It is valid for @@ -73,7 +73,7 @@ struct omap_gem_object { /** * # of users of dma_addr */ - uint32_t dma_addr_cnt; + u32 dma_addr_cnt; /** * If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag @@ -137,7 +137,7 @@ struct omap_drm_usergart { */ /** get mmap offset */ -static uint64_t mmap_offset(struct drm_gem_object *obj) +static u64 mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; int ret; @@ -331,14 +331,15 @@ static void omap_gem_detach_pages(struct drm_gem_object *obj) } /* get buffer flags */ -uint32_t omap_gem_flags(struct drm_gem_object *obj) +u32 omap_gem_flags(struct drm_gem_object *obj) { return to_omap_bo(obj)->flags; } -uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj) +u64 omap_gem_mmap_offset(struct drm_gem_object *obj) { - uint64_t offset; + u64 offset; + mutex_lock(&obj->dev->struct_mutex); offset = mmap_offset(obj); mutex_unlock(&obj->dev->struct_mutex); @@ -649,7 +650,7 @@ int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, * into user memory. We don't have to do much here at the moment. */ int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *offset) + u32 handle, u64 *offset) { struct drm_gem_object *obj; int ret = 0; @@ -675,10 +676,10 @@ fail: * * Call only from non-atomic contexts. */ -int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) +int omap_gem_roll(struct drm_gem_object *obj, u32 roll) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - uint32_t npages = obj->size >> PAGE_SHIFT; + u32 npages = obj->size >> PAGE_SHIFT; int ret = 0; if (roll > npages) { @@ -808,7 +809,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) if (!is_contiguous(omap_obj) && priv->has_dmm) { if (omap_obj->dma_addr_cnt == 0) { struct page **pages; - uint32_t npages = obj->size >> PAGE_SHIFT; + u32 npages = obj->size >> PAGE_SHIFT; enum tiler_fmt fmt = gem2fmt(omap_obj->flags); struct tiler_block *block; @@ -904,7 +905,7 @@ void omap_gem_unpin(struct drm_gem_object *obj) * specified orientation and x,y offset from top-left corner of buffer * (only valid for tiled 2d buffers) */ -int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, uint32_t orient, +int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, int x, int y, dma_addr_t *dma_addr) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -921,7 +922,7 @@ int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, uint32_t orient, } /* Get tiler stride for the buffer (only valid for 2d tiled buffers) */ -int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient) +int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient) { struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = -EINVAL; @@ -1003,7 +1004,8 @@ int omap_gem_resume(struct drm_device *dev) list_for_each_entry(omap_obj, &priv->obj_list, mm_list) { if (omap_obj->block) { struct drm_gem_object *obj = &omap_obj->base; - uint32_t npages = obj->size >> PAGE_SHIFT; + u32 npages = obj->size >> PAGE_SHIFT; + WARN_ON(!omap_obj->pages); /* this can't happen */ ret = tiler_pin(omap_obj->block, omap_obj->pages, npages, @@ -1027,7 +1029,7 @@ int omap_gem_resume(struct drm_device *dev) void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - uint64_t off; + u64 off; off = drm_vma_node_start(&obj->vma_node); @@ -1115,7 +1117,7 @@ void omap_gem_free_object(struct drm_gem_object *obj) /* GEM buffer object constructor */ struct drm_gem_object *omap_gem_new(struct drm_device *dev, - union omap_gem_size gsize, uint32_t flags) + union omap_gem_size gsize, u32 flags) { struct omap_drm_private *priv = dev->dev_private; struct omap_gem_object *omap_obj; @@ -1280,7 +1282,7 @@ done: /* convenience method to construct a GEM buffer object, and userspace handle */ int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, - union omap_gem_size gsize, uint32_t flags, uint32_t *handle) + union omap_gem_size gsize, u32 flags, u32 *handle) { struct drm_gem_object *obj; int ret; @@ -1327,7 +1329,8 @@ void omap_gem_init(struct drm_device *dev) /* reserve 4k aligned/wide regions for userspace mappings: */ for (i = 0; i < ARRAY_SIZE(fmts); i++) { - uint16_t h = 1, w = PAGE_SIZE >> i; + u16 h = 1, w = PAGE_SIZE >> i; + tiler_align(fmts[i], &w, &h); /* note: since each region is 1 4kb page wide, and minimum * number of rows, the height ends up being the same as the diff --git a/drivers/gpu/drm/omapdrm/omap_gem.h b/drivers/gpu/drm/omapdrm/omap_gem.h index 35fa690b3d90..a78bde05193a 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.h +++ b/drivers/gpu/drm/omapdrm/omap_gem.h @@ -53,17 +53,17 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); /* GEM Object Creation and Deletion */ struct drm_gem_object *omap_gem_new(struct drm_device *dev, - union omap_gem_size gsize, uint32_t flags); + union omap_gem_size gsize, u32 flags); struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, struct sg_table *sgt); int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, - union omap_gem_size gsize, uint32_t flags, uint32_t *handle); + union omap_gem_size gsize, u32 flags, u32 *handle); void omap_gem_free_object(struct drm_gem_object *obj); void *omap_gem_vaddr(struct drm_gem_object *obj); /* Dumb Buffers Interface */ int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *offset); + u32 handle, u64 *offset); int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); @@ -71,7 +71,7 @@ int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma); int omap_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma); -uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj); +u64 omap_gem_mmap_offset(struct drm_gem_object *obj); size_t omap_gem_mmap_size(struct drm_gem_object *obj); /* PRIME Interface */ @@ -81,7 +81,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, struct dma_buf *buffer); int omap_gem_fault(struct vm_fault *vmf); -int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll); +int omap_gem_roll(struct drm_gem_object *obj, u32 roll); void omap_gem_cpu_sync_page(struct drm_gem_object *obj, int pgoff); void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, enum dma_data_direction dir); @@ -91,9 +91,9 @@ int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap); int omap_gem_put_pages(struct drm_gem_object *obj); -uint32_t omap_gem_flags(struct drm_gem_object *obj); -int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, uint32_t orient, +u32 omap_gem_flags(struct drm_gem_object *obj); +int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, int x, int y, dma_addr_t *dma_addr); -int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient); +int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient); #endif /* __OMAPDRM_GEM_H__ */ diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 53ba424823b2..c85115049f86 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -20,7 +20,7 @@ struct omap_irq_wait { struct list_head node; wait_queue_head_t wq; - uint32_t irqmask; + u32 irqmask; int count; }; @@ -29,7 +29,7 @@ static void omap_irq_update(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_irq_wait *wait; - uint32_t irqmask = priv->irq_mask; + u32 irqmask = priv->irq_mask; assert_spin_locked(&priv->wait_lock); @@ -38,7 +38,7 @@ static void omap_irq_update(struct drm_device *dev) DBG("irqmask=%08x", irqmask); - priv->dispc_ops->write_irqenable(irqmask); + priv->dispc_ops->write_irqenable(priv->dispc, irqmask); } static void omap_irq_wait_handler(struct omap_irq_wait *wait) @@ -48,7 +48,7 @@ static void omap_irq_wait_handler(struct omap_irq_wait *wait) } struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, - uint32_t irqmask, int count) + u32 irqmask, int count) { struct omap_drm_private *priv = dev->dev_private; struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); @@ -108,7 +108,8 @@ int omap_irq_enable_vblank(struct drm_crtc *crtc) DBG("dev=%p, crtc=%u", dev, channel); spin_lock_irqsave(&priv->wait_lock, flags); - priv->irq_mask |= priv->dispc_ops->mgr_get_vsync_irq(channel); + priv->irq_mask |= priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, + channel); omap_irq_update(dev); spin_unlock_irqrestore(&priv->wait_lock, flags); @@ -134,7 +135,8 @@ void omap_irq_disable_vblank(struct drm_crtc *crtc) DBG("dev=%p, crtc=%u", dev, channel); spin_lock_irqsave(&priv->wait_lock, flags); - priv->irq_mask &= ~priv->dispc_ops->mgr_get_vsync_irq(channel); + priv->irq_mask &= ~priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, + channel); omap_irq_update(dev); spin_unlock_irqrestore(&priv->wait_lock, flags); } @@ -198,9 +200,9 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) unsigned int id; u32 irqstatus; - irqstatus = priv->dispc_ops->read_irqstatus(); - priv->dispc_ops->clear_irqstatus(irqstatus); - priv->dispc_ops->read_irqstatus(); /* flush posted write */ + irqstatus = priv->dispc_ops->read_irqstatus(priv->dispc); + priv->dispc_ops->clear_irqstatus(priv->dispc, irqstatus); + priv->dispc_ops->read_irqstatus(priv->dispc); /* flush posted write */ VERB("irqs: %08x", irqstatus); @@ -208,12 +210,12 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) struct drm_crtc *crtc = priv->crtcs[id]; enum omap_channel channel = omap_crtc_channel(crtc); - if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(channel)) { + if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, channel)) { drm_handle_vblank(dev, id); omap_crtc_vblank_irq(crtc); } - if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(channel)) + if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(priv->dispc, channel)) omap_crtc_error_irq(crtc, irqstatus); } @@ -247,7 +249,7 @@ static const u32 omap_underflow_irqs[] = { int omap_drm_irq_install(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - unsigned int num_mgrs = priv->dispc_ops->get_num_mgrs(); + unsigned int num_mgrs = priv->dispc_ops->get_num_mgrs(priv->dispc); unsigned int max_planes; unsigned int i; int ret; @@ -265,13 +267,13 @@ int omap_drm_irq_install(struct drm_device *dev) } for (i = 0; i < num_mgrs; ++i) - priv->irq_mask |= priv->dispc_ops->mgr_get_sync_lost_irq(i); + priv->irq_mask |= priv->dispc_ops->mgr_get_sync_lost_irq(priv->dispc, i); - priv->dispc_ops->runtime_get(); - priv->dispc_ops->clear_irqstatus(0xffffffff); - priv->dispc_ops->runtime_put(); + priv->dispc_ops->runtime_get(priv->dispc); + priv->dispc_ops->clear_irqstatus(priv->dispc, 0xffffffff); + priv->dispc_ops->runtime_put(priv->dispc); - ret = priv->dispc_ops->request_irq(omap_irq_handler, dev); + ret = priv->dispc_ops->request_irq(priv->dispc, omap_irq_handler, dev); if (ret < 0) return ret; @@ -289,5 +291,5 @@ void omap_drm_irq_uninstall(struct drm_device *dev) dev->irq_enabled = false; - priv->dispc_ops->free_irq(dev); + priv->dispc_ops->free_irq(priv->dispc, dev); } diff --git a/drivers/gpu/drm/omapdrm/omap_irq.h b/drivers/gpu/drm/omapdrm/omap_irq.h index 606c09932bc0..9d5441468eca 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.h +++ b/drivers/gpu/drm/omapdrm/omap_irq.h @@ -32,7 +32,7 @@ void omap_drm_irq_uninstall(struct drm_device *dev); int omap_drm_irq_install(struct drm_device *dev); struct omap_irq_wait *omap_irq_wait_init(struct drm_device *dev, - uint32_t irqmask, int count); + u32 irqmask, int count); int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, unsigned long timeout); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 7d789d1551a1..2899435cad6e 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -77,17 +77,17 @@ static void omap_plane_atomic_update(struct drm_plane *plane, &info.paddr, &info.p_uv_addr); /* and finally, update omapdss: */ - ret = priv->dispc_ops->ovl_setup(omap_plane->id, &info, + ret = priv->dispc_ops->ovl_setup(priv->dispc, omap_plane->id, &info, omap_crtc_timings(state->crtc), false, omap_crtc_channel(state->crtc)); if (ret) { dev_err(plane->dev->dev, "Failed to setup plane %s\n", omap_plane->name); - priv->dispc_ops->ovl_enable(omap_plane->id, false); + priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false); return; } - priv->dispc_ops->ovl_enable(omap_plane->id, true); + priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, true); } static void omap_plane_atomic_disable(struct drm_plane *plane, @@ -100,7 +100,7 @@ static void omap_plane_atomic_disable(struct drm_plane *plane, plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id; - priv->dispc_ops->ovl_enable(omap_plane->id, false); + priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false); } static int omap_plane_atomic_check(struct drm_plane *plane, @@ -201,7 +201,7 @@ static void omap_plane_reset(struct drm_plane *plane) static int omap_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, - uint64_t val) + u64 val) { struct omap_drm_private *priv = plane->dev->dev_private; @@ -216,7 +216,7 @@ static int omap_plane_atomic_set_property(struct drm_plane *plane, static int omap_plane_atomic_get_property(struct drm_plane *plane, const struct drm_plane_state *state, struct drm_property *property, - uint64_t *val) + u64 *val) { struct omap_drm_private *priv = plane->dev->dev_private; @@ -259,7 +259,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, u32 possible_crtcs) { struct omap_drm_private *priv = dev->dev_private; - unsigned int num_planes = priv->dispc_ops->get_num_ovls(); + unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc); struct drm_plane *plane; struct omap_plane *omap_plane; enum omap_plane_id id; @@ -278,7 +278,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, if (!omap_plane) return ERR_PTR(-ENOMEM); - formats = priv->dispc_ops->ovl_get_color_modes(id); + formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc, id); for (nformats = 0; formats[nformats]; ++nformats) ; omap_plane->id = id; diff --git a/drivers/gpu/drm/omapdrm/tcm-sita.c b/drivers/gpu/drm/omapdrm/tcm-sita.c index 661362d072f7..d7f7bc9f061a 100644 --- a/drivers/gpu/drm/omapdrm/tcm-sita.c +++ b/drivers/gpu/drm/omapdrm/tcm-sita.c @@ -33,8 +33,8 @@ static unsigned long mask[8]; * map ptr to bitmap * stride slots in a row */ -static void free_slots(unsigned long pos, uint16_t w, uint16_t h, - unsigned long *map, uint16_t stride) +static void free_slots(unsigned long pos, u16 w, u16 h, + unsigned long *map, u16 stride) { int i; @@ -48,7 +48,7 @@ static void free_slots(unsigned long pos, uint16_t w, uint16_t h, * map ptr to bitmap * num_bits number of bits in bitmap */ -static int r2l_b2t_1d(uint16_t w, unsigned long *pos, unsigned long *map, +static int r2l_b2t_1d(u16 w, unsigned long *pos, unsigned long *map, size_t num_bits) { unsigned long search_count = 0; @@ -84,7 +84,7 @@ static int r2l_b2t_1d(uint16_t w, unsigned long *pos, unsigned long *map, * num_bits = size of bitmap * stride = bits in one row of container */ -static int l2r_t2b(uint16_t w, uint16_t h, uint16_t a, int16_t offset, +static int l2r_t2b(u16 w, u16 h, u16 a, s16 offset, unsigned long *pos, unsigned long slot_bytes, unsigned long *map, size_t num_bits, size_t slot_stride) { @@ -179,7 +179,7 @@ static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots, } static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u16 align, - int16_t offset, uint16_t slot_bytes, + s16 offset, u16 slot_bytes, struct tcm_area *area) { unsigned long pos; @@ -208,7 +208,7 @@ static void sita_deinit(struct tcm *tcm) static s32 sita_free(struct tcm *tcm, struct tcm_area *area) { unsigned long pos; - uint16_t w, h; + u16 w, h; pos = area->p0.x + area->p0.y * tcm->width; if (area->is2d) { diff --git a/drivers/gpu/drm/omapdrm/tcm.h b/drivers/gpu/drm/omapdrm/tcm.h index d8a369a4f269..8efcda93c50d 100644 --- a/drivers/gpu/drm/omapdrm/tcm.h +++ b/drivers/gpu/drm/omapdrm/tcm.h @@ -65,7 +65,7 @@ struct tcm { /* function table */ s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align, - int16_t offset, uint16_t slot_bytes, + s16 offset, u16 slot_bytes, struct tcm_area *area); s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area); s32 (*free)(struct tcm *tcm, struct tcm_area *area); @@ -129,7 +129,7 @@ static inline void tcm_deinit(struct tcm *tcm) * allocation. */ static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height, - u16 align, int16_t offset, uint16_t slot_bytes, + u16 align, s16 offset, u16 slot_bytes, struct tcm_area *area) { /* perform rudimentary error checking */ diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 988048ebcc22..25682ff3449a 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -108,6 +108,15 @@ config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN Pi 7" Touchscreen. To compile this driver as a module, choose M here. +config DRM_PANEL_RAYDIUM_RM68200 + tristate "Raydium RM68200 720x1280 DSI video mode panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Raydium RM68200 + 720x1280 DSI video mode panel. + config DRM_PANEL_SAMSUNG_S6E3HA2 tristate "Samsung S6E3HA2 DSI video mode panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 3d2a88d0e965..f26efc11d746 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o +obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index b4ec0ecff807..bd38bf4f1ba6 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -179,7 +179,7 @@ enum ili9322_input { ILI9322_INPUT_UNKNOWN = 0xc, }; -const char *ili9322_inputs[] = { +static const char * const ili9322_inputs[] = { "8 bit serial RGB through", "8 bit serial RGB aligned", "8 bit serial RGB dummy 320x240", @@ -340,7 +340,7 @@ static bool ili9322_writeable_reg(struct device *dev, unsigned int reg) return true; } -const struct regmap_config ili9322_regmap_config = { +static const struct regmap_config ili9322_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0x44, diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c index b5e3994f0aa8..5185819c5b79 100644 --- a/drivers/gpu/drm/panel/panel-lvds.c +++ b/drivers/gpu/drm/panel/panel-lvds.c @@ -1,5 +1,5 @@ /* - * rcar_du_crtc.c -- R-Car Display Unit CRTCs + * Generic LVDS panel driver * * Copyright (C) 2016 Laurent Pinchart * Copyright (C) 2016 Renesas Electronics Corporation diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index c189cd6329c8..90f1ae4af93c 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -1,16 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) STMicroelectronics SA 2017 * * Authors: Philippe Cornu <philippe.cornu@st.com> * Yannick Fertre <yannick.fertre@st.com> - * - * License terms: GNU General Public License (GPL), version 2 */ + #include <drm/drmP.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> #include <linux/backlight.h> #include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> #include <video/mipi_display.h> #define DRV_NAME "orisetech_otm8009a" @@ -62,6 +63,7 @@ struct otm8009a { struct drm_panel panel; struct backlight_device *bl_dev; struct gpio_desc *reset_gpio; + struct regulator *supply; bool prepared; bool enabled; }; @@ -279,6 +281,8 @@ static int otm8009a_unprepare(struct drm_panel *panel) msleep(20); } + regulator_disable(ctx->supply); + ctx->prepared = false; return 0; @@ -292,6 +296,12 @@ static int otm8009a_prepare(struct drm_panel *panel) if (ctx->prepared) return 0; + ret = regulator_enable(ctx->supply); + if (ret < 0) { + DRM_ERROR("failed to enable supply: %d\n", ret); + return ret; + } + if (ctx->reset_gpio) { gpiod_set_value_cansleep(ctx->reset_gpio, 0); gpiod_set_value_cansleep(ctx->reset_gpio, 1); @@ -414,6 +424,13 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) return PTR_ERR(ctx->reset_gpio); } + ctx->supply = devm_regulator_get(dev, "power"); + if (IS_ERR(ctx->supply)) { + ret = PTR_ERR(ctx->supply); + dev_err(dev, "failed to request regulator: %d\n", ret); + return ret; + } + mipi_dsi_set_drvdata(dsi, ctx); ctx->dev = dev; diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c new file mode 100644 index 000000000000..77593533abcd --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics SA 2017 + * + * Authors: Philippe Cornu <philippe.cornu@st.com> + * Yannick Fertre <yannick.fertre@st.com> + */ + +#include <linux/backlight.h> +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drmP.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +/*** Manufacturer Command Set ***/ +#define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */ +#define MCS_CMD1_UCS 0x00 /* User Command Set (UCS = CMD1) */ +#define MCS_CMD2_P0 0x01 /* Manufacture Command Set Page0 (CMD2 P0) */ +#define MCS_CMD2_P1 0x02 /* Manufacture Command Set Page1 (CMD2 P1) */ +#define MCS_CMD2_P2 0x03 /* Manufacture Command Set Page2 (CMD2 P2) */ +#define MCS_CMD2_P3 0x04 /* Manufacture Command Set Page3 (CMD2 P3) */ + +/* CMD2 P0 commands (Display Options and Power) */ +#define MCS_STBCTR 0x12 /* TE1 Output Setting Zig-Zag Connection */ +#define MCS_SGOPCTR 0x16 /* Source Bias Current */ +#define MCS_SDCTR 0x1A /* Source Output Delay Time */ +#define MCS_INVCTR 0x1B /* Inversion Type */ +#define MCS_EXT_PWR_IC 0x24 /* External PWR IC Control */ +#define MCS_SETAVDD 0x27 /* PFM Control for AVDD Output */ +#define MCS_SETAVEE 0x29 /* PFM Control for AVEE Output */ +#define MCS_BT2CTR 0x2B /* DDVDL Charge Pump Control */ +#define MCS_BT3CTR 0x2F /* VGH Charge Pump Control */ +#define MCS_BT4CTR 0x34 /* VGL Charge Pump Control */ +#define MCS_VCMCTR 0x46 /* VCOM Output Level Control */ +#define MCS_SETVGN 0x52 /* VG M/S N Control */ +#define MCS_SETVGP 0x54 /* VG M/S P Control */ +#define MCS_SW_CTRL 0x5F /* Interface Control for PFM and MIPI */ + +/* CMD2 P2 commands (GOA Timing Control) - no description in datasheet */ +#define GOA_VSTV1 0x00 +#define GOA_VSTV2 0x07 +#define GOA_VCLK1 0x0E +#define GOA_VCLK2 0x17 +#define GOA_VCLK_OPT1 0x20 +#define GOA_BICLK1 0x2A +#define GOA_BICLK2 0x37 +#define GOA_BICLK3 0x44 +#define GOA_BICLK4 0x4F +#define GOA_BICLK_OPT1 0x5B +#define GOA_BICLK_OPT2 0x60 +#define MCS_GOA_GPO1 0x6D +#define MCS_GOA_GPO2 0x71 +#define MCS_GOA_EQ 0x74 +#define MCS_GOA_CLK_GALLON 0x7C +#define MCS_GOA_FS_SEL0 0x7E +#define MCS_GOA_FS_SEL1 0x87 +#define MCS_GOA_FS_SEL2 0x91 +#define MCS_GOA_FS_SEL3 0x9B +#define MCS_GOA_BS_SEL0 0xAC +#define MCS_GOA_BS_SEL1 0xB5 +#define MCS_GOA_BS_SEL2 0xBF +#define MCS_GOA_BS_SEL3 0xC9 +#define MCS_GOA_BS_SEL4 0xD3 + +/* CMD2 P3 commands (Gamma) */ +#define MCS_GAMMA_VP 0x60 /* Gamma VP1~VP16 */ +#define MCS_GAMMA_VN 0x70 /* Gamma VN1~VN16 */ + +struct rm68200 { + struct device *dev; + struct drm_panel panel; + struct gpio_desc *reset_gpio; + struct regulator *supply; + struct backlight_device *backlight; + bool prepared; + bool enabled; +}; + +static const struct drm_display_mode default_mode = { + .clock = 52582, + .hdisplay = 720, + .hsync_start = 720 + 38, + .hsync_end = 720 + 38 + 8, + .htotal = 720 + 38 + 8 + 38, + .vdisplay = 1280, + .vsync_start = 1280 + 12, + .vsync_end = 1280 + 12 + 4, + .vtotal = 1280 + 12 + 4 + 12, + .vrefresh = 50, + .flags = 0, + .width_mm = 68, + .height_mm = 122, +}; + +static inline struct rm68200 *panel_to_rm68200(struct drm_panel *panel) +{ + return container_of(panel, struct rm68200, panel); +} + +static void rm68200_dcs_write_buf(struct rm68200 *ctx, const void *data, + size_t len) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int err; + + err = mipi_dsi_dcs_write_buffer(dsi, data, len); + if (err < 0) + DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n", + err); +} + +static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int err; + + err = mipi_dsi_dcs_write(dsi, cmd, &value, 1); + if (err < 0) + DRM_ERROR_RATELIMITED("MIPI DSI DCS write failed: %d\n", err); +} + +#define dcs_write_seq(ctx, seq...) \ +({ \ + static const u8 d[] = { seq }; \ + \ + rm68200_dcs_write_buf(ctx, d, ARRAY_SIZE(d)); \ +}) + +/* + * This panel is not able to auto-increment all cmd addresses so for some of + * them, we need to send them one by one... + */ +#define dcs_write_cmd_seq(ctx, cmd, seq...) \ +({ \ + static const u8 d[] = { seq }; \ + unsigned int i; \ + \ + for (i = 0; i < ARRAY_SIZE(d) ; i++) \ + rm68200_dcs_write_cmd(ctx, cmd + i, d[i]); \ +}) + +static void rm68200_init_sequence(struct rm68200 *ctx) +{ + /* Enter CMD2 with page 0 */ + dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P0); + dcs_write_cmd_seq(ctx, MCS_EXT_PWR_IC, 0xC0, 0x53, 0x00); + dcs_write_seq(ctx, MCS_BT2CTR, 0xE5); + dcs_write_seq(ctx, MCS_SETAVDD, 0x0A); + dcs_write_seq(ctx, MCS_SETAVEE, 0x0A); + dcs_write_seq(ctx, MCS_SGOPCTR, 0x52); + dcs_write_seq(ctx, MCS_BT3CTR, 0x53); + dcs_write_seq(ctx, MCS_BT4CTR, 0x5A); + dcs_write_seq(ctx, MCS_INVCTR, 0x00); + dcs_write_seq(ctx, MCS_STBCTR, 0x0A); + dcs_write_seq(ctx, MCS_SDCTR, 0x06); + dcs_write_seq(ctx, MCS_VCMCTR, 0x56); + dcs_write_seq(ctx, MCS_SETVGN, 0xA0, 0x00); + dcs_write_seq(ctx, MCS_SETVGP, 0xA0, 0x00); + dcs_write_seq(ctx, MCS_SW_CTRL, 0x11); /* 2 data lanes, see doc */ + + dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P2); + dcs_write_seq(ctx, GOA_VSTV1, 0x05); + dcs_write_seq(ctx, 0x02, 0x0B); + dcs_write_seq(ctx, 0x03, 0x0F); + dcs_write_seq(ctx, 0x04, 0x7D, 0x00, 0x50); + dcs_write_cmd_seq(ctx, GOA_VSTV2, 0x05, 0x16, 0x0D, 0x11, 0x7D, 0x00, + 0x50); + dcs_write_cmd_seq(ctx, GOA_VCLK1, 0x07, 0x08, 0x01, 0x02, 0x00, 0x7D, + 0x00, 0x85, 0x08); + dcs_write_cmd_seq(ctx, GOA_VCLK2, 0x03, 0x04, 0x05, 0x06, 0x00, 0x7D, + 0x00, 0x85, 0x08); + dcs_write_seq(ctx, GOA_VCLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00); + dcs_write_cmd_seq(ctx, GOA_BICLK1, 0x07, 0x08); + dcs_write_seq(ctx, 0x2D, 0x01); + dcs_write_seq(ctx, 0x2F, 0x02, 0x00, 0x40, 0x05, 0x08, 0x54, 0x7D, + 0x00); + dcs_write_cmd_seq(ctx, GOA_BICLK2, 0x03, 0x04, 0x05, 0x06, 0x00); + dcs_write_seq(ctx, 0x3D, 0x40); + dcs_write_seq(ctx, 0x3F, 0x05, 0x08, 0x54, 0x7D, 0x00); + dcs_write_seq(ctx, GOA_BICLK3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(ctx, GOA_BICLK4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00); + dcs_write_seq(ctx, 0x58, 0x00, 0x00, 0x00); + dcs_write_seq(ctx, GOA_BICLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(ctx, GOA_BICLK_OPT2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(ctx, MCS_GOA_GPO1, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(ctx, MCS_GOA_GPO2, 0x00, 0x20, 0x00); + dcs_write_seq(ctx, MCS_GOA_EQ, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00); + dcs_write_seq(ctx, MCS_GOA_CLK_GALLON, 0x00, 0x00); + dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL0, 0xBF, 0x02, 0x06, 0x14, 0x10, + 0x16, 0x12, 0x08, 0x3F); + dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0C, + 0x0A, 0x0E, 0x3F, 0x3F, 0x00); + dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL2, 0x04, 0x3F, 0x3F, 0x3F, 0x3F, + 0x05, 0x01, 0x3F, 0x3F, 0x0F); + dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL3, 0x0B, 0x0D, 0x3F, 0x3F, 0x3F, + 0x3F); + dcs_write_cmd_seq(ctx, 0xA2, 0x3F, 0x09, 0x13, 0x17, 0x11, 0x15); + dcs_write_cmd_seq(ctx, 0xA9, 0x07, 0x03, 0x3F); + dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL0, 0x3F, 0x05, 0x01, 0x17, 0x13, + 0x15, 0x11, 0x0F, 0x3F); + dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0B, + 0x0D, 0x09, 0x3F, 0x3F, 0x07); + dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL2, 0x03, 0x3F, 0x3F, 0x3F, 0x3F, + 0x02, 0x06, 0x3F, 0x3F, 0x08); + dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL3, 0x0C, 0x0A, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x0E, 0x10, 0x14); + dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL4, 0x12, 0x16, 0x00, 0x04, 0x3F); + dcs_write_seq(ctx, 0xDC, 0x02); + dcs_write_seq(ctx, 0xDE, 0x12); + + dcs_write_seq(ctx, MCS_CMD_MODE_SW, 0x0E); /* No documentation */ + dcs_write_seq(ctx, 0x01, 0x75); + + dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P3); + dcs_write_cmd_seq(ctx, MCS_GAMMA_VP, 0x00, 0x0C, 0x12, 0x0E, 0x06, + 0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F, + 0x12, 0x0C, 0x00); + dcs_write_cmd_seq(ctx, MCS_GAMMA_VN, 0x00, 0x0C, 0x12, 0x0E, 0x06, + 0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F, + 0x12, 0x0C, 0x00); + + /* Exit CMD2 */ + dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD1_UCS); +} + +static int rm68200_disable(struct drm_panel *panel) +{ + struct rm68200 *ctx = panel_to_rm68200(panel); + + if (!ctx->enabled) + return 0; + + backlight_disable(ctx->backlight); + + ctx->enabled = false; + + return 0; +} + +static int rm68200_unprepare(struct drm_panel *panel) +{ + struct rm68200 *ctx = panel_to_rm68200(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + if (!ctx->prepared) + return 0; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret) + DRM_WARN("failed to set display off: %d\n", ret); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret) + DRM_WARN("failed to enter sleep mode: %d\n", ret); + + msleep(120); + + if (ctx->reset_gpio) { + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(20); + } + + regulator_disable(ctx->supply); + + ctx->prepared = false; + + return 0; +} + +static int rm68200_prepare(struct drm_panel *panel) +{ + struct rm68200 *ctx = panel_to_rm68200(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + if (ctx->prepared) + return 0; + + ret = regulator_enable(ctx->supply); + if (ret < 0) { + DRM_ERROR("failed to enable supply: %d\n", ret); + return ret; + } + + if (ctx->reset_gpio) { + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(20); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(100); + } + + rm68200_init_sequence(ctx); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret) + return ret; + + msleep(125); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret) + return ret; + + msleep(20); + + ctx->prepared = true; + + return 0; +} + +static int rm68200_enable(struct drm_panel *panel) +{ + struct rm68200 *ctx = panel_to_rm68200(panel); + + if (ctx->enabled) + return 0; + + backlight_enable(ctx->backlight); + + ctx->enabled = true; + + return 0; +} + +static int rm68200_get_modes(struct drm_panel *panel) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &default_mode); + if (!mode) { + DRM_ERROR("failed to add mode %ux%ux@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + default_mode.vrefresh); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(panel->connector, mode); + + panel->connector->display_info.width_mm = mode->width_mm; + panel->connector->display_info.height_mm = mode->height_mm; + + return 1; +} + +static const struct drm_panel_funcs rm68200_drm_funcs = { + .disable = rm68200_disable, + .unprepare = rm68200_unprepare, + .prepare = rm68200_prepare, + .enable = rm68200_enable, + .get_modes = rm68200_get_modes, +}; + +static int rm68200_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct rm68200 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) { + ret = PTR_ERR(ctx->reset_gpio); + dev_err(dev, "cannot get reset GPIO: %d\n", ret); + return ret; + } + + ctx->supply = devm_regulator_get(dev, "power"); + if (IS_ERR(ctx->supply)) { + ret = PTR_ERR(ctx->supply); + dev_err(dev, "cannot get regulator: %d\n", ret); + return ret; + } + + ctx->backlight = devm_of_find_backlight(dev); + if (IS_ERR(ctx->backlight)) + return PTR_ERR(ctx->backlight); + + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->dev = dev; + + dsi->lanes = 2; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + + drm_panel_init(&ctx->panel); + ctx->panel.dev = dev; + ctx->panel.funcs = &rm68200_drm_funcs; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static int rm68200_remove(struct mipi_dsi_device *dsi) +{ + struct rm68200 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); + + return 0; +} + +static const struct of_device_id raydium_rm68200_of_match[] = { + { .compatible = "raydium,rm68200" }, + { } +}; +MODULE_DEVICE_TABLE(of, raydium_rm68200_of_match); + +static struct mipi_dsi_driver raydium_rm68200_driver = { + .probe = rm68200_probe, + .remove = rm68200_remove, + .driver = { + .name = "panel-raydium-rm68200", + .of_match_table = raydium_rm68200_of_match, + }, +}; +module_mipi_dsi_driver(raydium_rm68200_driver); + +MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>"); +MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); +MODULE_DESCRIPTION("DRM Driver for Raydium RM68200 MIPI DSI panel"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5591984a392b..cbf1ab404ee7 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -581,6 +581,29 @@ static const struct panel_desc auo_b133htn01 = { }, }; +static const struct drm_display_mode auo_g104sn02_mode = { + .clock = 40000, + .hdisplay = 800, + .hsync_start = 800 + 40, + .hsync_end = 800 + 40 + 216, + .htotal = 800 + 40 + 216 + 128, + .vdisplay = 600, + .vsync_start = 600 + 10, + .vsync_end = 600 + 10 + 35, + .vtotal = 600 + 10 + 35 + 2, + .vrefresh = 60, +}; + +static const struct panel_desc auo_g104sn02 = { + .modes = &auo_g104sn02_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 211, + .height = 158, + }, +}; + static const struct display_timing auo_g133han01_timings = { .pixelclock = { 134000000, 141200000, 149000000 }, .hactive = { 1920, 1920, 1920 }, @@ -1217,6 +1240,30 @@ static const struct panel_desc innolux_zj070na_01p = { }, }; +static const struct display_timing koe_tx31d200vm0baa_timing = { + .pixelclock = { 39600000, 43200000, 48000000 }, + .hactive = { 1280, 1280, 1280 }, + .hfront_porch = { 16, 36, 56 }, + .hback_porch = { 16, 36, 56 }, + .hsync_len = { 8, 8, 8 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 6, 21, 33.5 }, + .vback_porch = { 6, 21, 33.5 }, + .vsync_len = { 8, 8, 8 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc koe_tx31d200vm0baa = { + .timings = &koe_tx31d200vm0baa_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 292, + .height = 109, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, +}; + static const struct display_timing kyo_tcg121xglp_timing = { .pixelclock = { 52000000, 65000000, 71000000 }, .hactive = { 1024, 1024, 1024 }, @@ -1597,7 +1644,7 @@ static const struct panel_desc ontat_yx700wv03 = { .width = 154, .height = 83, }, - .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, }; static const struct drm_display_mode ortustech_com43h4m85ulc_mode = { @@ -1741,23 +1788,22 @@ static const struct panel_desc sharp_lq101k1ly04 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, }; -static const struct drm_display_mode sharp_lq123p1jx31_mode = { - .clock = 252750, - .hdisplay = 2400, - .hsync_start = 2400 + 48, - .hsync_end = 2400 + 48 + 32, - .htotal = 2400 + 48 + 32 + 80, - .vdisplay = 1600, - .vsync_start = 1600 + 3, - .vsync_end = 1600 + 3 + 10, - .vtotal = 1600 + 3 + 10 + 33, - .vrefresh = 60, - .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +static const struct display_timing sharp_lq123p1jx31_timing = { + .pixelclock = { 252750000, 252750000, 266604720 }, + .hactive = { 2400, 2400, 2400 }, + .hfront_porch = { 48, 48, 48 }, + .hback_porch = { 80, 80, 84 }, + .hsync_len = { 32, 32, 32 }, + .vactive = { 1600, 1600, 1600 }, + .vfront_porch = { 3, 3, 3 }, + .vback_porch = { 33, 33, 120 }, + .vsync_len = { 10, 10, 10 }, + .flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW, }; static const struct panel_desc sharp_lq123p1jx31 = { - .modes = &sharp_lq123p1jx31_mode, - .num_modes = 1, + .timings = &sharp_lq123p1jx31_timing, + .num_timings = 1, .bpc = 8, .size = { .width = 259, @@ -2049,6 +2095,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "auo,b133xtn01", .data = &auo_b133xtn01, }, { + .compatible = "auo,g104sn02", + .data = &auo_g104sn02, + }, { .compatible = "auo,g133han01", .data = &auo_g133han01, }, { @@ -2124,6 +2173,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "innolux,zj070na-01p", .data = &innolux_zj070na_01p, }, { + .compatible = "koe,tx31d200vm0baa", + .data = &koe_tx31d200vm0baa, + }, { .compatible = "kyo,tcg121xglp", .data = &kyo_tcg121xglp, }, { diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 9a9214ae0fb5..ecb35ed0eac8 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -309,7 +309,7 @@ void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb) struct qxl_bo *bo = gem_to_qxl_bo(qxl_fb->obj); WARN_ON(bo->shadow); - drm_gem_object_unreference_unlocked(qxl_fb->obj); + drm_gem_object_put_unlocked(qxl_fb->obj); drm_framebuffer_cleanup(fb); kfree(qxl_fb); } @@ -1215,7 +1215,7 @@ qxl_user_framebuffer_create(struct drm_device *dev, ret = qxl_framebuffer_init(dev, qxl_fb, mode_cmd, obj, &qxl_fb_funcs); if (ret) { kfree(qxl_fb); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return NULL; } diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c index 11085ab01374..c666b89eed5d 100644 --- a/drivers/gpu/drm/qxl/qxl_dumb.c +++ b/drivers/gpu/drm/qxl/qxl_dumb.c @@ -82,6 +82,6 @@ int qxl_mode_dumb_mmap(struct drm_file *file_priv, return -ENOENT; qobj = gem_to_qxl_bo(gobj); *offset_p = qxl_bo_mmap_offset(qobj); - drm_gem_object_unreference_unlocked(gobj); + drm_gem_object_put_unlocked(gobj); return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 23af3e352673..338891401f35 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -95,7 +95,7 @@ static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj) qxl_bo_kunmap(qbo); qxl_bo_unpin(qbo); - drm_gem_object_unreference_unlocked(gobj); + drm_gem_object_put_unlocked(gobj); } int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, @@ -316,11 +316,11 @@ out_unref: qxl_bo_unpin(qbo); } if (fb && ret) { - drm_gem_object_unreference_unlocked(gobj); + drm_gem_object_put_unlocked(gobj); drm_framebuffer_cleanup(fb); kfree(fb); } - drm_gem_object_unreference_unlocked(gobj); + drm_gem_object_put_unlocked(gobj); return ret; } diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c index 85f546719adb..f5c1e7872e92 100644 --- a/drivers/gpu/drm/qxl/qxl_gem.c +++ b/drivers/gpu/drm/qxl/qxl_gem.c @@ -98,7 +98,7 @@ int qxl_gem_object_create_with_handle(struct qxl_device *qdev, return r; /* drop reference from allocate - handle holds it now */ *qobj = gem_to_qxl_bo(gobj); - drm_gem_object_unreference_unlocked(gobj); + drm_gem_object_put_unlocked(gobj); return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index e8c0b1037230..e238a1a2eca1 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -121,7 +121,7 @@ static int qxlhw_handle_to_bo(struct drm_file *file_priv, uint64_t handle, qobj = gem_to_qxl_bo(gobj); ret = qxl_release_list_add(release, qobj); - drm_gem_object_unreference_unlocked(gobj); + drm_gem_object_put_unlocked(gobj); if (ret) return ret; @@ -343,7 +343,7 @@ out2: qxl_bo_unreserve(qobj); out: - drm_gem_object_unreference_unlocked(gobj); + drm_gem_object_put_unlocked(gobj); return ret; } diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index af62824ed4cc..6a30196e9d6c 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -211,13 +211,13 @@ void qxl_bo_unref(struct qxl_bo **bo) if ((*bo) == NULL) return; - drm_gem_object_unreference_unlocked(&(*bo)->gem_base); + drm_gem_object_put_unlocked(&(*bo)->gem_base); *bo = NULL; } struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo) { - drm_gem_object_reference(&bo->gem_base); + drm_gem_object_get(&bo->gem_base); return bo; } @@ -318,7 +318,7 @@ void qxl_bo_force_delete(struct qxl_device *qdev) list_del_init(&bo->list); mutex_unlock(&qdev->gem.mutex); /* this should unref the ttm bo */ - drm_gem_object_unreference_unlocked(&bo->gem_base); + drm_gem_object_put_unlocked(&bo->gem_base); } } diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 2ad70eb96207..ee2340e31f06 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -291,19 +291,19 @@ static struct ttm_backend_func qxl_backend_func = { .destroy = &qxl_ttm_backend_destroy, }; -static struct ttm_tt *qxl_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo, + uint32_t page_flags) { struct qxl_device *qdev; struct qxl_ttm_tt *gtt; - qdev = qxl_get_qdev(bdev); + qdev = qxl_get_qdev(bo->bdev); gtt = kzalloc(sizeof(struct qxl_ttm_tt), GFP_KERNEL); if (gtt == NULL) return NULL; gtt->ttm.ttm.func = &qxl_backend_func; gtt->qdev = qdev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { + if (ttm_dma_tt_init(>t->ttm, bo, page_flags)) { kfree(gtt); return NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 5012f5e47a1e..b108eaabb6df 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -90,25 +90,18 @@ void radeon_connector_hotplug(struct drm_connector *connector) /* don't do anything if sink is not display port, i.e., * passive dp->(dvi|hdmi) adaptor */ - if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { - int saved_dpms = connector->dpms; - /* Only turn off the display if it's physically disconnected */ - if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - } else if (radeon_dp_needs_link_train(radeon_connector)) { - /* Don't try to start link training before we - * have the dpcd */ - if (!radeon_dp_getdpcd(radeon_connector)) - return; - - /* set it to OFF so that drm_helper_connector_dpms() - * won't return immediately since the current state - * is ON at this point. - */ - connector->dpms = DRM_MODE_DPMS_OFF; - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - } - connector->dpms = saved_dpms; + if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT && + radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) && + radeon_dp_needs_link_train(radeon_connector)) { + /* Don't start link training before we have the DPCD */ + if (!radeon_dp_getdpcd(radeon_connector)) + return; + + /* Turn the connector off and back on immediately, which + * will trigger link training + */ + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } } } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 31dd04f6baa1..b28288a781ef 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -415,7 +415,6 @@ static int radeon_pmops_runtime_suspend(struct device *dev) drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(drm_dev); - vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); ret = radeon_suspend_kms(drm_dev, false, false, false); pci_save_state(pdev); @@ -452,7 +451,6 @@ static int radeon_pmops_runtime_resume(struct device *dev) ret = radeon_resume_kms(drm_dev, false, false); drm_kms_helper_poll_enable(drm_dev); - vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index a9962ffba720..27d8e7dd2d06 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -34,8 +34,6 @@ void radeon_gem_object_free(struct drm_gem_object *gobj) struct radeon_bo *robj = gem_to_radeon_bo(gobj); if (robj) { - if (robj->gem_base.import_attach) - drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg); radeon_mn_unregister(robj); radeon_bo_unref(&robj); } diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 38431f682ed0..edbb4cd519fd 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -82,6 +82,8 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo) mutex_unlock(&bo->rdev->gem.mutex); radeon_bo_clear_surface_reg(bo); WARN_ON_ONCE(!list_empty(&bo->va)); + if (bo->gem_base.import_attach) + drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg); drm_gem_object_release(&bo->gem_base); kfree(bo); } diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 009f55a2bbf9..8689fcca051c 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -686,17 +686,17 @@ static struct ttm_backend_func radeon_backend_func = { .destroy = &radeon_ttm_backend_destroy, }; -static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +static struct ttm_tt *radeon_ttm_tt_create(struct ttm_buffer_object *bo, + uint32_t page_flags) { struct radeon_device *rdev; struct radeon_ttm_tt *gtt; - rdev = radeon_get_rdev(bdev); + rdev = radeon_get_rdev(bo->bdev); #if IS_ENABLED(CONFIG_AGP) if (rdev->flags & RADEON_IS_AGP) { - return ttm_agp_tt_create(bdev, rdev->ddev->agp->bridge, - size, page_flags); + return ttm_agp_tt_create(bo, rdev->ddev->agp->bridge, + page_flags); } #endif @@ -706,7 +706,7 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, } gtt->ttm.ttm.func = &radeon_backend_func; gtt->rdev = rdev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { + if (ttm_dma_tt_init(>t->ttm, bo, page_flags)) { kfree(gtt); return NULL; } diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 7d76ff47028d..3e8bf79bea58 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -71,10 +71,6 @@ struct rockchip_dp_device { struct regmap *grf; struct reset_control *rst; - struct work_struct psr_work; - struct mutex psr_lock; - unsigned int psr_state; - const struct rockchip_dp_chip_data *data; struct analogix_dp_device *adp; @@ -84,28 +80,13 @@ struct rockchip_dp_device { static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) { struct rockchip_dp_device *dp = to_dp(encoder); + int ret; - if (!analogix_dp_psr_supported(dp->adp)) + if (!analogix_dp_psr_enabled(dp->adp)) return; DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); - mutex_lock(&dp->psr_lock); - if (enabled) - dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; - else - dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; - - schedule_work(&dp->psr_work); - mutex_unlock(&dp->psr_lock); -} - -static void analogix_dp_psr_work(struct work_struct *work) -{ - struct rockchip_dp_device *dp = - container_of(work, typeof(*dp), psr_work); - int ret; - ret = rockchip_drm_wait_vact_end(dp->encoder.crtc, PSR_WAIT_LINE_FLAG_TIMEOUT_MS); if (ret) { @@ -113,12 +94,10 @@ static void analogix_dp_psr_work(struct work_struct *work) return; } - mutex_lock(&dp->psr_lock); - if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE) + if (enabled) analogix_dp_enable_psr(dp->adp); else analogix_dp_disable_psr(dp->adp); - mutex_unlock(&dp->psr_lock); } static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) @@ -135,8 +114,6 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) struct rockchip_dp_device *dp = to_dp(plat_data); int ret; - cancel_work_sync(&dp->psr_work); - ret = clk_prepare_enable(dp->pclk); if (ret < 0) { DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); @@ -355,10 +332,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.power_off = rockchip_dp_powerdown; dp->plat_data.get_modes = rockchip_dp_get_modes; - mutex_init(&dp->psr_lock); - dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; - INIT_WORK(&dp->psr_work, analogix_dp_psr_work); - ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); if (ret < 0) goto err_cleanup_encoder; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index ec999d9f15f6..c6fbdcd87c16 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -43,8 +43,6 @@ #define GRF_SOC_CON9 0x6224 #define DP_SEL_VOP_LIT BIT(12) #define GRF_SOC_CON26 0x6268 -#define UPHY_SEL_BIT 3 -#define UPHY_SEL_MASK BIT(19) #define DPTX_HPD_SEL (3 << 12) #define DPTX_HPD_DEL (2 << 12) #define DPTX_HPD_SEL_MASK (3 << 28) @@ -394,11 +392,6 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) union extcon_property_value property; int ret; - ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, - (port->id << UPHY_SEL_BIT) | UPHY_SEL_MASK); - if (ret) - return ret; - if (!port->phy_enabled) { ret = phy_power_on(port->phy); if (ret) { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 158e79e5062e..53d4afe15278 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -117,6 +117,8 @@ struct vop { spinlock_t reg_lock; /* lock vop irq reg */ spinlock_t irq_lock; + /* protects crtc enable/disable */ + struct mutex vop_lock; unsigned int irq; @@ -517,7 +519,10 @@ static int vop_enable(struct drm_crtc *crtc) goto err_disable_aclk; } - memcpy(vop->regs, vop->regsbak, vop->len); + spin_lock(&vop->reg_lock); + for (i = 0; i < vop->len; i += 4) + writel_relaxed(vop->regsbak[i / 4], vop->regs + i); + /* * We need to make sure that all windows are disabled before we * enable the crtc. Otherwise we might try to scan from a destroyed @@ -527,10 +532,9 @@ static int vop_enable(struct drm_crtc *crtc) struct vop_win *vop_win = &vop->win[i]; const struct vop_win_data *win = vop_win->data; - spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, enable, 0); - spin_unlock(&vop->reg_lock); } + spin_unlock(&vop->reg_lock); vop_cfg_done(vop); @@ -569,6 +573,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, WARN_ON(vop->event); + mutex_lock(&vop->vop_lock); drm_crtc_vblank_off(crtc); /* @@ -604,6 +609,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, clk_disable(vop->aclk); clk_disable(vop->hclk); pm_runtime_put(vop->dev); + mutex_unlock(&vop->vop_lock); if (crtc->state->event && !crtc->state->active) { spin_lock_irq(&crtc->dev->event_lock); @@ -868,10 +874,13 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, uint32_t pin_pol, val; int ret; + mutex_lock(&vop->vop_lock); + WARN_ON(vop->event); ret = vop_enable(crtc); if (ret) { + mutex_unlock(&vop->vop_lock); DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); return; } @@ -935,6 +944,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); VOP_REG_SET(vop, common, standby, 0); + mutex_unlock(&vop->vop_lock); } static bool vop_fs_irq_is_pending(struct vop *vop) @@ -1137,15 +1147,14 @@ static void vop_handle_vblank(struct vop *vop) { struct drm_device *drm = vop->drm_dev; struct drm_crtc *crtc = &vop->crtc; - unsigned long flags; - spin_lock_irqsave(&drm->event_lock, flags); + spin_lock(&drm->event_lock); if (vop->event) { drm_crtc_send_vblank_event(crtc, vop->event); drm_crtc_vblank_put(crtc); vop->event = NULL; } - spin_unlock_irqrestore(&drm->event_lock, flags); + spin_unlock(&drm->event_lock); if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq); @@ -1156,21 +1165,20 @@ static irqreturn_t vop_isr(int irq, void *data) struct vop *vop = data; struct drm_crtc *crtc = &vop->crtc; uint32_t active_irqs; - unsigned long flags; int ret = IRQ_NONE; /* * interrupt register has interrupt status, enable and clear bits, we * must hold irq_lock to avoid a race with enable/disable_vblank(). */ - spin_lock_irqsave(&vop->irq_lock, flags); + spin_lock(&vop->irq_lock); active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK); /* Clear all active interrupt sources */ if (active_irqs) VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1); - spin_unlock_irqrestore(&vop->irq_lock, flags); + spin_unlock(&vop->irq_lock); /* This is expected for vop iommu irqs, since the irq is shared */ if (!active_irqs) @@ -1393,7 +1401,11 @@ static int vop_initial(struct vop *vop) usleep_range(10, 20); reset_control_deassert(ahb_rst); - memcpy(vop->regsbak, vop->regs, vop->len); + VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1); + VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0); + + for (i = 0; i < vop->len; i += sizeof(u32)) + vop->regsbak[i / 4] = readl_relaxed(vop->regs + i); VOP_REG_SET(vop, misc, global_regdone_en, 1); VOP_REG_SET(vop, common, dsp_blank, 0); @@ -1473,15 +1485,21 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) { struct vop *vop = to_vop(crtc); unsigned long jiffies_left; + int ret = 0; if (!crtc || !vop->is_enabled) return -ENODEV; - if (mstimeout <= 0) - return -EINVAL; + mutex_lock(&vop->vop_lock); + if (mstimeout <= 0) { + ret = -EINVAL; + goto out; + } - if (vop_line_flag_irq_is_enabled(vop)) - return -EBUSY; + if (vop_line_flag_irq_is_enabled(vop)) { + ret = -EBUSY; + goto out; + } reinit_completion(&vop->line_flag_completion); vop_line_flag_irq_enable(vop); @@ -1492,10 +1510,13 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) if (jiffies_left == 0) { DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } - return 0; +out: + mutex_unlock(&vop->vop_lock); + return ret; } EXPORT_SYMBOL(rockchip_drm_wait_vact_end); @@ -1545,18 +1566,11 @@ static int vop_bind(struct device *dev, struct device *master, void *data) spin_lock_init(&vop->reg_lock); spin_lock_init(&vop->irq_lock); - - ret = devm_request_irq(dev, vop->irq, vop_isr, - IRQF_SHARED, dev_name(dev), vop); - if (ret) - return ret; - - /* IRQ is initially disabled; it gets enabled in power_on */ - disable_irq(vop->irq); + mutex_init(&vop->vop_lock); ret = vop_create_crtc(vop); if (ret) - goto err_enable_irq; + return ret; pm_runtime_enable(&pdev->dev); @@ -1567,13 +1581,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data) goto err_disable_pm_runtime; } + ret = devm_request_irq(dev, vop->irq, vop_isr, + IRQF_SHARED, dev_name(dev), vop); + if (ret) + goto err_disable_pm_runtime; + + /* IRQ is initially disabled; it gets enabled in power_on */ + disable_irq(vop->irq); + return 0; err_disable_pm_runtime: pm_runtime_disable(&pdev->dev); vop_destroy_crtc(vop); -err_enable_irq: - enable_irq(vop->irq); /* To balance out the disable_irq above */ return ret; } diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 092ade4ff6a5..9bad54f3de38 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -42,6 +42,56 @@ static const u32 sunxi_rgb2yuv_coef[12] = { 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 }; +/* + * These coefficients are taken from the A33 BSP from Allwinner. + * + * The formula is for each component, each coefficient being multiplied by + * 1024 and each constant being multiplied by 16: + * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 + * R = 1.164 * Y + 1.596 * V - 222 + * B = 1.164 * Y + 2.018 * U + 276 + * + * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], + * following the BT601 spec. + */ +static const u32 sunxi_bt601_yuv2rgb_coef[12] = { + 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, + 0x000004a7, 0x00000000, 0x00000662, 0x00003211, + 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, +}; + +static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YUV444: + return true; + default: + return false; + } +} + +static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + return true; + + default: + return false; + } +} + +static inline bool sun4i_backend_format_is_yuv(uint32_t format) +{ + return sun4i_backend_format_is_planar_yuv(format) || + sun4i_backend_format_is_packed_yuv422(format); +} + static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) { int i; @@ -166,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, return 0; } +static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend, + int layer, struct drm_plane *plane) +{ + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + uint32_t format = fb->format->format; + u32 val = SUN4I_BACKEND_IYUVCTL_EN; + int i; + + for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++) + regmap_write(backend->engine.regs, + SUN4I_BACKEND_YGCOEF_REG(i), + sunxi_bt601_yuv2rgb_coef[i]); + + /* + * We should do that only for a single plane, but the + * framebuffer's atomic_check has our back on this. + */ + regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); + + /* TODO: Add support for the multi-planar YUV formats */ + if (sun4i_backend_format_is_packed_yuv422(format)) + val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; + else + DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format); + + /* + * Allwinner seems to list the pixel sequence from right to left, while + * DRM lists it from left to right. + */ + switch (format) { + case DRM_FORMAT_YUYV: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY; + break; + case DRM_FORMAT_YVYU: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY; + break; + case DRM_FORMAT_UYVY: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU; + break; + case DRM_FORMAT_VYUY: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV; + break; + default: + DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n", + format); + } + + regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val); + + return 0; +} + int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, int layer, struct drm_plane *plane) { @@ -175,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, u32 val; int ret; + /* Clear the YUV mode */ + regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); + if (plane->state->crtc) interlaced = plane->state->crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE; @@ -186,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", interlaced ? "on" : "off"); + if (sun4i_backend_format_is_yuv(fb->format->format)) + return sun4i_backend_update_yuv_format(backend, layer, plane); + ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); if (ret) { DRM_DEBUG_DRIVER("Invalid format\n"); @@ -223,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, return 0; } +static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend, + struct drm_framebuffer *fb, + dma_addr_t paddr) +{ + /* TODO: Add support for the multi-planar YUV formats */ + DRM_DEBUG_DRIVER("Setting packed YUV buffer address to %pad\n", &paddr); + regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr); + + DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); + regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0), + fb->pitches[0] * 8); + + return 0; +} + int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, int layer, struct drm_plane *plane) { @@ -248,6 +375,9 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, */ paddr -= PHYS_OFFSET; + if (sun4i_backend_format_is_yuv(fb->format->format)) + return sun4i_backend_update_yuv_buffer(backend, fb, paddr); + /* Write the 32 lower bits of the address (in bits) */ lo_paddr = paddr << 3; DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); @@ -330,6 +460,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, unsigned int num_planes = 0; unsigned int num_alpha_planes = 0; unsigned int num_frontend_planes = 0; + unsigned int num_yuv_planes = 0; unsigned int current_pipe = 0; unsigned int i; @@ -362,6 +493,11 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, if (fb->format->has_alpha) num_alpha_planes++; + if (sun4i_backend_format_is_yuv(fb->format->format)) { + DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); + num_yuv_planes++; + } + DRM_DEBUG_DRIVER("Plane zpos is %d\n", plane_state->normalized_zpos); @@ -430,13 +566,20 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, s_state->pipe = current_pipe; } + /* We can only have a single YUV plane at a time */ + if (num_yuv_planes > SUN4I_BACKEND_NUM_YUV_PLANES) { + DRM_DEBUG_DRIVER("Too many planes with YUV, rejecting...\n"); + return -EINVAL; + } + if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) { DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n"); return -EINVAL; } - DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n", - num_planes, num_alpha_planes, num_frontend_planes); + DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video, %u YUV\n", + num_planes, num_alpha_planes, num_frontend_planes, + num_yuv_planes); return 0; } @@ -793,6 +936,9 @@ static const struct sun4i_backend_quirks sun7i_backend_quirks = { static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { }; +static const struct sun4i_backend_quirks sun9i_backend_quirks = { +}; + static const struct of_device_id sun4i_backend_of_table[] = { { .compatible = "allwinner,sun4i-a10-display-backend", @@ -814,6 +960,10 @@ static const struct of_device_id sun4i_backend_of_table[] = { .compatible = "allwinner,sun8i-a33-display-backend", .data = &sun8i_a33_backend_quirks, }, + { + .compatible = "allwinner,sun9i-a80-display-backend", + .data = &sun9i_backend_quirks, + }, { } }; MODULE_DEVICE_TABLE(of, sun4i_backend_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index 52e77591186a..316f2179e9e1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -72,6 +72,7 @@ #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15) #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10) #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10) +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2) #define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1) #define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l))) @@ -110,7 +111,23 @@ #define SUN4I_BACKEND_SPREN_REG 0x900 #define SUN4I_BACKEND_SPRFMTCTL_REG 0x908 #define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c + #define SUN4I_BACKEND_IYUVCTL_REG 0x920 +#define SUN4I_BACKEND_IYUVCTL_FBFMT_MASK GENMASK(14, 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV444 (4 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422 (3 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV444 (2 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV222 (1 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV111 (0 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBPS_MASK GENMASK(9, 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_YVYU (3 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_VYUY (2 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_YUYV (1 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_UYVY (0 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_VUYA (1 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_AYUV (0 << 8) +#define SUN4I_BACKEND_IYUVCTL_EN BIT(0) + #define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c))) #define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c))) @@ -149,6 +166,7 @@ #define SUN4I_BACKEND_NUM_LAYERS 4 #define SUN4I_BACKEND_NUM_ALPHA_LAYERS 1 #define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1 +#define SUN4I_BACKEND_NUM_YUV_PLANES 1 struct sun4i_backend { struct sunxi_engine engine; diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index a0f43b81c64c..7f0705ef9f4e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -176,7 +176,13 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node) of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") || of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") || of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") || - of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend"); + of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend") || + of_device_is_compatible(node, "allwinner,sun9i-a80-display-frontend"); +} + +static bool sun4i_drv_node_is_deu(struct device_node *node) +{ + return of_device_is_compatible(node, "allwinner,sun9i-a80-deu"); } static bool sun4i_drv_node_is_supported_frontend(struct device_node *node) @@ -257,7 +263,8 @@ static int sun4i_drv_add_endpoints(struct device *dev, * enabled frontend supported by the driver, we add it to our * component list. */ - if (!sun4i_drv_node_is_frontend(node) || + if (!(sun4i_drv_node_is_frontend(node) || + sun4i_drv_node_is_deu(node)) || (sun4i_drv_node_is_supported_frontend(node) && of_device_is_available(node))) { /* Add current component */ @@ -361,6 +368,7 @@ static const struct of_device_id sun4i_drv_of_table[] = { { .compatible = "allwinner,sun8i-a83t-display-engine" }, { .compatible = "allwinner,sun8i-h3-display-engine" }, { .compatible = "allwinner,sun8i-v3s-display-engine" }, + { .compatible = "allwinner,sun9i-a80-display-engine" }, { } }; MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 33ad377569ec..2949a3c912c1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -134,7 +134,11 @@ static const uint32_t sun4i_backend_layer_formats[] = { DRM_FORMAT_RGBA4444, DRM_FORMAT_RGB888, DRM_FORMAT_RGB565, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, }; static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c index be3f14d7746d..bffff4c9fbf5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c @@ -94,9 +94,64 @@ static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder) } } +static enum drm_mode_status sun4i_lvds_encoder_mode_valid(struct drm_encoder *crtc, + const struct drm_display_mode *mode) +{ + struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(crtc); + struct sun4i_tcon *tcon = lvds->tcon; + u32 hsync = mode->hsync_end - mode->hsync_start; + u32 vsync = mode->vsync_end - mode->vsync_start; + unsigned long rate = mode->clock * 1000; + long rounded_rate; + + DRM_DEBUG_DRIVER("Validating modes...\n"); + + if (hsync < 1) + return MODE_HSYNC_NARROW; + + if (hsync > 0x3ff) + return MODE_HSYNC_WIDE; + + if ((mode->hdisplay < 1) || (mode->htotal < 1)) + return MODE_H_ILLEGAL; + + if ((mode->hdisplay > 0x7ff) || (mode->htotal > 0xfff)) + return MODE_BAD_HVALUE; + + DRM_DEBUG_DRIVER("Horizontal parameters OK\n"); + + if (vsync < 1) + return MODE_VSYNC_NARROW; + + if (vsync > 0x3ff) + return MODE_VSYNC_WIDE; + + if ((mode->vdisplay < 1) || (mode->vtotal < 1)) + return MODE_V_ILLEGAL; + + if ((mode->vdisplay > 0x7ff) || (mode->vtotal > 0xfff)) + return MODE_BAD_VVALUE; + + DRM_DEBUG_DRIVER("Vertical parameters OK\n"); + + tcon->dclk_min_div = 7; + tcon->dclk_max_div = 7; + rounded_rate = clk_round_rate(tcon->dclk, rate); + if (rounded_rate < rate) + return MODE_CLOCK_LOW; + + if (rounded_rate > rate) + return MODE_CLOCK_HIGH; + + DRM_DEBUG_DRIVER("Clock rate OK\n"); + + return MODE_OK; +} + static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = { .disable = sun4i_lvds_encoder_disable, .enable = sun4i_lvds_encoder_enable, + .mode_valid = sun4i_lvds_encoder_mode_valid, }; static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = { diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 832f8f9bc47f..a2a697a099e6 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -52,10 +52,10 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector) return drm_panel_get_modes(tcon->panel); } -static int sun4i_rgb_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status sun4i_rgb_mode_valid(struct drm_encoder *crtc, + const struct drm_display_mode *mode) { - struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); + struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(crtc); struct sun4i_tcon *tcon = rgb->tcon; u32 hsync = mode->hsync_end - mode->hsync_start; u32 vsync = mode->vsync_end - mode->vsync_start; @@ -106,7 +106,6 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { .get_modes = sun4i_rgb_get_modes, - .mode_valid = sun4i_rgb_mode_valid, }; static void @@ -156,6 +155,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { .disable = sun4i_rgb_encoder_disable, .enable = sun4i_rgb_encoder_enable, + .mode_valid = sun4i_rgb_mode_valid, }; static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 0d6c5ed44795..1a114e380f13 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -17,6 +17,7 @@ #include <drm/drm_encoder.h> #include <drm/drm_modes.h> #include <drm/drm_of.h> +#include <drm/drm_panel.h> #include <uapi/drm/drm_mode.h> @@ -343,6 +344,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, const struct drm_display_mode *mode) { + struct drm_panel *panel = tcon->panel; + struct drm_connector *connector = panel->connector; + struct drm_display_info display_info = connector->display_info; unsigned int bp, hsync, vsync; u8 clk_delay; u32 val = 0; @@ -400,6 +404,27 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, if (mode->flags & DRM_MODE_FLAG_PVSYNC) val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; + /* + * On A20 and similar SoCs, the only way to achieve Positive Edge + * (Rising Edge), is setting dclk clock phase to 2/3(240°). + * By default TCON works in Negative Edge(Falling Edge), + * this is why phase is set to 0 in that case. + * Unfortunately there's no way to logically invert dclk through + * IO_POL register. + * The only acceptable way to work, triple checked with scope, + * is using clock phase set to 0° for Negative Edge and set to 240° + * for Positive Edge. + * On A33 and similar SoCs there would be a 90° phase option, + * but it divides also dclk by 2. + * Following code is a way to avoid quirks all around TCON + * and DOTCLOCK drivers. + */ + if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE) + clk_set_phase(tcon->dclk, 240); + + if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) + clk_set_phase(tcon->dclk, 0); + regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, val); @@ -850,6 +875,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, struct sunxi_engine *engine; struct device_node *remote; struct sun4i_tcon *tcon; + struct reset_control *edp_rstc; bool has_lvds_rst, has_lvds_alt, can_lvds; int ret; @@ -874,6 +900,20 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return PTR_ERR(tcon->lcd_rst); } + if (tcon->quirks->needs_edp_reset) { + edp_rstc = devm_reset_control_get_shared(dev, "edp"); + if (IS_ERR(edp_rstc)) { + dev_err(dev, "Couldn't get edp reset line\n"); + return PTR_ERR(edp_rstc); + } + + ret = reset_control_deassert(edp_rstc); + if (ret) { + dev_err(dev, "Couldn't deassert edp reset line\n"); + return ret; + } + } + /* Make sure our TCON is reset */ ret = reset_control_reset(tcon->lcd_rst); if (ret) { @@ -1166,6 +1206,16 @@ static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { .has_channel_0 = true, }; +static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = { + .has_channel_0 = true, + .needs_edp_reset = true, +}; + +static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = { + .has_channel_1 = true, + .needs_edp_reset = true, +}; + /* sun4i_drv uses this list to check if a device node is a TCON */ const struct of_device_id sun4i_tcon_of_table[] = { { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks }, @@ -1177,6 +1227,8 @@ const struct of_device_id sun4i_tcon_of_table[] = { { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks }, { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks }, { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks }, + { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks }, + { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks }, { } }; MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 78d55e7cd2b3..d3a945b7bb60 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -176,6 +176,7 @@ struct sun4i_tcon_quirks { bool has_channel_1; /* a33 does not have channel 1 */ bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ bool needs_de_be_mux; /* sun6i needs mux to select backend */ + bool needs_edp_reset; /* a80 edp reset needed for tcon0 access */ /* callback to handle tcon muxing options */ int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c index 09bba853e2a4..b5e071a49045 100644 --- a/drivers/gpu/drm/sun4i/sun6i_drc.c +++ b/drivers/gpu/drm/sun4i/sun6i_drc.c @@ -101,6 +101,7 @@ static const struct of_device_id sun6i_drc_of_table[] = { { .compatible = "allwinner,sun6i-a31-drc" }, { .compatible = "allwinner,sun6i-a31s-drc" }, { .compatible = "allwinner,sun8i-a33-drc" }, + { .compatible = "allwinner,sun9i-a80-drc" }, { } }; MODULE_DEVICE_TABLE(of, sun6i_drc_of_table); diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 49df2db2ad46..71152776b04c 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -383,6 +383,12 @@ static const u32 tegra20_primary_formats[] = { DRM_FORMAT_XRGB8888, }; +static const u64 tegra20_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED, + DRM_FORMAT_MOD_INVALID +}; + static const u32 tegra114_primary_formats[] = { DRM_FORMAT_ARGB4444, DRM_FORMAT_ARGB1555, @@ -430,6 +436,17 @@ static const u32 tegra124_primary_formats[] = { DRM_FORMAT_BGRX8888, }; +static const u64 tegra124_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5), + DRM_FORMAT_MOD_INVALID +}; + static int tegra_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { @@ -596,6 +613,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, enum drm_plane_type type = DRM_PLANE_TYPE_PRIMARY; struct tegra_plane *plane; unsigned int num_formats; + const u64 *modifiers; const u32 *formats; int err; @@ -610,10 +628,11 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, num_formats = dc->soc->num_primary_formats; formats = dc->soc->primary_formats; + modifiers = dc->soc->modifiers; err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, type, NULL); + num_formats, modifiers, type, NULL); if (err < 0) { kfree(plane); return ERR_PTR(err); @@ -864,11 +883,13 @@ static const u32 tegra124_overlay_formats[] = { static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, struct tegra_dc *dc, - unsigned int index) + unsigned int index, + bool cursor) { unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm); struct tegra_plane *plane; unsigned int num_formats; + enum drm_plane_type type; const u32 *formats; int err; @@ -883,10 +904,14 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, num_formats = dc->soc->num_overlay_formats; formats = dc->soc->overlay_formats; + if (!cursor) + type = DRM_PLANE_TYPE_OVERLAY; + else + type = DRM_PLANE_TYPE_CURSOR; + err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, - DRM_PLANE_TYPE_OVERLAY, NULL); + num_formats, NULL, type, NULL); if (err < 0) { kfree(plane); return ERR_PTR(err); @@ -938,6 +963,7 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) { struct drm_plane *planes[2], *primary; + unsigned int planes_num; unsigned int i; int err; @@ -945,8 +971,14 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm, if (IS_ERR(primary)) return primary; - for (i = 0; i < 2; i++) { - planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i); + if (dc->soc->supports_cursor) + planes_num = 2; + else + planes_num = 1; + + for (i = 0; i < planes_num; i++) { + planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i, + false); if (IS_ERR(planes[i])) { err = PTR_ERR(planes[i]); @@ -1704,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, drm_crtc_vblank_on(crtc); } -static int tegra_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - struct tegra_atomic_state *s = to_tegra_atomic_state(state->state); - struct tegra_dc_state *tegra = to_dc_state(state); - - /* - * The display hub display clock needs to be fed by the display clock - * with the highest frequency to ensure proper functioning of all the - * displays. - * - * Note that this isn't used before Tegra186, but it doesn't hurt and - * conditionalizing it would make the code less clean. - */ - if (state->active) { - if (!s->clk_disp || tegra->pclk > s->rate) { - s->dc = to_tegra_dc(crtc); - s->clk_disp = s->dc->clk; - s->rate = tegra->pclk; - } - } - - return 0; -} - static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -1765,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, } static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { - .atomic_check = tegra_crtc_atomic_check, .atomic_begin = tegra_crtc_atomic_begin, .atomic_flush = tegra_crtc_atomic_flush, .atomic_enable = tegra_crtc_atomic_enable, @@ -1864,6 +1870,13 @@ static int tegra_dc_init(struct host1x_client *client) err = PTR_ERR(cursor); goto cleanup; } + } else { + /* dedicate one overlay to mouse cursor */ + cursor = tegra_dc_overlay_plane_create(drm, dc, 2, true); + if (IS_ERR(cursor)) { + err = PTR_ERR(cursor); + goto cleanup; + } } err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor, @@ -1954,6 +1967,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { .primary_formats = tegra20_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), .overlay_formats = tegra20_overlay_formats, + .modifiers = tegra20_modifiers, }; static const struct tegra_dc_soc_info tegra30_dc_soc_info = { @@ -1970,6 +1984,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = { .primary_formats = tegra20_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), .overlay_formats = tegra20_overlay_formats, + .modifiers = tegra20_modifiers, }; static const struct tegra_dc_soc_info tegra114_dc_soc_info = { @@ -1986,6 +2001,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = { .primary_formats = tegra114_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), .overlay_formats = tegra114_overlay_formats, + .modifiers = tegra20_modifiers, }; static const struct tegra_dc_soc_info tegra124_dc_soc_info = { @@ -2002,6 +2018,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = { .primary_formats = tegra114_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats), .overlay_formats = tegra114_overlay_formats, + .modifiers = tegra124_modifiers, }; static const struct tegra_dc_soc_info tegra210_dc_soc_info = { @@ -2018,6 +2035,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = { .primary_formats = tegra114_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), .overlay_formats = tegra114_overlay_formats, + .modifiers = tegra124_modifiers, }; static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = { diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 096a81ad6d8d..d2b50d32de4d 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -66,6 +66,7 @@ struct tegra_dc_soc_info { unsigned int num_primary_formats; const u32 *overlay_formats; unsigned int num_overlay_formats; + const u64 *modifiers; }; struct tegra_dc { diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index d50bddb2e447..e20e013151f0 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm, if (err < 0) return err; + err = tegra_display_hub_atomic_check(drm, state); + if (err < 0) + return err; + err = drm_atomic_normalize_zpos(drm, state); if (err < 0) return err; @@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm, return 0; } -static struct drm_atomic_state * -tegra_atomic_state_alloc(struct drm_device *drm) -{ - struct tegra_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - - if (!state || drm_atomic_state_init(drm, &state->base) < 0) { - kfree(state); - return NULL; - } - - return &state->base; -} - -static void tegra_atomic_state_clear(struct drm_atomic_state *state) -{ - struct tegra_atomic_state *tegra = to_tegra_atomic_state(state); - - drm_atomic_state_default_clear(state); - tegra->clk_disp = NULL; - tegra->dc = NULL; - tegra->rate = 0; -} - -static void tegra_atomic_state_free(struct drm_atomic_state *state) -{ - drm_atomic_state_default_release(state); - kfree(state); -} - static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { .fb_create = tegra_fb_create, #ifdef CONFIG_DRM_FBDEV_EMULATION @@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { #endif .atomic_check = tegra_atomic_check, .atomic_commit = drm_atomic_helper_commit, - .atomic_state_alloc = tegra_atomic_state_alloc, - .atomic_state_clear = tegra_atomic_state_clear, - .atomic_state_free = tegra_atomic_state_free, }; static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 73b661ce7086..4f41aaec8530 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -42,20 +42,6 @@ struct tegra_fbdev { }; #endif -struct tegra_atomic_state { - struct drm_atomic_state base; - - struct clk *clk_disp; - struct tegra_dc *dc; - unsigned long rate; -}; - -static inline struct tegra_atomic_state * -to_tegra_atomic_state(struct drm_atomic_state *state) -{ - return container_of(state, struct tegra_atomic_state, base); -} - struct tegra_drm { struct drm_device *drm; diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 001cb77e2f59..e69434909a42 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -55,6 +55,11 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, uint64_t modifier = fb->base.modifier; switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + tiling->mode = TEGRA_BO_TILING_MODE_PITCH; + tiling->value = 0; + break; + case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED: tiling->mode = TEGRA_BO_TILING_MODE_TILED; tiling->value = 0; @@ -91,9 +96,7 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, break; default: - /* TODO: handle YUV formats? */ - *tiling = fb->planes[0]->tiling; - break; + return -EINVAL; } return 0; @@ -224,12 +227,28 @@ unreference: } #ifdef CONFIG_DRM_FBDEV_EMULATION +static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *helper = info->par; + struct tegra_bo *bo; + int err; + + bo = tegra_fb_get_plane(helper->fb, 0); + + err = drm_gem_mmap_obj(&bo->gem, bo->gem.size, vma); + if (err < 0) + return err; + + return __tegra_gem_mmap(&bo->gem, vma); +} + static struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, + .fb_mmap = tegra_fb_mmap, }; static int tegra_fbdev_probe(struct drm_fb_helper *helper, diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 49b9bf28f872..8b0b4ff64bb4 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -203,6 +203,8 @@ free: static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) { if (bo->pages) { + dma_unmap_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_BIDIRECTIONAL); drm_gem_put_pages(&bo->gem, bo->pages, true, true); sg_free_table(bo->sgt); kfree(bo->sgt); @@ -213,8 +215,7 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) { - struct scatterlist *s; - unsigned int i; + int err; bo->pages = drm_gem_get_pages(&bo->gem); if (IS_ERR(bo->pages)) @@ -223,27 +224,26 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) bo->num_pages = bo->gem.size >> PAGE_SHIFT; bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); - if (IS_ERR(bo->sgt)) + if (IS_ERR(bo->sgt)) { + err = PTR_ERR(bo->sgt); goto put_pages; + } - /* - * Fake up the SG table so that dma_sync_sg_for_device() can be used - * to flush the pages associated with it. - * - * TODO: Replace this by drm_clflash_sg() once it can be implemented - * without relying on symbols that are not exported. - */ - for_each_sg(bo->sgt->sgl, s, bo->sgt->nents, i) - sg_dma_address(s) = sg_phys(s); - - dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents, - DMA_TO_DEVICE); + err = dma_map_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_BIDIRECTIONAL); + if (err == 0) { + err = -EFAULT; + goto free_sgt; + } return 0; +free_sgt: + sg_free_table(bo->sgt); + kfree(bo->sgt); put_pages: drm_gem_put_pages(&bo->gem, bo->pages, false, false); - return PTR_ERR(bo->sgt); + return err; } static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) @@ -459,8 +459,7 @@ const struct vm_operations_struct tegra_bo_vm_ops = { .close = drm_gem_vm_close, }; -static int tegra_gem_mmap(struct drm_gem_object *gem, - struct vm_area_struct *vma) +int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma) { struct tegra_bo *bo = to_tegra_bo(gem); @@ -507,7 +506,7 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) gem = vma->vm_private_data; - return tegra_gem_mmap(gem, vma); + return __tegra_gem_mmap(gem, vma); } static struct sg_table * @@ -569,6 +568,34 @@ static void tegra_gem_prime_release(struct dma_buf *buf) drm_gem_dmabuf_release(buf); } +static int tegra_gem_prime_begin_cpu_access(struct dma_buf *buf, + enum dma_data_direction direction) +{ + struct drm_gem_object *gem = buf->priv; + struct tegra_bo *bo = to_tegra_bo(gem); + struct drm_device *drm = gem->dev; + + if (bo->pages) + dma_sync_sg_for_cpu(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_FROM_DEVICE); + + return 0; +} + +static int tegra_gem_prime_end_cpu_access(struct dma_buf *buf, + enum dma_data_direction direction) +{ + struct drm_gem_object *gem = buf->priv; + struct tegra_bo *bo = to_tegra_bo(gem); + struct drm_device *drm = gem->dev; + + if (bo->pages) + dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_TO_DEVICE); + + return 0; +} + static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, unsigned long page) { @@ -600,7 +627,7 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) if (err < 0) return err; - return tegra_gem_mmap(gem, vma); + return __tegra_gem_mmap(gem, vma); } static void *tegra_gem_prime_vmap(struct dma_buf *buf) @@ -619,6 +646,8 @@ static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { .map_dma_buf = tegra_gem_prime_map_dma_buf, .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, .release = tegra_gem_prime_release, + .begin_cpu_access = tegra_gem_prime_begin_cpu_access, + .end_cpu_access = tegra_gem_prime_end_cpu_access, .map_atomic = tegra_gem_prime_kmap_atomic, .unmap_atomic = tegra_gem_prime_kunmap_atomic, .map = tegra_gem_prime_kmap, diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index 8eb9fd24ef0e..6bd7dd7e55b4 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -68,10 +68,11 @@ void tegra_bo_free_object(struct drm_gem_object *gem); int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, struct drm_mode_create_dumb *args); -int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); - extern const struct vm_operations_struct tegra_bo_vm_ops; +int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma); +int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); + struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem, int flags); diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index e10a47d57313..9a3f23d4780f 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -49,6 +49,17 @@ static const u32 tegra_shared_plane_formats[] = { DRM_FORMAT_YUV422, }; +static const u64 tegra_shared_plane_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5), + DRM_FORMAT_MOD_INVALID +}; + static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, unsigned int offset) { @@ -527,6 +538,7 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, unsigned int possible_crtcs = 0x7; struct tegra_shared_plane *plane; unsigned int num_formats; + const u64 *modifiers; struct drm_plane *p; const u32 *formats; int err; @@ -545,10 +557,11 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, num_formats = ARRAY_SIZE(tegra_shared_plane_formats); formats = tegra_shared_plane_formats; + modifiers = tegra_shared_plane_modifiers; err = drm_universal_plane_init(drm, p, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, type, NULL); + num_formats, modifiers, type, NULL); if (err < 0) { kfree(plane); return ERR_PTR(err); @@ -560,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, return p; } +static struct drm_private_state * +tegra_display_hub_duplicate_state(struct drm_private_obj *obj) +{ + struct tegra_display_hub_state *state; + + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + + return &state->base; +} + +static void tegra_display_hub_destroy_state(struct drm_private_obj *obj, + struct drm_private_state *state) +{ + struct tegra_display_hub_state *hub_state = + to_tegra_display_hub_state(state); + + kfree(hub_state); +} + +static const struct drm_private_state_funcs tegra_display_hub_state_funcs = { + .atomic_duplicate_state = tegra_display_hub_duplicate_state, + .atomic_destroy_state = tegra_display_hub_destroy_state, +}; + +static struct tegra_display_hub_state * +tegra_display_hub_get_state(struct tegra_display_hub *hub, + struct drm_atomic_state *state) +{ + struct drm_device *drm = dev_get_drvdata(hub->client.parent); + struct drm_private_state *priv; + + WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex)); + + priv = drm_atomic_get_private_obj_state(state, &hub->base); + if (IS_ERR(priv)) + return ERR_CAST(priv); + + return to_tegra_display_hub_state(priv); +} + +int tegra_display_hub_atomic_check(struct drm_device *drm, + struct drm_atomic_state *state) +{ + struct tegra_drm *tegra = drm->dev_private; + struct tegra_display_hub_state *hub_state; + struct drm_crtc_state *old, *new; + struct drm_crtc *crtc; + unsigned int i; + + if (!tegra->hub) + return 0; + + hub_state = tegra_display_hub_get_state(tegra->hub, state); + if (IS_ERR(hub_state)) + return PTR_ERR(hub_state); + + /* + * The display hub display clock needs to be fed by the display clock + * with the highest frequency to ensure proper functioning of all the + * displays. + * + * Note that this isn't used before Tegra186, but it doesn't hurt and + * conditionalizing it would make the code less clean. + */ + for_each_oldnew_crtc_in_state(state, crtc, old, new, i) { + struct tegra_dc_state *dc = to_dc_state(new); + + if (new->active) { + if (!hub_state->clk || dc->pclk > hub_state->rate) { + hub_state->dc = to_tegra_dc(dc->base.crtc); + hub_state->clk = hub_state->dc->clk; + hub_state->rate = dc->pclk; + } + } + } + + return 0; +} + static void tegra_display_hub_update(struct tegra_dc *dc) { u32 value; @@ -585,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc) void tegra_display_hub_atomic_commit(struct drm_device *drm, struct drm_atomic_state *state) { - struct tegra_atomic_state *s = to_tegra_atomic_state(state); struct tegra_drm *tegra = drm->dev_private; struct tegra_display_hub *hub = tegra->hub; + struct tegra_display_hub_state *hub_state; struct device *dev = hub->client.dev; int err; - if (s->clk_disp) { - err = clk_set_rate(s->clk_disp, s->rate); + hub_state = tegra_display_hub_get_state(hub, state); + + if (hub_state->clk) { + err = clk_set_rate(hub_state->clk, hub_state->rate); if (err < 0) dev_err(dev, "failed to set rate of %pC to %lu Hz\n", - s->clk_disp, s->rate); + hub_state->clk, hub_state->rate); - err = clk_set_parent(hub->clk_disp, s->clk_disp); + err = clk_set_parent(hub->clk_disp, hub_state->clk); if (err < 0) dev_err(dev, "failed to set parent of %pC to %pC: %d\n", - hub->clk_disp, s->clk_disp, err); + hub->clk_disp, hub_state->clk, err); } - if (s->dc) - tegra_display_hub_update(s->dc); + if (hub_state->dc) + tegra_display_hub_update(hub_state->dc); } static int tegra_display_hub_init(struct host1x_client *client) @@ -612,6 +710,14 @@ static int tegra_display_hub_init(struct host1x_client *client) struct tegra_display_hub *hub = to_tegra_display_hub(client); struct drm_device *drm = dev_get_drvdata(client->parent); struct tegra_drm *tegra = drm->dev_private; + struct tegra_display_hub_state *state; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + drm_atomic_private_obj_init(&hub->base, &state->base, + &tegra_display_hub_state_funcs); tegra->hub = hub; @@ -623,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client) struct drm_device *drm = dev_get_drvdata(client->parent); struct tegra_drm *tegra = drm->dev_private; + drm_atomic_private_obj_fini(&tegra->hub->base); tegra->hub = NULL; return 0; diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h index 890a47cd05c3..85b8bf41a395 100644 --- a/drivers/gpu/drm/tegra/hub.h +++ b/drivers/gpu/drm/tegra/hub.h @@ -41,6 +41,7 @@ struct tegra_display_hub_soc { }; struct tegra_display_hub { + struct drm_private_obj base; struct host1x_client client; struct clk *clk_disp; struct clk *clk_dsc; @@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client) return container_of(client, struct tegra_display_hub, client); } +struct tegra_display_hub_state { + struct drm_private_state base; + + struct tegra_dc *dc; + unsigned long rate; + struct clk *clk; +}; + +static inline struct tegra_display_hub_state * +to_tegra_display_hub_state(struct drm_private_state *priv) +{ + return container_of(priv, struct tegra_display_hub_state, base); +} + struct tegra_dc; struct tegra_plane; @@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, unsigned int wgrp, unsigned int index); +int tegra_display_hub_atomic_check(struct drm_device *drm, + struct drm_atomic_state *state); void tegra_display_hub_atomic_commit(struct drm_device *drm, struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index a056fbf83b53..6d6e2d0091eb 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -68,6 +68,21 @@ static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, kfree(state); } +static bool tegra_plane_format_mod_supported(struct drm_plane *plane, + uint32_t format, + uint64_t modifier) +{ + const struct drm_format_info *info = drm_format_info(format); + + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + if (info->num_planes == 1) + return true; + + return false; +} + const struct drm_plane_funcs tegra_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -75,6 +90,7 @@ const struct drm_plane_funcs tegra_plane_funcs = { .reset = tegra_plane_reset, .atomic_duplicate_state = tegra_plane_atomic_duplicate_state, .atomic_destroy_state = tegra_plane_atomic_destroy_state, + .format_mod_supported = tegra_plane_format_mod_supported, }; int tegra_plane_state_add(struct tegra_plane *plane, @@ -296,8 +312,8 @@ int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha) return -EINVAL; } -unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, - struct tegra_plane *other) +static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, + struct tegra_plane *other) { unsigned int index = 0, i; diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c index f7c2aefbec7c..7c2485fe88d8 100644 --- a/drivers/gpu/drm/ttm/ttm_agp_backend.c +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -110,9 +110,9 @@ static struct ttm_backend_func ttm_agp_func = { .destroy = ttm_agp_destroy, }; -struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev, +struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo, struct agp_bridge_data *bridge, - unsigned long size, uint32_t page_flags) + uint32_t page_flags) { struct ttm_agp_backend *agp_be; @@ -124,7 +124,7 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev, agp_be->bridge = bridge; agp_be->ttm.func = &ttm_agp_func; - if (ttm_tt_init(&agp_be->ttm, bdev, size, page_flags)) { + if (ttm_tt_init(&agp_be->ttm, bo, page_flags)) { kfree(agp_be); return NULL; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index ad142a92eb80..98e06f8bf23b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -622,14 +622,23 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, reservation_object_assert_held(bo->resv); + placement.num_placement = 0; + placement.num_busy_placement = 0; + bdev->driver->evict_flags(bo, &placement); + + if (!placement.num_placement && !placement.num_busy_placement) { + ret = ttm_bo_pipeline_gutting(bo); + if (ret) + return ret; + + return ttm_tt_create(bo, false); + } + evict_mem = bo->mem; evict_mem.mm_node = NULL; evict_mem.bus.io_reserved_vm = false; evict_mem.bus.io_reserved_count = 0; - placement.num_placement = 0; - placement.num_busy_placement = 0; - bdev->driver->evict_flags(bo, &placement); ret = ttm_bo_mem_space(bo, &placement, &evict_mem, ctx); if (ret) { if (ret != -ERESTARTSYS) { diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 6d6a3f46143b..2ebbae6067ab 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -255,6 +255,54 @@ static int ttm_copy_io_page(void *dst, void *src, unsigned long page) return 0; } +#ifdef CONFIG_X86 +#define __ttm_kmap_atomic_prot(__page, __prot) kmap_atomic_prot(__page, __prot) +#define __ttm_kunmap_atomic(__addr) kunmap_atomic(__addr) +#else +#define __ttm_kmap_atomic_prot(__page, __prot) vmap(&__page, 1, 0, __prot) +#define __ttm_kunmap_atomic(__addr) vunmap(__addr) +#endif + + +/** + * ttm_kmap_atomic_prot - Efficient kernel map of a single page with + * specified page protection. + * + * @page: The page to map. + * @prot: The page protection. + * + * This function maps a TTM page using the kmap_atomic api if available, + * otherwise falls back to vmap. The user must make sure that the + * specified page does not have an aliased mapping with a different caching + * policy unless the architecture explicitly allows it. Also mapping and + * unmapping using this api must be correctly nested. Unmapping should + * occur in the reverse order of mapping. + */ +void *ttm_kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + if (pgprot_val(prot) == pgprot_val(PAGE_KERNEL)) + return kmap_atomic(page); + else + return __ttm_kmap_atomic_prot(page, prot); +} +EXPORT_SYMBOL(ttm_kmap_atomic_prot); + +/** + * ttm_kunmap_atomic_prot - Unmap a page that was mapped using + * ttm_kmap_atomic_prot. + * + * @addr: The virtual address from the map. + * @prot: The page protection. + */ +void ttm_kunmap_atomic_prot(void *addr, pgprot_t prot) +{ + if (pgprot_val(prot) == pgprot_val(PAGE_KERNEL)) + kunmap_atomic(addr); + else + __ttm_kunmap_atomic(addr); +} +EXPORT_SYMBOL(ttm_kunmap_atomic_prot); + static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, unsigned long page, pgprot_t prot) @@ -266,28 +314,13 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, return -ENOMEM; src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); - -#ifdef CONFIG_X86 - dst = kmap_atomic_prot(d, prot); -#else - if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) - dst = vmap(&d, 1, 0, prot); - else - dst = kmap(d); -#endif + dst = ttm_kmap_atomic_prot(d, prot); if (!dst) return -ENOMEM; memcpy_fromio(dst, src, PAGE_SIZE); -#ifdef CONFIG_X86 - kunmap_atomic(dst); -#else - if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) - vunmap(dst); - else - kunmap(d); -#endif + ttm_kunmap_atomic_prot(dst, prot); return 0; } @@ -303,27 +336,13 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, return -ENOMEM; dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); -#ifdef CONFIG_X86 - src = kmap_atomic_prot(s, prot); -#else - if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) - src = vmap(&s, 1, 0, prot); - else - src = kmap(s); -#endif + src = ttm_kmap_atomic_prot(s, prot); if (!src) return -ENOMEM; memcpy_toio(dst, src, PAGE_SIZE); -#ifdef CONFIG_X86 - kunmap_atomic(src); -#else - if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) - vunmap(src); - else - kunmap(s); -#endif + ttm_kunmap_atomic_prot(src, prot); return 0; } @@ -801,3 +820,27 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, return 0; } EXPORT_SYMBOL(ttm_bo_pipeline_move); + +int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo) +{ + struct ttm_buffer_object *ghost; + int ret; + + ret = ttm_buffer_object_transfer(bo, &ghost); + if (ret) + return ret; + + ret = reservation_object_copy_fences(ghost->resv, bo->resv); + /* Last resort, wait for the BO to be idle when we are OOM */ + if (ret) + ttm_bo_wait(bo, false, false); + + memset(&bo->mem, 0, sizeof(bo->mem)); + bo->mem.mem_type = TTM_PL_SYSTEM; + bo->ttm = NULL; + + ttm_bo_unreserve(ghost); + ttm_bo_unref(&ghost); + + return 0; +} diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 0ee3b8f11605..7e672be987b5 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -31,17 +31,11 @@ #define pr_fmt(fmt) "[TTM] " fmt #include <linux/sched.h> -#include <linux/highmem.h> #include <linux/pagemap.h> #include <linux/shmem_fs.h> #include <linux/file.h> -#include <linux/swap.h> -#include <linux/slab.h> -#include <linux/export.h> #include <drm/drm_cache.h> -#include <drm/ttm/ttm_module.h> #include <drm/ttm/ttm_bo_driver.h> -#include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_page_alloc.h> #ifdef CONFIG_X86 #include <asm/set_memory.h> @@ -79,14 +73,10 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) return -EINVAL; } - bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags); + bo->ttm = bdev->driver->ttm_tt_create(bo, page_flags); if (unlikely(bo->ttm == NULL)) return -ENOMEM; - if (bo->type == ttm_bo_type_sg) - bo->ttm->sg = bo->sg; - return 0; } @@ -114,6 +104,16 @@ static int ttm_dma_tt_alloc_page_directory(struct ttm_dma_tt *ttm) return 0; } +static int ttm_sg_tt_alloc_page_directory(struct ttm_dma_tt *ttm) +{ + ttm->dma_address = kvmalloc_array(ttm->ttm.num_pages, + sizeof(*ttm->dma_address), + GFP_KERNEL | __GFP_ZERO); + if (!ttm->dma_address) + return -ENOMEM; + return 0; +} + #ifdef CONFIG_X86 static inline int ttm_tt_set_page_caching(struct page *p, enum ttm_caching_state c_old, @@ -233,15 +233,22 @@ void ttm_tt_destroy(struct ttm_tt *ttm) ttm->func->destroy(ttm); } -int ttm_tt_init(struct ttm_tt *ttm, struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +void ttm_tt_init_fields(struct ttm_tt *ttm, struct ttm_buffer_object *bo, + uint32_t page_flags) { - ttm->bdev = bdev; - ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + ttm->bdev = bo->bdev; + ttm->num_pages = bo->num_pages; ttm->caching_state = tt_cached; ttm->page_flags = page_flags; ttm->state = tt_unpopulated; ttm->swap_storage = NULL; + ttm->sg = bo->sg; +} + +int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo, + uint32_t page_flags) +{ + ttm_tt_init_fields(ttm, bo, page_flags); if (ttm_tt_alloc_page_directory(ttm)) { ttm_tt_destroy(ttm); @@ -259,17 +266,12 @@ void ttm_tt_fini(struct ttm_tt *ttm) } EXPORT_SYMBOL(ttm_tt_fini); -int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_buffer_object *bo, + uint32_t page_flags) { struct ttm_tt *ttm = &ttm_dma->ttm; - ttm->bdev = bdev; - ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->caching_state = tt_cached; - ttm->page_flags = page_flags; - ttm->state = tt_unpopulated; - ttm->swap_storage = NULL; + ttm_tt_init_fields(ttm, bo, page_flags); INIT_LIST_HEAD(&ttm_dma->pages_list); if (ttm_dma_tt_alloc_page_directory(ttm_dma)) { @@ -281,11 +283,36 @@ int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev, } EXPORT_SYMBOL(ttm_dma_tt_init); +int ttm_sg_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_buffer_object *bo, + uint32_t page_flags) +{ + struct ttm_tt *ttm = &ttm_dma->ttm; + int ret; + + ttm_tt_init_fields(ttm, bo, page_flags); + + INIT_LIST_HEAD(&ttm_dma->pages_list); + if (page_flags & TTM_PAGE_FLAG_SG) + ret = ttm_sg_tt_alloc_page_directory(ttm_dma); + else + ret = ttm_dma_tt_alloc_page_directory(ttm_dma); + if (ret) { + ttm_tt_destroy(ttm); + pr_err("Failed allocating page table\n"); + return -ENOMEM; + } + return 0; +} +EXPORT_SYMBOL(ttm_sg_tt_init); + void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma) { struct ttm_tt *ttm = &ttm_dma->ttm; - kvfree(ttm->pages); + if (ttm->pages) + kvfree(ttm->pages); + else + kvfree(ttm_dma->dma_address); ttm->pages = NULL; ttm_dma->dma_address = NULL; } diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index ce1e3b9e14c9..bf4667481935 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -643,9 +643,12 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); struct drm_plane *plane; + struct vc4_plane_state *vc4_plane_state; bool debug_dump_regs = false; + bool enable_bg_fill = false; u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start; u32 __iomem *dlist_next = dlist_start; @@ -656,6 +659,20 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, /* Copy all the active planes' dlist contents to the hardware dlist. */ drm_atomic_crtc_for_each_plane(plane, crtc) { + /* Is this the first active plane? */ + if (dlist_next == dlist_start) { + /* We need to enable background fill when a plane + * could be alpha blending from the background, i.e. + * where no other plane is underneath. It suffices to + * consider the first active plane here since we set + * needs_bg_fill such that either the first plane + * already needs it or all planes on top blend from + * the first or a lower plane. + */ + vc4_plane_state = to_vc4_plane_state(plane->state); + enable_bg_fill = vc4_plane_state->needs_bg_fill; + } + dlist_next += vc4_plane_write_dlist(plane, dlist_next); } @@ -664,6 +681,14 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); + if (enable_bg_fill) + /* This sets a black background color fill, as is the case + * with other DRM drivers. + */ + HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), + HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) | + SCALER_DISPBKGND_FILL); + /* Only update DISPLIST if the CRTC was already running and is not * being disabled. * vc4_crtc_enable() takes care of updating the dlist just after diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index fefa1664a9f5..1b4cd1fabf56 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -310,6 +310,66 @@ to_vc4_plane(struct drm_plane *plane) return (struct vc4_plane *)plane; } +enum vc4_scaling_mode { + VC4_SCALING_NONE, + VC4_SCALING_TPZ, + VC4_SCALING_PPF, +}; + +struct vc4_plane_state { + struct drm_plane_state base; + /* System memory copy of the display list for this element, computed + * at atomic_check time. + */ + u32 *dlist; + u32 dlist_size; /* Number of dwords allocated for the display list */ + u32 dlist_count; /* Number of used dwords in the display list. */ + + /* Offset in the dlist to various words, for pageflip or + * cursor updates. + */ + u32 pos0_offset; + u32 pos2_offset; + u32 ptr0_offset; + + /* Offset where the plane's dlist was last stored in the + * hardware at vc4_crtc_atomic_flush() time. + */ + u32 __iomem *hw_dlist; + + /* Clipped coordinates of the plane on the display. */ + int crtc_x, crtc_y, crtc_w, crtc_h; + /* Clipped area being scanned from in the FB. */ + u32 src_x, src_y; + + u32 src_w[2], src_h[2]; + + /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */ + enum vc4_scaling_mode x_scaling[2], y_scaling[2]; + bool is_unity; + bool is_yuv; + + /* Offset to start scanning out from the start of the plane's + * BO. + */ + u32 offsets[3]; + + /* Our allocation in LBM for temporary storage during scaling. */ + struct drm_mm_node lbm; + + /* Set when the plane has per-pixel alpha content or does not cover + * the entire screen. This is a hint to the CRTC that it might need + * to enable background color fill. + */ + bool needs_bg_fill; +}; + +static inline struct vc4_plane_state * +to_vc4_plane_state(struct drm_plane_state *state) +{ + return (struct vc4_plane_state *)state; +} + enum vc4_encoder_type { VC4_ENCODER_TYPE_NONE, VC4_ENCODER_TYPE_HDMI, diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index c4c7af11fec5..ce39390be389 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -27,60 +27,6 @@ #include "vc4_drv.h" #include "vc4_regs.h" -enum vc4_scaling_mode { - VC4_SCALING_NONE, - VC4_SCALING_TPZ, - VC4_SCALING_PPF, -}; - -struct vc4_plane_state { - struct drm_plane_state base; - /* System memory copy of the display list for this element, computed - * at atomic_check time. - */ - u32 *dlist; - u32 dlist_size; /* Number of dwords allocated for the display list */ - u32 dlist_count; /* Number of used dwords in the display list. */ - - /* Offset in the dlist to various words, for pageflip or - * cursor updates. - */ - u32 pos0_offset; - u32 pos2_offset; - u32 ptr0_offset; - - /* Offset where the plane's dlist was last stored in the - * hardware at vc4_crtc_atomic_flush() time. - */ - u32 __iomem *hw_dlist; - - /* Clipped coordinates of the plane on the display. */ - int crtc_x, crtc_y, crtc_w, crtc_h; - /* Clipped area being scanned from in the FB. */ - u32 src_x, src_y; - - u32 src_w[2], src_h[2]; - - /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */ - enum vc4_scaling_mode x_scaling[2], y_scaling[2]; - bool is_unity; - bool is_yuv; - - /* Offset to start scanning out from the start of the plane's - * BO. - */ - u32 offsets[3]; - - /* Our allocation in LBM for temporary storage during scaling. */ - struct drm_mm_node lbm; -}; - -static inline struct vc4_plane_state * -to_vc4_plane_state(struct drm_plane_state *state) -{ - return (struct vc4_plane_state *)state; -} - static const struct hvs_format { u32 drm; /* DRM_FORMAT_* */ u32 hvs; /* HVS_FORMAT_* */ @@ -521,6 +467,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, u32 ctl0_offset = vc4_state->dlist_count; const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); int num_planes = drm_format_num_planes(format->drm); + bool covers_screen; u32 scl0, scl1, pitch0; u32 lbm_size, tiling; unsigned long irqflags; @@ -618,13 +565,14 @@ static int vc4_plane_mode_set(struct drm_plane *plane, SCALER_POS1_SCL_HEIGHT)); } - /* Position Word 2: Source Image Size, Alpha Mode */ + /* Position Word 2: Source Image Size, Alpha */ vc4_state->pos2_offset = vc4_state->dlist_count; vc4_dlist_write(vc4_state, VC4_SET_FIELD(fb->format->has_alpha ? SCALER_POS2_ALPHA_MODE_PIPELINE : SCALER_POS2_ALPHA_MODE_FIXED, SCALER_POS2_ALPHA_MODE) | + (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) | VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); @@ -700,6 +648,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_state->dlist[ctl0_offset] |= VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); + /* crtc_* are already clipped coordinates. */ + covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 && + vc4_state->crtc_w == state->crtc->mode.hdisplay && + vc4_state->crtc_h == state->crtc->mode.vdisplay; + /* Background fill might be necessary when the plane has per-pixel + * alpha content and blends from the background or does not cover + * the entire screen. + */ + vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen; + return 0; } diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index b9749cb24063..a141496104a6 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -848,6 +848,7 @@ enum hvs_pixel_format { #define SCALER_POS2_ALPHA_MODE_FIXED 1 #define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO 2 #define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3 +#define SCALER_POS2_ALPHA_PREMULT BIT(29) #define SCALER_POS2_HEIGHT_MASK VC4_MASK(27, 16) #define SCALER_POS2_HEIGHT_SHIFT 16 diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 2db485abb186..eec76af49f04 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c @@ -753,7 +753,7 @@ validate_gl_shader_rec(struct drm_device *dev, 28, /* cs */ }; uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets); - struct drm_gem_cma_object *bo[shader_reloc_count + 8]; + struct drm_gem_cma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8]; uint32_t nr_attributes, nr_relocs, packet_size; int i; diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index fd5d9450878e..11f8ae5b5332 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -322,20 +322,19 @@ static struct ttm_backend_func virtio_gpu_backend_func = { .destroy = &virtio_gpu_ttm_backend_destroy, }; -static struct ttm_tt *virtio_gpu_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, +static struct ttm_tt *virtio_gpu_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags) { struct virtio_gpu_device *vgdev; struct virtio_gpu_ttm_tt *gtt; - vgdev = virtio_gpu_get_vgdev(bdev); + vgdev = virtio_gpu_get_vgdev(bo->bdev); gtt = kzalloc(sizeof(struct virtio_gpu_ttm_tt), GFP_KERNEL); if (gtt == NULL) return NULL; gtt->ttm.ttm.func = &virtio_gpu_backend_func; gtt->vgdev = vgdev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { + if (ttm_dma_tt_init(>t->ttm, bo, page_flags)) { kfree(gtt); return NULL; } diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index ad80211e1098..794cc9d5c9b0 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -7,6 +7,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ - vmwgfx_simple_resource.o vmwgfx_va.o + vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h index 6e0ccb70a700..88e72bf9a534 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h @@ -372,6 +372,14 @@ SVGAGuestPtr; * PA, not biased by the offset. When the command buffer is finished * the guest should not read the offset field as there is no guarantee * what it will set to. + * + * When the SVGA_CAP_HP_CMD_QUEUE cap bit is set a new command queue + * SVGA_CB_CONTEXT_1 is available. Commands submitted to this queue + * will be executed as quickly as possible by the SVGA device + * potentially before already queued commands on SVGA_CB_CONTEXT_0. + * The SVGA device guarantees that any command buffers submitted to + * SVGA_CB_CONTEXT_0 will be executed after any _already_ submitted + * command buffers to SVGA_CB_CONTEXT_1. */ #define SVGA_CB_MAX_SIZE (512 * 1024) /* 512 KB */ @@ -382,7 +390,8 @@ SVGAGuestPtr; typedef enum { SVGA_CB_CONTEXT_DEVICE = 0x3f, SVGA_CB_CONTEXT_0 = 0x0, - SVGA_CB_CONTEXT_MAX = 0x1, + SVGA_CB_CONTEXT_1 = 0x1, /* Supported with SVGA_CAP_HP_CMD_QUEUE */ + SVGA_CB_CONTEXT_MAX = 0x2, } SVGACBContext; @@ -689,6 +698,7 @@ SVGASignedPoint; #define SVGA_CAP_CMD_BUFFERS_2 0x04000000 #define SVGA_CAP_GBOBJECTS 0x08000000 #define SVGA_CAP_DX 0x10000000 +#define SVGA_CAP_HP_CMD_QUEUE 0x20000000 #define SVGA_CAP_CMD_RESERVED 0x80000000 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c new file mode 100644 index 000000000000..e8c94b19db7b --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c @@ -0,0 +1,506 @@ +/************************************************************************** + * + * Copyright © 2017 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "vmwgfx_drv.h" + +/* + * Template that implements find_first_diff() for a generic + * unsigned integer type. @size and return value are in bytes. + */ +#define VMW_FIND_FIRST_DIFF(_type) \ +static size_t vmw_find_first_diff_ ## _type \ + (const _type * dst, const _type * src, size_t size)\ +{ \ + size_t i; \ + \ + for (i = 0; i < size; i += sizeof(_type)) { \ + if (*dst++ != *src++) \ + break; \ + } \ + \ + return i; \ +} + + +/* + * Template that implements find_last_diff() for a generic + * unsigned integer type. Pointers point to the item following the + * *end* of the area to be examined. @size and return value are in + * bytes. + */ +#define VMW_FIND_LAST_DIFF(_type) \ +static ssize_t vmw_find_last_diff_ ## _type( \ + const _type * dst, const _type * src, size_t size) \ +{ \ + while (size) { \ + if (*--dst != *--src) \ + break; \ + \ + size -= sizeof(_type); \ + } \ + return size; \ +} + + +/* + * Instantiate find diff functions for relevant unsigned integer sizes, + * assuming that wider integers are faster (including aligning) up to the + * architecture native width, which is assumed to be 32 bit unless + * CONFIG_64BIT is defined. + */ +VMW_FIND_FIRST_DIFF(u8); +VMW_FIND_LAST_DIFF(u8); + +VMW_FIND_FIRST_DIFF(u16); +VMW_FIND_LAST_DIFF(u16); + +VMW_FIND_FIRST_DIFF(u32); +VMW_FIND_LAST_DIFF(u32); + +#ifdef CONFIG_64BIT +VMW_FIND_FIRST_DIFF(u64); +VMW_FIND_LAST_DIFF(u64); +#endif + + +/* We use size aligned copies. This computes (addr - align(addr)) */ +#define SPILL(_var, _type) ((unsigned long) _var & (sizeof(_type) - 1)) + + +/* + * Template to compute find_first_diff() for a certain integer type + * including a head copy for alignment, and adjustment of parameters + * for tail find or increased resolution find using an unsigned integer find + * of smaller width. If finding is complete, and resolution is sufficient, + * the macro executes a return statement. Otherwise it falls through. + */ +#define VMW_TRY_FIND_FIRST_DIFF(_type) \ +do { \ + unsigned int spill = SPILL(dst, _type); \ + size_t diff_offs; \ + \ + if (spill && spill == SPILL(src, _type) && \ + sizeof(_type) - spill <= size) { \ + spill = sizeof(_type) - spill; \ + diff_offs = vmw_find_first_diff_u8(dst, src, spill); \ + if (diff_offs < spill) \ + return round_down(offset + diff_offs, granularity); \ + \ + dst += spill; \ + src += spill; \ + size -= spill; \ + offset += spill; \ + spill = 0; \ + } \ + if (!spill && !SPILL(src, _type)) { \ + size_t to_copy = size & ~(sizeof(_type) - 1); \ + \ + diff_offs = vmw_find_first_diff_ ## _type \ + ((_type *) dst, (_type *) src, to_copy); \ + if (diff_offs >= size || granularity == sizeof(_type)) \ + return (offset + diff_offs); \ + \ + dst += diff_offs; \ + src += diff_offs; \ + size -= diff_offs; \ + offset += diff_offs; \ + } \ +} while (0) \ + + +/** + * vmw_find_first_diff - find the first difference between dst and src + * + * @dst: The destination address + * @src: The source address + * @size: Number of bytes to compare + * @granularity: The granularity needed for the return value in bytes. + * return: The offset from find start where the first difference was + * encountered in bytes. If no difference was found, the function returns + * a value >= @size. + */ +static size_t vmw_find_first_diff(const u8 *dst, const u8 *src, size_t size, + size_t granularity) +{ + size_t offset = 0; + + /* + * Try finding with large integers if alignment allows, or we can + * fix it. Fall through if we need better resolution or alignment + * was bad. + */ +#ifdef CONFIG_64BIT + VMW_TRY_FIND_FIRST_DIFF(u64); +#endif + VMW_TRY_FIND_FIRST_DIFF(u32); + VMW_TRY_FIND_FIRST_DIFF(u16); + + return round_down(offset + vmw_find_first_diff_u8(dst, src, size), + granularity); +} + + +/* + * Template to compute find_last_diff() for a certain integer type + * including a tail copy for alignment, and adjustment of parameters + * for head find or increased resolution find using an unsigned integer find + * of smaller width. If finding is complete, and resolution is sufficient, + * the macro executes a return statement. Otherwise it falls through. + */ +#define VMW_TRY_FIND_LAST_DIFF(_type) \ +do { \ + unsigned int spill = SPILL(dst, _type); \ + ssize_t location; \ + ssize_t diff_offs; \ + \ + if (spill && spill <= size && spill == SPILL(src, _type)) { \ + diff_offs = vmw_find_last_diff_u8(dst, src, spill); \ + if (diff_offs) { \ + location = size - spill + diff_offs - 1; \ + return round_down(location, granularity); \ + } \ + \ + dst -= spill; \ + src -= spill; \ + size -= spill; \ + spill = 0; \ + } \ + if (!spill && !SPILL(src, _type)) { \ + size_t to_copy = round_down(size, sizeof(_type)); \ + \ + diff_offs = vmw_find_last_diff_ ## _type \ + ((_type *) dst, (_type *) src, to_copy); \ + location = size - to_copy + diff_offs - sizeof(_type); \ + if (location < 0 || granularity == sizeof(_type)) \ + return location; \ + \ + dst -= to_copy - diff_offs; \ + src -= to_copy - diff_offs; \ + size -= to_copy - diff_offs; \ + } \ +} while (0) + + +/** + * vmw_find_last_diff - find the last difference between dst and src + * + * @dst: The destination address + * @src: The source address + * @size: Number of bytes to compare + * @granularity: The granularity needed for the return value in bytes. + * return: The offset from find start where the last difference was + * encountered in bytes, or a negative value if no difference was found. + */ +static ssize_t vmw_find_last_diff(const u8 *dst, const u8 *src, size_t size, + size_t granularity) +{ + dst += size; + src += size; + +#ifdef CONFIG_64BIT + VMW_TRY_FIND_LAST_DIFF(u64); +#endif + VMW_TRY_FIND_LAST_DIFF(u32); + VMW_TRY_FIND_LAST_DIFF(u16); + + return round_down(vmw_find_last_diff_u8(dst, src, size) - 1, + granularity); +} + + +/** + * vmw_memcpy - A wrapper around kernel memcpy with allowing to plug it into a + * struct vmw_diff_cpy. + * + * @diff: The struct vmw_diff_cpy closure argument (unused). + * @dest: The copy destination. + * @src: The copy source. + * @n: Number of bytes to copy. + */ +void vmw_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, size_t n) +{ + memcpy(dest, src, n); +} + + +/** + * vmw_adjust_rect - Adjust rectangle coordinates for newly found difference + * + * @diff: The struct vmw_diff_cpy used to track the modified bounding box. + * @diff_offs: The offset from @diff->line_offset where the difference was + * found. + */ +static void vmw_adjust_rect(struct vmw_diff_cpy *diff, size_t diff_offs) +{ + size_t offs = (diff_offs + diff->line_offset) / diff->cpp; + struct drm_rect *rect = &diff->rect; + + rect->x1 = min_t(int, rect->x1, offs); + rect->x2 = max_t(int, rect->x2, offs + 1); + rect->y1 = min_t(int, rect->y1, diff->line); + rect->y2 = max_t(int, rect->y2, diff->line + 1); +} + +/** + * vmw_diff_memcpy - memcpy that creates a bounding box of modified content. + * + * @diff: The struct vmw_diff_cpy used to track the modified bounding box. + * @dest: The copy destination. + * @src: The copy source. + * @n: Number of bytes to copy. + * + * In order to correctly track the modified content, the field @diff->line must + * be pre-loaded with the current line number, the field @diff->line_offset must + * be pre-loaded with the line offset in bytes where the copy starts, and + * finally the field @diff->cpp need to be preloaded with the number of bytes + * per unit in the horizontal direction of the area we're examining. + * Typically bytes per pixel. + * This is needed to know the needed granularity of the difference computing + * operations. A higher cpp generally leads to faster execution at the cost of + * bounding box width precision. + */ +void vmw_diff_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, + size_t n) +{ + ssize_t csize, byte_len; + + if (WARN_ON_ONCE(round_down(n, diff->cpp) != n)) + return; + + /* TODO: Possibly use a single vmw_find_first_diff per line? */ + csize = vmw_find_first_diff(dest, src, n, diff->cpp); + if (csize < n) { + vmw_adjust_rect(diff, csize); + byte_len = diff->cpp; + + /* + * Starting from where first difference was found, find + * location of last difference, and then copy. + */ + diff->line_offset += csize; + dest += csize; + src += csize; + n -= csize; + csize = vmw_find_last_diff(dest, src, n, diff->cpp); + if (csize >= 0) { + byte_len += csize; + vmw_adjust_rect(diff, csize); + } + memcpy(dest, src, byte_len); + } + diff->line_offset += n; +} + +/** + * struct vmw_bo_blit_line_data - Convenience argument to vmw_bo_cpu_blit_line + * + * @mapped_dst: Already mapped destination page index in @dst_pages. + * @dst_addr: Kernel virtual address of mapped destination page. + * @dst_pages: Array of destination bo pages. + * @dst_num_pages: Number of destination bo pages. + * @dst_prot: Destination bo page protection. + * @mapped_src: Already mapped source page index in @dst_pages. + * @src_addr: Kernel virtual address of mapped source page. + * @src_pages: Array of source bo pages. + * @src_num_pages: Number of source bo pages. + * @src_prot: Source bo page protection. + * @diff: Struct vmw_diff_cpy, in the end forwarded to the memcpy routine. + */ +struct vmw_bo_blit_line_data { + u32 mapped_dst; + u8 *dst_addr; + struct page **dst_pages; + u32 dst_num_pages; + pgprot_t dst_prot; + u32 mapped_src; + u8 *src_addr; + struct page **src_pages; + u32 src_num_pages; + pgprot_t src_prot; + struct vmw_diff_cpy *diff; +}; + +/** + * vmw_bo_cpu_blit_line - Blit part of a line from one bo to another. + * + * @d: Blit data as described above. + * @dst_offset: Destination copy start offset from start of bo. + * @src_offset: Source copy start offset from start of bo. + * @bytes_to_copy: Number of bytes to copy in this line. + */ +static int vmw_bo_cpu_blit_line(struct vmw_bo_blit_line_data *d, + u32 dst_offset, + u32 src_offset, + u32 bytes_to_copy) +{ + struct vmw_diff_cpy *diff = d->diff; + + while (bytes_to_copy) { + u32 copy_size = bytes_to_copy; + u32 dst_page = dst_offset >> PAGE_SHIFT; + u32 src_page = src_offset >> PAGE_SHIFT; + u32 dst_page_offset = dst_offset & ~PAGE_MASK; + u32 src_page_offset = src_offset & ~PAGE_MASK; + bool unmap_dst = d->dst_addr && dst_page != d->mapped_dst; + bool unmap_src = d->src_addr && (src_page != d->mapped_src || + unmap_dst); + + copy_size = min_t(u32, copy_size, PAGE_SIZE - dst_page_offset); + copy_size = min_t(u32, copy_size, PAGE_SIZE - src_page_offset); + + if (unmap_src) { + ttm_kunmap_atomic_prot(d->src_addr, d->src_prot); + d->src_addr = NULL; + } + + if (unmap_dst) { + ttm_kunmap_atomic_prot(d->dst_addr, d->dst_prot); + d->dst_addr = NULL; + } + + if (!d->dst_addr) { + if (WARN_ON_ONCE(dst_page >= d->dst_num_pages)) + return -EINVAL; + + d->dst_addr = + ttm_kmap_atomic_prot(d->dst_pages[dst_page], + d->dst_prot); + if (!d->dst_addr) + return -ENOMEM; + + d->mapped_dst = dst_page; + } + + if (!d->src_addr) { + if (WARN_ON_ONCE(src_page >= d->src_num_pages)) + return -EINVAL; + + d->src_addr = + ttm_kmap_atomic_prot(d->src_pages[src_page], + d->src_prot); + if (!d->src_addr) + return -ENOMEM; + + d->mapped_src = src_page; + } + diff->do_cpy(diff, d->dst_addr + dst_page_offset, + d->src_addr + src_page_offset, copy_size); + + bytes_to_copy -= copy_size; + dst_offset += copy_size; + src_offset += copy_size; + } + + return 0; +} + +/** + * ttm_bo_cpu_blit - in-kernel cpu blit. + * + * @dst: Destination buffer object. + * @dst_offset: Destination offset of blit start in bytes. + * @dst_stride: Destination stride in bytes. + * @src: Source buffer object. + * @src_offset: Source offset of blit start in bytes. + * @src_stride: Source stride in bytes. + * @w: Width of blit. + * @h: Height of blit. + * return: Zero on success. Negative error value on failure. Will print out + * kernel warnings on caller bugs. + * + * Performs a CPU blit from one buffer object to another avoiding a full + * bo vmap which may exhaust- or fragment vmalloc space. + * On supported architectures (x86), we're using kmap_atomic which avoids + * cross-processor TLB- and cache flushes and may, on non-HIGHMEM systems + * reference already set-up mappings. + * + * Neither of the buffer objects may be placed in PCI memory + * (Fixed memory in TTM terminology) when using this function. + */ +int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, + u32 dst_offset, u32 dst_stride, + struct ttm_buffer_object *src, + u32 src_offset, u32 src_stride, + u32 w, u32 h, + struct vmw_diff_cpy *diff) +{ + struct ttm_operation_ctx ctx = { + .interruptible = false, + .no_wait_gpu = false + }; + u32 j, initial_line = dst_offset / dst_stride; + struct vmw_bo_blit_line_data d; + int ret = 0; + + /* Buffer objects need to be either pinned or reserved: */ + if (!(dst->mem.placement & TTM_PL_FLAG_NO_EVICT)) + lockdep_assert_held(&dst->resv->lock.base); + if (!(src->mem.placement & TTM_PL_FLAG_NO_EVICT)) + lockdep_assert_held(&src->resv->lock.base); + + if (dst->ttm->state == tt_unpopulated) { + ret = dst->ttm->bdev->driver->ttm_tt_populate(dst->ttm, &ctx); + if (ret) + return ret; + } + + if (src->ttm->state == tt_unpopulated) { + ret = src->ttm->bdev->driver->ttm_tt_populate(src->ttm, &ctx); + if (ret) + return ret; + } + + d.mapped_dst = 0; + d.mapped_src = 0; + d.dst_addr = NULL; + d.src_addr = NULL; + d.dst_pages = dst->ttm->pages; + d.src_pages = src->ttm->pages; + d.dst_num_pages = dst->num_pages; + d.src_num_pages = src->num_pages; + d.dst_prot = ttm_io_prot(dst->mem.placement, PAGE_KERNEL); + d.src_prot = ttm_io_prot(src->mem.placement, PAGE_KERNEL); + d.diff = diff; + + for (j = 0; j < h; ++j) { + diff->line = j + initial_line; + diff->line_offset = dst_offset % dst_stride; + ret = vmw_bo_cpu_blit_line(&d, dst_offset, src_offset, w); + if (ret) + goto out; + + dst_offset += dst_stride; + src_offset += src_stride; + } +out: + if (d.src_addr) + ttm_kunmap_atomic_prot(d.src_addr, d.src_prot); + if (d.dst_addr) + ttm_kunmap_atomic_prot(d.dst_addr, d.dst_prot); + + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index fead3f2dbb46..21111fd091f9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -185,6 +185,22 @@ static const struct ttm_place evictable_placement_flags[] = { } }; +static const struct ttm_place nonfixed_placement_flags[] = { + { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED + }, { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED + }, { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED + } +}; + struct ttm_placement vmw_evictable_placement = { .num_placement = 4, .placement = evictable_placement_flags, @@ -213,6 +229,13 @@ struct ttm_placement vmw_mob_ne_placement = { .busy_placement = &mob_ne_placement_flags }; +struct ttm_placement vmw_nonfixed_placement = { + .num_placement = 3, + .placement = nonfixed_placement_flags, + .num_busy_placement = 1, + .busy_placement = &sys_placement_flags +}; + struct vmw_ttm_tt { struct ttm_dma_tt dma_ttm; struct vmw_private *dev_priv; @@ -693,8 +716,8 @@ static struct ttm_backend_func vmw_ttm_func = { .destroy = vmw_ttm_destroy, }; -static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags) +static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo, + uint32_t page_flags) { struct vmw_ttm_tt *vmw_be; int ret; @@ -704,13 +727,13 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, return NULL; vmw_be->dma_ttm.ttm.func = &vmw_ttm_func; - vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev); + vmw_be->dev_priv = container_of(bo->bdev, struct vmw_private, bdev); vmw_be->mob = NULL; if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent) - ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags); + ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bo, page_flags); else - ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bdev, size, page_flags); + ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bo, page_flags); if (unlikely(ret != 0)) goto out_no_init; @@ -841,6 +864,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, */ static void vmw_swap_notify(struct ttm_buffer_object *bo) { + vmw_resource_swap_notify(bo); (void) ttm_bo_wait(bo, false, false); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index f283324ce598..9f45d5004cae 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -101,6 +101,7 @@ struct vmw_cmdbuf_context { * @handle: DMA address handle for the command buffer space if @using_mob is * false. Immutable. * @size: The size of the command buffer space. Immutable. + * @num_contexts: Number of contexts actually enabled. */ struct vmw_cmdbuf_man { struct mutex cur_mutex; @@ -128,6 +129,7 @@ struct vmw_cmdbuf_man { bool has_pool; dma_addr_t handle; size_t size; + u32 num_contexts; }; /** @@ -185,7 +187,7 @@ struct vmw_cmdbuf_alloc_info { /* Loop over each context in the command buffer manager. */ #define for_each_cmdbuf_ctx(_man, _i, _ctx) \ - for (_i = 0, _ctx = &(_man)->ctx[0]; (_i) < SVGA_CB_CONTEXT_MAX; \ + for (_i = 0, _ctx = &(_man)->ctx[0]; (_i) < (_man)->num_contexts; \ ++(_i), ++(_ctx)) static int vmw_cmdbuf_startstop(struct vmw_cmdbuf_man *man, u32 context, @@ -514,6 +516,7 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) struct list_head restart_head[SVGA_CB_CONTEXT_MAX]; int i; struct vmw_cmdbuf_context *ctx; + bool global_block = false; for_each_cmdbuf_ctx(man, i, ctx) { INIT_LIST_HEAD(&restart_head[i]); @@ -531,6 +534,7 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) list_del_init(&entry->list); restart[entry->cb_context] = true; + global_block = true; if (!vmw_cmd_describe(header, &error_cmd_size, &cmd_name)) { DRM_ERROR("Unknown command causing device error.\n"); @@ -564,23 +568,21 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) cb_hdr->length -= new_start_offset; cb_hdr->errorOffset = 0; cb_hdr->offset = 0; + list_add_tail(&entry->list, &restart_head[entry->cb_context]); - man->ctx[entry->cb_context].block_submission = true; } + + for_each_cmdbuf_ctx(man, i, ctx) + man->ctx[i].block_submission = true; + spin_unlock(&man->lock); - /* Preempt all contexts with errors */ - for_each_cmdbuf_ctx(man, i, ctx) { - if (ctx->block_submission && vmw_cmdbuf_preempt(man, i)) - DRM_ERROR("Failed preempting command buffer " - "context %u.\n", i); - } + /* Preempt all contexts */ + if (global_block && vmw_cmdbuf_preempt(man, 0)) + DRM_ERROR("Failed preempting command buffer contexts\n"); spin_lock(&man->lock); for_each_cmdbuf_ctx(man, i, ctx) { - if (!ctx->block_submission) - continue; - /* Move preempted command buffers to the preempted queue. */ vmw_cmdbuf_ctx_process(man, ctx, &dummy); @@ -594,19 +596,16 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) * Finally add all command buffers first in the submitted * queue, to rerun them. */ - list_splice_init(&restart_head[i], &ctx->submitted); ctx->block_submission = false; + list_splice_init(&restart_head[i], &ctx->submitted); } vmw_cmdbuf_man_process(man); spin_unlock(&man->lock); - for_each_cmdbuf_ctx(man, i, ctx) { - if (restart[i] && vmw_cmdbuf_startstop(man, i, true)) - DRM_ERROR("Failed restarting command buffer " - "context %u.\n", i); - } + if (global_block && vmw_cmdbuf_startstop(man, 0, true)) + DRM_ERROR("Failed restarting command buffer contexts\n"); /* Send a new fence in case one was removed */ if (send_fence) { @@ -1307,6 +1306,8 @@ struct vmw_cmdbuf_man *vmw_cmdbuf_man_create(struct vmw_private *dev_priv) if (!man) return ERR_PTR(-ENOMEM); + man->num_contexts = (dev_priv->capabilities & SVGA_CAP_HP_CMD_QUEUE) ? + 2 : 1; man->headers = dma_pool_create("vmwgfx cmdbuf", &dev_priv->dev->pdev->dev, sizeof(SVGACBHeader), @@ -1341,14 +1342,11 @@ struct vmw_cmdbuf_man *vmw_cmdbuf_man_create(struct vmw_private *dev_priv) INIT_WORK(&man->work, &vmw_cmdbuf_work_func); vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ERROR, &dev_priv->error_waiters); - for_each_cmdbuf_ctx(man, i, ctx) { - ret = vmw_cmdbuf_startstop(man, i, true); - if (ret) { - DRM_ERROR("Failed starting command buffer " - "context %u.\n", i); - vmw_cmdbuf_man_destroy(man); - return ERR_PTR(ret); - } + ret = vmw_cmdbuf_startstop(man, 0, true); + if (ret) { + DRM_ERROR("Failed starting command buffer contexts\n"); + vmw_cmdbuf_man_destroy(man); + return ERR_PTR(ret); } return man; @@ -1398,16 +1396,11 @@ void vmw_cmdbuf_remove_pool(struct vmw_cmdbuf_man *man) */ void vmw_cmdbuf_man_destroy(struct vmw_cmdbuf_man *man) { - struct vmw_cmdbuf_context *ctx; - unsigned int i; - WARN_ON_ONCE(man->has_pool); (void) vmw_cmdbuf_idle(man, false, 10*HZ); - for_each_cmdbuf_ctx(man, i, ctx) - if (vmw_cmdbuf_startstop(man, i, false)) - DRM_ERROR("Failed stopping command buffer " - "context %u.\n", i); + if (vmw_cmdbuf_startstop(man, 0, false)) + DRM_ERROR("Failed stopping command buffer contexts.\n"); vmw_generic_waiter_remove(man->dev_priv, SVGA_IRQFLAG_ERROR, &man->dev_priv->error_waiters); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index d45d2caffa5a..d59d9dd16ebc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -323,3 +323,54 @@ void vmw_bo_pin_reserved(struct vmw_dma_buffer *vbo, bool pin) BUG_ON(ret != 0 || bo->mem.mem_type != old_mem_type); } + + +/* + * vmw_dma_buffer_unmap - Tear down a cached buffer object map. + * + * @vbo: The buffer object whose map we are tearing down. + * + * This function tears down a cached map set up using + * vmw_dma_buffer_map_and_cache(). + */ +void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo) +{ + if (vbo->map.bo == NULL) + return; + + ttm_bo_kunmap(&vbo->map); +} + + +/* + * vmw_dma_buffer_map_and_cache - Map a buffer object and cache the map + * + * @vbo: The buffer object to map + * Return: A kernel virtual address or NULL if mapping failed. + * + * This function maps a buffer object into the kernel address space, or + * returns the virtual kernel address of an already existing map. The virtual + * address remains valid as long as the buffer object is pinned or reserved. + * The cached map is torn down on either + * 1) Buffer object move + * 2) Buffer object swapout + * 3) Buffer object destruction + * + */ +void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo) +{ + struct ttm_buffer_object *bo = &vbo->base; + bool not_used; + void *virtual; + int ret; + + virtual = ttm_kmap_obj_virtual(&vbo->map, ¬_used); + if (virtual) + return virtual; + + ret = ttm_bo_kmap(bo, 0, bo->num_pages, &vbo->map); + if (ret) + DRM_ERROR("Buffer object map failed: %d.\n", ret); + + return ttm_kmap_obj_virtual(&vbo->map, ¬_used); +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 184340d486c3..61a03ac90f8c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -301,6 +301,8 @@ static void vmw_print_capabilities(uint32_t capabilities) DRM_INFO(" Guest Backed Resources.\n"); if (capabilities & SVGA_CAP_DX) DRM_INFO(" DX Features.\n"); + if (capabilities & SVGA_CAP_HP_CMD_QUEUE) + DRM_INFO(" HP Command Queue.\n"); } /** @@ -1277,8 +1279,7 @@ static void vmw_master_drop(struct drm_device *dev, ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); ttm_vt_unlock(&dev_priv->fbdev_master.lock); - if (dev_priv->enable_fb) - vmw_fb_on(dev_priv); + vmw_fb_refresh(dev_priv); } /** @@ -1368,28 +1369,23 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, switch (val) { case PM_HIBERNATION_PREPARE: - if (dev_priv->enable_fb) - vmw_fb_off(dev_priv); - ttm_suspend_lock(&dev_priv->reservation_sem); - /* - * This empties VRAM and unbinds all GMR bindings. - * Buffer contents is moved to swappable memory. + * Take the reservation sem in write mode, which will make sure + * there are no other processes holding a buffer object + * reservation, meaning we should be able to evict all buffer + * objects if needed. + * Once user-space processes have been frozen, we can release + * the lock again. */ - vmw_execbuf_release_pinned_bo(dev_priv); - vmw_resource_evict_all(dev_priv); - vmw_release_device_early(dev_priv); - ttm_bo_swapout_all(&dev_priv->bdev); - vmw_fence_fifo_down(dev_priv->fman); + ttm_suspend_lock(&dev_priv->reservation_sem); + dev_priv->suspend_locked = true; break; case PM_POST_HIBERNATION: case PM_POST_RESTORE: - vmw_fence_fifo_up(dev_priv->fman); - ttm_suspend_unlock(&dev_priv->reservation_sem); - if (dev_priv->enable_fb) - vmw_fb_on(dev_priv); - break; - case PM_RESTORE_PREPARE: + if (READ_ONCE(dev_priv->suspend_locked)) { + dev_priv->suspend_locked = false; + ttm_suspend_unlock(&dev_priv->reservation_sem); + } break; default: break; @@ -1440,25 +1436,48 @@ static int vmw_pm_freeze(struct device *kdev) struct pci_dev *pdev = to_pci_dev(kdev); struct drm_device *dev = pci_get_drvdata(pdev); struct vmw_private *dev_priv = vmw_priv(dev); + int ret; - dev_priv->suspended = true; + /* + * Unlock for vmw_kms_suspend. + * No user-space processes should be running now. + */ + ttm_suspend_unlock(&dev_priv->reservation_sem); + ret = vmw_kms_suspend(dev_priv->dev); + if (ret) { + ttm_suspend_lock(&dev_priv->reservation_sem); + DRM_ERROR("Failed to freeze modesetting.\n"); + return ret; + } if (dev_priv->enable_fb) - vmw_fifo_resource_dec(dev_priv); + vmw_fb_off(dev_priv); + ttm_suspend_lock(&dev_priv->reservation_sem); + vmw_execbuf_release_pinned_bo(dev_priv); + vmw_resource_evict_all(dev_priv); + vmw_release_device_early(dev_priv); + ttm_bo_swapout_all(&dev_priv->bdev); + if (dev_priv->enable_fb) + vmw_fifo_resource_dec(dev_priv); if (atomic_read(&dev_priv->num_fifo_resources) != 0) { DRM_ERROR("Can't hibernate while 3D resources are active.\n"); if (dev_priv->enable_fb) vmw_fifo_resource_inc(dev_priv); WARN_ON(vmw_request_device_late(dev_priv)); - dev_priv->suspended = false; + dev_priv->suspend_locked = false; + ttm_suspend_unlock(&dev_priv->reservation_sem); + if (dev_priv->suspend_state) + vmw_kms_resume(dev); + if (dev_priv->enable_fb) + vmw_fb_on(dev_priv); + vmw_fb_refresh(dev_priv); return -EBUSY; } - if (dev_priv->enable_fb) - __vmw_svga_disable(dev_priv); + vmw_fence_fifo_down(dev_priv->fman); + __vmw_svga_disable(dev_priv); vmw_release_device_late(dev_priv); - return 0; } @@ -1482,7 +1501,16 @@ static int vmw_pm_restore(struct device *kdev) if (dev_priv->enable_fb) __vmw_svga_enable(dev_priv); - dev_priv->suspended = false; + vmw_fence_fifo_up(dev_priv->fman); + dev_priv->suspend_locked = false; + ttm_suspend_unlock(&dev_priv->reservation_sem); + if (dev_priv->suspend_state) + vmw_kms_resume(dev_priv->dev); + + if (dev_priv->enable_fb) + vmw_fb_on(dev_priv); + + vmw_fb_refresh(dev_priv); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d08753e8fd94..9e60de95b863 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -43,10 +43,10 @@ #include <linux/sync_file.h> #define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_DRIVER_DATE "20170612" +#define VMWGFX_DRIVER_DATE "20180322" #define VMWGFX_DRIVER_MAJOR 2 #define VMWGFX_DRIVER_MINOR 14 -#define VMWGFX_DRIVER_PATCHLEVEL 0 +#define VMWGFX_DRIVER_PATCHLEVEL 1 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 @@ -92,6 +92,8 @@ struct vmw_dma_buffer { s32 pin_count; /* Not ref-counted. Protected by binding_mutex */ struct vmw_resource *dx_query_ctx; + /* Protected by reservation */ + struct ttm_bo_kmap_obj map; }; /** @@ -423,6 +425,7 @@ struct vmw_private { struct vmw_framebuffer *implicit_fb; struct mutex global_kms_state_mutex; spinlock_t cursor_lock; + struct drm_atomic_state *suspend_state; /* * Context and surface management. @@ -494,8 +497,8 @@ struct vmw_private { struct vmw_master *active_master; struct vmw_master fbdev_master; struct notifier_block pm_nb; - bool suspended; bool refuse_hibernation; + bool suspend_locked; struct mutex release_mutex; atomic_t num_fifo_resources; @@ -673,11 +676,13 @@ extern void vmw_resource_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); extern void vmw_query_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); +extern void vmw_resource_swap_notify(struct ttm_buffer_object *bo); extern int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob); extern void vmw_fence_single_bo(struct ttm_buffer_object *bo, struct vmw_fence_obj *fence); extern void vmw_resource_evict_all(struct vmw_private *dev_priv); + /** * DMA buffer helper routines - vmwgfx_dmabuf.c */ @@ -700,6 +705,8 @@ extern int vmw_dmabuf_unpin(struct vmw_private *vmw_priv, extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf, SVGAGuestPtr *ptr); extern void vmw_bo_pin_reserved(struct vmw_dma_buffer *bo, bool pin); +extern void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo); +extern void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo); /** * Misc Ioctl functionality - vmwgfx_ioctl.c @@ -766,6 +773,7 @@ extern struct ttm_placement vmw_evictable_placement; extern struct ttm_placement vmw_srf_placement; extern struct ttm_placement vmw_mob_placement; extern struct ttm_placement vmw_mob_ne_placement; +extern struct ttm_placement vmw_nonfixed_placement; extern struct ttm_bo_driver vmw_bo_driver; extern int vmw_dma_quiescent(struct drm_device *dev); extern int vmw_bo_map_dma(struct ttm_buffer_object *bo); @@ -902,6 +910,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv); int vmw_fb_close(struct vmw_private *dev_priv); int vmw_fb_off(struct vmw_private *vmw_priv); int vmw_fb_on(struct vmw_private *vmw_priv); +void vmw_fb_refresh(struct vmw_private *vmw_priv); /** * Kernel modesetting - vmwgfx_kms.c @@ -938,6 +947,8 @@ int vmw_kms_present(struct vmw_private *dev_priv, int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv); +int vmw_kms_suspend(struct drm_device *dev); +int vmw_kms_resume(struct drm_device *dev); int vmw_dumb_create(struct drm_file *file_priv, struct drm_device *dev, @@ -1165,6 +1176,53 @@ extern int vmw_cmdbuf_cur_flush(struct vmw_cmdbuf_man *man, bool interruptible); extern void vmw_cmdbuf_irqthread(struct vmw_cmdbuf_man *man); +/* CPU blit utilities - vmwgfx_blit.c */ + +/** + * struct vmw_diff_cpy - CPU blit information structure + * + * @rect: The output bounding box rectangle. + * @line: The current line of the blit. + * @line_offset: Offset of the current line segment. + * @cpp: Bytes per pixel (granularity information). + * @memcpy: Which memcpy function to use. + */ +struct vmw_diff_cpy { + struct drm_rect rect; + size_t line; + size_t line_offset; + int cpp; + void (*do_cpy)(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, + size_t n); +}; + +#define VMW_CPU_BLIT_INITIALIZER { \ + .do_cpy = vmw_memcpy, \ +} + +#define VMW_CPU_BLIT_DIFF_INITIALIZER(_cpp) { \ + .line = 0, \ + .line_offset = 0, \ + .rect = { .x1 = INT_MAX/2, \ + .y1 = INT_MAX/2, \ + .x2 = INT_MIN/2, \ + .y2 = INT_MIN/2 \ + }, \ + .cpp = _cpp, \ + .do_cpy = vmw_diff_memcpy, \ +} + +void vmw_diff_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, + size_t n); + +void vmw_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, size_t n); + +int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, + u32 dst_offset, u32 dst_stride, + struct ttm_buffer_object *src, + u32 src_offset, u32 src_stride, + u32 w, u32 h, + struct vmw_diff_cpy *diff); /** * Inline helper functions diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index d23a18aae476..2582ffd36bb5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -43,8 +43,6 @@ struct vmw_fb_par { struct mutex bo_mutex; struct vmw_dma_buffer *vmw_bo; - struct ttm_bo_kmap_obj map; - void *bo_ptr; unsigned bo_size; struct drm_framebuffer *set_fb; struct drm_display_mode *set_mode; @@ -163,10 +161,17 @@ static int vmw_fb_blank(int blank, struct fb_info *info) return 0; } -/* - * Dirty code +/** + * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer + * + * @work: The struct work_struct associated with this task. + * + * This function flushes the dirty regions of the vmalloc framebuffer to the + * kms framebuffer, and if the kms framebuffer is visible, also updated the + * corresponding displays. Note that this function runs even if the kms + * framebuffer is not bound to a crtc and thus not visible, but it's turned + * off during hibernation using the par->dirty.active bool. */ - static void vmw_fb_dirty_flush(struct work_struct *work) { struct vmw_fb_par *par = container_of(work, struct vmw_fb_par, @@ -174,13 +179,15 @@ static void vmw_fb_dirty_flush(struct work_struct *work) struct vmw_private *vmw_priv = par->vmw_priv; struct fb_info *info = vmw_priv->fb_info; unsigned long irq_flags; - s32 dst_x1, dst_x2, dst_y1, dst_y2, w, h; + s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0; u32 cpp, max_x, max_y; struct drm_clip_rect clip; struct drm_framebuffer *cur_fb; u8 *src_ptr, *dst_ptr; + struct vmw_dma_buffer *vbo = par->vmw_bo; + void *virtual; - if (vmw_priv->suspended) + if (!READ_ONCE(par->dirty.active)) return; mutex_lock(&par->bo_mutex); @@ -188,10 +195,16 @@ static void vmw_fb_dirty_flush(struct work_struct *work) if (!cur_fb) goto out_unlock; + (void) ttm_read_lock(&vmw_priv->reservation_sem, false); + (void) ttm_bo_reserve(&vbo->base, false, false, NULL); + virtual = vmw_dma_buffer_map_and_cache(vbo); + if (!virtual) + goto out_unreserve; + spin_lock_irqsave(&par->dirty.lock, irq_flags); if (!par->dirty.active) { spin_unlock_irqrestore(&par->dirty.lock, irq_flags); - goto out_unlock; + goto out_unreserve; } /* @@ -221,7 +234,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work) spin_unlock_irqrestore(&par->dirty.lock, irq_flags); if (w && h) { - dst_ptr = (u8 *)par->bo_ptr + + dst_ptr = (u8 *)virtual + (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); src_ptr = (u8 *)par->vmalloc + ((dst_y1 + par->fb_y) * info->fix.line_length + @@ -237,7 +250,12 @@ static void vmw_fb_dirty_flush(struct work_struct *work) clip.x2 = dst_x2; clip.y1 = dst_y1; clip.y2 = dst_y2; + } +out_unreserve: + ttm_bo_unreserve(&vbo->base); + ttm_read_unlock(&vmw_priv->reservation_sem); + if (w && h) { WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, &clip, 1)); vmw_fifo_flush(vmw_priv, false); @@ -500,22 +518,12 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par, } if (cur_fb) { - drm_framebuffer_unreference(cur_fb); + drm_framebuffer_put(cur_fb); par->set_fb = NULL; } - if (par->vmw_bo && detach_bo) { - struct vmw_private *vmw_priv = par->vmw_priv; - - if (par->bo_ptr) { - ttm_bo_kunmap(&par->map); - par->bo_ptr = NULL; - } - if (unref_bo) - vmw_dmabuf_unreference(&par->vmw_bo); - else if (vmw_priv->active_display_unit != vmw_du_legacy) - vmw_dmabuf_unpin(par->vmw_priv, par->vmw_bo, false); - } + if (par->vmw_bo && detach_bo && unref_bo) + vmw_dmabuf_unreference(&par->vmw_bo); return 0; } @@ -636,38 +644,6 @@ static int vmw_fb_set_par(struct fb_info *info) if (ret) goto out_unlock; - if (!par->bo_ptr) { - struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(set.fb); - - /* - * Pin before mapping. Since we don't know in what placement - * to pin, call into KMS to do it for us. LDU doesn't require - * additional pinning because set_config() would've pinned - * it already - */ - if (vmw_priv->active_display_unit != vmw_du_legacy) { - ret = vfb->pin(vfb); - if (ret) { - DRM_ERROR("Could not pin the fbdev " - "framebuffer.\n"); - goto out_unlock; - } - } - - ret = ttm_bo_kmap(&par->vmw_bo->base, 0, - par->vmw_bo->base.num_pages, &par->map); - if (ret) { - if (vmw_priv->active_display_unit != vmw_du_legacy) - vfb->unpin(vfb); - - DRM_ERROR("Could not map the fbdev framebuffer.\n"); - goto out_unlock; - } - - par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite); - } - - vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width, par->set_fb->height); @@ -883,12 +859,6 @@ int vmw_fb_off(struct vmw_private *vmw_priv) flush_delayed_work(&info->deferred_work); flush_delayed_work(&par->local_work); - mutex_lock(&par->bo_mutex); - drm_modeset_lock_all(vmw_priv->dev); - (void) vmw_fb_kms_detach(par, true, false); - drm_modeset_unlock_all(vmw_priv->dev); - mutex_unlock(&par->bo_mutex); - return 0; } @@ -904,10 +874,24 @@ int vmw_fb_on(struct vmw_private *vmw_priv) info = vmw_priv->fb_info; par = info->par; - vmw_fb_set_par(info); spin_lock_irqsave(&par->dirty.lock, flags); par->dirty.active = true; spin_unlock_irqrestore(&par->dirty.lock, flags); return 0; } + +/** + * vmw_fb_refresh - Refresh fb display + * + * @vmw_priv: Pointer to device private + * + * Call into kms to show the fbdev display(s). + */ +void vmw_fb_refresh(struct vmw_private *vmw_priv) +{ + if (!vmw_priv->fb_info) + return; + + vmw_fb_set_par(vmw_priv->fb_info); +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 6c5c75cf5e6c..9ed544f8958f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -901,11 +901,12 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action) spin_lock_irq(&dev->event_lock); if (likely(eaction->tv_sec != NULL)) { - struct timeval tv; + struct timespec64 ts; - do_gettimeofday(&tv); - *eaction->tv_sec = tv.tv_sec; - *eaction->tv_usec = tv.tv_usec; + ktime_get_ts64(&ts); + /* monotonic time, so no y2038 overflow */ + *eaction->tv_sec = ts.tv_sec; + *eaction->tv_usec = ts.tv_nsec / NSEC_PER_USEC; } drm_send_event_locked(dev, eaction->event); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 67f844678ac8..c5e8eae0dbe2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -316,7 +316,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, out_no_surface: ttm_read_unlock(&dev_priv->reservation_sem); out_no_ttm_lock: - drm_framebuffer_unreference(fb); + drm_framebuffer_put(fb); out_no_fb: drm_modeset_unlock_all(dev); out_no_copy: @@ -393,7 +393,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, ttm_read_unlock(&dev_priv->reservation_sem); out_no_ttm_lock: - drm_framebuffer_unreference(fb); + drm_framebuffer_put(fb); out_no_fb: drm_modeset_unlock_all(dev); out_no_copy: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 34ecc27fc30a..3628a9fe705f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -393,13 +393,13 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, du->cursor_surface = vps->surf; du->cursor_dmabuf = vps->dmabuf; - /* setup new image */ if (vps->surf) { du->cursor_age = du->cursor_surface->snooper.age; ret = vmw_cursor_update_image(dev_priv, vps->surf->snooper.image, - 64, 64, hotspot_x, hotspot_y); + 64, 64, hotspot_x, + hotspot_y); } else if (vps->dmabuf) { ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf, plane->state->crtc_w, @@ -497,11 +497,22 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, struct vmw_surface *surface = NULL; struct drm_framebuffer *fb = new_state->fb; + struct drm_rect src = drm_plane_state_src(new_state); + struct drm_rect dest = drm_plane_state_dest(new_state); /* Turning off */ if (!fb) return ret; + ret = drm_plane_helper_check_update(plane, new_state->crtc, fb, + &src, &dest, + DRM_MODE_ROTATE_0, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true, &new_state->visible); + if (!ret) + return ret; + /* A lot of the code assumes this */ if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { DRM_ERROR("Invalid cursor dimensions (%d, %d)\n", @@ -566,13 +577,9 @@ void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, crtc->state->event = NULL; spin_lock_irq(&crtc->dev->event_lock); - if (drm_crtc_vblank_get(crtc) == 0) - drm_crtc_arm_vblank_event(crtc, event); - else - drm_crtc_send_vblank_event(crtc, event); + drm_crtc_send_vblank_event(crtc, event); spin_unlock_irq(&crtc->dev->event_lock); } - } @@ -675,9 +682,6 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) return NULL; vps->pinned = 0; - - /* Mapping is managed by prepare_fb/cleanup_fb */ - memset(&vps->host_map, 0, sizeof(vps->host_map)); vps->cpp = 0; /* Each ref counted resource needs to be acquired again */ @@ -739,11 +743,6 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, /* Should have been freed by cleanup_fb */ - if (vps->host_map.virtual) { - DRM_ERROR("Host mapping not freed\n"); - ttm_bo_kunmap(&vps->host_map); - } - if (vps->surf) vmw_surface_unreference(&vps->surf); @@ -888,11 +887,11 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, if (dev_priv->active_display_unit == vmw_du_screen_object) ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, clips, NULL, NULL, 0, 0, - num_clips, inc, NULL); + num_clips, inc, NULL, NULL); else ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, clips, NULL, NULL, 0, 0, - num_clips, inc, NULL); + num_clips, inc, NULL, NULL); vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); @@ -928,11 +927,12 @@ int vmw_kms_readback(struct vmw_private *dev_priv, switch (dev_priv->active_display_unit) { case vmw_du_screen_object: return vmw_kms_sou_readback(dev_priv, file_priv, vfb, - user_fence_rep, vclips, num_clips); + user_fence_rep, vclips, num_clips, + NULL); case vmw_du_screen_target: return vmw_kms_stdu_dma(dev_priv, file_priv, vfb, user_fence_rep, NULL, vclips, num_clips, - 1, false, true); + 1, false, true, NULL); default: WARN_ONCE(true, "Readback called with invalid display system.\n"); @@ -1090,12 +1090,12 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, case vmw_du_screen_target: ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, clips, NULL, num_clips, increment, - true, true); + true, true, NULL); break; case vmw_du_screen_object: ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, clips, NULL, num_clips, - increment, true, NULL); + increment, true, NULL, NULL); break; case vmw_du_legacy: ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, @@ -1121,12 +1121,14 @@ static const struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { }; /** - * Pin the dmabuffer to the start of vram. + * Pin the dmabuffer in a location suitable for access by the + * display system. */ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); struct vmw_dma_buffer *buf; + struct ttm_placement *placement; int ret; buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : @@ -1143,12 +1145,24 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) break; case vmw_du_screen_object: case vmw_du_screen_target: - if (vfb->dmabuf) - return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, - false); + if (vfb->dmabuf) { + if (dev_priv->capabilities & SVGA_CAP_3D) { + /* + * Use surface DMA to get content to + * sreen target surface. + */ + placement = &vmw_vram_gmr_placement; + } else { + /* Use CPU blit. */ + placement = &vmw_sys_placement; + } + } else { + /* Use surface / image update */ + placement = &vmw_mob_placement; + } - return vmw_dmabuf_pin_in_placement(dev_priv, buf, - &vmw_mob_placement, false); + return vmw_dmabuf_pin_in_placement(dev_priv, buf, placement, + false); default: return -EINVAL; } @@ -1539,35 +1553,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev, return drm_atomic_helper_check(dev, state); } - -/** - * vmw_kms_atomic_commit - Perform an atomic state commit - * - * @dev: DRM device - * @state: the driver state object - * @nonblock: Whether nonblocking behaviour is requested - * - * This is a simple wrapper around drm_atomic_helper_commit() for - * us to clear the nonblocking value. - * - * Nonblocking commits currently cause synchronization issues - * for vmwgfx. - * - * RETURNS - * Zero for success or negative error code on failure. - */ -int vmw_kms_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock) -{ - return drm_atomic_helper_commit(dev, state, false); -} - - static const struct drm_mode_config_funcs vmw_kms_funcs = { .fb_create = vmw_kms_fb_create, .atomic_check = vmw_kms_atomic_check_modeset, - .atomic_commit = vmw_kms_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; static int vmw_kms_generic_present(struct vmw_private *dev_priv, @@ -1581,7 +1570,7 @@ static int vmw_kms_generic_present(struct vmw_private *dev_priv, { return vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, clips, &surface->res, destX, destY, - num_clips, 1, NULL); + num_clips, 1, NULL, NULL); } @@ -1600,7 +1589,7 @@ int vmw_kms_present(struct vmw_private *dev_priv, case vmw_du_screen_target: ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, clips, &surface->res, destX, destY, - num_clips, 1, NULL); + num_clips, 1, NULL, NULL); break; case vmw_du_screen_object: ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, @@ -2328,10 +2317,16 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, dirty->dev_priv = dev_priv; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); + /* If crtc is passed, no need to iterate over other display units */ + if (dirty->crtc) { + units[num_units++] = vmw_crtc_to_du(dirty->crtc); + } else { + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, + head) { + if (crtc->primary->fb != &framebuffer->base) + continue; + units[num_units++] = vmw_crtc_to_du(crtc); + } } for (k = 0; k < num_units; k++) { @@ -2430,14 +2425,21 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool interruptible, - bool validate_as_mob) + bool validate_as_mob, + bool for_cpu_blit) { + struct ttm_operation_ctx ctx = { + .interruptible = interruptible, + .no_wait_gpu = false}; struct ttm_buffer_object *bo = &buf->base; int ret; ttm_bo_reserve(bo, false, false, NULL); - ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, - validate_as_mob); + if (for_cpu_blit) + ret = ttm_bo_validate(bo, &vmw_nonfixed_placement, &ctx); + else + ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, + validate_as_mob); if (ret) ttm_bo_unreserve(bo); @@ -2549,7 +2551,8 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, if (res->backup) { ret = vmw_kms_helper_buffer_prepare(res->dev_priv, res->backup, interruptible, - res->dev_priv->has_mob); + res->dev_priv->has_mob, + false); if (ret) goto out_unreserve; } @@ -2845,3 +2848,51 @@ int vmw_kms_set_config(struct drm_mode_set *set, return drm_atomic_helper_set_config(set, ctx); } + + +/** + * vmw_kms_suspend - Save modesetting state and turn modesetting off. + * + * @dev: Pointer to the drm device + * Return: 0 on success. Negative error code on failure. + */ +int vmw_kms_suspend(struct drm_device *dev) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + + dev_priv->suspend_state = drm_atomic_helper_suspend(dev); + if (IS_ERR(dev_priv->suspend_state)) { + int ret = PTR_ERR(dev_priv->suspend_state); + + DRM_ERROR("Failed kms suspend: %d\n", ret); + dev_priv->suspend_state = NULL; + + return ret; + } + + return 0; +} + + +/** + * vmw_kms_resume - Re-enable modesetting and restore state + * + * @dev: Pointer to the drm device + * Return: 0 on success. Negative error code on failure. + * + * State is resumed from a previous vmw_kms_suspend(). It's illegal + * to call this function without a previous vmw_kms_suspend(). + */ +int vmw_kms_resume(struct drm_device *dev) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + int ret; + + if (WARN_ON(!dev_priv->suspend_state)) + return 0; + + ret = drm_atomic_helper_resume(dev, dev_priv->suspend_state); + dev_priv->suspend_state = NULL; + + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index cd9da2dd79af..4e8749a8717e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -50,6 +50,7 @@ * @unit: The current display unit. Set up by the helper before a call to @clip. * @cmd: The allocated fifo space. Set up by the helper before the first @clip * call. + * @crtc: The crtc for which to build dirty commands. * @num_hits: Number of clip rect commands for this display unit. * Cleared by the helper before the first @clip call. Updated by the @clip * callback. @@ -71,6 +72,7 @@ struct vmw_kms_dirty { struct vmw_private *dev_priv; struct vmw_display_unit *unit; void *cmd; + struct drm_crtc *crtc; u32 num_hits; s32 fb_x; s32 fb_y; @@ -175,7 +177,6 @@ struct vmw_plane_state { int pinned; /* For CPU Blit */ - struct ttm_bo_kmap_obj host_map; unsigned int cpp; }; @@ -287,7 +288,8 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool interruptible, - bool validate_as_mob); + bool validate_as_mob, + bool for_cpu_blit); void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf); void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, struct drm_file *file_priv, @@ -398,20 +400,23 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, s32 dest_x, s32 dest_y, unsigned num_clips, int inc, - struct vmw_fence_obj **out_fence); + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc); int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, struct drm_clip_rect *clips, struct drm_vmw_rect *vclips, unsigned num_clips, int increment, bool interruptible, - struct vmw_fence_obj **out_fence); + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc); int vmw_kms_sou_readback(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_rect *vclips, - uint32_t num_clips); + uint32_t num_clips, + struct drm_crtc *crtc); /* * Screen Target Display Unit functions - vmwgfx_stdu.c @@ -425,7 +430,8 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, s32 dest_x, s32 dest_y, unsigned num_clips, int inc, - struct vmw_fence_obj **out_fence); + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc); int vmw_kms_stdu_dma(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, @@ -435,7 +441,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, uint32_t num_clips, int increment, bool to_surface, - bool interruptible); + bool interruptible, + struct drm_crtc *crtc); int vmw_kms_set_config(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 97000996b8dc..cdff99211602 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -328,7 +328,7 @@ int vmw_host_get_guestinfo(const char *guest_info_param, { struct rpc_channel channel; char *msg, *reply = NULL; - size_t msg_len, reply_len = 0; + size_t reply_len = 0; int ret = 0; @@ -338,15 +338,12 @@ int vmw_host_get_guestinfo(const char *guest_info_param, if (!guest_info_param || !length) return -EINVAL; - msg_len = strlen(guest_info_param) + strlen("info-get ") + 1; - msg = kzalloc(msg_len, GFP_KERNEL); + msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param); if (!msg) { DRM_ERROR("Cannot allocate memory to get %s", guest_info_param); return -ENOMEM; } - sprintf(msg, "info-get %s", guest_info_param); - if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || vmw_send_msg(&channel, msg) || vmw_recv_msg(&channel, (void *) &reply, &reply_len) || @@ -388,7 +385,6 @@ int vmw_host_log(const char *log) { struct rpc_channel channel; char *msg; - int msg_len; int ret = 0; @@ -398,15 +394,12 @@ int vmw_host_log(const char *log) if (!log) return ret; - msg_len = strlen(log) + strlen("log ") + 1; - msg = kzalloc(msg_len, GFP_KERNEL); + msg = kasprintf(GFP_KERNEL, "log %s", log); if (!msg) { DRM_ERROR("Cannot allocate memory for log message\n"); return -ENOMEM; } - sprintf(msg, "log %s", log); - if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || vmw_send_msg(&channel, msg) || vmw_close_channel(&channel)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 9e101450cc4d..6b3a942b18df 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -354,6 +354,7 @@ void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) { struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); + vmw_dma_buffer_unmap(vmw_bo); kfree(vmw_bo); } @@ -361,6 +362,7 @@ static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) { struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); + vmw_dma_buffer_unmap(&vmw_user_bo->dma); ttm_prime_object_kfree(vmw_user_bo, prime); } @@ -1239,6 +1241,12 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, dma_buf = container_of(bo, struct vmw_dma_buffer, base); + /* + * Kill any cached kernel maps before move. An optimization could + * be to do this iff source or destination memory type is VRAM. + */ + vmw_dma_buffer_unmap(dma_buf); + if (mem->mem_type != VMW_PL_MOB) { struct vmw_resource *res, *n; struct ttm_validate_buffer val_buf; @@ -1262,6 +1270,21 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, } +/** + * vmw_resource_swap_notify - swapout notify callback. + * + * @bo: The buffer object to be swapped out. + */ +void vmw_resource_swap_notify(struct ttm_buffer_object *bo) +{ + if (bo->destroy != vmw_dmabuf_bo_free && + bo->destroy != vmw_user_dmabuf_destroy) + return; + + /* Kill any cached kernel maps before swapout */ + vmw_dma_buffer_unmap(vmw_dma_buffer(bo)); +} + /** * vmw_query_readback_all - Read back cached query states diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 63a4cd794b73..419185f60278 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -316,69 +316,21 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); - struct drm_framebuffer *old_fb = crtc->primary->fb; - struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); - struct vmw_fence_obj *fence = NULL; - struct drm_vmw_rect vclips; int ret; if (!vmw_kms_crtc_flippable(dev_priv, crtc)) return -EINVAL; - flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; - ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx); + ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); if (ret) { DRM_ERROR("Page flip error %d.\n", ret); return ret; } - /* do a full screen dirty update */ - vclips.x = crtc->x; - vclips.y = crtc->y; - vclips.w = crtc->mode.hdisplay; - vclips.h = crtc->mode.vdisplay; - - if (vfb->dmabuf) - ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, - NULL, &vclips, 1, 1, - true, &fence); - else - ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, - NULL, &vclips, NULL, - 0, 0, 1, 1, &fence); - - - if (ret != 0) - goto out_no_fence; - if (!fence) { - ret = -EINVAL; - goto out_no_fence; - } - - if (event) { - struct drm_file *file_priv = event->base.file_priv; - - ret = vmw_event_fence_action_queue(file_priv, fence, - &event->base, - &event->event.vbl.tv_sec, - &event->event.vbl.tv_usec, - true); - } - - /* - * No need to hold on to this now. The only cleanup - * we need to do if we fail is unref the fence. - */ - vmw_fence_obj_unreference(&fence); - if (vmw_crtc_to_du(crtc)->is_implicit) vmw_kms_update_implicit_fb(dev_priv, crtc); return ret; - -out_no_fence: - drm_atomic_set_fb_for_plane(crtc->primary->state, old_fb); - return ret; } static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { @@ -453,7 +405,11 @@ vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); + struct drm_crtc *crtc = plane->state->crtc ? + plane->state->crtc : old_state->crtc; + if (vps->dmabuf) + vmw_dmabuf_unpin(vmw_priv(crtc->dev), vps->dmabuf, false); vmw_dmabuf_unreference(&vps->dmabuf); vps->dmabuf_size = 0; @@ -491,10 +447,17 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, } size = new_state->crtc_w * new_state->crtc_h * 4; + dev_priv = vmw_priv(crtc->dev); if (vps->dmabuf) { - if (vps->dmabuf_size == size) - return 0; + if (vps->dmabuf_size == size) { + /* + * Note that this might temporarily up the pin-count + * to 2, until cleanup_fb() is called. + */ + return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, + true); + } vmw_dmabuf_unreference(&vps->dmabuf); vps->dmabuf_size = 0; @@ -504,7 +467,6 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, if (!vps->dmabuf) return -ENOMEM; - dev_priv = vmw_priv(crtc->dev); vmw_svga_enable(dev_priv); /* After we have alloced the backing store might not be able to @@ -515,13 +477,16 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, &vmw_vram_ne_placement, false, &vmw_dmabuf_bo_free); vmw_overlay_resume_all(dev_priv); - - if (ret != 0) + if (ret) { vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */ - else - vps->dmabuf_size = size; + return ret; + } - return ret; + /* + * TTM already thinks the buffer is pinned, but make sure the + * pin_count is upped. + */ + return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, true); } @@ -530,9 +495,71 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct drm_crtc *crtc = plane->state->crtc; + struct drm_pending_vblank_event *event = NULL; + struct vmw_fence_obj *fence = NULL; + int ret; + + if (crtc && plane->state->fb) { + struct vmw_private *dev_priv = vmw_priv(crtc->dev); + struct vmw_framebuffer *vfb = + vmw_framebuffer_to_vfb(plane->state->fb); + struct drm_vmw_rect vclips; + + vclips.x = crtc->x; + vclips.y = crtc->y; + vclips.w = crtc->mode.hdisplay; + vclips.h = crtc->mode.vdisplay; + + if (vfb->dmabuf) + ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, NULL, + &vclips, 1, 1, true, + &fence, crtc); + else + ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, + &vclips, NULL, 0, 0, + 1, 1, &fence, crtc); + + /* + * We cannot really fail this function, so if we do, then output + * an error and maintain consistent atomic state. + */ + if (ret != 0) + DRM_ERROR("Failed to update screen.\n"); - if (crtc) crtc->primary->fb = plane->state->fb; + } else { + /* + * When disabling a plane, CRTC and FB should always be NULL + * together, otherwise it's an error. + * Here primary plane is being disable so should really blank + * the screen object display unit, if not already done. + */ + return; + } + + event = crtc->state->event; + /* + * In case of failure and other cases, vblank event will be sent in + * vmw_du_crtc_atomic_flush. + */ + if (event && fence) { + struct drm_file *file_priv = event->base.file_priv; + + ret = vmw_event_fence_action_queue(file_priv, + fence, + &event->base, + &event->event.vbl.tv_sec, + &event->event.vbl.tv_usec, + true); + + if (unlikely(ret != 0)) + DRM_ERROR("Failed to queue event on fence.\n"); + else + crtc->state->event = NULL; + } + + if (fence) + vmw_fence_obj_unreference(&fence); } @@ -892,6 +919,7 @@ static void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty) * @out_fence: If non-NULL, will return a ref-counted pointer to a * struct vmw_fence_obj. The returned fence pointer may be NULL in which * case the device has already synchronized. + * @crtc: If crtc is passed, perform surface dirty on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. @@ -904,7 +932,8 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, s32 dest_x, s32 dest_y, unsigned num_clips, int inc, - struct vmw_fence_obj **out_fence) + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc) { struct vmw_framebuffer_surface *vfbs = container_of(framebuffer, typeof(*vfbs), base); @@ -923,6 +952,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, sdirty.base.dev_priv = dev_priv; sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) * num_clips; + sdirty.base.crtc = crtc; sdirty.sid = srf->id; sdirty.left = sdirty.top = S32_MAX; @@ -994,6 +1024,7 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) * @out_fence: If non-NULL, will return a ref-counted pointer to a * struct vmw_fence_obj. The returned fence pointer may be NULL in which * case the device has already synchronized. + * @crtc: If crtc is passed, perform dmabuf dirty on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. @@ -1004,7 +1035,8 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct drm_vmw_rect *vclips, unsigned num_clips, int increment, bool interruptible, - struct vmw_fence_obj **out_fence) + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc) { struct vmw_dma_buffer *buf = container_of(framebuffer, struct vmw_framebuffer_dmabuf, @@ -1013,7 +1045,7 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, int ret; ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, - false); + false, false); if (ret) return ret; @@ -1021,6 +1053,7 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, if (unlikely(ret != 0)) goto out_revert; + dirty.crtc = crtc; dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit; dirty.clip = vmw_sou_dmabuf_clip; dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * @@ -1092,6 +1125,7 @@ static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty) * Must be set to non-NULL if @file_priv is non-NULL. * @vclips: Array of clip rects. * @num_clips: Number of clip rects in @vclips. + * @crtc: If crtc is passed, readback on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. @@ -1101,14 +1135,16 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, struct vmw_framebuffer *vfb, struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_rect *vclips, - uint32_t num_clips) + uint32_t num_clips, + struct drm_crtc *crtc) { struct vmw_dma_buffer *buf = container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; struct vmw_kms_dirty dirty; int ret; - ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false); + ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false, + false); if (ret) return ret; @@ -1116,6 +1152,7 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, if (unlikely(ret != 0)) goto out_revert; + dirty.crtc = crtc; dirty.fifo_commit = vmw_sou_readback_fifo_commit; dirty.clip = vmw_sou_readback_clip; dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index b68d74888ab1..8eec88920851 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -114,7 +114,6 @@ struct vmw_screen_target_display_unit { bool defined; /* For CPU Blit */ - struct ttm_bo_kmap_obj host_map; unsigned int cpp; }; @@ -492,71 +491,17 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); - struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); - struct drm_vmw_rect vclips; int ret; - dev_priv = vmw_priv(crtc->dev); - stdu = vmw_crtc_to_stdu(crtc); - if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) return -EINVAL; - /* - * We're always async, but the helper doesn't know how to set async - * so lie to the helper. Also, the helper expects someone - * to pick the event up from the crtc state, and if nobody does, - * it will free it. Since we handle the event in this function, - * don't hand it to the helper. - */ - flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; - ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx); + ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); if (ret) { DRM_ERROR("Page flip error %d.\n", ret); return ret; } - if (stdu->base.is_implicit) - vmw_kms_update_implicit_fb(dev_priv, crtc); - - /* - * Now that we've bound a new surface to the screen target, - * update the contents. - */ - vclips.x = crtc->x; - vclips.y = crtc->y; - vclips.w = crtc->mode.hdisplay; - vclips.h = crtc->mode.vdisplay; - - if (vfb->dmabuf) - ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips, - 1, 1, true, false); - else - ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips, - NULL, 0, 0, 1, 1, NULL); - if (ret) { - DRM_ERROR("Page flip update error %d.\n", ret); - return ret; - } - - if (event) { - struct vmw_fence_obj *fence = NULL; - struct drm_file *file_priv = event->base.file_priv; - - vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - if (!fence) - return -ENOMEM; - - ret = vmw_event_fence_action_queue(file_priv, fence, - &event->base, - &event->event.vbl.tv_sec, - &event->event.vbl.tv_usec, - true); - vmw_fence_obj_unreference(&fence); - } else { - (void) vmw_fifo_flush(dev_priv, false); - } - return 0; } @@ -693,10 +638,9 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) container_of(dirty->unit, typeof(*stdu), base); s32 width, height; s32 src_pitch, dst_pitch; - u8 *src, *dst; - bool not_used; - struct ttm_bo_kmap_obj guest_map; - int ret; + struct ttm_buffer_object *src_bo, *dst_bo; + u32 src_offset, dst_offset; + struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(stdu->cpp); if (!dirty->num_hits) return; @@ -707,57 +651,38 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) if (width == 0 || height == 0) return; - ret = ttm_bo_kmap(&ddirty->buf->base, 0, ddirty->buf->base.num_pages, - &guest_map); - if (ret) { - DRM_ERROR("Failed mapping framebuffer for blit: %d\n", - ret); - goto out_cleanup; - } - - /* Assume we are blitting from Host (display_srf) to Guest (dmabuf) */ - src_pitch = stdu->display_srf->base_size.width * stdu->cpp; - src = ttm_kmap_obj_virtual(&stdu->host_map, ¬_used); - src += ddirty->top * src_pitch + ddirty->left * stdu->cpp; - - dst_pitch = ddirty->pitch; - dst = ttm_kmap_obj_virtual(&guest_map, ¬_used); - dst += ddirty->fb_top * dst_pitch + ddirty->fb_left * stdu->cpp; - - - /* Figure out the real direction */ - if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { - u8 *tmp; - s32 tmp_pitch; - - tmp = src; - tmp_pitch = src_pitch; + /* Assume we are blitting from Guest (dmabuf) to Host (display_srf) */ + dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; + dst_bo = &stdu->display_srf->res.backup->base; + dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp; - src = dst; - src_pitch = dst_pitch; + src_pitch = ddirty->pitch; + src_bo = &ddirty->buf->base; + src_offset = ddirty->fb_top * src_pitch + ddirty->fb_left * stdu->cpp; - dst = tmp; - dst_pitch = tmp_pitch; + /* Swap src and dst if the assumption was wrong. */ + if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) { + swap(dst_pitch, src_pitch); + swap(dst_bo, src_bo); + swap(src_offset, dst_offset); } - /* CPU Blit */ - while (height-- > 0) { - memcpy(dst, src, width * stdu->cpp); - dst += dst_pitch; - src += src_pitch; - } + (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, + src_bo, src_offset, src_pitch, + width * stdu->cpp, height, &diff); - if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { + if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM && + drm_rect_visible(&diff.rect)) { struct vmw_private *dev_priv; struct vmw_stdu_update *cmd; struct drm_clip_rect region; int ret; /* We are updating the actual surface, not a proxy */ - region.x1 = ddirty->left; - region.x2 = ddirty->right; - region.y1 = ddirty->top; - region.y2 = ddirty->bottom; + region.x1 = diff.rect.x1; + region.x2 = diff.rect.x2; + region.y1 = diff.rect.y1; + region.y2 = diff.rect.y2; ret = vmw_kms_update_proxy( (struct vmw_resource *) &stdu->display_srf->res, (const struct drm_clip_rect *) ®ion, 1, 1); @@ -774,13 +699,12 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) } vmw_stdu_populate_update(cmd, stdu->base.unit, - ddirty->left, ddirty->right, - ddirty->top, ddirty->bottom); + region.x1, region.x2, + region.y1, region.y2); vmw_fifo_commit(dev_priv, sizeof(*cmd)); } - ttm_bo_kunmap(&guest_map); out_cleanup: ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX; ddirty->right = ddirty->bottom = S32_MIN; @@ -802,6 +726,7 @@ out_cleanup: * @to_surface: Whether to DMA to the screen target system as opposed to * from the screen target system. * @interruptible: Whether to perform waits interruptible if possible. + * @crtc: If crtc is passed, perform stdu dma on that crtc only. * * If DMA-ing till the screen target system, the function will also notify * the screen target system that a bounding box of the cliprects has been @@ -818,15 +743,22 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, uint32_t num_clips, int increment, bool to_surface, - bool interruptible) + bool interruptible, + struct drm_crtc *crtc) { struct vmw_dma_buffer *buf = container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; struct vmw_stdu_dirty ddirty; int ret; + bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); + /* + * VMs without 3D support don't have the surface DMA command and + * we'll be using a CPU blit, and the framebuffer should be moved out + * of VRAM. + */ ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, - false); + false, cpu_blit); if (ret) return ret; @@ -845,13 +777,15 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, if (to_surface) ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update); - /* 2D VMs cannot use SVGA_3D_CMD_SURFACE_DMA so do CPU blit instead */ - if (!(dev_priv->capabilities & SVGA_CAP_3D)) { + + if (cpu_blit) { ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit; ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip; ddirty.base.fifo_reserve_size = 0; } + ddirty.base.crtc = crtc; + ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips, 0, 0, num_clips, increment, &ddirty.base); vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL, @@ -963,6 +897,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) * @out_fence: If non-NULL, will return a ref-counted pointer to a * struct vmw_fence_obj. The returned fence pointer may be NULL in which * case the device has already synchronized. + * @crtc: If crtc is passed, perform surface dirty on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. @@ -975,7 +910,8 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, s32 dest_x, s32 dest_y, unsigned num_clips, int inc, - struct vmw_fence_obj **out_fence) + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc) { struct vmw_framebuffer_surface *vfbs = container_of(framebuffer, typeof(*vfbs), base); @@ -1000,6 +936,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) * num_clips + sizeof(struct vmw_stdu_update); + sdirty.base.crtc = crtc; sdirty.sid = srf->id; sdirty.left = sdirty.top = S32_MAX; sdirty.right = sdirty.bottom = S32_MIN; @@ -1118,9 +1055,6 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, { struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); - if (vps->host_map.virtual) - ttm_bo_kunmap(&vps->host_map); - if (vps->surf) WARN_ON(!vps->pinned); @@ -1282,24 +1216,11 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, * so cache these mappings */ if (vps->content_fb_type == SEPARATE_DMA && - !(dev_priv->capabilities & SVGA_CAP_3D)) { - ret = ttm_bo_kmap(&vps->surf->res.backup->base, 0, - vps->surf->res.backup->base.num_pages, - &vps->host_map); - if (ret) { - DRM_ERROR("Failed to map display buffer to CPU\n"); - goto out_srf_unpin; - } - + !(dev_priv->capabilities & SVGA_CAP_3D)) vps->cpp = new_fb->pitches[0] / new_fb->width; - } return 0; -out_srf_unpin: - vmw_resource_unpin(&vps->surf->res); - vps->pinned--; - out_srf_unref: vmw_surface_unreference(&vps->surf); return ret; @@ -1322,41 +1243,104 @@ static void vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct vmw_private *dev_priv; - struct vmw_screen_target_display_unit *stdu; struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state); - struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc; + struct drm_crtc *crtc = plane->state->crtc; + struct vmw_screen_target_display_unit *stdu; + struct drm_pending_vblank_event *event; + struct vmw_private *dev_priv; int ret; - stdu = vmw_crtc_to_stdu(crtc); - dev_priv = vmw_priv(crtc->dev); + /* + * We cannot really fail this function, so if we do, then output an + * error and maintain consistent atomic state. + */ + if (crtc && plane->state->fb) { + struct vmw_framebuffer *vfb = + vmw_framebuffer_to_vfb(plane->state->fb); + struct drm_vmw_rect vclips; + stdu = vmw_crtc_to_stdu(crtc); + dev_priv = vmw_priv(crtc->dev); + + stdu->display_srf = vps->surf; + stdu->content_fb_type = vps->content_fb_type; + stdu->cpp = vps->cpp; + + vclips.x = crtc->x; + vclips.y = crtc->y; + vclips.w = crtc->mode.hdisplay; + vclips.h = crtc->mode.vdisplay; + + ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); + if (ret) + DRM_ERROR("Failed to bind surface to STDU.\n"); + + if (vfb->dmabuf) + ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, + &vclips, 1, 1, true, false, + crtc); + else + ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, + &vclips, NULL, 0, 0, + 1, 1, NULL, crtc); + if (ret) + DRM_ERROR("Failed to update STDU.\n"); - stdu->display_srf = vps->surf; - stdu->content_fb_type = vps->content_fb_type; - stdu->cpp = vps->cpp; - memcpy(&stdu->host_map, &vps->host_map, sizeof(vps->host_map)); + crtc->primary->fb = plane->state->fb; + } else { + crtc = old_state->crtc; + stdu = vmw_crtc_to_stdu(crtc); + dev_priv = vmw_priv(crtc->dev); - if (!stdu->defined) - return; + /* + * When disabling a plane, CRTC and FB should always be NULL + * together, otherwise it's an error. + * Here primary plane is being disable so blank the screen + * target display unit, if not already done. + */ + if (!stdu->defined) + return; - if (plane->state->fb) - ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); - else ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); + if (ret) + DRM_ERROR("Failed to blank STDU\n"); + + ret = vmw_stdu_update_st(dev_priv, stdu); + if (ret) + DRM_ERROR("Failed to update STDU.\n"); + + return; + } + event = crtc->state->event; /* - * We cannot really fail this function, so if we do, then output an - * error and quit + * In case of failure and other cases, vblank event will be sent in + * vmw_du_crtc_atomic_flush. */ - if (ret) - DRM_ERROR("Failed to bind surface to STDU.\n"); - else - crtc->primary->fb = plane->state->fb; + if (event && (ret == 0)) { + struct vmw_fence_obj *fence = NULL; + struct drm_file *file_priv = event->base.file_priv; - ret = vmw_stdu_update_st(dev_priv, stdu); + vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - if (ret) - DRM_ERROR("Failed to update STDU.\n"); + /* + * If fence is NULL, then already sync. + */ + if (fence) { + ret = vmw_event_fence_action_queue( + file_priv, fence, &event->base, + &event->event.vbl.tv_sec, + &event->event.vbl.tv_usec, + true); + if (ret) + DRM_ERROR("Failed to queue event on fence.\n"); + else + crtc->state->event = NULL; + + vmw_fence_obj_unreference(&fence); + } + } else { + (void) vmw_fifo_flush(dev_priv, false); + } } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index db1bb166845e..b236c48bf265 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -345,7 +345,6 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res) dev_priv->used_memory_size -= res->backup_size; mutex_unlock(&dev_priv->cmdbuf_mutex); } - vmw_fifo_resource_dec(dev_priv); } /** @@ -407,6 +406,8 @@ static int vmw_legacy_srf_create(struct vmw_resource *res) vmw_surface_define_encode(srf, cmd); vmw_fifo_commit(dev_priv, submit_size); + vmw_fifo_resource_inc(dev_priv); + /* * Surface memory usage accounting. */ @@ -558,6 +559,7 @@ static int vmw_legacy_srf_destroy(struct vmw_resource *res) */ vmw_resource_release_id(res); + vmw_fifo_resource_dec(dev_priv); return 0; } @@ -579,15 +581,11 @@ static int vmw_surface_init(struct vmw_private *dev_priv, struct vmw_resource *res = &srf->res; BUG_ON(!res_free); - if (!dev_priv->has_mob) - vmw_fifo_resource_inc(dev_priv); ret = vmw_resource_init(dev_priv, res, true, res_free, (dev_priv->has_mob) ? &vmw_gb_surface_func : &vmw_legacy_surface_func); if (unlikely(ret != 0)) { - if (!dev_priv->has_mob) - vmw_fifo_resource_dec(dev_priv); res_free(res); return ret; } diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 3cd153c6d271..fc4adf3d34e8 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -92,7 +92,8 @@ * struct vga_switcheroo_client - registered client * @pdev: client pci device * @fb_info: framebuffer to which console is remapped on switching - * @pwr_state: current power state + * @pwr_state: current power state if manual power control is used. + * For driver power control, call vga_switcheroo_pwr_state(). * @ops: client callbacks * @id: client identifier. Determining the id requires the handler, * so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID @@ -104,8 +105,7 @@ * @list: client list * * Registered client. A client can be either a GPU or an audio device on a GPU. - * For audio clients, the @fb_info, @active and @driver_power_control members - * are bogus. + * For audio clients, the @fb_info and @active members are bogus. */ struct vga_switcheroo_client { struct pci_dev *pdev; @@ -331,8 +331,8 @@ EXPORT_SYMBOL(vga_switcheroo_register_client); * @ops: client callbacks * @id: client identifier * - * Register audio client (audio device on a GPU). The power state of the - * client is assumed to be ON. Beforehand, vga_switcheroo_client_probe_defer() + * Register audio client (audio device on a GPU). The client is assumed + * to use runtime PM. Beforehand, vga_switcheroo_client_probe_defer() * shall be called to ensure that all prerequisites are met. * * Return: 0 on success, -ENOMEM on memory allocation error. @@ -341,7 +341,7 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev, const struct vga_switcheroo_client_ops *ops, enum vga_switcheroo_client_id id) { - return register_client(pdev, ops, id | ID_BIT_AUDIO, false, false); + return register_client(pdev, ops, id | ID_BIT_AUDIO, false, true); } EXPORT_SYMBOL(vga_switcheroo_register_audio_client); @@ -406,6 +406,19 @@ bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) } EXPORT_SYMBOL(vga_switcheroo_client_probe_defer); +static enum vga_switcheroo_state +vga_switcheroo_pwr_state(struct vga_switcheroo_client *client) +{ + if (client->driver_power_control) + if (pm_runtime_enabled(&client->pdev->dev) && + pm_runtime_active(&client->pdev->dev)) + return VGA_SWITCHEROO_ON; + else + return VGA_SWITCHEROO_OFF; + else + return client->pwr_state; +} + /** * vga_switcheroo_get_client_state() - obtain power state of a given client * @pdev: client pci device @@ -425,7 +438,7 @@ enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *pdev) if (!client) ret = VGA_SWITCHEROO_NOT_FOUND; else - ret = client->pwr_state; + ret = vga_switcheroo_pwr_state(client); mutex_unlock(&vgasr_mutex); return ret; } @@ -598,7 +611,7 @@ static int vga_switcheroo_show(struct seq_file *m, void *v) client_is_vga(client) ? "" : "-Audio", client->active ? '+' : ' ', client->driver_power_control ? "Dyn" : "", - client->pwr_state ? "Pwr" : "Off", + vga_switcheroo_pwr_state(client) ? "Pwr" : "Off", pci_name(client->pdev)); i++; } @@ -641,10 +654,8 @@ static void set_audio_state(enum vga_switcheroo_client_id id, struct vga_switcheroo_client *client; client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO); - if (client && client->pwr_state != state) { + if (client) client->ops->set_gpu_state(client->pdev, state); - client->pwr_state = state; - } } /* stage one happens before delay */ @@ -656,7 +667,7 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) if (!active) return 0; - if (new_client->pwr_state == VGA_SWITCHEROO_OFF) + if (vga_switcheroo_pwr_state(new_client) == VGA_SWITCHEROO_OFF) vga_switchon(new_client); vga_set_default_device(new_client->pdev); @@ -675,7 +686,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) active->active = false; - set_audio_state(active->id, VGA_SWITCHEROO_OFF); + /* let HDA controller autosuspend if GPU uses driver power control */ + if (!active->driver_power_control) + set_audio_state(active->id, VGA_SWITCHEROO_OFF); if (new_client->fb_info) { struct fb_event event; @@ -695,10 +708,12 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) if (new_client->ops->reprobe) new_client->ops->reprobe(new_client->pdev); - if (active->pwr_state == VGA_SWITCHEROO_ON) + if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON) vga_switchoff(active); - set_audio_state(new_client->id, VGA_SWITCHEROO_ON); + /* let HDA controller autoresume if GPU uses driver power control */ + if (!new_client->driver_power_control) + set_audio_state(new_client->id, VGA_SWITCHEROO_ON); new_client->active = true; return 0; @@ -939,11 +954,6 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch); * Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel * command line disables it. * - * When the driver decides to power up or down, it notifies vga_switcheroo - * thereof so that it can (a) power the audio device on the GPU up or down, - * and (b) update its internal power state representation for the device. - * This is achieved by vga_switcheroo_set_dynamic_switch(). - * * After the GPU has been suspended, the handler needs to be called to cut * power to the GPU. Likewise it needs to reinstate power before the GPU * can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(), @@ -951,8 +961,9 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch); * calls to the handler. * * When the audio device resumes, the GPU needs to be woken. This is achieved - * by vga_switcheroo_init_domain_pm_optimus_hdmi_audio(), which augments the - * audio device's resume function. + * by a PCI quirk which calls device_link_add() to declare a dependency on the + * GPU. That way, the GPU is kept awake whenever and as long as the audio + * device is in use. * * On muxed machines, if the mux is initially switched to the discrete GPU, * the user ends up with a black screen when the GPU powers down after boot. @@ -978,35 +989,6 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev, vgasr_priv.handler->power_state(client->id, state); } -/** - * vga_switcheroo_set_dynamic_switch() - helper for driver power control - * @pdev: client pci device - * @dynamic: new power state - * - * Helper for GPUs whose power state is controlled by the driver's runtime pm. - * When the driver decides to power up or down, it notifies vga_switcheroo - * thereof using this helper so that it can (a) power the audio device on - * the GPU up or down, and (b) update its internal power state representation - * for the device. - */ -void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, - enum vga_switcheroo_state dynamic) -{ - struct vga_switcheroo_client *client; - - mutex_lock(&vgasr_mutex); - client = find_client_from_pci(&vgasr_priv.clients, pdev); - if (!client || !client->driver_power_control) { - mutex_unlock(&vgasr_mutex); - return; - } - - client->pwr_state = dynamic; - set_audio_state(client->id, dynamic); - mutex_unlock(&vgasr_mutex); -} -EXPORT_SYMBOL(vga_switcheroo_set_dynamic_switch); - /* switcheroo power domain */ static int vga_switcheroo_runtime_suspend(struct device *dev) { @@ -1022,6 +1004,7 @@ static int vga_switcheroo_runtime_suspend(struct device *dev) vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD); mutex_unlock(&vgasr_priv.mux_hw_lock); } + pci_bus_set_current_state(pdev->bus, PCI_D3cold); vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF); mutex_unlock(&vgasr_mutex); return 0; @@ -1035,6 +1018,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev) mutex_lock(&vgasr_mutex); vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON); mutex_unlock(&vgasr_mutex); + pci_wakeup_bus(pdev->bus); ret = dev->bus->pm->runtime_resume(dev); if (ret) return ret; @@ -1076,69 +1060,3 @@ void vga_switcheroo_fini_domain_pm_ops(struct device *dev) dev_pm_domain_set(dev, NULL); } EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops); - -static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct vga_switcheroo_client *client; - struct device *video_dev = NULL; - int ret; - - /* we need to check if we have to switch back on the video - * device so the audio device can come back - */ - mutex_lock(&vgasr_mutex); - list_for_each_entry(client, &vgasr_priv.clients, list) { - if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) && - client_is_vga(client)) { - video_dev = &client->pdev->dev; - break; - } - } - mutex_unlock(&vgasr_mutex); - - if (video_dev) { - ret = pm_runtime_get_sync(video_dev); - if (ret && ret != 1) - return ret; - } - ret = dev->bus->pm->runtime_resume(dev); - - /* put the reference for the gpu */ - if (video_dev) { - pm_runtime_mark_last_busy(video_dev); - pm_runtime_put_autosuspend(video_dev); - } - return ret; -} - -/** - * vga_switcheroo_init_domain_pm_optimus_hdmi_audio() - helper for driver - * power control - * @dev: audio client device - * @domain: power domain - * - * Helper for GPUs whose power state is controlled by the driver's runtime pm. - * When the audio device resumes, the GPU needs to be woken. This helper - * augments the audio device's resume function to do that. - * - * Return: 0 on success, -EINVAL if no power management operations are - * defined for this device. - */ -int -vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, - struct dev_pm_domain *domain) -{ - /* copy over all the bus versions */ - if (dev->bus && dev->bus->pm) { - domain->ops = *dev->bus->pm; - domain->ops.runtime_resume = - vga_switcheroo_runtime_resume_hdmi_audio; - - dev_pm_domain_set(dev, domain); - return 0; - } - dev_pm_domain_set(dev, NULL); - return -EINVAL; -} -EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 3bed6beda051..6a67cdbd0e6a 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1224,11 +1224,14 @@ static int pci_pm_runtime_suspend(struct device *dev) int error; /* - * If pci_dev->driver is not set (unbound), the device should - * always remain in D0 regardless of the runtime PM status + * If pci_dev->driver is not set (unbound), we leave the device in D0, + * but it may go to D3cold when the bridge above it runtime suspends. + * Save its config space in case that happens. */ - if (!pci_dev->driver) + if (!pci_dev->driver) { + pci_save_state(pci_dev); return 0; + } if (!pm || !pm->runtime_suspend) return -ENOSYS; @@ -1276,16 +1279,18 @@ static int pci_pm_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; /* - * If pci_dev->driver is not set (unbound), the device should - * always remain in D0 regardless of the runtime PM status + * Restoring config space is necessary even if the device is not bound + * to a driver because although we left it in D0, it may have gone to + * D3cold when the bridge above it runtime suspended. */ + pci_restore_standard_config(pci_dev); + if (!pci_dev->driver) return 0; if (!pm || !pm->runtime_resume) return -ENOSYS; - pci_restore_standard_config(pci_dev); pci_fixup_device(pci_fixup_resume_early, pci_dev); pci_enable_wake(pci_dev, PCI_D0, false); pci_fixup_device(pci_fixup_resume, pci_dev); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f6a4dd10d9b0..bd6f156dc3cf 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -800,7 +800,7 @@ static int pci_wakeup(struct pci_dev *pci_dev, void *ign) * pci_wakeup_bus - Walk given bus and wake up devices on it * @bus: Top bus of the subtree to walk. */ -static void pci_wakeup_bus(struct pci_bus *bus) +void pci_wakeup_bus(struct pci_bus *bus) { if (bus) pci_walk_bus(bus, pci_wakeup, NULL); @@ -850,11 +850,11 @@ static int __pci_dev_set_current_state(struct pci_dev *dev, void *data) } /** - * __pci_bus_set_current_state - Walk given bus and set current state of devices + * pci_bus_set_current_state - Walk given bus and set current state of devices * @bus: Top bus of the subtree to walk. * @state: state to be set */ -static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state) +void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state) { if (bus) pci_walk_bus(bus, __pci_dev_set_current_state, &state); @@ -876,7 +876,7 @@ int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state) ret = pci_platform_power_transition(dev, state); /* Power off the bridge may power off the whole hierarchy */ if (!ret && state == PCI_D3cold) - __pci_bus_set_current_state(dev->subordinate, PCI_D3cold); + pci_bus_set_current_state(dev->subordinate, PCI_D3cold); return ret; } EXPORT_SYMBOL_GPL(__pci_complete_power_transition); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index fc734014206f..ec582d37c189 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -26,6 +26,7 @@ #include <linux/ktime.h> #include <linux/mm.h> #include <linux/platform_data/x86/apple.h> +#include <linux/pm_runtime.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include "pci.h" @@ -4832,3 +4833,41 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev) pdev->no_msi = 1; } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi); + +/* + * GPUs with integrated HDA controller for streaming audio to attached displays + * need a device link from the HDA controller (consumer) to the GPU (supplier) + * so that the GPU is powered up whenever the HDA controller is accessed. + * The GPU and HDA controller are functions 0 and 1 of the same PCI device. + * The device link stays in place until shutdown (or removal of the PCI device + * if it's hotplugged). Runtime PM is allowed by default on the HDA controller + * to prevent it from permanently keeping the GPU awake. + */ +static void quirk_gpu_hda(struct pci_dev *hda) +{ + struct pci_dev *gpu; + + if (PCI_FUNC(hda->devfn) != 1) + return; + + gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus), + hda->bus->number, + PCI_DEVFN(PCI_SLOT(hda->devfn), 0)); + if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) { + pci_dev_put(gpu); + return; + } + + if (!device_link_add(&hda->dev, &gpu->dev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) + pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu)); + + pm_runtime_allow(&hda->dev); + pci_dev_put(gpu); +} +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID, + PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID, + PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c index 2c7daa3d0f24..548edb7c494b 100644 --- a/drivers/staging/vboxvideo/vbox_ttm.c +++ b/drivers/staging/vboxvideo/vbox_ttm.c @@ -193,8 +193,7 @@ static struct ttm_backend_func vbox_tt_backend_func = { .destroy = &vbox_ttm_backend_destroy, }; -static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, +static struct ttm_tt *vbox_ttm_tt_create(struct ttm_buffer_object *bo, u32 page_flags) { struct ttm_tt *tt; @@ -204,7 +203,7 @@ static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev, return NULL; tt->func = &vbox_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags)) { + if (ttm_tt_init(tt, bo, page_flags)) { kfree(tt); return NULL; } diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 711fff9b6803..e9a1116d2f8e 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -41,7 +41,7 @@ struct analogix_dp_plat_data { struct drm_connector *); }; -int analogix_dp_psr_supported(struct analogix_dp_device *dp); +int analogix_dp_psr_enabled(struct analogix_dp_device *dp); int analogix_dp_enable_psr(struct analogix_dp_device *dp); int analogix_dp_disable_psr(struct analogix_dp_device *dp); diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index b3b6d302ca8c..44f04233e3db 100644 --- a/include/drm/drm_color_mgmt.h +++ b/include/drm/drm_color_mgmt.h @@ -38,6 +38,18 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size); +/** + * drm_color_lut_size - calculate the number of entries in the LUT + * @blob: blob containing the LUT + * + * Returns: + * The number of entries in the color LUT stored in @blob. + */ +static inline int drm_color_lut_size(const struct drm_property_blob *blob) +{ + return blob->length / sizeof(struct drm_color_lut); +} + enum drm_color_encoding { DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_BT709, diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 4de97e94ef9d..62903bae0221 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -288,6 +288,7 @@ #define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ # define DP_PSR_IS_SUPPORTED 1 # define DP_PSR2_IS_SUPPORTED 2 /* eDP 1.4 */ +# define DP_PSR2_WITH_Y_COORD_IS_SUPPORTED 3 /* eDP 1.4a */ #define DP_PSR_CAPS 0x071 /* XXX 1.2? */ # define DP_PSR_NO_TRAIN_ON_EXIT 1 diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h index 7ba3913f30b5..c34a3e8030e1 100644 --- a/include/drm/drm_mode_object.h +++ b/include/drm/drm_mode_object.h @@ -120,30 +120,6 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, void drm_mode_object_get(struct drm_mode_object *obj); void drm_mode_object_put(struct drm_mode_object *obj); -/** - * drm_mode_object_reference - acquire a mode object reference - * @obj: DRM mode object - * - * This is a compatibility alias for drm_mode_object_get() and should not be - * used by new code. - */ -static inline void drm_mode_object_reference(struct drm_mode_object *obj) -{ - drm_mode_object_get(obj); -} - -/** - * drm_mode_object_unreference - release a mode object reference - * @obj: DRM mode object - * - * This is a compatibility alias for drm_mode_object_put() and should not be - * used by new code. - */ -static inline void drm_mode_object_unreference(struct drm_mode_object *obj) -{ - drm_mode_object_put(obj); -} - int drm_object_property_set_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t val); diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 2a4a42e59a47..e1a46e9991cc 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -196,21 +196,22 @@ static inline struct drm_printer drm_debug_printer(const char *prefix) #define DRM_UT_STATE 0x40 #define DRM_UT_LEASE 0x80 -__printf(6, 7) +__printf(3, 4) void drm_dev_printk(const struct device *dev, const char *level, - unsigned int category, const char *function_name, - const char *prefix, const char *format, ...); + const char *format, ...); __printf(3, 4) -void drm_printk(const char *level, unsigned int category, - const char *format, ...); +void drm_dev_dbg(const struct device *dev, unsigned int category, + const char *format, ...); + +__printf(2, 3) +void drm_dbg(unsigned int category, const char *format, ...); +__printf(1, 2) +void drm_err(const char *format, ...); /* Macros to make printk easier */ #define _DRM_PRINTK(once, level, fmt, ...) \ - do { \ - printk##once(KERN_##level "[" DRM_NAME "] " fmt, \ - ##__VA_ARGS__); \ - } while (0) + printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__) #define DRM_INFO(fmt, ...) \ _DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__) @@ -233,10 +234,9 @@ void drm_printk(const char *level, unsigned int category, * @fmt: printf() like format string. */ #define DRM_DEV_ERROR(dev, fmt, ...) \ - drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\ - fmt, ##__VA_ARGS__) + drm_dev_printk(dev, KERN_ERR, "*ERROR* " fmt, ##__VA_ARGS__) #define DRM_ERROR(fmt, ...) \ - drm_printk(KERN_ERR, DRM_UT_NONE, fmt, ##__VA_ARGS__) + drm_err(fmt, ##__VA_ARGS__) /** * Rate limited error output. Like DRM_ERROR() but won't flood the log. @@ -257,8 +257,7 @@ void drm_printk(const char *level, unsigned int category, DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__) #define DRM_DEV_INFO(dev, fmt, ...) \ - drm_dev_printk(dev, KERN_INFO, DRM_UT_NONE, __func__, "", fmt, \ - ##__VA_ARGS__) + drm_dev_printk(dev, KERN_INFO, fmt, ##__VA_ARGS__) #define DRM_DEV_INFO_ONCE(dev, fmt, ...) \ ({ \ @@ -275,53 +274,46 @@ void drm_printk(const char *level, unsigned int category, * @dev: device pointer * @fmt: printf() like format string. */ -#define DRM_DEV_DEBUG(dev, fmt, args...) \ - drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \ - ##args) +#define DRM_DEV_DEBUG(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_CORE, fmt, ##__VA_ARGS__) #define DRM_DEBUG(fmt, ...) \ - drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__) + drm_dbg(DRM_UT_CORE, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...) \ - drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "", \ - fmt, ##args) +#define DRM_DEV_DEBUG_DRIVER(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) #define DRM_DEBUG_DRIVER(fmt, ...) \ - drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) + drm_dbg(DRM_UT_DRIVER, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_KMS(dev, fmt, args...) \ - drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, \ - ##args) -#define DRM_DEBUG_KMS(fmt, ...) \ - drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__) +#define DRM_DEV_DEBUG_KMS(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_KMS, fmt, ##__VA_ARGS__) +#define DRM_DEBUG_KMS(fmt, ...) \ + drm_dbg(DRM_UT_KMS, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_PRIME(dev, fmt, args...) \ - drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "", \ - fmt, ##args) +#define DRM_DEV_DEBUG_PRIME(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__) #define DRM_DEBUG_PRIME(fmt, ...) \ - drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__) + drm_dbg(DRM_UT_PRIME, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...) \ - drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", \ - fmt, ##args) +#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) #define DRM_DEBUG_ATOMIC(fmt, ...) \ - drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) + drm_dbg(DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_VBL(dev, fmt, args...) \ - drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, \ - ##args) -#define DRM_DEBUG_VBL(fmt, ...) \ - drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__) +#define DRM_DEV_DEBUG_VBL(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_VBL, fmt, ##__VA_ARGS__) +#define DRM_DEBUG_VBL(fmt, ...) \ + drm_dbg(DRM_UT_VBL, fmt, ##__VA_ARGS__) #define DRM_DEBUG_LEASE(fmt, ...) \ - drm_printk(KERN_DEBUG, DRM_UT_LEASE, fmt, ##__VA_ARGS__) + drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__) -#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...) \ +#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \ ({ \ static DEFINE_RATELIMIT_STATE(_rs, \ DEFAULT_RATELIMIT_INTERVAL, \ DEFAULT_RATELIMIT_BURST); \ if (__ratelimit(&_rs)) \ - drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ ## level, \ - __func__, "", fmt, ##args); \ + drm_dev_dbg(dev, category, fmt, ##__VA_ARGS__); \ }) /** @@ -330,21 +322,28 @@ void drm_printk(const char *level, unsigned int category, * @dev: device pointer * @fmt: printf() like format string. */ -#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, args...) \ - DEV__DRM_DEFINE_DEBUG_RATELIMITED(dev, CORE, fmt, ##args) -#define DRM_DEBUG_RATELIMITED(fmt, args...) \ - DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##args) -#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, args...) \ - _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRIVER, fmt, ##args) -#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, args...) \ - DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##args) -#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, args...) \ - _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, KMS, fmt, ##args) -#define DRM_DEBUG_KMS_RATELIMITED(fmt, args...) \ - DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##args) -#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, args...) \ - _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, PRIME, fmt, ##args) -#define DRM_DEBUG_PRIME_RATELIMITED(fmt, args...) \ - DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##args) +#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, ...) \ + _DEV_DRM_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_CORE, \ + fmt, ##__VA_ARGS__) +#define DRM_DEBUG_RATELIMITED(fmt, ...) \ + DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + +#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, ...) \ + _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_DRIVER, \ + fmt, ##__VA_ARGS__) +#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, ...) \ + DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + +#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, ...) \ + _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_KMS, \ + fmt, ##__VA_ARGS__) +#define DRM_DEBUG_KMS_RATELIMITED(fmt, ...) \ + DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + +#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, ...) \ + _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME, \ + fmt, ##__VA_ARGS__) +#define DRM_DEBUG_PRIME_RATELIMITED(fmt, ...) \ + DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##__VA_ARGS__) #endif /* DRM_PRINT_H_ */ diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index 937757a8a568..d1423c7f3c73 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -209,7 +209,7 @@ struct drm_property_blob { struct list_head head_global; struct list_head head_file; size_t length; - unsigned char data[]; + void *data; }; struct drm_prop_enum_list { diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 8e2fb1ac4e0c..c67977aa1a0e 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -709,6 +709,10 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo); int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, struct ttm_bo_device *bdev); +void *ttm_kmap_atomic_prot(struct page *page, pgprot_t prot); + +void ttm_kunmap_atomic_prot(void *addr, pgprot_t prot); + /** * ttm_bo_io * diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 4312b5326f0b..3234cc322e70 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -42,111 +42,10 @@ #include "ttm_memory.h" #include "ttm_module.h" #include "ttm_placement.h" +#include "ttm_tt.h" #define TTM_MAX_BO_PRIORITY 4U -struct ttm_backend_func { - /** - * struct ttm_backend_func member bind - * - * @ttm: Pointer to a struct ttm_tt. - * @bo_mem: Pointer to a struct ttm_mem_reg describing the - * memory type and location for binding. - * - * Bind the backend pages into the aperture in the location - * indicated by @bo_mem. This function should be able to handle - * differences between aperture and system page sizes. - */ - int (*bind) (struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem); - - /** - * struct ttm_backend_func member unbind - * - * @ttm: Pointer to a struct ttm_tt. - * - * Unbind previously bound backend pages. This function should be - * able to handle differences between aperture and system page sizes. - */ - int (*unbind) (struct ttm_tt *ttm); - - /** - * struct ttm_backend_func member destroy - * - * @ttm: Pointer to a struct ttm_tt. - * - * Destroy the backend. This will be call back from ttm_tt_destroy so - * don't call ttm_tt_destroy from the callback or infinite loop. - */ - void (*destroy) (struct ttm_tt *ttm); -}; - -#define TTM_PAGE_FLAG_WRITE (1 << 3) -#define TTM_PAGE_FLAG_SWAPPED (1 << 4) -#define TTM_PAGE_FLAG_PERSISTENT_SWAP (1 << 5) -#define TTM_PAGE_FLAG_ZERO_ALLOC (1 << 6) -#define TTM_PAGE_FLAG_DMA32 (1 << 7) -#define TTM_PAGE_FLAG_SG (1 << 8) -#define TTM_PAGE_FLAG_NO_RETRY (1 << 9) - -enum ttm_caching_state { - tt_uncached, - tt_wc, - tt_cached -}; - -/** - * struct ttm_tt - * - * @bdev: Pointer to a struct ttm_bo_device. - * @func: Pointer to a struct ttm_backend_func that describes - * the backend methods. - * pointer. - * @pages: Array of pages backing the data. - * @num_pages: Number of pages in the page array. - * @bdev: Pointer to the current struct ttm_bo_device. - * @be: Pointer to the ttm backend. - * @swap_storage: Pointer to shmem struct file for swap storage. - * @caching_state: The current caching state of the pages. - * @state: The current binding state of the pages. - * - * This is a structure holding the pages, caching- and aperture binding - * status for a buffer object that isn't backed by fixed (VRAM / AGP) - * memory. - */ - -struct ttm_tt { - struct ttm_bo_device *bdev; - struct ttm_backend_func *func; - struct page **pages; - uint32_t page_flags; - unsigned long num_pages; - struct sg_table *sg; /* for SG objects via dma-buf */ - struct file *swap_storage; - enum ttm_caching_state caching_state; - enum { - tt_bound, - tt_unbound, - tt_unpopulated, - } state; -}; - -/** - * struct ttm_dma_tt - * - * @ttm: Base ttm_tt struct. - * @dma_address: The DMA (bus) addresses of the pages - * @pages_list: used by some page allocation backend - * - * This is a structure holding the pages, caching- and aperture binding - * status for a buffer object that isn't backed by fixed (VRAM / AGP) - * memory. - */ -struct ttm_dma_tt { - struct ttm_tt ttm; - dma_addr_t *dma_address; - struct list_head pages_list; -}; - #define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */ #define TTM_MEMTYPE_FLAG_MAPPABLE (1 << 1) /* Memory mappable */ #define TTM_MEMTYPE_FLAG_CMA (1 << 3) /* Can't map aperture */ @@ -326,8 +225,7 @@ struct ttm_bo_driver { /** * ttm_tt_create * - * @bdev: pointer to a struct ttm_bo_device: - * @size: Size of the data needed backing. + * @bo: The buffer object to create the ttm for. * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. * * Create a struct ttm_tt to back data with system memory pages. @@ -335,8 +233,7 @@ struct ttm_bo_driver { * Returns: * NULL: Out of memory. */ - struct ttm_tt *(*ttm_tt_create)(struct ttm_bo_device *bdev, - unsigned long size, + struct ttm_tt *(*ttm_tt_create)(struct ttm_buffer_object *bo, uint32_t page_flags); /** @@ -610,117 +507,6 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask) return *old; } -/** - * ttm_tt_create - * - * @bo: pointer to a struct ttm_buffer_object - * @zero_alloc: true if allocated pages needs to be zeroed - * - * Make sure we have a TTM structure allocated for the given BO. - * No pages are actually allocated. - */ -int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc); - -/** - * ttm_tt_init - * - * @ttm: The struct ttm_tt. - * @bdev: pointer to a struct ttm_bo_device: - * @size: Size of the data needed backing. - * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. - * - * Create a struct ttm_tt to back data with system memory pages. - * No pages are actually allocated. - * Returns: - * NULL: Out of memory. - */ -int ttm_tt_init(struct ttm_tt *ttm, struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags); -int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags); - -/** - * ttm_tt_fini - * - * @ttm: the ttm_tt structure. - * - * Free memory of ttm_tt structure - */ -void ttm_tt_fini(struct ttm_tt *ttm); -void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma); - -/** - * ttm_ttm_bind: - * - * @ttm: The struct ttm_tt containing backing pages. - * @bo_mem: The struct ttm_mem_reg identifying the binding location. - * - * Bind the pages of @ttm to an aperture location identified by @bo_mem - */ -int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem, - struct ttm_operation_ctx *ctx); - -/** - * ttm_ttm_destroy: - * - * @ttm: The struct ttm_tt. - * - * Unbind, unpopulate and destroy common struct ttm_tt. - */ -void ttm_tt_destroy(struct ttm_tt *ttm); - -/** - * ttm_ttm_unbind: - * - * @ttm: The struct ttm_tt. - * - * Unbind a struct ttm_tt. - */ -void ttm_tt_unbind(struct ttm_tt *ttm); - -/** - * ttm_tt_swapin: - * - * @ttm: The struct ttm_tt. - * - * Swap in a previously swap out ttm_tt. - */ -int ttm_tt_swapin(struct ttm_tt *ttm); - -/** - * ttm_tt_set_placement_caching: - * - * @ttm A struct ttm_tt the backing pages of which will change caching policy. - * @placement: Flag indicating the desired caching policy. - * - * This function will change caching policy of any default kernel mappings of - * the pages backing @ttm. If changing from cached to uncached or - * write-combined, - * all CPU caches will first be flushed to make sure the data of the pages - * hit RAM. This function may be very costly as it involves global TLB - * and cache flushes and potential page splitting / combining. - */ -int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement); -int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage); - -/** - * ttm_tt_populate - allocate pages for a ttm - * - * @ttm: Pointer to the ttm_tt structure - * - * Calls the driver method to allocate pages for a ttm - */ -int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx); - -/** - * ttm_tt_unpopulate - free pages from a ttm - * - * @ttm: Pointer to the ttm_tt structure - * - * Calls the driver method to free all pages from a ttm - */ -void ttm_tt_unpopulate(struct ttm_tt *ttm); - /* * ttm_bo.c */ @@ -1062,6 +848,15 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem); /** + * ttm_bo_pipeline_gutting. + * + * @bo: A pointer to a struct ttm_buffer_object. + * + * Pipelined gutting a BO of it's backing store. + */ +int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo); + +/** * ttm_io_prot * * @c_state: Caching state. @@ -1074,27 +869,4 @@ pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp); extern const struct ttm_mem_type_manager_func ttm_bo_manager_func; -#if IS_ENABLED(CONFIG_AGP) -#include <linux/agp_backend.h> - -/** - * ttm_agp_tt_create - * - * @bdev: Pointer to a struct ttm_bo_device. - * @bridge: The agp bridge this device is sitting on. - * @size: Size of the data needed backing. - * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. - * - * - * Create a TTM backend that uses the indicated AGP bridge as an aperture - * for TT memory. This function uses the linux agpgart interface to - * bind and unbind memory backing a ttm_tt. - */ -struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev, - struct agp_bridge_data *bridge, - unsigned long size, uint32_t page_flags); -int ttm_agp_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx); -void ttm_agp_tt_unpopulate(struct ttm_tt *ttm); -#endif - #endif diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h new file mode 100644 index 000000000000..c0e928abf592 --- /dev/null +++ b/include/drm/ttm/ttm_tt.h @@ -0,0 +1,272 @@ +/************************************************************************** + * + * Copyright (c) 2006-2009 Vmware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +#ifndef _TTM_TT_H_ +#define _TTM_TT_H_ + +#include <linux/types.h> + +struct ttm_tt; +struct ttm_mem_reg; +struct ttm_buffer_object; +struct ttm_operation_ctx; + +#define TTM_PAGE_FLAG_WRITE (1 << 3) +#define TTM_PAGE_FLAG_SWAPPED (1 << 4) +#define TTM_PAGE_FLAG_PERSISTENT_SWAP (1 << 5) +#define TTM_PAGE_FLAG_ZERO_ALLOC (1 << 6) +#define TTM_PAGE_FLAG_DMA32 (1 << 7) +#define TTM_PAGE_FLAG_SG (1 << 8) +#define TTM_PAGE_FLAG_NO_RETRY (1 << 9) + +enum ttm_caching_state { + tt_uncached, + tt_wc, + tt_cached +}; + +struct ttm_backend_func { + /** + * struct ttm_backend_func member bind + * + * @ttm: Pointer to a struct ttm_tt. + * @bo_mem: Pointer to a struct ttm_mem_reg describing the + * memory type and location for binding. + * + * Bind the backend pages into the aperture in the location + * indicated by @bo_mem. This function should be able to handle + * differences between aperture and system page sizes. + */ + int (*bind) (struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem); + + /** + * struct ttm_backend_func member unbind + * + * @ttm: Pointer to a struct ttm_tt. + * + * Unbind previously bound backend pages. This function should be + * able to handle differences between aperture and system page sizes. + */ + int (*unbind) (struct ttm_tt *ttm); + + /** + * struct ttm_backend_func member destroy + * + * @ttm: Pointer to a struct ttm_tt. + * + * Destroy the backend. This will be call back from ttm_tt_destroy so + * don't call ttm_tt_destroy from the callback or infinite loop. + */ + void (*destroy) (struct ttm_tt *ttm); +}; + +/** + * struct ttm_tt + * + * @bdev: Pointer to a struct ttm_bo_device. + * @func: Pointer to a struct ttm_backend_func that describes + * the backend methods. + * pointer. + * @pages: Array of pages backing the data. + * @num_pages: Number of pages in the page array. + * @bdev: Pointer to the current struct ttm_bo_device. + * @be: Pointer to the ttm backend. + * @swap_storage: Pointer to shmem struct file for swap storage. + * @caching_state: The current caching state of the pages. + * @state: The current binding state of the pages. + * + * This is a structure holding the pages, caching- and aperture binding + * status for a buffer object that isn't backed by fixed (VRAM / AGP) + * memory. + */ +struct ttm_tt { + struct ttm_bo_device *bdev; + struct ttm_backend_func *func; + struct page **pages; + uint32_t page_flags; + unsigned long num_pages; + struct sg_table *sg; /* for SG objects via dma-buf */ + struct file *swap_storage; + enum ttm_caching_state caching_state; + enum { + tt_bound, + tt_unbound, + tt_unpopulated, + } state; +}; + +/** + * struct ttm_dma_tt + * + * @ttm: Base ttm_tt struct. + * @dma_address: The DMA (bus) addresses of the pages + * @pages_list: used by some page allocation backend + * + * This is a structure holding the pages, caching- and aperture binding + * status for a buffer object that isn't backed by fixed (VRAM / AGP) + * memory. + */ +struct ttm_dma_tt { + struct ttm_tt ttm; + dma_addr_t *dma_address; + struct list_head pages_list; +}; + +/** + * ttm_tt_create + * + * @bo: pointer to a struct ttm_buffer_object + * @zero_alloc: true if allocated pages needs to be zeroed + * + * Make sure we have a TTM structure allocated for the given BO. + * No pages are actually allocated. + */ +int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc); + +/** + * ttm_tt_init + * + * @ttm: The struct ttm_tt. + * @bo: The buffer object we create the ttm for. + * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. + * + * Create a struct ttm_tt to back data with system memory pages. + * No pages are actually allocated. + * Returns: + * NULL: Out of memory. + */ +int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo, + uint32_t page_flags); +int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_buffer_object *bo, + uint32_t page_flags); +int ttm_sg_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_buffer_object *bo, + uint32_t page_flags); + +/** + * ttm_tt_fini + * + * @ttm: the ttm_tt structure. + * + * Free memory of ttm_tt structure + */ +void ttm_tt_fini(struct ttm_tt *ttm); +void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma); + +/** + * ttm_ttm_bind: + * + * @ttm: The struct ttm_tt containing backing pages. + * @bo_mem: The struct ttm_mem_reg identifying the binding location. + * + * Bind the pages of @ttm to an aperture location identified by @bo_mem + */ +int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem, + struct ttm_operation_ctx *ctx); + +/** + * ttm_ttm_destroy: + * + * @ttm: The struct ttm_tt. + * + * Unbind, unpopulate and destroy common struct ttm_tt. + */ +void ttm_tt_destroy(struct ttm_tt *ttm); + +/** + * ttm_ttm_unbind: + * + * @ttm: The struct ttm_tt. + * + * Unbind a struct ttm_tt. + */ +void ttm_tt_unbind(struct ttm_tt *ttm); + +/** + * ttm_tt_swapin: + * + * @ttm: The struct ttm_tt. + * + * Swap in a previously swap out ttm_tt. + */ +int ttm_tt_swapin(struct ttm_tt *ttm); + +/** + * ttm_tt_set_placement_caching: + * + * @ttm A struct ttm_tt the backing pages of which will change caching policy. + * @placement: Flag indicating the desired caching policy. + * + * This function will change caching policy of any default kernel mappings of + * the pages backing @ttm. If changing from cached to uncached or + * write-combined, + * all CPU caches will first be flushed to make sure the data of the pages + * hit RAM. This function may be very costly as it involves global TLB + * and cache flushes and potential page splitting / combining. + */ +int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement); +int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage); + +/** + * ttm_tt_populate - allocate pages for a ttm + * + * @ttm: Pointer to the ttm_tt structure + * + * Calls the driver method to allocate pages for a ttm + */ +int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx); + +/** + * ttm_tt_unpopulate - free pages from a ttm + * + * @ttm: Pointer to the ttm_tt structure + * + * Calls the driver method to free all pages from a ttm + */ +void ttm_tt_unpopulate(struct ttm_tt *ttm); + +#if IS_ENABLED(CONFIG_AGP) +#include <linux/agp_backend.h> + +/** + * ttm_agp_tt_create + * + * @bo: Buffer object we allocate the ttm for. + * @bridge: The agp bridge this device is sitting on. + * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. + * + * + * Create a TTM backend that uses the indicated AGP bridge as an aperture + * for TT memory. This function uses the linux agpgart interface to + * bind and unbind memory backing a ttm_tt. + */ +struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo, + struct agp_bridge_data *bridge, + uint32_t page_flags); +int ttm_agp_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx); +void ttm_agp_tt_unpopulate(struct ttm_tt *ttm); +#endif + +#endif diff --git a/include/linux/pci.h b/include/linux/pci.h index 024a1beda008..ae42289662df 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1147,6 +1147,8 @@ void pci_pme_wakeup_bus(struct pci_bus *bus); void pci_d3cold_enable(struct pci_dev *dev); void pci_d3cold_disable(struct pci_dev *dev); bool pcie_relaxed_ordering_enabled(struct pci_dev *dev); +void pci_wakeup_bus(struct pci_bus *bus); +void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state); /* PCI Virtual Channel */ int pci_save_vc_state(struct pci_dev *dev); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index a6b30667a331..a637a7d8ce5b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -45,6 +45,7 @@ #define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400 #define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 #define PCI_CLASS_MULTIMEDIA_PHONE 0x0402 +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 #define PCI_CLASS_MULTIMEDIA_OTHER 0x0480 #define PCI_BASE_CLASS_MEMORY 0x05 diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h index 960bedbdec87..77f0f0af3a71 100644 --- a/include/linux/vga_switcheroo.h +++ b/include/linux/vga_switcheroo.h @@ -168,11 +168,8 @@ int vga_switcheroo_process_delayed_switch(void); bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev); enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev); -void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic); - int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain); void vga_switcheroo_fini_domain_pm_ops(struct device *dev); -int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain); #else static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {} @@ -192,11 +189,8 @@ static inline int vga_switcheroo_process_delayed_switch(void) { return 0; } static inline bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) { return false; } static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; } -static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {} - static inline int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; } static inline void vga_switcheroo_fini_domain_pm_ops(struct device *dev) {} -static inline int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; } #endif #endif /* _LINUX_VGA_SWITCHEROO_H_ */ diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 68169e3749de..5b2ed12f58ce 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -227,9 +227,6 @@ struct hdac_io_ops { #define HDA_UNSOL_QUEUE_SIZE 64 #define HDA_MAX_CODECS 8 /* limit by controller side */ -/* HD Audio class code */ -#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 - /* * CORB/RIRB * diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 1816bd8200d1..528f6d041e90 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -806,6 +806,7 @@ struct drm_amdgpu_info_firmware { #define AMDGPU_VRAM_TYPE_GDDR5 5 #define AMDGPU_VRAM_TYPE_HBM 6 #define AMDGPU_VRAM_TYPE_DDR3 7 +#define AMDGPU_VRAM_TYPE_DDR4 8 struct drm_amdgpu_info_device { /** PCI Device ID */ diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h index e9b997a0ef27..0d5c49dc478c 100644 --- a/include/uapi/drm/etnaviv_drm.h +++ b/include/uapi/drm/etnaviv_drm.h @@ -55,6 +55,12 @@ struct drm_etnaviv_timespec { #define ETNAVIV_PARAM_GPU_FEATURES_4 0x07 #define ETNAVIV_PARAM_GPU_FEATURES_5 0x08 #define ETNAVIV_PARAM_GPU_FEATURES_6 0x09 +#define ETNAVIV_PARAM_GPU_FEATURES_7 0x0a +#define ETNAVIV_PARAM_GPU_FEATURES_8 0x0b +#define ETNAVIV_PARAM_GPU_FEATURES_9 0x0c +#define ETNAVIV_PARAM_GPU_FEATURES_10 0x0d +#define ETNAVIV_PARAM_GPU_FEATURES_11 0x0e +#define ETNAVIV_PARAM_GPU_FEATURES_12 0x0f #define ETNAVIV_PARAM_GPU_STREAM_COUNT 0x10 #define ETNAVIV_PARAM_GPU_REGISTER_MAX 0x11 diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index bbbaffad772d..c06d0a5bdd80 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -201,10 +201,12 @@ struct drm_msm_gem_submit_bo { #define MSM_SUBMIT_NO_IMPLICIT 0x80000000 /* disable implicit sync */ #define MSM_SUBMIT_FENCE_FD_IN 0x40000000 /* enable input fence_fd */ #define MSM_SUBMIT_FENCE_FD_OUT 0x20000000 /* enable output fence_fd */ +#define MSM_SUBMIT_SUDO 0x10000000 /* run submitted cmds from RB */ #define MSM_SUBMIT_FLAGS ( \ MSM_SUBMIT_NO_IMPLICIT | \ MSM_SUBMIT_FENCE_FD_IN | \ MSM_SUBMIT_FENCE_FD_OUT | \ + MSM_SUBMIT_SUDO | \ 0) /* Each cmdstream submit consists of a table of buffers involved, and diff --git a/scripts/coccinelle/api/drm-get-put.cocci b/scripts/coccinelle/api/drm-get-put.cocci index 91fceb8f1fa2..ceb71ea7f61c 100644 --- a/scripts/coccinelle/api/drm-get-put.cocci +++ b/scripts/coccinelle/api/drm-get-put.cocci @@ -16,12 +16,6 @@ expression object; @@ ( -- drm_mode_object_reference(object) -+ drm_mode_object_get(object) -| -- drm_mode_object_unreference(object) -+ drm_mode_object_put(object) -| - drm_connector_reference(object) + drm_connector_get(object) | @@ -62,10 +56,6 @@ position p; @@ ( -drm_mode_object_unreference@p(object) -| -drm_mode_object_reference@p(object) -| drm_connector_unreference@p(object) | drm_connector_reference@p(object) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c71dcacea807..ec4e6b829ee2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1227,6 +1227,7 @@ static void azx_vs_set_state(struct pci_dev *pci, struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hda_codec *codec; bool disabled; wait_for_completion(&hda->probe_wait); @@ -1251,8 +1252,12 @@ static void azx_vs_set_state(struct pci_dev *pci, dev_info(chip->card->dev, "%s via vga_switcheroo\n", disabled ? "Disabling" : "Enabling"); if (disabled) { - pm_runtime_put_sync_suspend(card->dev); - azx_suspend(card->dev); + list_for_each_codec(codec, &chip->bus) { + pm_runtime_suspend(hda_codec_dev(codec)); + pm_runtime_disable(hda_codec_dev(codec)); + } + pm_runtime_suspend(card->dev); + pm_runtime_disable(card->dev); /* when we get suspended by vga_switcheroo we end up in D3cold, * however we have no ACPI handle, so pci/acpi can't put us there, * put ourselves there */ @@ -1263,9 +1268,12 @@ static void azx_vs_set_state(struct pci_dev *pci, "Cannot lock devices!\n"); } else { snd_hda_unlock_devices(&chip->bus); - pm_runtime_get_noresume(card->dev); chip->disabled = false; - azx_resume(card->dev); + pm_runtime_enable(card->dev); + list_for_each_codec(codec, &chip->bus) { + pm_runtime_enable(hda_codec_dev(codec)); + pm_runtime_resume(hda_codec_dev(codec)); + } } } } @@ -1295,6 +1303,7 @@ static void init_vga_switcheroo(struct azx *chip) dev_info(chip->card->dev, "Handle vga_switcheroo audio client\n"); hda->use_vga_switcheroo = 1; + chip->driver_caps |= AZX_DCAPS_PM_RUNTIME; pci_dev_put(p); } } @@ -1320,9 +1329,6 @@ static int register_vga_switcheroo(struct azx *chip) return err; hda->vga_switcheroo_registered = 1; - /* register as an optimus hdmi audio power domain */ - vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev, - &hda->hdmi_pm_domain); return 0; } #else @@ -1351,10 +1357,8 @@ static int azx_free(struct azx *chip) if (use_vga_switcheroo(hda)) { if (chip->disabled && hda->probe_continued) snd_hda_unlock_devices(&chip->bus); - if (hda->vga_switcheroo_registered) { + if (hda->vga_switcheroo_registered) vga_switcheroo_unregister_client(chip->pci); - vga_switcheroo_fini_domain_pm_ops(chip->card->dev); - } } if (bus->chip_init) { @@ -2197,6 +2201,7 @@ static int azx_probe_continue(struct azx *chip) struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct hdac_bus *bus = azx_bus(chip); struct pci_dev *pci = chip->pci; + struct hda_codec *codec; int dev = chip->dev_index; int err; @@ -2278,8 +2283,17 @@ static int azx_probe_continue(struct azx *chip) chip->running = 1; azx_add_card_list(chip); + + /* + * The discrete GPU cannot power down unless the HDA controller runtime + * suspends, so activate runtime PM on codecs even if power_save == 0. + */ + if (use_vga_switcheroo(hda)) + list_for_each_codec(codec, &chip->bus) + codec->auto_runtime_pm = 1; + snd_hda_set_power_save(&chip->bus, power_save * 1000); - if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) + if (azx_has_pm_runtime(chip)) pm_runtime_put_autosuspend(&pci->dev); out_free: diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index ff0c4d617bc1..e3a3d318d2e5 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -40,9 +40,6 @@ struct hda_intel { unsigned int vga_switcheroo_registered:1; unsigned int init_failed:1; /* delayed init failed */ - /* secondary power domain for hdmi audio under vga device */ - struct dev_pm_domain hdmi_pm_domain; - bool need_i915_power:1; /* the hda controller needs i915 power */ }; |