* Re: [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
@ 2024-05-21 7:18 ` Krzysztof Kozlowski
2024-05-21 8:03 ` Heiko Stübner
` (10 subsequent siblings)
11 siblings, 0 replies; 53+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-21 7:18 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel
On 21/05/2024 12:58, keith wrote:
> Verisilicon/DC8200 display controller IP has 2 display pipes and each
> pipe support a primary plane and a cursor plane .
> In addition, there are four overlay planes as two display pipes common resources.
>
> The first display pipe is bound to the inno HDMI encoder.
> The second display pipe is bound to a simple encoder, which is used to
> find dsi bridge by dts node.
>
> Patch 1 adds YAML schema for JH7110 display pipeline.
>
> Patches 2 to 3 add inno common api and match the ROCKCHIP inno hdmi driver
> by calling the common api.
> The collating public interface is based on ROCKCHIP inno hdmi,
> and it can be resused by JH7110 inno hdmi.
> Those common api are tested on rk-3128 SDK, which kernel version is 4.x.
> step1, make sure the process is consistent with the latest kernel version.
> step2, just remove the interface and add a common interface.
>
> Patches 4 to 8 add kms driver for dc8200 display controller.
>
> Patch 9 adds inno hdmi support for JH7110 display pipeline.
>
> Patch 10 adds a simple encoder.
>
> This patchset should be applied on next branch.
>
Please fix your clock, so this patchset does not appear +4h in the
future and on top of other patches...
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline
2024-05-21 10:58 ` [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline keith
@ 2024-05-21 7:30 ` Krzysztof Kozlowski
2024-05-21 9:50 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-21 7:30 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel
On 21/05/2024 12:58, keith wrote:
> JH7110 SoC display pipeline includes a display controller and hdmi.
> Dc controller IP : Vivante DC8200 Dual Display
> HDMI IP : INNOSILICON HDMI2.0
>
> As the INNO hdmi ip is also used by rockchip SoC in the driver code,
> the innosilicon,inno-hdmi.yaml schema containing the common properties
> for the INNO DesignWare HDMI TX controller isn't a full device
> tree binding specification, but is meant to be referenced by
> platform-specific bindings for the IP core.
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> .../display/bridge/innosilicon,inno-hdmi.yaml | 49 +++++
> .../display/rockchip/rockchip,inno-hdmi.yaml | 27 +--
> .../starfive/starfive,dsi-encoder.yaml | 92 ++++++++++
> .../starfive/starfive,jh7110-dc8200.yaml | 169 ++++++++++++++++++
> .../starfive/starfive,jh7110-inno-hdmi.yaml | 75 ++++++++
> .../soc/starfive/starfive,jh7110-syscon.yaml | 1 +
> MAINTAINERS | 8 +
> 7 files changed, 396 insertions(+), 25 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
>
> diff --git a/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
> new file mode 100644
> index 000000000000..8540174dcaeb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
> @@ -0,0 +1,49 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/bridge/innosilicon,inno-hdmi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Common Properties for Innosilicon HDMI TX IP
Your patch is difficult to review. Split changing existing bindings (and
defining common part) to a separate patch.
> +
> +maintainers:
> + - Keith Zhao <keith.zhao@starfivetech.com>
> +
> +description: |
> + This document defines device tree properties for the Innosilicon HDMI TX
Nothing improved here. Don't say obvious that this documents says
something. It cannot do anything else.
"Innosilicon HDMI TX is a foo bar device present on zap SoC ...."
> + controller (INNO HDMI) IP core. It doesn't constitute a full device tree
> + binding specification by itself but is meant to be referenced by device tree
> + bindings for the platform-specific integrations of the INNO HDMI.
I don't understand this at all. I don't know what is "full device tree
binding specification".
> +
> + When referenced from platform device tree bindings the properties defined in
> + this document are defined as follows. The platform device tree bindings are
> + responsible for defining whether each property is required or optional.
Nothing improved - drop paragraph.
> +
> +properties:
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> +
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/properties/port
> + description:
> + Port node with one endpoint connected to a display controller node.
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/properties/port
> + description:
> + Port node with one endpoint connected to a hdmi-connector node.
> +
> + required:
> + - port@0
> + - port@1
...
> diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
> new file mode 100644
> index 000000000000..07aa147a9db1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
> @@ -0,0 +1,92 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/starfive/starfive,dsi-encoder.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: starfive jh7110 SoC Encoder
> +
> +maintainers:
> + - Keith Zhao <keith.zhao@starfivetech.com>
> +
> +description:
> + Device-Tree bindings for simple encoder.
Again you ignored the comments.
When you receive a comment, apply it everywhere, not in only one part of
patch while keeping wrong code everywhere else.
> + Simple encoder driver only has basic functionality.
Not related to bindings, drop. This is about hardware, not your driver.
> + the hardware of dc8200 has 2 output interface, and uses
> + syscon to select which one to be used.
Nothing improved.
Read my previous comments:
1. Please make it a proper sentences, with proper wrapping.
> +
> +properties:
> + compatible:
> + const: starfive,dsi-encoder
> +
> + starfive,syscon:
> + $ref: /schemas/types.yaml#/definitions/phandle-array
> + items:
> + - items:
> + - description: phandle to syscon that select crtc output.
> + - description: Offset of crtc selection
> + - description: Shift of crtc selection
> + description:
> + A phandle to syscon with two arguments that configure select output.
> + The argument one is the offset of crtc selection, the
> + argument two is the shift of crtc selection.
Don't repeat constraints in free form text. Say something useful
instead, like what is its purpose.
No reg? Then why this is not just part of syscon? That's not a separate
device, no.
You received a feedback already about this: do not create fake bindings
just to instantiate your drivers.
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> +
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/properties/port
> + description:
> + The first port should be the input coming from the associated dc channel.
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/properties/port
> + description:
> + The second port should be the output coming from the associated bridge.
> +
> + required:
> + - port@0
> + - port@1
> +
> +required:
> + - compatible
> + - ports
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + dssctrl: dssctrl@295b0000 {
Drop node, not erlated.
> + compatible = "starfive,jh7110-vout-syscon", "syscon";
> + reg = <0x295b0000 0x90>;
> + };
> +
> + dsi_encoder: dsi_encoder {
Totally messed indentation. Use 4 spaces for example indentation.
Also, drop label.
Also, underscores are not allowed in node names.
Also, Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
This is terrible code.
> + compatible = "starfive,dsi-encoder";
> + starfive,syscon = <&dssctrl 0x8 0x12>;
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + /* input */
> + port@0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0>;
> + dsi_input0:endpoint@0 {
> + reg = <0>;
> + remote-endpoint = <&dc_out_dpi1>;
> + };
> + };
> + /* output */
> + port@1 {
> + reg = <1>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> + dsi_out:endpoint {
> + remote-endpoint = <&mipi_in>;
> + };
> + };
> + };
> + };
> diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
> new file mode 100644
> index 000000000000..a28dfdd471b6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
> @@ -0,0 +1,169 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/starfive/starfive,jh7110-dc8200.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: STARFIVE JH7110 SoC display controller
> +
> +description:
> + The STARFIVE JH7110 SoC uses the display controller based on Verisilicon IP(DC8200)
> + to transfer the image data from a video memory buffer to an external LCD interface.
> +
> + pipe0 binds HDMI for primary display,
> + pipe1 binds DSI for external display.
> +
> + +------------------------------+
> + | |
> + | |
> + +----+ | +-------------------+ | +-------+ +------+ +------+
> + | +----->+ dc controller 0 +--->----->+HDMICtl| ->+ PHY +-->+PANEL0+
> + |AXI | | +-------------------+ | +-------+ +------+ +------+
> + | | | |
> + | | | |
> + | | | |
> + | | | |
> + |APB | | +-------------------+ +---------+ +------+ +-------+
> + | +----->+ dc controller 1 +--->---->+ dsiTx +--->+DPHY +->+ PANEL1+
> + | | | +-------------------+ +---------+ +------+ +-------+
> + +----+ | |
> + +------------------------------+
> +
> +maintainers:
> + - Keith Zhao <keith.zhao@starfivetech.com>
> +
> +properties:
> + compatible:
> + const: starfive,jh7110-dc8200
> +
> + reg:
> + items:
> + - description: host interface address and length
> + - description: display physical base address and length
> +
> + reg-names:
> + items:
> + - const: host
> + - const: base
> +
> + clocks:
> + items:
> + - description: Clock for display system noc bus.
> + - description: Core clock for display controller.
> + - description: Clock for axi bus to access ddr.
> + - description: Clock for ahb bus to R/W the phy regs.
> + - description: Pixel clock for display channel 0.
> + - description: Pixel clock for display channel 1.
> + - description: Pixel clock from hdmi.
> + - description: Pixel clock for soc .
> +
> + clock-names:
> + items:
> + - const: noc_bus
> + - const: dc_core
> + - const: axi_core
> + - const: ahb
> + - const: channel0
> + - const: channel1
> + - const: hdmi_tx
> + - const: dc_parent
> +
> + resets:
> + items:
> + - description: Reset for axi bus.
> + - description: Reset for ahb bus.
> + - description: Core reset of display controller.
> +
> + reset-names:
> + items:
> + - const: axi
> + - const: ahb
> + - const: core
> +
> + interrupts:
> + items:
> + - description: The interrupt will be generated when DC finish one frame
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> +
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/properties/port
> + description:
> + channel 0 output
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/properties/port
> + description:
> + channel 1 output
> +
> + required:
> + - port@0
> + - port@1
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - clocks
> + - clock-names
> + - ports
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/starfive,jh7110-crg.h>
> + #include <dt-bindings/reset/starfive,jh7110-crg.h>
> + dc8200: lcd-controller@29400000 {
> + compatible = "starfive,jh7110-dc8200";
> + reg = <0x29400000 0x100>,
> + <0x29400800 0x2000>;
> + reg-names = "host", "base";
> +
> + interrupts = <95>;
> + clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_DISP_AXI>,
> + <&voutcrg JH7110_VOUTCLK_DC8200_CORE>,
Align the lines. In other places as well.
> + <&voutcrg JH7110_VOUTCLK_DC8200_AXI>,
> + <&voutcrg JH7110_VOUTCLK_DC8200_AHB>,
> + <&voutcrg JH7110_VOUTCLK_DC8200_PIX0>,
> + <&voutcrg JH7110_VOUTCLK_DC8200_PIX1>,
> + <&hdmitx0_pixelclk>,
> + <&voutcrg JH7110_VOUTCLK_DC8200_PIX>;
> + clock-names = "noc_bus", "dc_core", "axi_core", "ahb",
> + "channel0", "channel1", "hdmi_tx", "dc_parent";
> + resets = <&voutcrg JH7110_VOUTRST_DC8200_AXI>,
> + <&voutcrg JH7110_VOUTRST_DC8200_AHB>,
> + <&voutcrg JH7110_VOUTRST_DC8200_CORE>;
> + reset-names = "axi","ahb", "core";
> +
> + crtc_out: ports {
Totally messed indentation.
> diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
> new file mode 100644
> index 000000000000..bfd7dc41fc14
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
> @@ -0,0 +1,75 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/starfive/starfive,jh7110-inno-hdmi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Starfive JH7110 Innosilicon HDMI controller
> +
> +maintainers:
> + - Keith Zhao <keith.zhao@starfivetech.com>
> +
> +allOf:
> + - $ref: ../bridge/innosilicon,inno-hdmi.yaml#
> +
> +properties:
> + compatible:
> + const: "starfive,jh7110-inno-hdmi"
You did not test it. Drop quotes.
Untested bindings, so I will skip review for now.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
2024-05-21 7:18 ` Krzysztof Kozlowski
@ 2024-05-21 8:03 ` Heiko Stübner
2024-05-21 14:55 ` Alex Bee
2024-05-21 10:58 ` [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline keith
` (9 subsequent siblings)
11 siblings, 1 reply; 53+ messages in thread
From: Heiko Stübner @ 2024-05-21 8:03 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, keith, Alex Bee
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
Hi Alex,
Am Dienstag, 21. Mai 2024, 12:58:07 CEST schrieb keith:
> Verisilicon/DC8200 display controller IP has 2 display pipes and each
> pipe support a primary plane and a cursor plane .
> In addition, there are four overlay planes as two display pipes common resources.
>
> The first display pipe is bound to the inno HDMI encoder.
> The second display pipe is bound to a simple encoder, which is used to
> find dsi bridge by dts node.
>
> Patch 1 adds YAML schema for JH7110 display pipeline.
>
> Patches 2 to 3 add inno common api and match the ROCKCHIP inno hdmi driver
> by calling the common api.
> The collating public interface is based on ROCKCHIP inno hdmi,
> and it can be resused by JH7110 inno hdmi.
> Those common api are tested on rk-3128 SDK, which kernel version is 4.x.
as you were working on the rk3128-inno-hdmi variant recently
and I don't really have a rk3036 or rk3128 in working condition
right now, could you give this series a try.
For reference, the full series is at lore:
https://lore.kernel.org/dri-devel/20240521105817.3301-1-keith.zhao@starfivetech.com/
and generalizes the inno-hdmi driver into the bridge model we
have in a number of other places already.
Thanks
Heiko
> step1, make sure the process is consistent with the latest kernel version.
> step2, just remove the interface and add a common interface.
>
> Patches 4 to 8 add kms driver for dc8200 display controller.
>
> Patch 9 adds inno hdmi support for JH7110 display pipeline.
>
> Patch 10 adds a simple encoder.
>
> This patchset should be applied on next branch.
>
> V1:
> Changes since v1:
> - Further standardize the yaml file.
> - Dts naming convention improved.
> - Fix the problem of compiling and loading ko files.
> - Use drm new api to automatically manage resources.
> - Drop vs_crtc_funcs&vs_plane_funcs, subdivide the plane's help interface.
> - Reduce the modifiers unused.
> - Optimize the hdmi driver code
>
> V2:
> Changes since v2:
> - fix the error about checking the yaml file.
> - match drm driver GEM DMA API.
> - Delete the custom crtc property .
> - hdmi use drmm_ new api to automatically manage resources.
> - update the modifiers comments.
> - enabling KASAN, fix the error during removing module
>
> V3:
> Changes since v3:
> - Delete the custom plane property.
> - Delete the custom fourcc modifiers.
> - Adjust the calculation mode of hdmi pixclock.
> - Add match data for dc8200 driver.
> - Adjust some magic values.
> - Add a simple encoder for dsi output.
>
> V4:
> Changes since v4:
> - Delete the display subsystem module as all crtcs and planes are a driver.
> - Delete the custom struct, directly use the drm struct data.
> - Tidy up the inno hdmi public interface.
> - Add a simple encoder for dsi output.
>
> keith (10):
> dt-bindings: display: Add YAML schema for JH7110 display pipeline
> drm/bridge: add common api for inno hdmi
> drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver
> drm/vs: Add hardware funcs for vs.
> drm/vs: add vs mode config init
> drm/vs: add vs plane api
> drm/vs: add ctrc fun
> drm/vs: add vs drm master driver
> drm/vs: Innosilicon HDMI support
> drm/vs: add simple dsi encoder
>
> .../display/bridge/innosilicon,inno-hdmi.yaml | 49 +
> .../display/rockchip/rockchip,inno-hdmi.yaml | 27 +-
> .../starfive/starfive,dsi-encoder.yaml | 92 ++
> .../starfive/starfive,jh7110-dc8200.yaml | 169 +++
> .../starfive/starfive,jh7110-inno-hdmi.yaml | 75 ++
> .../soc/starfive/starfive,jh7110-syscon.yaml | 1 +
> MAINTAINERS | 11 +
> drivers/gpu/drm/Kconfig | 2 +
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/bridge/Kconfig | 2 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
> drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
> .../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 +++++++++
> .../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 ++
> drivers/gpu/drm/rockchip/Kconfig | 1 +
> drivers/gpu/drm/rockchip/Makefile | 2 +-
> drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++
> .../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 -
> drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 -----------------
> drivers/gpu/drm/verisilicon/Kconfig | 23 +
> drivers/gpu/drm/verisilicon/Makefile | 11 +
> .../gpu/drm/verisilicon/inno_hdmi-starfive.c | 481 ++++++++
> .../gpu/drm/verisilicon/inno_hdmi-starfive.h | 152 +++
> drivers/gpu/drm/verisilicon/vs_crtc.c | 241 ++++
> drivers/gpu/drm/verisilicon/vs_crtc.h | 17 +
> drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1060 ++++++++++++++++
> drivers/gpu/drm/verisilicon/vs_dc_hw.h | 493 ++++++++
> drivers/gpu/drm/verisilicon/vs_drv.c | 721 +++++++++++
> drivers/gpu/drm/verisilicon/vs_drv.h | 98 ++
> drivers/gpu/drm/verisilicon/vs_modeset.c | 36 +
> drivers/gpu/drm/verisilicon/vs_modeset.h | 10 +
> drivers/gpu/drm/verisilicon/vs_plane.c | 487 ++++++++
> drivers/gpu/drm/verisilicon/vs_plane.h | 26 +
> drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 +++
> drivers/gpu/drm/verisilicon/vs_simple_enc.h | 25 +
> drivers/gpu/drm/verisilicon/vs_type.h | 84 ++
> include/drm/bridge/inno_hdmi.h | 69 ++
> 38 files changed, 5840 insertions(+), 1144 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
> create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h} (85%)
> delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
> create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
> create mode 100644 drivers/gpu/drm/verisilicon/Makefile
> create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c
> create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
> create mode 100644 include/drm/bridge/inno_hdmi.h
>
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
2024-05-21 10:58 ` [PATCH v4 02/10] drm/bridge: add common api for inno hdmi keith
@ 2024-05-21 9:30 ` Krzysztof Kozlowski
2024-05-21 15:36 ` Alex Bee
2024-06-23 18:42 ` Markus Elfring
2 siblings, 0 replies; 53+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-21 9:30 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel
On 21/05/2024 12:58, keith wrote:
> Add INNO common api so that it can be used by vendor
> drivers which implement vendor specific extensions to Innosilicon HDMI.
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> MAINTAINERS | 2 +
> +}
> +
> +static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static const struct i2c_algorithm inno_hdmi_algorithm = {
> + .master_xfer = inno_hdmi_i2c_xfer,
> + .functionality = inno_hdmi_i2c_func,
> +};
> +
> +static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
> +{
> + struct i2c_adapter *adap;
> + struct inno_hdmi_i2c *i2c;
> + int ret;
> +
> + i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);
> + if (!i2c)
> + return ERR_PTR(-ENOMEM);
> +
> + mutex_init(&i2c->lock);
> + init_completion(&i2c->cmp);
> +
> + adap = &i2c->adap;
> + adap->owner = THIS_MODULE;
> + adap->dev.parent = hdmi->dev;
> + adap->dev.of_node = hdmi->dev->of_node;
> + adap->algo = &inno_hdmi_algorithm;
> + strscpy(adap->name, "Inno HDMI", sizeof(adap->name));
> + i2c_set_adapdata(adap, hdmi);
> +
> + ret = i2c_add_adapter(adap);
> + if (ret) {
> + dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
> + devm_kfree(hdmi->dev, i2c);
Hm, why freeing? That's a devm. You don't free other pieces in bind paths...
> + return ERR_PTR(ret);
> + }
> +
> + hdmi->i2c = i2c;
> +
> + DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name);
Please do not print simple success messages. Tracing tells you this and
driver should be quiet in typical cases.
You have also some weird tabs instead of spaces here and there... like
before 'encoder' arguments. This is needs some basic style check.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 09/10] drm/vs: Innosilicon HDMI support
2024-05-21 10:58 ` [PATCH v4 09/10] drm/vs: Innosilicon HDMI support keith
@ 2024-05-21 9:31 ` Krzysztof Kozlowski
0 siblings, 0 replies; 53+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-21 9:31 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel
On 21/05/2024 12:58, keith wrote:
> add inno hdmi driver which binds to vs display controller
> and this driver uses the commom api from the inno hdmi
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
...
> +static int starfive_hdmi_bind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct drm_device *drm = dev_get_drvdata(master);
> + struct stf_inno_hdmi *stf_hdmi;
> + struct inno_hdmi *hdmi;
> + struct resource *iores;
> +
> + int ret;
> + unsigned long long rate;
> +
> + stf_hdmi = drmm_simple_encoder_alloc(drm, struct stf_inno_hdmi,
> + encoder, DRM_MODE_ENCODER_TMDS);
> + hdmi = &stf_hdmi->inno_hdmi;
> +
> + hdmi->dev = dev;
> + hdmi->plat_data = (struct inno_hdmi_plat_data *)of_device_get_match_data(dev);
> +
> + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + hdmi->regs = devm_ioremap_resource(dev, iores);
There's a helper combining these two.
> + if (IS_ERR(hdmi->regs))
> + return PTR_ERR(hdmi->regs);
> +
> + ret = starfive_hdmi_get_clk_rst(dev, stf_hdmi);
> + if (ret < 0)
> + return ret;
> +
> + ret = starfive_hdmi_enable_clk_rst(dev, stf_hdmi);
> + if (ret)
> + return ret;
> +
> + rate = clk_get_rate(stf_hdmi->clk_hdmi[CLK_SYS].clk);
> + inno_hdmi_i2c_init(hdmi, rate);
> +
> + ret = inno_hdmi_bind(drm, hdmi, &stf_hdmi->encoder);
> + if (ret)
> + goto err_disable_clk;
> +
> + dev_set_drvdata(dev, stf_hdmi);
> +
> + return 0;
> +
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline
2024-05-21 7:30 ` Krzysztof Kozlowski
@ 2024-05-21 9:50 ` Keith Zhao
0 siblings, 0 replies; 53+ messages in thread
From: Keith Zhao @ 2024-05-21 9:50 UTC (permalink / raw)
To: Krzysztof Kozlowski, andrzej.hajda@intel.com,
neil.armstrong@linaro.org, rfoss@kernel.org,
Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se,
jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de,
andy.yan@rock-chips.com, Xingyu Wu, p.zabel@pengutronix.de,
Jack Zhu, Shengyang Chen
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Krzysztof:
> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: 2024年5月21日 15:30
> To: Keith Zhao <keith.zhao@starfivetech.com>; andrzej.hajda@intel.com;
> neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>
> Cc: dri-devel@lists.freedesktop.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110
> display pipeline
>
> On 21/05/2024 12:58, keith wrote:
> > JH7110 SoC display pipeline includes a display controller and hdmi.
> > Dc controller IP : Vivante DC8200 Dual Display HDMI IP : INNOSILICON
> > HDMI2.0
> >
> > As the INNO hdmi ip is also used by rockchip SoC in the driver code,
> > the innosilicon,inno-hdmi.yaml schema containing the common properties
> > for the INNO DesignWare HDMI TX controller isn't a full device tree
> > binding specification, but is meant to be referenced by
> > platform-specific bindings for the IP core.
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > ---
> > .../display/bridge/innosilicon,inno-hdmi.yaml | 49 +++++
> > .../display/rockchip/rockchip,inno-hdmi.yaml | 27 +--
> > .../starfive/starfive,dsi-encoder.yaml | 92 ++++++++++
> > .../starfive/starfive,jh7110-dc8200.yaml | 169 ++++++++++++++++++
> > .../starfive/starfive,jh7110-inno-hdmi.yaml | 75 ++++++++
> > .../soc/starfive/starfive,jh7110-syscon.yaml | 1 +
> > MAINTAINERS | 8 +
> > 7 files changed, 396 insertions(+), 25 deletions(-) create mode
> > 100644
> > Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi
> > .yaml create mode 100644
> > Documentation/devicetree/bindings/display/starfive/starfive,dsi-encode
> > r.yaml create mode 100644
> > Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8
> > 200.yaml create mode 100644
> > Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inn
> > o-hdmi.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hd
> > mi.yaml
> > b/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hd
> > mi.yaml
> > new file mode 100644
> > index 000000000000..8540174dcaeb
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/bridge/innosilicon,inn
> > +++ o-hdmi.yaml
> > @@ -0,0 +1,49 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/display/bridge/innosilicon,inno-hdmi.ya
> > +ml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Common Properties for Innosilicon HDMI TX IP
>
> Your patch is difficult to review. Split changing existing bindings (and defining
> common part) to a separate patch.
The background is that because the existing inno hdmi driver on the main line has some interfaces that can be public,
its yaml counterpart attempts to make a public reference file
>
> > +
> > +maintainers:
> > + - Keith Zhao <keith.zhao@starfivetech.com>
> > +
> > +description: |
> > + This document defines device tree properties for the Innosilicon
> > +HDMI TX
>
> Nothing improved here. Don't say obvious that this documents says something.
> It cannot do anything else.
>
> "Innosilicon HDMI TX is a foo bar device present on zap SoC ...."
>
>
> > + controller (INNO HDMI) IP core. It doesn't constitute a full device
> > + tree binding specification by itself but is meant to be referenced
> > + by device tree bindings for the platform-specific integrations of the INNO
> HDMI.
>
> I don't understand this at all. I don't know what is "full device tree binding
> specification".
>
> > +
> > + When referenced from platform device tree bindings the properties
> > + defined in this document are defined as follows. The platform
> > + device tree bindings are responsible for defining whether each property is
> required or optional.
>
> Nothing improved - drop paragraph.
These descriptions are based this file, and because their roles are close, only some key elements have been changed
of course, I will make corresponding modifications according to your remarks
https://elixir.bootlin.com/linux/v6.9/source/Documentation/devicetree/bindings/display/bridge/synopsys,dw-hdmi.yaml
>
> > +
> > +properties:
> > + reg:
> > + maxItems: 1
> > +
> > + interrupts:
> > + maxItems: 1
> > +
> > + ports:
> > + $ref: /schemas/graph.yaml#/properties/ports
> > +
> > + properties:
> > + port@0:
> > + $ref: /schemas/graph.yaml#/properties/port
> > + description:
> > + Port node with one endpoint connected to a display controller
> node.
> > +
> > + port@1:
> > + $ref: /schemas/graph.yaml#/properties/port
> > + description:
> > + Port node with one endpoint connected to a hdmi-connector
> node.
> > +
> > + required:
> > + - port@0
> > + - port@1
>
> ...
>
> > diff --git
> > a/Documentation/devicetree/bindings/display/starfive/starfive,dsi-enco
> > der.yaml
> > b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-enco
> > der.yaml
> > new file mode 100644
> > index 000000000000..07aa147a9db1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-
> > +++ encoder.yaml
> > @@ -0,0 +1,92 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/display/starfive/starfive,dsi-encoder.y
> > +aml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: starfive jh7110 SoC Encoder
> > +
> > +maintainers:
> > + - Keith Zhao <keith.zhao@starfivetech.com>
> > +
> > +description:
> > + Device-Tree bindings for simple encoder.
>
> Again you ignored the comments.
>
> When you receive a comment, apply it everywhere, not in only one part of patch
> while keeping wrong code everywhere else.
>
> > + Simple encoder driver only has basic functionality.
>
> Not related to bindings, drop. This is about hardware, not your driver.
>
> > + the hardware of dc8200 has 2 output interface, and uses syscon to
> > + select which one to be used.
>
> Nothing improved.
>
> Read my previous comments:
>
> 1. Please make it a proper sentences, with proper wrapping.
>
> > +
> > +properties:
> > + compatible:
> > + const: starfive,dsi-encoder
> > +
> > + starfive,syscon:
> > + $ref: /schemas/types.yaml#/definitions/phandle-array
> > + items:
> > + - items:
> > + - description: phandle to syscon that select crtc output.
> > + - description: Offset of crtc selection
> > + - description: Shift of crtc selection
> > + description:
> > + A phandle to syscon with two arguments that configure select
> output.
> > + The argument one is the offset of crtc selection, the
> > + argument two is the shift of crtc selection.
>
> Don't repeat constraints in free form text. Say something useful instead, like
> what is its purpose.
>
> No reg? Then why this is not just part of syscon? That's not a separate device,
> no.
>
> You received a feedback already about this: do not create fake bindings just to
> instantiate your drivers.
>
Yes , "do not create fake bindings just to instantiate your drivers." , I got this message ,
In lastest patchset, there was a display-subsystem dt-binding with no reg , I deleted it.
reg != syscon reg , got it .
I will restructure the code structure in the next version to meet this requirement,
so that this dts node can not be added, same with yaml file.
> > +
> > + ports:
> > + $ref: /schemas/graph.yaml#/properties/ports
> > +
> > + properties:
> > + port@0:
> > + $ref: /schemas/graph.yaml#/properties/port
> > + description:
> > + The first port should be the input coming from the associated dc
> channel.
> > +
> > + port@1:
> > + $ref: /schemas/graph.yaml#/properties/port
> > + description:
> > + The second port should be the output coming from the
> associated bridge.
> > +
> > + required:
> > + - port@0
> > + - port@1
> > +
> > +required:
> > + - compatible
> > + - ports
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + dssctrl: dssctrl@295b0000 {
>
> Drop node, not erlated.
>
> > + compatible = "starfive,jh7110-vout-syscon", "syscon";
> > + reg = <0x295b0000 0x90>;
> > + };
> > +
> > + dsi_encoder: dsi_encoder {
>
> Totally messed indentation. Use 4 spaces for example indentation.
>
> Also, drop label.
>
> Also, underscores are not allowed in node names.
>
> Also, Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-
> basics.html#generic-names-recommendation
>
> This is terrible code.
>
> > + compatible = "starfive,dsi-encoder";
> > + starfive,syscon = <&dssctrl 0x8 0x12>;
> > +
> > + ports {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + /* input */
> > + port@0 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + reg = <0>;
> > + dsi_input0:endpoint@0 {
> > + reg = <0>;
> > + remote-endpoint = <&dc_out_dpi1>;
> > + };
> > + };
> > + /* output */
> > + port@1 {
> > + reg = <1>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + dsi_out:endpoint {
> > + remote-endpoint = <&mipi_in>;
> > + };
> > + };
> > + };
> > + };
> > diff --git
> > a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-d
> > c8200.yaml
> > b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-d
> > c8200.yaml
> > new file mode 100644
> > index 000000000000..a28dfdd471b6
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh71
> > +++ 10-dc8200.yaml
> > @@ -0,0 +1,169 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/display/starfive/starfive,jh7110-dc8200
> > +.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: STARFIVE JH7110 SoC display controller
> > +
> > +description:
> > + The STARFIVE JH7110 SoC uses the display controller based on
> > +Verisilicon IP(DC8200)
> > + to transfer the image data from a video memory buffer to an external LCD
> interface.
> > +
> > + pipe0 binds HDMI for primary display,
> > + pipe1 binds DSI for external display.
> > +
> > + +------------------------------+
> > + | |
> > + | |
> > + +----+ | +-------------------+ | +-------+ +------+ +------+
> > + | +----->+ dc controller 0 +--->----->+HDMICtl| ->+ PHY
> +-->+PANEL0+
> > + |AXI | | +-------------------+ | +-------+ +------+ +------+
> > + | | | |
> > + | | | |
> > + | | | |
> > + | | | |
> > + |APB | | +-------------------+ +---------+ +------+ +-------+
> > + | +----->+ dc controller 1 +--->---->+ dsiTx +--->+DPHY +->+
> PANEL1+
> > + | | | +-------------------+ +---------+ +------+ +-------+
> > + +----+ | |
> > + +------------------------------+
> > +
> > +maintainers:
> > + - Keith Zhao <keith.zhao@starfivetech.com>
> > +
> > +properties:
> > + compatible:
> > + const: starfive,jh7110-dc8200
> > +
> > + reg:
> > + items:
> > + - description: host interface address and length
> > + - description: display physical base address and length
> > +
> > + reg-names:
> > + items:
> > + - const: host
> > + - const: base
> > +
> > + clocks:
> > + items:
> > + - description: Clock for display system noc bus.
> > + - description: Core clock for display controller.
> > + - description: Clock for axi bus to access ddr.
> > + - description: Clock for ahb bus to R/W the phy regs.
> > + - description: Pixel clock for display channel 0.
> > + - description: Pixel clock for display channel 1.
> > + - description: Pixel clock from hdmi.
> > + - description: Pixel clock for soc .
> > +
> > + clock-names:
> > + items:
> > + - const: noc_bus
> > + - const: dc_core
> > + - const: axi_core
> > + - const: ahb
> > + - const: channel0
> > + - const: channel1
> > + - const: hdmi_tx
> > + - const: dc_parent
> > +
> > + resets:
> > + items:
> > + - description: Reset for axi bus.
> > + - description: Reset for ahb bus.
> > + - description: Core reset of display controller.
> > +
> > + reset-names:
> > + items:
> > + - const: axi
> > + - const: ahb
> > + - const: core
> > +
> > + interrupts:
> > + items:
> > + - description: The interrupt will be generated when DC finish
> > + one frame
> > +
> > + ports:
> > + $ref: /schemas/graph.yaml#/properties/ports
> > +
> > + properties:
> > + port@0:
> > + $ref: /schemas/graph.yaml#/properties/port
> > + description:
> > + channel 0 output
> > +
> > + port@1:
> > + $ref: /schemas/graph.yaml#/properties/port
> > + description:
> > + channel 1 output
> > +
> > + required:
> > + - port@0
> > + - port@1
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - interrupts
> > + - clocks
> > + - clock-names
> > + - ports
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/clock/starfive,jh7110-crg.h>
> > + #include <dt-bindings/reset/starfive,jh7110-crg.h>
> > + dc8200: lcd-controller@29400000 {
> > + compatible = "starfive,jh7110-dc8200";
> > + reg = <0x29400000 0x100>,
> > + <0x29400800 0x2000>;
> > + reg-names = "host", "base";
> > +
> > + interrupts = <95>;
> > + clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_DISP_AXI>,
> > + <&voutcrg JH7110_VOUTCLK_DC8200_CORE>,
>
> Align the lines. In other places as well.
>
> > + <&voutcrg JH7110_VOUTCLK_DC8200_AXI>,
> > + <&voutcrg JH7110_VOUTCLK_DC8200_AHB>,
> > + <&voutcrg JH7110_VOUTCLK_DC8200_PIX0>,
> > + <&voutcrg JH7110_VOUTCLK_DC8200_PIX1>,
> > + <&hdmitx0_pixelclk>,
> > + <&voutcrg JH7110_VOUTCLK_DC8200_PIX>;
> > + clock-names = "noc_bus", "dc_core", "axi_core", "ahb",
> > + "channel0", "channel1", "hdmi_tx", "dc_parent";
> > + resets = <&voutcrg JH7110_VOUTRST_DC8200_AXI>,
> > + <&voutcrg JH7110_VOUTRST_DC8200_AHB>,
> > + <&voutcrg JH7110_VOUTRST_DC8200_CORE>;
> > + reset-names = "axi","ahb", "core";
> > +
> > + crtc_out: ports {
>
> Totally messed indentation.
>
>
> > diff --git
> > a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-i
> > nno-hdmi.yaml
> > b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-i
> > nno-hdmi.yaml
> > new file mode 100644
> > index 000000000000..bfd7dc41fc14
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh71
> > +++ 10-inno-hdmi.yaml
> > @@ -0,0 +1,75 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/display/starfive/starfive,jh7110-inno-h
> > +dmi.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Starfive JH7110 Innosilicon HDMI controller
> > +
> > +maintainers:
> > + - Keith Zhao <keith.zhao@starfivetech.com>
> > +
> > +allOf:
> > + - $ref: ../bridge/innosilicon,inno-hdmi.yaml#
> > +
> > +properties:
> > + compatible:
> > + const: "starfive,jh7110-inno-hdmi"
>
> You did not test it. Drop quotes.
>
> Untested bindings, so I will skip review for now.
In fact, I have used the check instruction, the result is pass with no warning, is there a difference in the command?
make -j8 dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/display/starfive/
......
DTEX Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.example.dts
DTEX Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.example.dts
DTEX Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.example.dts
DTC_CHK Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.example.dtb
DTC_CHK Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.example.dtb
DTC_CHK Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.example.dtb
Thanks for your remarks , I hope it does not affect your happy life
>
>
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi
@ 2024-05-21 10:58 keith
2024-05-21 7:18 ` Krzysztof Kozlowski
` (11 more replies)
0 siblings, 12 replies; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
Verisilicon/DC8200 display controller IP has 2 display pipes and each
pipe support a primary plane and a cursor plane .
In addition, there are four overlay planes as two display pipes common resources.
The first display pipe is bound to the inno HDMI encoder.
The second display pipe is bound to a simple encoder, which is used to
find dsi bridge by dts node.
Patch 1 adds YAML schema for JH7110 display pipeline.
Patches 2 to 3 add inno common api and match the ROCKCHIP inno hdmi driver
by calling the common api.
The collating public interface is based on ROCKCHIP inno hdmi,
and it can be resused by JH7110 inno hdmi.
Those common api are tested on rk-3128 SDK, which kernel version is 4.x.
step1, make sure the process is consistent with the latest kernel version.
step2, just remove the interface and add a common interface.
Patches 4 to 8 add kms driver for dc8200 display controller.
Patch 9 adds inno hdmi support for JH7110 display pipeline.
Patch 10 adds a simple encoder.
This patchset should be applied on next branch.
V1:
Changes since v1:
- Further standardize the yaml file.
- Dts naming convention improved.
- Fix the problem of compiling and loading ko files.
- Use drm new api to automatically manage resources.
- Drop vs_crtc_funcs&vs_plane_funcs, subdivide the plane's help interface.
- Reduce the modifiers unused.
- Optimize the hdmi driver code
V2:
Changes since v2:
- fix the error about checking the yaml file.
- match drm driver GEM DMA API.
- Delete the custom crtc property .
- hdmi use drmm_ new api to automatically manage resources.
- update the modifiers comments.
- enabling KASAN, fix the error during removing module
V3:
Changes since v3:
- Delete the custom plane property.
- Delete the custom fourcc modifiers.
- Adjust the calculation mode of hdmi pixclock.
- Add match data for dc8200 driver.
- Adjust some magic values.
- Add a simple encoder for dsi output.
V4:
Changes since v4:
- Delete the display subsystem module as all crtcs and planes are a driver.
- Delete the custom struct, directly use the drm struct data.
- Tidy up the inno hdmi public interface.
- Add a simple encoder for dsi output.
keith (10):
dt-bindings: display: Add YAML schema for JH7110 display pipeline
drm/bridge: add common api for inno hdmi
drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver
drm/vs: Add hardware funcs for vs.
drm/vs: add vs mode config init
drm/vs: add vs plane api
drm/vs: add ctrc fun
drm/vs: add vs drm master driver
drm/vs: Innosilicon HDMI support
drm/vs: add simple dsi encoder
.../display/bridge/innosilicon,inno-hdmi.yaml | 49 +
.../display/rockchip/rockchip,inno-hdmi.yaml | 27 +-
.../starfive/starfive,dsi-encoder.yaml | 92 ++
.../starfive/starfive,jh7110-dc8200.yaml | 169 +++
.../starfive/starfive,jh7110-inno-hdmi.yaml | 75 ++
.../soc/starfive/starfive,jh7110-syscon.yaml | 1 +
MAINTAINERS | 11 +
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/bridge/Kconfig | 2 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
.../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 +++++++++
.../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 ++
drivers/gpu/drm/rockchip/Kconfig | 1 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++
.../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 -
drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 -----------------
drivers/gpu/drm/verisilicon/Kconfig | 23 +
drivers/gpu/drm/verisilicon/Makefile | 11 +
.../gpu/drm/verisilicon/inno_hdmi-starfive.c | 481 ++++++++
.../gpu/drm/verisilicon/inno_hdmi-starfive.h | 152 +++
drivers/gpu/drm/verisilicon/vs_crtc.c | 241 ++++
drivers/gpu/drm/verisilicon/vs_crtc.h | 17 +
drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1060 ++++++++++++++++
drivers/gpu/drm/verisilicon/vs_dc_hw.h | 493 ++++++++
drivers/gpu/drm/verisilicon/vs_drv.c | 721 +++++++++++
drivers/gpu/drm/verisilicon/vs_drv.h | 98 ++
drivers/gpu/drm/verisilicon/vs_modeset.c | 36 +
drivers/gpu/drm/verisilicon/vs_modeset.h | 10 +
drivers/gpu/drm/verisilicon/vs_plane.c | 487 ++++++++
drivers/gpu/drm/verisilicon/vs_plane.h | 26 +
drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 +++
drivers/gpu/drm/verisilicon/vs_simple_enc.h | 25 +
drivers/gpu/drm/verisilicon/vs_type.h | 84 ++
include/drm/bridge/inno_hdmi.h | 69 ++
38 files changed, 5840 insertions(+), 1144 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h} (85%)
delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
create mode 100644 drivers/gpu/drm/verisilicon/Makefile
create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c
create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
create mode 100644 include/drm/bridge/inno_hdmi.h
--
2.27.0
^ permalink raw reply [flat|nested] 53+ messages in thread
* [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
2024-05-21 7:18 ` Krzysztof Kozlowski
2024-05-21 8:03 ` Heiko Stübner
@ 2024-05-21 10:58 ` keith
2024-05-21 7:30 ` Krzysztof Kozlowski
2024-05-21 10:58 ` [PATCH v4 02/10] drm/bridge: add common api for inno hdmi keith
` (8 subsequent siblings)
11 siblings, 1 reply; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
JH7110 SoC display pipeline includes a display controller and hdmi.
Dc controller IP : Vivante DC8200 Dual Display
HDMI IP : INNOSILICON HDMI2.0
As the INNO hdmi ip is also used by rockchip SoC in the driver code,
the innosilicon,inno-hdmi.yaml schema containing the common properties
for the INNO DesignWare HDMI TX controller isn't a full device
tree binding specification, but is meant to be referenced by
platform-specific bindings for the IP core.
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
.../display/bridge/innosilicon,inno-hdmi.yaml | 49 +++++
.../display/rockchip/rockchip,inno-hdmi.yaml | 27 +--
.../starfive/starfive,dsi-encoder.yaml | 92 ++++++++++
.../starfive/starfive,jh7110-dc8200.yaml | 169 ++++++++++++++++++
.../starfive/starfive,jh7110-inno-hdmi.yaml | 75 ++++++++
.../soc/starfive/starfive,jh7110-syscon.yaml | 1 +
MAINTAINERS | 8 +
7 files changed, 396 insertions(+), 25 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
diff --git a/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
new file mode 100644
index 000000000000..8540174dcaeb
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/innosilicon,inno-hdmi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Common Properties for Innosilicon HDMI TX IP
+
+maintainers:
+ - Keith Zhao <keith.zhao@starfivetech.com>
+
+description: |
+ This document defines device tree properties for the Innosilicon HDMI TX
+ controller (INNO HDMI) IP core. It doesn't constitute a full device tree
+ binding specification by itself but is meant to be referenced by device tree
+ bindings for the platform-specific integrations of the INNO HDMI.
+
+ When referenced from platform device tree bindings the properties defined in
+ this document are defined as follows. The platform device tree bindings are
+ responsible for defining whether each property is required or optional.
+
+properties:
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Port node with one endpoint connected to a display controller node.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Port node with one endpoint connected to a hdmi-connector node.
+
+ required:
+ - port@0
+ - port@1
+
+additionalProperties: true
+
+...
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml
index 5b87b0f1963e..589dedfcbee0 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml
@@ -16,12 +16,6 @@ properties:
- rockchip,rk3036-inno-hdmi
- rockchip,rk3128-inno-hdmi
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
clocks:
minItems: 1
items:
@@ -40,24 +34,6 @@ properties:
"#sound-dai-cells":
const: 0
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
-
- properties:
- port@0:
- $ref: /schemas/graph.yaml#/properties/port
- description:
- Port node with one endpoint connected to a vop node.
-
- port@1:
- $ref: /schemas/graph.yaml#/properties/port
- description:
- Port node with one endpoint connected to a hdmi-connector node.
-
- required:
- - port@0
- - port@1
-
required:
- compatible
- reg
@@ -69,6 +45,7 @@ required:
- ports
allOf:
+ - $ref: ../bridge/innosilicon,inno-hdmi.yaml#
- $ref: /schemas/sound/dai-common.yaml#
- if:
properties:
@@ -95,7 +72,7 @@ allOf:
required:
- power-domains
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
new file mode 100644
index 000000000000..07aa147a9db1
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/starfive/starfive,dsi-encoder.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: starfive jh7110 SoC Encoder
+
+maintainers:
+ - Keith Zhao <keith.zhao@starfivetech.com>
+
+description:
+ Device-Tree bindings for simple encoder.
+ Simple encoder driver only has basic functionality.
+ the hardware of dc8200 has 2 output interface, and uses
+ syscon to select which one to be used.
+
+properties:
+ compatible:
+ const: starfive,dsi-encoder
+
+ starfive,syscon:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to syscon that select crtc output.
+ - description: Offset of crtc selection
+ - description: Shift of crtc selection
+ description:
+ A phandle to syscon with two arguments that configure select output.
+ The argument one is the offset of crtc selection, the
+ argument two is the shift of crtc selection.
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ The first port should be the input coming from the associated dc channel.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ The second port should be the output coming from the associated bridge.
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ dssctrl: dssctrl@295b0000 {
+ compatible = "starfive,jh7110-vout-syscon", "syscon";
+ reg = <0x295b0000 0x90>;
+ };
+
+ dsi_encoder: dsi_encoder {
+ compatible = "starfive,dsi-encoder";
+ starfive,syscon = <&dssctrl 0x8 0x12>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /* input */
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ dsi_input0:endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&dc_out_dpi1>;
+ };
+ };
+ /* output */
+ port@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dsi_out:endpoint {
+ remote-endpoint = <&mipi_in>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
new file mode 100644
index 000000000000..a28dfdd471b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
@@ -0,0 +1,169 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/starfive/starfive,jh7110-dc8200.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STARFIVE JH7110 SoC display controller
+
+description:
+ The STARFIVE JH7110 SoC uses the display controller based on Verisilicon IP(DC8200)
+ to transfer the image data from a video memory buffer to an external LCD interface.
+
+ pipe0 binds HDMI for primary display,
+ pipe1 binds DSI for external display.
+
+ +------------------------------+
+ | |
+ | |
+ +----+ | +-------------------+ | +-------+ +------+ +------+
+ | +----->+ dc controller 0 +--->----->+HDMICtl| ->+ PHY +-->+PANEL0+
+ |AXI | | +-------------------+ | +-------+ +------+ +------+
+ | | | |
+ | | | |
+ | | | |
+ | | | |
+ |APB | | +-------------------+ +---------+ +------+ +-------+
+ | +----->+ dc controller 1 +--->---->+ dsiTx +--->+DPHY +->+ PANEL1+
+ | | | +-------------------+ +---------+ +------+ +-------+
+ +----+ | |
+ +------------------------------+
+
+maintainers:
+ - Keith Zhao <keith.zhao@starfivetech.com>
+
+properties:
+ compatible:
+ const: starfive,jh7110-dc8200
+
+ reg:
+ items:
+ - description: host interface address and length
+ - description: display physical base address and length
+
+ reg-names:
+ items:
+ - const: host
+ - const: base
+
+ clocks:
+ items:
+ - description: Clock for display system noc bus.
+ - description: Core clock for display controller.
+ - description: Clock for axi bus to access ddr.
+ - description: Clock for ahb bus to R/W the phy regs.
+ - description: Pixel clock for display channel 0.
+ - description: Pixel clock for display channel 1.
+ - description: Pixel clock from hdmi.
+ - description: Pixel clock for soc .
+
+ clock-names:
+ items:
+ - const: noc_bus
+ - const: dc_core
+ - const: axi_core
+ - const: ahb
+ - const: channel0
+ - const: channel1
+ - const: hdmi_tx
+ - const: dc_parent
+
+ resets:
+ items:
+ - description: Reset for axi bus.
+ - description: Reset for ahb bus.
+ - description: Core reset of display controller.
+
+ reset-names:
+ items:
+ - const: axi
+ - const: ahb
+ - const: core
+
+ interrupts:
+ items:
+ - description: The interrupt will be generated when DC finish one frame
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ channel 0 output
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ channel 1 output
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/starfive,jh7110-crg.h>
+ #include <dt-bindings/reset/starfive,jh7110-crg.h>
+ dc8200: lcd-controller@29400000 {
+ compatible = "starfive,jh7110-dc8200";
+ reg = <0x29400000 0x100>,
+ <0x29400800 0x2000>;
+ reg-names = "host", "base";
+
+ interrupts = <95>;
+ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_DISP_AXI>,
+ <&voutcrg JH7110_VOUTCLK_DC8200_CORE>,
+ <&voutcrg JH7110_VOUTCLK_DC8200_AXI>,
+ <&voutcrg JH7110_VOUTCLK_DC8200_AHB>,
+ <&voutcrg JH7110_VOUTCLK_DC8200_PIX0>,
+ <&voutcrg JH7110_VOUTCLK_DC8200_PIX1>,
+ <&hdmitx0_pixelclk>,
+ <&voutcrg JH7110_VOUTCLK_DC8200_PIX>;
+ clock-names = "noc_bus", "dc_core", "axi_core", "ahb",
+ "channel0", "channel1", "hdmi_tx", "dc_parent";
+ resets = <&voutcrg JH7110_VOUTRST_DC8200_AXI>,
+ <&voutcrg JH7110_VOUTRST_DC8200_AHB>,
+ <&voutcrg JH7110_VOUTRST_DC8200_CORE>;
+ reset-names = "axi","ahb", "core";
+
+ crtc_out: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dc_out0: port@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dc_out_dpi0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&hdmi_enc>;
+ };
+
+ };
+
+ dc_out1: port@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dc_out_dpi1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&dsi_enc>;
+ };
+
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
new file mode 100644
index 000000000000..bfd7dc41fc14
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/starfive/starfive,jh7110-inno-hdmi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Starfive JH7110 Innosilicon HDMI controller
+
+maintainers:
+ - Keith Zhao <keith.zhao@starfivetech.com>
+
+allOf:
+ - $ref: ../bridge/innosilicon,inno-hdmi.yaml#
+
+properties:
+ compatible:
+ const: "starfive,jh7110-inno-hdmi"
+
+ clocks:
+ items:
+ - description: System clock of HDMI module.
+ - description: Mclk clock of HDMI audio.
+ - description: Bclk clock of HDMI audio.
+
+ clock-names:
+ items:
+ - const: sysclk
+ - const: mclk
+ - const: bclk
+
+ resets:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - resets
+ - ports
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/starfive,jh7110-pinctrl.h>
+ #include <dt-bindings/gpio/gpio.h>
+ hdmi: hdmi@29590000 {
+ compatible = "starfive,jh7110-inno-hdmi";
+ reg = <0x29590000 0x4000>;
+ interrupts = <99>;
+ clocks = <&voutcrg 17>, <&voutcrg 15>, <&voutcrg 16>;
+ clock-names = "sysclk", "mclk","bclk";
+ resets = <&voutcrg 9>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi_in: port@0 {
+ reg = <0>;
+ hdmi_in_vop: endpoint {
+ remote-endpoint = <&dc_out_dpi0>;
+ };
+ };
+
+ hdmi_out: port@1 {
+ reg = <1>;
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml b/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml
index 0039319e91fe..cf9b657d0e8a 100644
--- a/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml
+++ b/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml
@@ -24,6 +24,7 @@ properties:
- enum:
- starfive,jh7110-aon-syscon
- starfive,jh7110-stg-syscon
+ - starfive,jh7110-vout-syscon
- const: syscon
reg:
diff --git a/MAINTAINERS b/MAINTAINERS
index c675fc296b19..8881652bb8b6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7148,6 +7148,14 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/ste,mcde.yaml
F: drivers/gpu/drm/mcde/
+DRM DRIVERS FOR STARFIVE
+M: Keith Zhao <keith.zhao@starfivetech.com>
+L: dri-devel@lists.freedesktop.org
+S: Maintained
+T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F: Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
+F: Documentation/devicetree/bindings/display/starfive/
+
DRM DRIVER FOR SYNAPTICS R63353 PANELS
M: Michael Trimarchi <michael@amarulasolutions.com>
S: Maintained
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (2 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline keith
@ 2024-05-21 10:58 ` keith
2024-05-21 9:30 ` Krzysztof Kozlowski
` (2 more replies)
2024-05-21 10:58 ` [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver keith
` (7 subsequent siblings)
11 siblings, 3 replies; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
Add INNO common api so that it can be used by vendor
drivers which implement vendor specific extensions to Innosilicon HDMI.
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
MAINTAINERS | 2 +
drivers/gpu/drm/bridge/Kconfig | 2 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
.../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 ++++++++++++++++++
.../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 +++
include/drm/bridge/inno_hdmi.h | 69 ++
8 files changed, 766 insertions(+)
create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
create mode 100644 include/drm/bridge/inno_hdmi.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 8881652bb8b6..cf2d66f88a83 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7155,6 +7155,8 @@ S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
F: Documentation/devicetree/bindings/display/starfive/
+F: drivers/gpu/drm/bridge/innosilicon/
+F: include/drm/bridge/inno_hdmi.h
DRM DRIVER FOR SYNAPTICS R63353 PANELS
M: Michael Trimarchi <michael@amarulasolutions.com>
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index c621be1a99a8..59fcdb810125 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -415,6 +415,8 @@ source "drivers/gpu/drm/bridge/cadence/Kconfig"
source "drivers/gpu/drm/bridge/imx/Kconfig"
+source "drivers/gpu/drm/bridge/innosilicon/Kconfig"
+
source "drivers/gpu/drm/bridge/synopsys/Kconfig"
endmenu
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 7df87b582dca..cca7400566b2 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -40,4 +40,5 @@ obj-$(CONFIG_DRM_ITE_IT66121) += ite-it66121.o
obj-y += analogix/
obj-y += cadence/
obj-y += imx/
+obj-y += innosilicon/
obj-y += synopsys/
diff --git a/drivers/gpu/drm/bridge/innosilicon/Kconfig b/drivers/gpu/drm/bridge/innosilicon/Kconfig
new file mode 100644
index 000000000000..73dbed3b1c4d
--- /dev/null
+++ b/drivers/gpu/drm/bridge/innosilicon/Kconfig
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DRM_INNO_HDMI
+ tristate
+ help
+ Support the common interface which is part of the INNO
+ Designware HDMI block.
diff --git a/drivers/gpu/drm/bridge/innosilicon/Makefile b/drivers/gpu/drm/bridge/innosilicon/Makefile
new file mode 100644
index 000000000000..3b3a961ab9fb
--- /dev/null
+++ b/drivers/gpu/drm/bridge/innosilicon/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_DRM_INNO_HDMI) += inno-hdmi.o
diff --git a/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
new file mode 100644
index 000000000000..2378ce06a876
--- /dev/null
+++ b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
@@ -0,0 +1,587 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Zheng Yang <zhengyang@rock-chips.com>
+ * Yakir Yang <ykk@rock-chips.com>
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include <drm/bridge/inno_hdmi.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "inno-hdmi.h"
+
+struct inno_hdmi_i2c {
+ struct i2c_adapter adap;
+
+ u8 ddc_addr;
+ u8 segment_addr;
+
+ struct mutex lock; /* For i2c operation. */
+ struct completion cmp;
+};
+
+struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector)
+{
+ return container_of(connector, struct inno_hdmi, connector);
+}
+EXPORT_SYMBOL_GPL(connector_to_inno_hdmi);
+
+u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
+{
+ return readl_relaxed(hdmi->regs + (offset) * 0x04);
+}
+EXPORT_SYMBOL_GPL(hdmi_readb);
+
+void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val)
+{
+ writel_relaxed(val, hdmi->regs + (offset) * 0x04);
+}
+EXPORT_SYMBOL_GPL(hdmi_writeb);
+
+void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, u32 msk, u32 val)
+{
+ u8 temp = hdmi_readb(hdmi, offset) & ~msk;
+
+ temp |= val & msk;
+ hdmi_writeb(hdmi, offset, temp);
+}
+EXPORT_SYMBOL_GPL(hdmi_modb);
+
+void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate)
+{
+ unsigned long long ddc_bus_freq = rate >> 2;
+
+ do_div(ddc_bus_freq, HDMI_SCL_RATE);
+
+ hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
+ hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
+
+ /* Clear the EDID interrupt flag and mute the interrupt */
+ hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
+ hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
+}
+EXPORT_SYMBOL_GPL(inno_hdmi_i2c_init);
+
+void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable)
+{
+ if (enable)
+ hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_ON);
+ else
+ hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF);
+}
+EXPORT_SYMBOL_GPL(inno_hdmi_sys_power);
+
+static enum drm_connector_status
+inno_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
+
+ return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ?
+ connector_status_connected : connector_status_disconnected;
+}
+
+static int inno_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+ struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
+ const struct drm_edid *drm_edid;
+ int ret = 0;
+
+ if (!hdmi->ddc)
+ return 0;
+
+ drm_edid = drm_edid_read_ddc(connector, hdmi->ddc);
+ drm_edid_connector_update(connector, drm_edid);
+ ret = drm_edid_connector_add_modes(connector);
+ drm_edid_free(drm_edid);
+
+ return ret;
+}
+
+static enum drm_mode_status
+inno_hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+{
+ struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
+
+ const struct inno_hdmi_plat_data *pdata = hdmi->plat_data;
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (pdata->mode_valid)
+ mode_status = pdata->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
+static void
+inno_hdmi_connector_destroy_state(struct drm_connector *connector,
+ struct drm_connector_state *state)
+{
+ struct inno_hdmi_connector_state *inno_conn_state =
+ to_inno_hdmi_conn_state(state);
+
+ __drm_atomic_helper_connector_destroy_state(&inno_conn_state->base);
+ kfree(inno_conn_state);
+}
+
+static void inno_hdmi_connector_reset(struct drm_connector *connector)
+{
+ struct inno_hdmi_connector_state *inno_conn_state;
+
+ if (connector->state) {
+ inno_hdmi_connector_destroy_state(connector, connector->state);
+ connector->state = NULL;
+ }
+
+ inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL);
+ if (!inno_conn_state)
+ return;
+
+ __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base);
+
+ inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709;
+ inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB;
+ inno_conn_state->rgb_limited_range = false;
+}
+
+static struct drm_connector_state *
+inno_hdmi_connector_duplicate_state(struct drm_connector *connector)
+{
+ struct inno_hdmi_connector_state *inno_conn_state;
+
+ if (WARN_ON(!connector->state))
+ return NULL;
+
+ inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state),
+ sizeof(*inno_conn_state), GFP_KERNEL);
+
+ if (!inno_conn_state)
+ return NULL;
+
+ __drm_atomic_helper_connector_duplicate_state(connector,
+ &inno_conn_state->base);
+
+ return &inno_conn_state->base;
+}
+
+static const struct drm_connector_funcs inno_hdmi_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = inno_hdmi_connector_detect,
+ .reset = inno_hdmi_connector_reset,
+ .atomic_duplicate_state = inno_hdmi_connector_duplicate_state,
+ .atomic_destroy_state = inno_hdmi_connector_destroy_state,
+};
+
+static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
+ .get_modes = inno_hdmi_connector_get_modes,
+ .mode_valid = inno_hdmi_connector_mode_valid,
+};
+
+static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi,
+ struct drm_encoder *encoder)
+{
+ struct device *dev = hdmi->dev;
+ const struct inno_hdmi_plat_data *pdata = hdmi->plat_data;
+
+ if (RK3128_HDMI == pdata->soc_type || RK3036_HDMI == pdata->soc_type)
+ drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (encoder->possible_crtcs == 0)
+ return -EPROBE_DEFER;
+
+ drm_encoder_helper_add(encoder, pdata->helper_private);
+
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ drm_connector_helper_add(&hdmi->connector,
+ &inno_hdmi_connector_helper_funcs);
+
+ drmm_connector_init(drm, &hdmi->connector,
+ &inno_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ hdmi->ddc);
+
+ drm_connector_attach_encoder(&hdmi->connector, encoder);
+
+ return 0;
+}
+
+static irqreturn_t inno_hdmi_i2c_irq(struct inno_hdmi *hdmi)
+{
+ struct inno_hdmi_i2c *i2c = hdmi->i2c;
+ u8 stat;
+
+ stat = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1);
+ if (!(stat & m_INT_EDID_READY))
+ return IRQ_NONE;
+
+ /* Clear HDMI EDID interrupt flag */
+ hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
+
+ complete(&i2c->cmp);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t inno_hdmi_hardirq(int irq, void *dev_id)
+{
+ struct inno_hdmi *hdmi = dev_id;
+ irqreturn_t ret = IRQ_NONE;
+ u8 interrupt;
+
+ if (hdmi->i2c)
+ ret = inno_hdmi_i2c_irq(hdmi);
+
+ interrupt = hdmi_readb(hdmi, HDMI_STATUS);
+ if (interrupt & m_INT_HOTPLUG) {
+ hdmi_modb(hdmi, HDMI_STATUS, m_INT_HOTPLUG, m_INT_HOTPLUG);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ return ret;
+}
+
+static irqreturn_t inno_hdmi_irq(int irq, void *dev_id)
+{
+ struct inno_hdmi *hdmi = dev_id;
+
+ drm_helper_hpd_irq_event(hdmi->connector.dev);
+
+ return IRQ_HANDLED;
+}
+
+static int inno_hdmi_i2c_read(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
+{
+ int length = msgs->len;
+ u8 *buf = msgs->buf;
+ int ret;
+
+ ret = wait_for_completion_timeout(&hdmi->i2c->cmp, HZ / 10);
+ if (!ret)
+ return -EAGAIN;
+
+ while (length--)
+ *buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR);
+
+ return 0;
+}
+
+static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
+{
+ /*
+ * The DDC module only support read EDID message, so
+ * we assume that each word write to this i2c adapter
+ * should be the offset of EDID word address.
+ */
+ if (msgs->len != 1 || (msgs->addr != DDC_ADDR && msgs->addr != DDC_SEGMENT_ADDR))
+ return -EINVAL;
+
+ reinit_completion(&hdmi->i2c->cmp);
+
+ if (msgs->addr == DDC_SEGMENT_ADDR)
+ hdmi->i2c->segment_addr = msgs->buf[0];
+ if (msgs->addr == DDC_ADDR)
+ hdmi->i2c->ddc_addr = msgs->buf[0];
+
+ /* Set edid fifo first addr */
+ hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00);
+
+ /* Set edid word address 0x00/0x80 */
+ hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr);
+
+ /* Set edid segment pointer */
+ hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr);
+
+ return 0;
+}
+
+static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct inno_hdmi *hdmi = i2c_get_adapdata(adap);
+ struct inno_hdmi_i2c *i2c = hdmi->i2c;
+ int i, ret = 0;
+
+ mutex_lock(&i2c->lock);
+
+ /* Clear the EDID interrupt flag and unmute the interrupt */
+ hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, m_INT_EDID_READY);
+ hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
+
+ for (i = 0; i < num; i++) {
+ DRM_DEV_DEBUG(hdmi->dev,
+ "xfer: num: %d/%d, len: %d, flags: %#x\n",
+ i + 1, num, msgs[i].len, msgs[i].flags);
+
+ if (msgs[i].flags & I2C_M_RD)
+ ret = inno_hdmi_i2c_read(hdmi, &msgs[i]);
+ else
+ ret = inno_hdmi_i2c_write(hdmi, &msgs[i]);
+
+ if (ret < 0)
+ break;
+ }
+
+ if (!ret)
+ ret = num;
+
+ /* Mute HDMI EDID interrupt */
+ hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
+
+ mutex_unlock(&i2c->lock);
+
+ return ret;
+}
+
+static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm inno_hdmi_algorithm = {
+ .master_xfer = inno_hdmi_i2c_xfer,
+ .functionality = inno_hdmi_i2c_func,
+};
+
+static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
+{
+ struct i2c_adapter *adap;
+ struct inno_hdmi_i2c *i2c;
+ int ret;
+
+ i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&i2c->lock);
+ init_completion(&i2c->cmp);
+
+ adap = &i2c->adap;
+ adap->owner = THIS_MODULE;
+ adap->dev.parent = hdmi->dev;
+ adap->dev.of_node = hdmi->dev->of_node;
+ adap->algo = &inno_hdmi_algorithm;
+ strscpy(adap->name, "Inno HDMI", sizeof(adap->name));
+ i2c_set_adapdata(adap, hdmi);
+
+ ret = i2c_add_adapter(adap);
+ if (ret) {
+ dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
+ devm_kfree(hdmi->dev, i2c);
+ return ERR_PTR(ret);
+ }
+
+ hdmi->i2c = i2c;
+
+ DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name);
+
+ return adap;
+}
+
+int inno_hdmi_bind(struct drm_device *drm, struct inno_hdmi *hdmi, struct drm_encoder *encoder)
+{
+ int ret, irq;
+ struct platform_device *pdev = to_platform_device(hdmi->dev);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ return ret;
+ }
+
+ hdmi->ddc = inno_hdmi_i2c_adapter(hdmi);
+ if (IS_ERR(hdmi->ddc)) {
+ ret = PTR_ERR(hdmi->ddc);
+ hdmi->ddc = NULL;
+ return ret;
+ }
+
+ ret = inno_hdmi_register(drm, hdmi, encoder);
+ if (ret)
+ goto err_put_adapter;
+
+ /* Unmute hotplug interrupt */
+ hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
+
+ ret = devm_request_threaded_irq(hdmi->dev, irq, inno_hdmi_hardirq,
+ inno_hdmi_irq, IRQF_SHARED,
+ dev_name(hdmi->dev), hdmi);
+ if (ret)
+ goto err_put_adapter;
+
+ return ret;
+err_put_adapter:
+ i2c_put_adapter(hdmi->ddc);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(inno_hdmi_bind);
+
+static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi,
+ enum hdmi_infoframe_type type)
+{
+ struct drm_connector *connector = &hdmi->connector;
+
+ if (type != HDMI_INFOFRAME_TYPE_AVI) {
+ drm_err(connector->dev,
+ "Unsupported infoframe type: %u\n", type);
+ return;
+ }
+
+ hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
+}
+
+static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi,
+ union hdmi_infoframe *frame, enum hdmi_infoframe_type type)
+{
+ struct drm_connector *connector = &hdmi->connector;
+ u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
+ ssize_t rc, i;
+
+ if (type != HDMI_INFOFRAME_TYPE_AVI) {
+ drm_err(connector->dev,
+ "Unsupported infoframe type: %u\n", type);
+ return 0;
+ }
+
+ inno_hdmi_disable_frame(hdmi, type);
+
+ rc = hdmi_infoframe_pack(frame, packed_frame,
+ sizeof(packed_frame));
+ if (rc < 0)
+ return rc;
+
+ for (i = 0; i < rc; i++)
+ hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
+ packed_frame[i]);
+
+ return 0;
+}
+
+int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode)
+{
+ struct drm_connector *connector = &hdmi->connector;
+ struct drm_connector_state *conn_state = connector->state;
+ struct inno_hdmi_connector_state *inno_conn_state =
+ to_inno_hdmi_conn_state(conn_state);
+ union hdmi_infoframe frame;
+ int rc;
+
+ rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
+ &hdmi->connector,
+ mode);
+ if (rc) {
+ inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI);
+ return rc;
+ }
+
+ if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444)
+ frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
+ else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422)
+ frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
+ else
+ frame.avi.colorspace = HDMI_COLORSPACE_RGB;
+
+ if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
+ drm_hdmi_avi_infoframe_quant_range(&frame.avi,
+ connector, mode,
+ inno_conn_state->rgb_limited_range ?
+ HDMI_QUANTIZATION_RANGE_LIMITED :
+ HDMI_QUANTIZATION_RANGE_FULL);
+ } else {
+ frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
+ frame.avi.ycc_quantization_range =
+ HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+ }
+
+ return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI);
+}
+EXPORT_SYMBOL_GPL(inno_hdmi_config_video_avi);
+
+int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, struct drm_display_mode *mode)
+{
+ int value;
+
+ /* Set detail external video timing polarity and interlace mode */
+ value = v_EXTERANL_VIDEO(1);
+ if (hdmi->plat_data->soc_type == STARFIVE_HDMI) {
+ value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
+ v_HSYNC_POLARITY_SF(1) : v_HSYNC_POLARITY_SF(0);
+ value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
+ v_VSYNC_POLARITY_SF(1) : v_VSYNC_POLARITY_SF(0);
+ } else {
+ value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
+ v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0);
+ value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
+ v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0);
+ }
+ value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
+ v_INETLACE(1) : v_INETLACE(0);
+ hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
+
+ /* Set detail external video timing */
+ value = mode->htotal;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF);
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
+
+ value = mode->htotal - mode->hdisplay;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
+
+ value = mode->htotal - mode->hsync_start;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
+
+ value = mode->hsync_end - mode->hsync_start;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF);
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
+
+ value = mode->vtotal;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF);
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
+
+ value = mode->vtotal - mode->vdisplay;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
+
+ value = mode->vtotal - mode->vsync_start;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
+
+ value = mode->vsync_end - mode->vsync_start;
+ hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF);
+
+ if (hdmi->plat_data->soc_type == STARFIVE_HDMI)
+ return 0;
+
+ hdmi_writeb(hdmi, HDMI_PHY_PRE_DIV_RATIO, 0x1e);
+ hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c);
+ hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(inno_hdmi_config_video_timing);
+
+MODULE_DESCRIPTION("INNO HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:inno-hdmi");
diff --git a/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
new file mode 100644
index 000000000000..233077cfb136
--- /dev/null
+++ b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Zheng Yang <zhengyang@rock-chips.com>
+ * Yakir Yang <ykk@rock-chips.com>
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef __INNO_H__
+#define __INNO_H__
+
+#define DDC_SEGMENT_ADDR 0x30
+
+#define HDMI_SCL_RATE (100 * 1000)
+#define DDC_BUS_FREQ_L 0x4b
+#define DDC_BUS_FREQ_H 0x4c
+
+#define HDMI_SYS_CTRL 0x00
+#define m_RST_ANALOG (1 << 6)
+#define v_RST_ANALOG (0 << 6)
+#define v_NOT_RST_ANALOG (1 << 6)
+#define m_RST_DIGITAL (1 << 5)
+#define v_RST_DIGITAL (0 << 5)
+#define v_NOT_RST_DIGITAL (1 << 5)
+#define m_REG_CLK_INV (1 << 4)
+#define v_REG_CLK_NOT_INV (0 << 4)
+#define v_REG_CLK_INV (1 << 4)
+#define m_VCLK_INV (1 << 3)
+#define v_VCLK_NOT_INV (0 << 3)
+#define v_VCLK_INV (1 << 3)
+#define m_REG_CLK_SOURCE (1 << 2)
+#define v_REG_CLK_SOURCE_TMDS (0 << 2)
+#define v_REG_CLK_SOURCE_SYS (1 << 2)
+#define m_POWER (1 << 1)
+#define v_PWR_ON (0 << 1)
+#define v_PWR_OFF (1 << 1)
+#define m_INT_POL (1 << 0)
+#define v_INT_POL_HIGH 1
+#define v_INT_POL_LOW 0
+
+#define HDMI_VIDEO_TIMING_CTL 0x08
+#define v_HSYNC_POLARITY(n) ((n) << 3)
+#define v_VSYNC_POLARITY(n) ((n) << 2)
+#define v_VSYNC_POLARITY_SF(n) ((n) << 3)
+#define v_HSYNC_POLARITY_SF(n) ((n) << 2)
+#define v_INETLACE(n) ((n) << 1)
+#define v_EXTERANL_VIDEO(n) ((n) << 0)
+
+#define HDMI_VIDEO_EXT_HTOTAL_L 0x09
+#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a
+#define HDMI_VIDEO_EXT_HBLANK_L 0x0b
+#define HDMI_VIDEO_EXT_HBLANK_H 0x0c
+#define HDMI_VIDEO_EXT_HDELAY_L 0x0d
+#define HDMI_VIDEO_EXT_HDELAY_H 0x0e
+#define HDMI_VIDEO_EXT_HDURATION_L 0x0f
+#define HDMI_VIDEO_EXT_HDURATION_H 0x10
+#define HDMI_VIDEO_EXT_VTOTAL_L 0x11
+#define HDMI_VIDEO_EXT_VTOTAL_H 0x12
+#define HDMI_VIDEO_EXT_VBLANK 0x13
+#define HDMI_VIDEO_EXT_VDELAY 0x14
+#define HDMI_VIDEO_EXT_VDURATION 0x15
+
+#define HDMI_EDID_SEGMENT_POINTER 0x4d
+#define HDMI_EDID_WORD_ADDR 0x4e
+#define HDMI_EDID_FIFO_OFFSET 0x4f
+#define HDMI_EDID_FIFO_ADDR 0x50
+
+#define HDMI_INTERRUPT_MASK1 0xc0
+#define HDMI_INTERRUPT_STATUS1 0xc1
+#define m_INT_ACTIVE_VSYNC (1 << 5)
+#define m_INT_EDID_READY (1 << 2)
+
+#define HDMI_CONTROL_PACKET_BUF_INDEX 0x9f
+enum {
+ INFOFRAME_VSI = 0x05,
+ INFOFRAME_AVI = 0x06,
+ INFOFRAME_AAI = 0x08,
+};
+
+#define HDMI_CONTROL_PACKET_ADDR 0xa0
+#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11
+
+#define HDMI_STATUS 0xc8
+#define m_HOTPLUG (1 << 7)
+#define m_MASK_INT_HOTPLUG (1 << 5)
+#define m_INT_HOTPLUG (1 << 1)
+#define v_MASK_INT_HOTPLUG(n) (((n) & 0x1) << 5)
+
+#define HDMI_PHY_FEEDBACK_DIV_RATIO_LOW 0xe7
+#define v_FEEDBACK_DIV_LOW(n) ((n) & 0xff)
+#define HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH 0xe8
+#define v_FEEDBACK_DIV_HIGH(n) ((n) & 1)
+
+#define HDMI_PHY_PRE_DIV_RATIO 0xed
+#define v_PRE_DIV_RATIO(n) ((n) & 0x1f)
+
+#endif /* __INNO_H__ */
diff --git a/include/drm/bridge/inno_hdmi.h b/include/drm/bridge/inno_hdmi.h
new file mode 100644
index 000000000000..bc865f5343ce
--- /dev/null
+++ b/include/drm/bridge/inno_hdmi.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef __INNO_COMMON_HDMI__
+#define __INNO_COMMON_HDMI__
+
+#include <drm/drm_connector.h>
+#include <drm/drm_encoder.h>
+
+struct inno_hdmi_connector_state {
+ struct drm_connector_state base;
+ unsigned int enc_out_format;
+ unsigned int colorimetry;
+ bool rgb_limited_range;
+};
+
+enum inno_hdmi_devtype {
+ RK3036_HDMI,
+ RK3128_HDMI,
+ STARFIVE_HDMI,
+};
+
+#define to_inno_hdmi_conn_state(conn_state) \
+ container_of_const(conn_state, struct inno_hdmi_connector_state, base)
+
+struct inno_hdmi_phy_config {
+ unsigned long pixelclock;
+ u8 pre_emphasis;
+ u8 voltage_level_control;
+};
+
+struct inno_hdmi_plat_data {
+ enum inno_hdmi_devtype soc_type;
+
+ /* Platform-specific mode validation*/
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ /* Platform-specific encoder helper funcs*/
+ const struct drm_encoder_helper_funcs *helper_private;
+
+ /* Platform-specific phy_configs Optional*/
+ struct inno_hdmi_phy_config *phy_configs;
+ struct inno_hdmi_phy_config *default_phy_config;
+};
+
+struct inno_hdmi {
+ struct device *dev;
+ void __iomem *regs;
+
+ struct drm_connector connector;
+ struct inno_hdmi_i2c *i2c;
+ struct i2c_adapter *ddc;
+ const struct inno_hdmi_plat_data *plat_data;
+};
+
+u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset);
+void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val);
+void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, u32 msk, u32 val);
+
+struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector);
+void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate);
+int inno_hdmi_bind(struct drm_device *drm, struct inno_hdmi *hdmi, struct drm_encoder *encoder);
+void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable);
+int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode);
+int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, struct drm_display_mode *mode);
+
+#endif /* __INNO_COMMON_HDMI__ */
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (3 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 02/10] drm/bridge: add common api for inno hdmi keith
@ 2024-05-21 10:58 ` keith
2024-05-22 7:24 ` Maxime Ripard
2024-05-21 10:58 ` [PATCH v4 04/10] drm/vs: Add hardware funcs for vs keith
` (6 subsequent siblings)
11 siblings, 1 reply; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
Add the ROCKCHIP inno hdmi driver that uses the Inno DesignWare
HDMI TX bridge and remove the old separate one.
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
drivers/gpu/drm/rockchip/Kconfig | 1 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++
.../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 -
drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 -----------------
5 files changed, 519 insertions(+), 1119 deletions(-)
create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h} (85%)
delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 1bf3e2829cd0..cc6cfd5a30d6 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -74,6 +74,7 @@ config ROCKCHIP_DW_MIPI_DSI
config ROCKCHIP_INNO_HDMI
bool "Rockchip specific extensions for Innosilicon HDMI"
+ select DRM_INNO_HDMI
help
This selects support for Rockchip SoC specific extensions
for the Innosilicon HDMI driver. If you want to enable
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 3ff7b21c0414..4b2d0cba8db3 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -12,7 +12,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
-rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
+rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
new file mode 100644
index 000000000000..69d0e913e13b
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
@@ -0,0 +1,517 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Zheng Yang <zhengyang@rock-chips.com>
+ * Yakir Yang <ykk@rock-chips.com>
+ */
+
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include <drm/bridge/inno_hdmi.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "rockchip_drm_drv.h"
+
+#include "inno_hdmi-rockchip.h"
+
+#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
+
+struct rk_inno_hdmi {
+ struct rockchip_encoder encoder;
+ struct inno_hdmi inno_hdmi;
+ struct clk *pclk;
+ struct clk *refclk;
+};
+
+static struct inno_hdmi *rk_encoder_to_inno_hdmi(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+ struct rk_inno_hdmi *rk_hdmi = container_of(rkencoder, struct rk_inno_hdmi, encoder);
+
+ return &rk_hdmi->inno_hdmi;
+}
+
+enum {
+ CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
+ CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
+ CSC_RGB_0_255_TO_RGB_16_235_8BIT,
+};
+
+static const char coeff_csc[][24] = {
+ /*
+ * RGB2YUV:601 SD mode:
+ * Cb = -0.291G - 0.148R + 0.439B + 128
+ * Y = 0.504G + 0.257R + 0.098B + 16
+ * Cr = -0.368G + 0.439R - 0.071B + 128
+ */
+ {
+ 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
+ 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
+ 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
+ },
+ /*
+ * RGB2YUV:709 HD mode:
+ * Cb = - 0.338G - 0.101R + 0.439B + 128
+ * Y = 0.614G + 0.183R + 0.062B + 16
+ * Cr = - 0.399G + 0.439R - 0.040B + 128
+ */
+ {
+ 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
+ 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
+ 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
+ },
+ /*
+ * RGB[0:255]2RGB[16:235]:
+ * R' = R x (235-16)/255 + 16;
+ * G' = G x (235-16)/255 + 16;
+ * B' = B x (235-16)/255 + 16;
+ */
+ {
+ 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
+ 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
+ },
+};
+
+static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
+ { 74250000, 0x3f, 0xbb },
+ { 165000000, 0x6f, 0xbb },
+ { ~0UL, 0x00, 0x00 }
+};
+
+static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = {
+ { 74250000, 0x3f, 0xaa },
+ { 165000000, 0x5f, 0xaa },
+ { ~0UL, 0x00, 0x00 }
+};
+
+static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi,
+ unsigned long pixelclk)
+{
+ const struct inno_hdmi_phy_config *phy_configs = hdmi->plat_data->phy_configs;
+ int i;
+
+ for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) {
+ if (pixelclk <= phy_configs[i].pixelclock)
+ return i;
+ }
+
+ DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n",
+ pixelclk);
+
+ return -EINVAL;
+}
+
+static void inno_hdmi_standby(struct inno_hdmi *hdmi)
+{
+ inno_hdmi_sys_power(hdmi, false);
+
+ hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
+ hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
+ hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
+ hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
+};
+
+static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
+ unsigned long mpixelclock)
+{
+ struct inno_hdmi_phy_config *phy_config;
+ int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock);
+
+ if (ret < 0) {
+ phy_config = hdmi->plat_data->default_phy_config;
+ DRM_DEV_ERROR(hdmi->dev,
+ "Using default phy configuration for TMDS rate %lu",
+ mpixelclock);
+ } else {
+ phy_config = &hdmi->plat_data->phy_configs[ret];
+ }
+
+ inno_hdmi_sys_power(hdmi, false);
+
+ hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis);
+ hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control);
+ hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
+ hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
+ hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
+ hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
+ hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
+ hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
+
+ inno_hdmi_sys_power(hdmi, true);
+};
+
+static void inno_hdmi_reset(struct inno_hdmi *hdmi)
+{
+ u32 val;
+ u32 msk;
+
+ hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
+ udelay(100);
+
+ hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
+ udelay(100);
+
+ msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
+ val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
+ hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
+
+ inno_hdmi_standby(hdmi);
+}
+
+static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
+{
+ struct drm_connector *connector = &hdmi->connector;
+ struct drm_connector_state *conn_state = connector->state;
+ struct inno_hdmi_connector_state *inno_conn_state =
+ to_inno_hdmi_conn_state(conn_state);
+ int c0_c2_change = 0;
+ int csc_enable = 0;
+ int csc_mode = 0;
+ int auto_csc = 0;
+ int value;
+ int i;
+
+ /* Input video mode is SDR RGB24bit, data enable signal from external */
+ hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
+ v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
+
+ /* Input color hardcode to RGB, and output color hardcode to RGB888 */
+ value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
+ v_VIDEO_OUTPUT_COLOR(0) |
+ v_VIDEO_INPUT_CSP(0);
+ hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
+
+ if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
+ if (inno_conn_state->rgb_limited_range) {
+ csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT;
+ auto_csc = AUTO_CSC_DISABLE;
+ c0_c2_change = C0_C2_CHANGE_DISABLE;
+ csc_enable = v_CSC_ENABLE;
+
+ } else {
+ value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
+ hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
+
+ hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
+ m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
+ v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
+ v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
+ return 0;
+ }
+ } else {
+ if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) {
+ if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
+ csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
+ auto_csc = AUTO_CSC_DISABLE;
+ c0_c2_change = C0_C2_CHANGE_DISABLE;
+ csc_enable = v_CSC_ENABLE;
+ }
+ } else {
+ if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
+ csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
+ auto_csc = AUTO_CSC_DISABLE;
+ c0_c2_change = C0_C2_CHANGE_DISABLE;
+ csc_enable = v_CSC_ENABLE;
+ }
+ }
+ }
+
+ for (i = 0; i < 24; i++)
+ hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
+ coeff_csc[csc_mode][i]);
+
+ value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1);
+ hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
+ hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
+ m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
+ v_VIDEO_C0_C2_SWAP(c0_c2_change));
+
+ return 0;
+}
+
+static int inno_hdmi_setup(struct inno_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ struct drm_display_info *display = &hdmi->connector.display_info;
+ unsigned long mpixelclock = mode->clock * 1000;
+
+ /* Mute video and audio output */
+ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
+ v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
+
+ /* Set HDMI Mode */
+ hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
+ v_HDMI_DVI(display->is_hdmi));
+
+ inno_hdmi_config_video_timing(hdmi, mode);
+
+ inno_hdmi_config_video_csc(hdmi);
+
+ if (display->is_hdmi)
+ inno_hdmi_config_video_avi(hdmi, mode);
+
+ /*
+ * When IP controller have configured to an accurate video
+ * timing, then the TMDS clock source would be switched to
+ * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
+ * clock rate, and reconfigure the DDC clock.
+ */
+ inno_hdmi_i2c_init(hdmi, mpixelclock);
+
+ /* Unmute video and audio output */
+ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
+ v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
+
+ inno_hdmi_power_up(hdmi, mpixelclock);
+
+ return 0;
+}
+
+static enum drm_mode_status rk_inno_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
+ struct rk_inno_hdmi *rk_hdmi = dev_get_drvdata(hdmi->dev);
+
+ unsigned long mpixelclk, max_tolerance;
+ long rounded_refclk;
+
+ /* No support for double-clock modes */
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ return MODE_BAD;
+
+ mpixelclk = mode->clock * 1000;
+
+ if (mpixelclk < INNO_HDMI_MIN_TMDS_CLOCK)
+ return MODE_CLOCK_LOW;
+
+ if (inno_hdmi_find_phy_config(hdmi, mpixelclk) < 0)
+ return MODE_CLOCK_HIGH;
+
+ if (rk_hdmi->refclk) {
+ rounded_refclk = clk_round_rate(rk_hdmi->refclk, mpixelclk);
+ if (rounded_refclk < 0)
+ return MODE_BAD;
+
+ /* Vesa DMT standard mentions +/- 0.5% max tolerance */
+ max_tolerance = mpixelclk / 200;
+ if (abs_diff((unsigned long)rounded_refclk, mpixelclk) > max_tolerance)
+ return MODE_NOCLOCK;
+ }
+
+ return MODE_OK;
+}
+
+static void rk_inno_hdmi_encoder_enable(struct drm_encoder *encoder,
+ struct drm_atomic_state *state)
+{
+ struct inno_hdmi *hdmi = rk_encoder_to_inno_hdmi(encoder);
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+
+ conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector);
+ if (WARN_ON(!conn_state))
+ return;
+
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ if (WARN_ON(!crtc_state))
+ return;
+
+ inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode);
+}
+
+static void rk_inno_hdmi_encoder_disable(struct drm_encoder *encoder,
+ struct drm_atomic_state *state)
+{
+ struct inno_hdmi *hdmi = rk_encoder_to_inno_hdmi(encoder);
+
+ inno_hdmi_standby(hdmi);
+}
+
+static int
+rk_inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+ struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+ u8 vic = drm_match_cea_mode(mode);
+ struct inno_hdmi_connector_state *inno_conn_state =
+ to_inno_hdmi_conn_state(conn_state);
+
+ s->output_mode = ROCKCHIP_OUT_MODE_P888;
+ s->output_type = DRM_MODE_CONNECTOR_HDMIA;
+
+ if (vic == 6 || vic == 7 ||
+ vic == 21 || vic == 22 ||
+ vic == 2 || vic == 3 ||
+ vic == 17 || vic == 18)
+ inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601;
+ else
+ inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709;
+
+ inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB;
+ inno_conn_state->rgb_limited_range =
+ drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED;
+
+ return rk_inno_hdmi_connector_mode_valid(conn_state->connector,
+ &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL;
+}
+
+static const struct drm_encoder_helper_funcs rk_inno_encoder_helper_funcs = {
+ .atomic_check = rk_inno_hdmi_encoder_atomic_check,
+ .atomic_enable = rk_inno_hdmi_encoder_enable,
+ .atomic_disable = rk_inno_hdmi_encoder_disable,
+};
+
+static int rk_inno_hdmi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct inno_hdmi *hdmi;
+ int ret;
+ struct rk_inno_hdmi *rk_hdmi;
+
+ rk_hdmi = devm_kzalloc(dev, sizeof(*rk_hdmi), GFP_KERNEL);
+ if (!rk_hdmi)
+ return -ENOMEM;
+ hdmi = &rk_hdmi->inno_hdmi;
+
+ hdmi->dev = dev;
+ hdmi->plat_data = (struct inno_hdmi_plat_data *)of_device_get_match_data(dev);
+
+ hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(hdmi->regs))
+ return PTR_ERR(hdmi->regs);
+
+ rk_hdmi->pclk = devm_clk_get(hdmi->dev, "pclk");
+ if (IS_ERR(rk_hdmi->pclk)) {
+ DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n");
+ return PTR_ERR(rk_hdmi->pclk);
+ }
+
+ ret = clk_prepare_enable(rk_hdmi->pclk);
+ if (ret) {
+ DRM_DEV_ERROR(hdmi->dev,
+ "Cannot enable HDMI pclk clock: %d\n", ret);
+ return ret;
+ }
+
+ rk_hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref");
+ if (IS_ERR(rk_hdmi->refclk)) {
+ DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n");
+ ret = PTR_ERR(rk_hdmi->refclk);
+ goto err_disable_pclk;
+ }
+
+ ret = clk_prepare_enable(rk_hdmi->refclk);
+ if (ret) {
+ DRM_DEV_ERROR(hdmi->dev,
+ "Cannot enable HDMI reference clock: %d\n", ret);
+ goto err_disable_pclk;
+ }
+
+ inno_hdmi_reset(hdmi);
+ /*
+ * When the controller isn't configured to an accurate
+ * video timing and there is no reference clock available,
+ * then the TMDS clock source would be switched to PCLK_HDMI,
+ * so we need to init the TMDS rate to PCLK rate, and
+ * reconfigure the DDC clock.
+ */
+ if (rk_hdmi->refclk)
+ inno_hdmi_i2c_init(hdmi, clk_get_rate(rk_hdmi->refclk));
+ else
+ inno_hdmi_i2c_init(hdmi, clk_get_rate(rk_hdmi->pclk));
+
+ ret = inno_hdmi_bind(drm, hdmi, &rk_hdmi->encoder.encoder);
+ if (ret)
+ goto err_cleanup_hdmi;
+
+ dev_set_drvdata(dev, rk_hdmi);
+
+ return 0;
+
+err_cleanup_hdmi:
+ rk_hdmi->encoder.encoder.funcs->destroy(&rk_hdmi->encoder.encoder);
+ clk_disable_unprepare(rk_hdmi->refclk);
+err_disable_pclk:
+ clk_disable_unprepare(rk_hdmi->pclk);
+ return ret;
+}
+
+static void rk_inno_hdmi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct rk_inno_hdmi *rk_hdmi = dev_get_drvdata(dev);
+ struct inno_hdmi *hdmi = &rk_hdmi->inno_hdmi;
+
+ rk_hdmi->encoder.encoder.funcs->destroy(&rk_hdmi->encoder.encoder);
+ i2c_put_adapter(hdmi->ddc);
+ clk_disable_unprepare(rk_hdmi->refclk);
+ clk_disable_unprepare(rk_hdmi->pclk);
+}
+
+static const struct component_ops inno_hdmi_ops = {
+ .bind = rk_inno_hdmi_bind,
+ .unbind = rk_inno_hdmi_unbind,
+};
+
+static int inno_hdmi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &inno_hdmi_ops);
+}
+
+static void inno_hdmi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &inno_hdmi_ops);
+}
+
+static const struct inno_hdmi_plat_data rk3036_inno_info = {
+ .soc_type = RK3036_HDMI,
+ .mode_valid = rk_inno_hdmi_connector_mode_valid,
+ .helper_private = &rk_inno_encoder_helper_funcs,
+ .phy_configs = rk3036_hdmi_phy_configs,
+ .default_phy_config = &rk3036_hdmi_phy_configs[1],
+};
+
+static const struct inno_hdmi_plat_data rk3128_inno_info = {
+ .soc_type = RK3128_HDMI,
+ .mode_valid = rk_inno_hdmi_connector_mode_valid,
+ .helper_private = &rk_inno_encoder_helper_funcs,
+ .phy_configs = rk3128_hdmi_phy_configs,
+ .default_phy_config = &rk3128_hdmi_phy_configs[1],
+};
+
+static const struct of_device_id inno_hdmi_dt_ids[] = {
+ { .compatible = "rockchip,rk3036-inno-hdmi",
+ .data = &rk3036_inno_info,
+ },
+ { .compatible = "rockchip,rk3128-inno-hdmi",
+ .data = &rk3128_inno_info,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids);
+
+struct platform_driver inno_hdmi_driver = {
+ .probe = inno_hdmi_probe,
+ .remove_new = inno_hdmi_remove,
+ .driver = {
+ .name = "innohdmi-rockchip",
+ .of_match_table = inno_hdmi_dt_ids,
+ },
+};
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.h
similarity index 85%
rename from drivers/gpu/drm/rockchip/inno_hdmi.h
rename to drivers/gpu/drm/rockchip/inno_hdmi-rockchip.h
index a7edf3559e60..c90458d75378 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.h
+++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.h
@@ -8,12 +8,6 @@
#ifndef __INNO_HDMI_H__
#define __INNO_HDMI_H__
-#define DDC_SEGMENT_ADDR 0x30
-
-#define HDMI_SCL_RATE (100*1000)
-#define DDC_BUS_FREQ_L 0x4b
-#define DDC_BUS_FREQ_H 0x4c
-
#define HDMI_SYS_CTRL 0x00
#define m_RST_ANALOG (1 << 6)
#define v_RST_ANALOG (0 << 6)
@@ -98,26 +92,6 @@ enum {
#define v_AUDIO_MUTE(n) (n << 1)
#define v_VIDEO_MUTE(n) (n << 0)
-#define HDMI_VIDEO_TIMING_CTL 0x08
-#define v_HSYNC_POLARITY(n) (n << 3)
-#define v_VSYNC_POLARITY(n) (n << 2)
-#define v_INETLACE(n) (n << 1)
-#define v_EXTERANL_VIDEO(n) (n << 0)
-
-#define HDMI_VIDEO_EXT_HTOTAL_L 0x09
-#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a
-#define HDMI_VIDEO_EXT_HBLANK_L 0x0b
-#define HDMI_VIDEO_EXT_HBLANK_H 0x0c
-#define HDMI_VIDEO_EXT_HDELAY_L 0x0d
-#define HDMI_VIDEO_EXT_HDELAY_H 0x0e
-#define HDMI_VIDEO_EXT_HDURATION_L 0x0f
-#define HDMI_VIDEO_EXT_HDURATION_H 0x10
-#define HDMI_VIDEO_EXT_VTOTAL_L 0x11
-#define HDMI_VIDEO_EXT_VTOTAL_H 0x12
-#define HDMI_VIDEO_EXT_VBLANK 0x13
-#define HDMI_VIDEO_EXT_VDELAY 0x14
-#define HDMI_VIDEO_EXT_VDURATION 0x15
-
#define HDMI_VIDEO_CSC_COEF 0x18
#define HDMI_AUDIO_CTRL1 0x35
@@ -202,14 +176,6 @@ enum {
#define HDMI_AUDIO_CTS_M 0x46
#define HDMI_AUDIO_CTS_L 0x47
-#define HDMI_DDC_CLK_L 0x4b
-#define HDMI_DDC_CLK_H 0x4c
-
-#define HDMI_EDID_SEGMENT_POINTER 0x4d
-#define HDMI_EDID_WORD_ADDR 0x4e
-#define HDMI_EDID_FIFO_OFFSET 0x4f
-#define HDMI_EDID_FIFO_ADDR 0x50
-
#define HDMI_PACKET_SEND_MANUAL 0x9c
#define HDMI_PACKET_SEND_AUTO 0x9d
#define m_PACKET_GCP_EN (1 << 7)
@@ -254,23 +220,12 @@ enum {
#define m_HDMI_DVI (1 << 1)
#define v_HDMI_DVI(n) (n << 1)
-#define HDMI_INTERRUPT_MASK1 0xc0
-#define HDMI_INTERRUPT_STATUS1 0xc1
-#define m_INT_ACTIVE_VSYNC (1 << 5)
-#define m_INT_EDID_READY (1 << 2)
-
#define HDMI_INTERRUPT_MASK2 0xc2
#define HDMI_INTERRUPT_STATUS2 0xc3
#define m_INT_HDCP_ERR (1 << 7)
#define m_INT_BKSV_FLAG (1 << 6)
#define m_INT_HDCP_OK (1 << 4)
-#define HDMI_STATUS 0xc8
-#define m_HOTPLUG (1 << 7)
-#define m_MASK_INT_HOTPLUG (1 << 5)
-#define m_INT_HOTPLUG (1 << 1)
-#define v_MASK_INT_HOTPLUG(n) ((n & 0x1) << 5)
-
#define HDMI_COLORBAR 0xc9
#define HDMI_PHY_SYNC 0xce
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
deleted file mode 100644
index 3df2cfcf9998..000000000000
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ /dev/null
@@ -1,1073 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
- * Zheng Yang <zhengyang@rock-chips.com>
- * Yakir Yang <ykk@rock-chips.com>
- */
-
-#include <linux/irq.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/hdmi.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-
-#include "rockchip_drm_drv.h"
-
-#include "inno_hdmi.h"
-
-#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
-
-struct inno_hdmi_phy_config {
- unsigned long pixelclock;
- u8 pre_emphasis;
- u8 voltage_level_control;
-};
-
-struct inno_hdmi_variant {
- struct inno_hdmi_phy_config *phy_configs;
- struct inno_hdmi_phy_config *default_phy_config;
-};
-
-struct inno_hdmi_i2c {
- struct i2c_adapter adap;
-
- u8 ddc_addr;
- u8 segment_addr;
-
- struct mutex lock;
- struct completion cmp;
-};
-
-struct inno_hdmi {
- struct device *dev;
-
- struct clk *pclk;
- struct clk *refclk;
- void __iomem *regs;
-
- struct drm_connector connector;
- struct rockchip_encoder encoder;
-
- struct inno_hdmi_i2c *i2c;
- struct i2c_adapter *ddc;
-
- const struct inno_hdmi_variant *variant;
-};
-
-struct inno_hdmi_connector_state {
- struct drm_connector_state base;
- unsigned int enc_out_format;
- unsigned int colorimetry;
- bool rgb_limited_range;
-};
-
-static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder)
-{
- struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
-
- return container_of(rkencoder, struct inno_hdmi, encoder);
-}
-
-static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector)
-{
- return container_of(connector, struct inno_hdmi, connector);
-}
-
-#define to_inno_hdmi_conn_state(conn_state) \
- container_of_const(conn_state, struct inno_hdmi_connector_state, base)
-
-enum {
- CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
- CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
- CSC_RGB_0_255_TO_RGB_16_235_8BIT,
-};
-
-static const char coeff_csc[][24] = {
- /*
- * RGB2YUV:601 SD mode:
- * Cb = -0.291G - 0.148R + 0.439B + 128
- * Y = 0.504G + 0.257R + 0.098B + 16
- * Cr = -0.368G + 0.439R - 0.071B + 128
- */
- {
- 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
- 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
- 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
- },
- /*
- * RGB2YUV:709 HD mode:
- * Cb = - 0.338G - 0.101R + 0.439B + 128
- * Y = 0.614G + 0.183R + 0.062B + 16
- * Cr = - 0.399G + 0.439R - 0.040B + 128
- */
- {
- 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
- 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
- 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
- },
- /*
- * RGB[0:255]2RGB[16:235]:
- * R' = R x (235-16)/255 + 16;
- * G' = G x (235-16)/255 + 16;
- * B' = B x (235-16)/255 + 16;
- */
- {
- 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
- 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
- },
-};
-
-static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
- { 74250000, 0x3f, 0xbb },
- { 165000000, 0x6f, 0xbb },
- { ~0UL, 0x00, 0x00 }
-};
-
-static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = {
- { 74250000, 0x3f, 0xaa },
- { 165000000, 0x5f, 0xaa },
- { ~0UL, 0x00, 0x00 }
-};
-
-static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi,
- unsigned long pixelclk)
-{
- const struct inno_hdmi_phy_config *phy_configs =
- hdmi->variant->phy_configs;
- int i;
-
- for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) {
- if (pixelclk <= phy_configs[i].pixelclock)
- return i;
- }
-
- DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n",
- pixelclk);
-
- return -EINVAL;
-}
-
-static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
-{
- return readl_relaxed(hdmi->regs + (offset) * 0x04);
-}
-
-static inline void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val)
-{
- writel_relaxed(val, hdmi->regs + (offset) * 0x04);
-}
-
-static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset,
- u32 msk, u32 val)
-{
- u8 temp = hdmi_readb(hdmi, offset) & ~msk;
-
- temp |= val & msk;
- hdmi_writeb(hdmi, offset, temp);
-}
-
-static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate)
-{
- unsigned long long ddc_bus_freq = rate >> 2;
-
- do_div(ddc_bus_freq, HDMI_SCL_RATE);
-
- hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
- hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
-
- /* Clear the EDID interrupt flag and mute the interrupt */
- hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
- hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
-}
-
-static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable)
-{
- if (enable)
- hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_ON);
- else
- hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF);
-}
-
-static void inno_hdmi_standby(struct inno_hdmi *hdmi)
-{
- inno_hdmi_sys_power(hdmi, false);
-
- hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
- hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
- hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
- hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
-};
-
-static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
- unsigned long mpixelclock)
-{
- struct inno_hdmi_phy_config *phy_config;
- int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock);
-
- if (ret < 0) {
- phy_config = hdmi->variant->default_phy_config;
- DRM_DEV_ERROR(hdmi->dev,
- "Using default phy configuration for TMDS rate %lu",
- mpixelclock);
- } else {
- phy_config = &hdmi->variant->phy_configs[ret];
- }
-
- inno_hdmi_sys_power(hdmi, false);
-
- hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis);
- hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control);
- hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
- hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
- hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
- hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
- hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
- hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
-
- inno_hdmi_sys_power(hdmi, true);
-};
-
-static void inno_hdmi_reset(struct inno_hdmi *hdmi)
-{
- u32 val;
- u32 msk;
-
- hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
- udelay(100);
-
- hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
- udelay(100);
-
- msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
- val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
- hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
-
- inno_hdmi_standby(hdmi);
-}
-
-static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi,
- enum hdmi_infoframe_type type)
-{
- struct drm_connector *connector = &hdmi->connector;
-
- if (type != HDMI_INFOFRAME_TYPE_AVI) {
- drm_err(connector->dev,
- "Unsupported infoframe type: %u\n", type);
- return;
- }
-
- hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
-}
-
-static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi,
- union hdmi_infoframe *frame, enum hdmi_infoframe_type type)
-{
- struct drm_connector *connector = &hdmi->connector;
- u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
- ssize_t rc, i;
-
- if (type != HDMI_INFOFRAME_TYPE_AVI) {
- drm_err(connector->dev,
- "Unsupported infoframe type: %u\n", type);
- return 0;
- }
-
- inno_hdmi_disable_frame(hdmi, type);
-
- rc = hdmi_infoframe_pack(frame, packed_frame,
- sizeof(packed_frame));
- if (rc < 0)
- return rc;
-
- for (i = 0; i < rc; i++)
- hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
- packed_frame[i]);
-
- return 0;
-}
-
-static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
- struct drm_connector *connector = &hdmi->connector;
- struct drm_connector_state *conn_state = connector->state;
- struct inno_hdmi_connector_state *inno_conn_state =
- to_inno_hdmi_conn_state(conn_state);
- union hdmi_infoframe frame;
- int rc;
-
- rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
- &hdmi->connector,
- mode);
- if (rc) {
- inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI);
- return rc;
- }
-
- if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444)
- frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
- else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422)
- frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
- else
- frame.avi.colorspace = HDMI_COLORSPACE_RGB;
-
- if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
- drm_hdmi_avi_infoframe_quant_range(&frame.avi,
- connector, mode,
- inno_conn_state->rgb_limited_range ?
- HDMI_QUANTIZATION_RANGE_LIMITED :
- HDMI_QUANTIZATION_RANGE_FULL);
- } else {
- frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
- frame.avi.ycc_quantization_range =
- HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
- }
-
- return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI);
-}
-
-static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
-{
- struct drm_connector *connector = &hdmi->connector;
- struct drm_connector_state *conn_state = connector->state;
- struct inno_hdmi_connector_state *inno_conn_state =
- to_inno_hdmi_conn_state(conn_state);
- int c0_c2_change = 0;
- int csc_enable = 0;
- int csc_mode = 0;
- int auto_csc = 0;
- int value;
- int i;
-
- /* Input video mode is SDR RGB24bit, data enable signal from external */
- hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
- v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
-
- /* Input color hardcode to RGB, and output color hardcode to RGB888 */
- value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
- v_VIDEO_OUTPUT_COLOR(0) |
- v_VIDEO_INPUT_CSP(0);
- hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
-
- if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
- if (inno_conn_state->rgb_limited_range) {
- csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT;
- auto_csc = AUTO_CSC_DISABLE;
- c0_c2_change = C0_C2_CHANGE_DISABLE;
- csc_enable = v_CSC_ENABLE;
-
- } else {
- value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
- hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
-
- hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
- m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
- v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
- v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
- return 0;
- }
- } else {
- if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) {
- if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
- csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
- auto_csc = AUTO_CSC_DISABLE;
- c0_c2_change = C0_C2_CHANGE_DISABLE;
- csc_enable = v_CSC_ENABLE;
- }
- } else {
- if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
- csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
- auto_csc = AUTO_CSC_DISABLE;
- c0_c2_change = C0_C2_CHANGE_DISABLE;
- csc_enable = v_CSC_ENABLE;
- }
- }
- }
-
- for (i = 0; i < 24; i++)
- hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
- coeff_csc[csc_mode][i]);
-
- value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1);
- hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
- hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
- m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
- v_VIDEO_C0_C2_SWAP(c0_c2_change));
-
- return 0;
-}
-
-static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
- int value;
-
- /* Set detail external video timing polarity and interlace mode */
- value = v_EXTERANL_VIDEO(1);
- value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
- v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0);
- value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
- v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0);
- value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
- v_INETLACE(1) : v_INETLACE(0);
- hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
-
- /* Set detail external video timing */
- value = mode->htotal;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF);
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
-
- value = mode->htotal - mode->hdisplay;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
-
- value = mode->htotal - mode->hsync_start;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
-
- value = mode->hsync_end - mode->hsync_start;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF);
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
-
- value = mode->vtotal;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF);
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
-
- value = mode->vtotal - mode->vdisplay;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
-
- value = mode->vtotal - mode->vsync_start;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
-
- value = mode->vsync_end - mode->vsync_start;
- hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF);
-
- hdmi_writeb(hdmi, HDMI_PHY_PRE_DIV_RATIO, 0x1e);
- hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c);
- hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01);
-
- return 0;
-}
-
-static int inno_hdmi_setup(struct inno_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
- struct drm_display_info *display = &hdmi->connector.display_info;
- unsigned long mpixelclock = mode->clock * 1000;
-
- /* Mute video and audio output */
- hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
- v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
-
- /* Set HDMI Mode */
- hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
- v_HDMI_DVI(display->is_hdmi));
-
- inno_hdmi_config_video_timing(hdmi, mode);
-
- inno_hdmi_config_video_csc(hdmi);
-
- if (display->is_hdmi)
- inno_hdmi_config_video_avi(hdmi, mode);
-
- /*
- * When IP controller have configured to an accurate video
- * timing, then the TMDS clock source would be switched to
- * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
- * clock rate, and reconfigure the DDC clock.
- */
- inno_hdmi_i2c_init(hdmi, mpixelclock);
-
- /* Unmute video and audio output */
- hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
- v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
-
- inno_hdmi_power_up(hdmi, mpixelclock);
-
- return 0;
-}
-
-static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
- unsigned long mpixelclk, max_tolerance;
- long rounded_refclk;
-
- /* No support for double-clock modes */
- if (mode->flags & DRM_MODE_FLAG_DBLCLK)
- return MODE_BAD;
-
- mpixelclk = mode->clock * 1000;
-
- if (mpixelclk < INNO_HDMI_MIN_TMDS_CLOCK)
- return MODE_CLOCK_LOW;
-
- if (inno_hdmi_find_phy_config(hdmi, mpixelclk) < 0)
- return MODE_CLOCK_HIGH;
-
- if (hdmi->refclk) {
- rounded_refclk = clk_round_rate(hdmi->refclk, mpixelclk);
- if (rounded_refclk < 0)
- return MODE_BAD;
-
- /* Vesa DMT standard mentions +/- 0.5% max tolerance */
- max_tolerance = mpixelclk / 200;
- if (abs_diff((unsigned long)rounded_refclk, mpixelclk) > max_tolerance)
- return MODE_NOCLOCK;
- }
-
- return MODE_OK;
-}
-
-static void inno_hdmi_encoder_enable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
-{
- struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
- struct drm_connector_state *conn_state;
- struct drm_crtc_state *crtc_state;
-
- conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector);
- if (WARN_ON(!conn_state))
- return;
-
- crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
- if (WARN_ON(!crtc_state))
- return;
-
- inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode);
-}
-
-static void inno_hdmi_encoder_disable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
-{
- struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
-
- inno_hdmi_standby(hdmi);
-}
-
-static int
-inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
-{
- struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
- struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
- struct drm_display_mode *mode = &crtc_state->adjusted_mode;
- u8 vic = drm_match_cea_mode(mode);
- struct inno_hdmi_connector_state *inno_conn_state =
- to_inno_hdmi_conn_state(conn_state);
-
- s->output_mode = ROCKCHIP_OUT_MODE_P888;
- s->output_type = DRM_MODE_CONNECTOR_HDMIA;
-
- if (vic == 6 || vic == 7 ||
- vic == 21 || vic == 22 ||
- vic == 2 || vic == 3 ||
- vic == 17 || vic == 18)
- inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601;
- else
- inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709;
-
- inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB;
- inno_conn_state->rgb_limited_range =
- drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED;
-
- return inno_hdmi_display_mode_valid(hdmi,
- &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL;
-}
-
-static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = {
- .atomic_check = inno_hdmi_encoder_atomic_check,
- .atomic_enable = inno_hdmi_encoder_enable,
- .atomic_disable = inno_hdmi_encoder_disable,
-};
-
-static enum drm_connector_status
-inno_hdmi_connector_detect(struct drm_connector *connector, bool force)
-{
- struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
-
- return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ?
- connector_status_connected : connector_status_disconnected;
-}
-
-static int inno_hdmi_connector_get_modes(struct drm_connector *connector)
-{
- struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
- const struct drm_edid *drm_edid;
- int ret = 0;
-
- if (!hdmi->ddc)
- return 0;
-
- drm_edid = drm_edid_read_ddc(connector, hdmi->ddc);
- drm_edid_connector_update(connector, drm_edid);
- ret = drm_edid_connector_add_modes(connector);
- drm_edid_free(drm_edid);
-
- return ret;
-}
-
-static enum drm_mode_status
-inno_hdmi_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
-
- return inno_hdmi_display_mode_valid(hdmi, mode);
-}
-
-static void inno_hdmi_connector_destroy(struct drm_connector *connector)
-{
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
-}
-
-static void
-inno_hdmi_connector_destroy_state(struct drm_connector *connector,
- struct drm_connector_state *state)
-{
- struct inno_hdmi_connector_state *inno_conn_state =
- to_inno_hdmi_conn_state(state);
-
- __drm_atomic_helper_connector_destroy_state(&inno_conn_state->base);
- kfree(inno_conn_state);
-}
-
-static void inno_hdmi_connector_reset(struct drm_connector *connector)
-{
- struct inno_hdmi_connector_state *inno_conn_state;
-
- if (connector->state) {
- inno_hdmi_connector_destroy_state(connector, connector->state);
- connector->state = NULL;
- }
-
- inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL);
- if (!inno_conn_state)
- return;
-
- __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base);
-
- inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709;
- inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB;
- inno_conn_state->rgb_limited_range = false;
-}
-
-static struct drm_connector_state *
-inno_hdmi_connector_duplicate_state(struct drm_connector *connector)
-{
- struct inno_hdmi_connector_state *inno_conn_state;
-
- if (WARN_ON(!connector->state))
- return NULL;
-
- inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state),
- sizeof(*inno_conn_state), GFP_KERNEL);
-
- if (!inno_conn_state)
- return NULL;
-
- __drm_atomic_helper_connector_duplicate_state(connector,
- &inno_conn_state->base);
-
- return &inno_conn_state->base;
-}
-
-static const struct drm_connector_funcs inno_hdmi_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .detect = inno_hdmi_connector_detect,
- .destroy = inno_hdmi_connector_destroy,
- .reset = inno_hdmi_connector_reset,
- .atomic_duplicate_state = inno_hdmi_connector_duplicate_state,
- .atomic_destroy_state = inno_hdmi_connector_destroy_state,
-};
-
-static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
- .get_modes = inno_hdmi_connector_get_modes,
- .mode_valid = inno_hdmi_connector_mode_valid,
-};
-
-static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi)
-{
- struct drm_encoder *encoder = &hdmi->encoder.encoder;
- struct device *dev = hdmi->dev;
-
- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
-
- /*
- * If we failed to find the CRTC(s) which this encoder is
- * supposed to be connected to, it's because the CRTC has
- * not been registered yet. Defer probing, and hope that
- * the required CRTC is added later.
- */
- if (encoder->possible_crtcs == 0)
- return -EPROBE_DEFER;
-
- drm_encoder_helper_add(encoder, &inno_hdmi_encoder_helper_funcs);
- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
-
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
-
- drm_connector_helper_add(&hdmi->connector,
- &inno_hdmi_connector_helper_funcs);
- drm_connector_init_with_ddc(drm, &hdmi->connector,
- &inno_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA,
- hdmi->ddc);
-
- drm_connector_attach_encoder(&hdmi->connector, encoder);
-
- return 0;
-}
-
-static irqreturn_t inno_hdmi_i2c_irq(struct inno_hdmi *hdmi)
-{
- struct inno_hdmi_i2c *i2c = hdmi->i2c;
- u8 stat;
-
- stat = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1);
- if (!(stat & m_INT_EDID_READY))
- return IRQ_NONE;
-
- /* Clear HDMI EDID interrupt flag */
- hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
-
- complete(&i2c->cmp);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t inno_hdmi_hardirq(int irq, void *dev_id)
-{
- struct inno_hdmi *hdmi = dev_id;
- irqreturn_t ret = IRQ_NONE;
- u8 interrupt;
-
- if (hdmi->i2c)
- ret = inno_hdmi_i2c_irq(hdmi);
-
- interrupt = hdmi_readb(hdmi, HDMI_STATUS);
- if (interrupt & m_INT_HOTPLUG) {
- hdmi_modb(hdmi, HDMI_STATUS, m_INT_HOTPLUG, m_INT_HOTPLUG);
- ret = IRQ_WAKE_THREAD;
- }
-
- return ret;
-}
-
-static irqreturn_t inno_hdmi_irq(int irq, void *dev_id)
-{
- struct inno_hdmi *hdmi = dev_id;
-
- drm_helper_hpd_irq_event(hdmi->connector.dev);
-
- return IRQ_HANDLED;
-}
-
-static int inno_hdmi_i2c_read(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
-{
- int length = msgs->len;
- u8 *buf = msgs->buf;
- int ret;
-
- ret = wait_for_completion_timeout(&hdmi->i2c->cmp, HZ / 10);
- if (!ret)
- return -EAGAIN;
-
- while (length--)
- *buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR);
-
- return 0;
-}
-
-static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
-{
- /*
- * The DDC module only support read EDID message, so
- * we assume that each word write to this i2c adapter
- * should be the offset of EDID word address.
- */
- if ((msgs->len != 1) ||
- ((msgs->addr != DDC_ADDR) && (msgs->addr != DDC_SEGMENT_ADDR)))
- return -EINVAL;
-
- reinit_completion(&hdmi->i2c->cmp);
-
- if (msgs->addr == DDC_SEGMENT_ADDR)
- hdmi->i2c->segment_addr = msgs->buf[0];
- if (msgs->addr == DDC_ADDR)
- hdmi->i2c->ddc_addr = msgs->buf[0];
-
- /* Set edid fifo first addr */
- hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00);
-
- /* Set edid word address 0x00/0x80 */
- hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr);
-
- /* Set edid segment pointer */
- hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr);
-
- return 0;
-}
-
-static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg *msgs, int num)
-{
- struct inno_hdmi *hdmi = i2c_get_adapdata(adap);
- struct inno_hdmi_i2c *i2c = hdmi->i2c;
- int i, ret = 0;
-
- mutex_lock(&i2c->lock);
-
- /* Clear the EDID interrupt flag and unmute the interrupt */
- hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, m_INT_EDID_READY);
- hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
-
- for (i = 0; i < num; i++) {
- DRM_DEV_DEBUG(hdmi->dev,
- "xfer: num: %d/%d, len: %d, flags: %#x\n",
- i + 1, num, msgs[i].len, msgs[i].flags);
-
- if (msgs[i].flags & I2C_M_RD)
- ret = inno_hdmi_i2c_read(hdmi, &msgs[i]);
- else
- ret = inno_hdmi_i2c_write(hdmi, &msgs[i]);
-
- if (ret < 0)
- break;
- }
-
- if (!ret)
- ret = num;
-
- /* Mute HDMI EDID interrupt */
- hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
-
- mutex_unlock(&i2c->lock);
-
- return ret;
-}
-
-static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-static const struct i2c_algorithm inno_hdmi_algorithm = {
- .master_xfer = inno_hdmi_i2c_xfer,
- .functionality = inno_hdmi_i2c_func,
-};
-
-static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
-{
- struct i2c_adapter *adap;
- struct inno_hdmi_i2c *i2c;
- int ret;
-
- i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);
- if (!i2c)
- return ERR_PTR(-ENOMEM);
-
- mutex_init(&i2c->lock);
- init_completion(&i2c->cmp);
-
- adap = &i2c->adap;
- adap->owner = THIS_MODULE;
- adap->dev.parent = hdmi->dev;
- adap->dev.of_node = hdmi->dev->of_node;
- adap->algo = &inno_hdmi_algorithm;
- strscpy(adap->name, "Inno HDMI", sizeof(adap->name));
- i2c_set_adapdata(adap, hdmi);
-
- ret = i2c_add_adapter(adap);
- if (ret) {
- dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
- devm_kfree(hdmi->dev, i2c);
- return ERR_PTR(ret);
- }
-
- hdmi->i2c = i2c;
-
- DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name);
-
- return adap;
-}
-
-static int inno_hdmi_bind(struct device *dev, struct device *master,
- void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct drm_device *drm = data;
- struct inno_hdmi *hdmi;
- const struct inno_hdmi_variant *variant;
- int irq;
- int ret;
-
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->dev = dev;
-
- variant = of_device_get_match_data(hdmi->dev);
- if (!variant)
- return -EINVAL;
-
- hdmi->variant = variant;
-
- hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
-
- hdmi->pclk = devm_clk_get(hdmi->dev, "pclk");
- if (IS_ERR(hdmi->pclk)) {
- DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n");
- return PTR_ERR(hdmi->pclk);
- }
-
- ret = clk_prepare_enable(hdmi->pclk);
- if (ret) {
- DRM_DEV_ERROR(hdmi->dev,
- "Cannot enable HDMI pclk clock: %d\n", ret);
- return ret;
- }
-
- hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref");
- if (IS_ERR(hdmi->refclk)) {
- DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n");
- ret = PTR_ERR(hdmi->refclk);
- goto err_disable_pclk;
- }
-
- ret = clk_prepare_enable(hdmi->refclk);
- if (ret) {
- DRM_DEV_ERROR(hdmi->dev,
- "Cannot enable HDMI reference clock: %d\n", ret);
- goto err_disable_pclk;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto err_disable_clk;
- }
-
- inno_hdmi_reset(hdmi);
-
- hdmi->ddc = inno_hdmi_i2c_adapter(hdmi);
- if (IS_ERR(hdmi->ddc)) {
- ret = PTR_ERR(hdmi->ddc);
- hdmi->ddc = NULL;
- goto err_disable_clk;
- }
-
- /*
- * When the controller isn't configured to an accurate
- * video timing and there is no reference clock available,
- * then the TMDS clock source would be switched to PCLK_HDMI,
- * so we need to init the TMDS rate to PCLK rate, and
- * reconfigure the DDC clock.
- */
- if (hdmi->refclk)
- inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk));
- else
- inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk));
-
- ret = inno_hdmi_register(drm, hdmi);
- if (ret)
- goto err_put_adapter;
-
- dev_set_drvdata(dev, hdmi);
-
- /* Unmute hotplug interrupt */
- hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
-
- ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
- inno_hdmi_irq, IRQF_SHARED,
- dev_name(dev), hdmi);
- if (ret < 0)
- goto err_cleanup_hdmi;
-
- return 0;
-err_cleanup_hdmi:
- hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
-err_put_adapter:
- i2c_put_adapter(hdmi->ddc);
-err_disable_clk:
- clk_disable_unprepare(hdmi->refclk);
-err_disable_pclk:
- clk_disable_unprepare(hdmi->pclk);
- return ret;
-}
-
-static void inno_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct inno_hdmi *hdmi = dev_get_drvdata(dev);
-
- hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
-
- i2c_put_adapter(hdmi->ddc);
- clk_disable_unprepare(hdmi->refclk);
- clk_disable_unprepare(hdmi->pclk);
-}
-
-static const struct component_ops inno_hdmi_ops = {
- .bind = inno_hdmi_bind,
- .unbind = inno_hdmi_unbind,
-};
-
-static int inno_hdmi_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &inno_hdmi_ops);
-}
-
-static void inno_hdmi_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &inno_hdmi_ops);
-}
-
-static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = {
- .phy_configs = rk3036_hdmi_phy_configs,
- .default_phy_config = &rk3036_hdmi_phy_configs[1],
-};
-
-static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = {
- .phy_configs = rk3128_hdmi_phy_configs,
- .default_phy_config = &rk3128_hdmi_phy_configs[1],
-};
-
-static const struct of_device_id inno_hdmi_dt_ids[] = {
- { .compatible = "rockchip,rk3036-inno-hdmi",
- .data = &rk3036_inno_hdmi_variant,
- },
- { .compatible = "rockchip,rk3128-inno-hdmi",
- .data = &rk3128_inno_hdmi_variant,
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids);
-
-struct platform_driver inno_hdmi_driver = {
- .probe = inno_hdmi_probe,
- .remove_new = inno_hdmi_remove,
- .driver = {
- .name = "innohdmi-rockchip",
- .of_match_table = inno_hdmi_dt_ids,
- },
-};
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (4 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver keith
@ 2024-05-21 10:58 ` keith
2024-05-21 20:50 ` kernel test robot
` (3 more replies)
2024-05-21 10:58 ` [PATCH v4 05/10] drm/vs: add vs mode config init keith
` (5 subsequent siblings)
11 siblings, 4 replies; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
add hardware base api for vs drm
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
MAINTAINERS | 1 +
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/verisilicon/Kconfig | 13 +
drivers/gpu/drm/verisilicon/Makefile | 5 +
drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1060 ++++++++++++++++++++++++
drivers/gpu/drm/verisilicon/vs_dc_hw.h | 493 +++++++++++
drivers/gpu/drm/verisilicon/vs_type.h | 84 ++
8 files changed, 1659 insertions(+)
create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
create mode 100644 drivers/gpu/drm/verisilicon/Makefile
create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
diff --git a/MAINTAINERS b/MAINTAINERS
index cf2d66f88a83..9cb376f76f74 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7156,6 +7156,7 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
F: Documentation/devicetree/bindings/display/starfive/
F: drivers/gpu/drm/bridge/innosilicon/
+F: drivers/gpu/drm/verisilicon
F: include/drm/bridge/inno_hdmi.h
DRM DRIVER FOR SYNAPTICS R63353 PANELS
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 026444eeb5c6..5413d87ef1d6 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -423,6 +423,8 @@ source "drivers/gpu/drm/sprd/Kconfig"
source "drivers/gpu/drm/imagination/Kconfig"
+source "drivers/gpu/drm/verisilicon/Kconfig"
+
config DRM_HYPERV
tristate "DRM Support for Hyper-V synthetic video device"
depends on DRM && PCI && MMU && HYPERV
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f9ca4f8fa6c5..cb27092b1672 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -219,3 +219,4 @@ obj-y += solomon/
obj-$(CONFIG_DRM_SPRD) += sprd/
obj-$(CONFIG_DRM_LOONGSON) += loongson/
obj-$(CONFIG_DRM_POWERVR) += imagination/
+obj-$(CONFIG_DRM_VERISILICON_DC8200) += verisilicon/
diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig
new file mode 100644
index 000000000000..2d733f93439e
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+config DRM_VERISILICON_DC8200
+ tristate "DRM Support for VeriSilicon DC8200"
+ depends on DRM
+ select DRM_KMS_HELPER
+ select DRM_GEM_DMA_HELPER
+ select CMA
+ select DMA_CMA
+ help
+ Choose this option if you have a VeriSilicon DC8200 chipset.
+ This driver provides VeriSilicon kernel mode
+ setting and buffer management. It does not
+ provide 2D or 3D acceleration.
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
new file mode 100644
index 000000000000..7da54b259940
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+vs_drm-objs := vs_dc_hw.o
+
+obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
new file mode 100644
index 000000000000..69f020f8352f
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
@@ -0,0 +1,1060 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/io.h>
+#include <linux/media-bus-format.h>
+//#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_fb_dma_helper.h>
+
+#include "vs_dc_hw.h"
+
+static const u32 horkernel[] = {
+ 0x00000000, 0x20000000, 0x00002000, 0x00000000,
+ 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
+ 0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
+ 0x00000000, 0x00000000, 0x00000000, 0x2b981468,
+ 0x00000000, 0x00000000, 0x00000000, 0x10f00000,
+ 0x00002f10, 0x00000000, 0x00000000, 0x00000000,
+ 0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
+ 0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
+ 0x00000000, 0x3781087f, 0x00000000, 0x00000000,
+ 0x00000000, 0x06660000, 0x0000399a, 0x00000000,
+ 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
+ 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
+ 0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
+ 0x00000000, 0x00000000, 0x00000000, 0x01470000,
+ 0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
+ 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
+ 0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
+ 0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00004000, 0x00000000,
+ 0x00000000, 0x00000000, 0x20002000, 0x00000000,
+ 0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
+ 0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
+ 0x00000000, 0x00000000, 0x00000000, 0x14680000,
+ 0x00002b98, 0x00000000, 0x00000000, 0x00000000,
+ 0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
+ 0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
+ 0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
+ 0x00000000, 0x087f0000, 0x00003781, 0x00000000,
+ 0x00000000, 0x00000000, 0x399a0666, 0x00000000,
+ 0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
+ 0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
+ 0x00000000, 0x00000000, 0x00000000, 0x021f0000,
+};
+
+#define H_COEF_SIZE ARRAY_SIZE(horkernel)
+
+static const u32 verkernel[] = {
+ 0x00000000, 0x20000000, 0x00002000, 0x00000000,
+ 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
+ 0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
+ 0x00000000, 0x00000000, 0x00000000, 0x2b981468,
+ 0x00000000, 0x00000000, 0x00000000, 0x10f00000,
+ 0x00002f10, 0x00000000, 0x00000000, 0x00000000,
+ 0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
+ 0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
+ 0x00000000, 0x3781087f, 0x00000000, 0x00000000,
+ 0x00000000, 0x06660000, 0x0000399a, 0x00000000,
+ 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
+ 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
+ 0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
+ 0x00000000, 0x00000000, 0x00000000, 0x01470000,
+ 0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
+ 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
+ 0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
+ 0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00004000, 0x00000000,
+ 0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
+ 0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
+ 0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+ 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+};
+
+#define V_COEF_SIZE ARRAY_SIZE(verkernel)
+
+/*
+ * RGB 709->2020 conversion parameters
+ */
+static const u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
+ 10279, 5395, 709,
+ 1132, 15065, 187,
+ 269, 1442, 14674
+};
+
+/*
+ * YUV601 to RGB conversion parameters
+ * YUV2RGB[0] - [8] : C0 - C8;
+ * YUV2RGB[9] - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static const s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+ 1196, 0, 1640, 1196,
+ -404, -836, 1196, 2076,
+ 0, -916224, 558336, -1202944,
+ 64, 940, 64, 960
+};
+
+/*
+ * YUV709 to RGB conversion parameters
+ * YUV2RGB[0] - [8] : C0 - C8;
+ * YUV2RGB[9] - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+ 1196, 0, 1844, 1196,
+ -220, -548, 1196, 2172,
+ 0, -1020672, 316672, -1188608,
+ 64, 940, 64, 960
+};
+
+/*
+ * YUV2020 to RGB conversion parameters
+ * YUV2RGB[0] - [8] : C0 - C8;
+ * YUV2RGB[9] - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+ 1196, 0, 1724, 1196,
+ -192, -668, 1196, 2200,
+ 0, -959232, 363776, -1202944,
+ 64, 940, 64, 960
+};
+
+/*
+ * RGB to YUV2020 conversion parameters
+ * RGB2YUV[0] - [8] : C0 - C8;
+ * RGB2YUV[9] - [11]: D0 - D2;
+ */
+static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
+ 230, 594, 52,
+ -125, -323, 448,
+ 448, -412, -36,
+ 64, 512, 512
+};
+
+/* one is for primary plane and the other is for all overlay planes */
+static const struct dc_hw_plane_reg dc_plane_reg[] = {
+ {
+ .y_address = DC_FRAMEBUFFER_ADDRESS,
+ .u_address = DC_FRAMEBUFFER_U_ADDRESS,
+ .v_address = DC_FRAMEBUFFER_V_ADDRESS,
+ .y_stride = DC_FRAMEBUFFER_STRIDE,
+ .u_stride = DC_FRAMEBUFFER_U_STRIDE,
+ .v_stride = DC_FRAMEBUFFER_V_STRIDE,
+ .size = DC_FRAMEBUFFER_SIZE,
+ .top_left = DC_FRAMEBUFFER_TOP_LEFT,
+ .bottom_right = DC_FRAMEBUFFER_BOTTOM_RIGHT,
+ .scale_factor_x = DC_FRAMEBUFFER_SCALE_FACTOR_X,
+ .scale_factor_y = DC_FRAMEBUFFER_SCALE_FACTOR_Y,
+ .h_filter_coef_index = DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
+ .h_filter_coef_data = DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
+ .v_filter_coef_index = DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
+ .v_filter_coef_data = DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
+ .init_offset = DC_FRAMEBUFFER_INIT_OFFSET,
+ .color_key = DC_FRAMEBUFFER_COLOR_KEY,
+ .color_key_high = DC_FRAMEBUFFER_COLOR_KEY_HIGH,
+ .clear_value = DC_FRAMEBUFFER_CLEAR_VALUE,
+ .color_table_index = DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
+ .color_table_data = DC_FRAMEBUFFER_COLOR_TABLE_DATA,
+ .scale_config = DC_FRAMEBUFFER_SCALE_CONFIG,
+ .water_mark = DC_FRAMEBUFFER_WATER_MARK,
+ .degamma_index = DC_FRAMEBUFFER_DEGAMMA_INDEX,
+ .degamma_data = DC_FRAMEBUFFER_DEGAMMA_DATA,
+ .degamma_ex_data = DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
+ .src_global_color = DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
+ .dst_global_color = DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
+ .blend_config = DC_FRAMEBUFFER_BLEND_CONFIG,
+ .roi_origin = DC_FRAMEBUFFER_ROI_ORIGIN,
+ .roi_size = DC_FRAMEBUFFER_ROI_SIZE,
+ .yuv_to_rgb_coef0 = DC_FRAMEBUFFER_YUVTORGB_COEF0,
+ .yuv_to_rgb_coef1 = DC_FRAMEBUFFER_YUVTORGB_COEF1,
+ .yuv_to_rgb_coef2 = DC_FRAMEBUFFER_YUVTORGB_COEF2,
+ .yuv_to_rgb_coef3 = DC_FRAMEBUFFER_YUVTORGB_COEF3,
+ .yuv_to_rgb_coef4 = DC_FRAMEBUFFER_YUVTORGB_COEF4,
+ .yuv_to_rgb_coefd0 = DC_FRAMEBUFFER_YUVTORGB_COEFD0,
+ .yuv_to_rgb_coefd1 = DC_FRAMEBUFFER_YUVTORGB_COEFD1,
+ .yuv_to_rgb_coefd2 = DC_FRAMEBUFFER_YUVTORGB_COEFD2,
+ .y_clamp_bound = DC_FRAMEBUFFER_Y_CLAMP_BOUND,
+ .uv_clamp_bound = DC_FRAMEBUFFER_UV_CLAMP_BOUND,
+ .rgb_to_rgb_coef0 = DC_FRAMEBUFFER_RGBTORGB_COEF0,
+ .rgb_to_rgb_coef1 = DC_FRAMEBUFFER_RGBTORGB_COEF1,
+ .rgb_to_rgb_coef2 = DC_FRAMEBUFFER_RGBTORGB_COEF2,
+ .rgb_to_rgb_coef3 = DC_FRAMEBUFFER_RGBTORGB_COEF3,
+ .rgb_to_rgb_coef4 = DC_FRAMEBUFFER_RGBTORGB_COEF4,
+ },
+ {
+ .y_address = DC_OVERLAY_ADDRESS,
+ .u_address = DC_OVERLAY_U_ADDRESS,
+ .v_address = DC_OVERLAY_V_ADDRESS,
+ .y_stride = DC_OVERLAY_STRIDE,
+ .u_stride = DC_OVERLAY_U_STRIDE,
+ .v_stride = DC_OVERLAY_V_STRIDE,
+ .size = DC_OVERLAY_SIZE,
+ .top_left = DC_OVERLAY_TOP_LEFT,
+ .bottom_right = DC_OVERLAY_BOTTOM_RIGHT,
+ .scale_factor_x = DC_OVERLAY_SCALE_FACTOR_X,
+ .scale_factor_y = DC_OVERLAY_SCALE_FACTOR_Y,
+ .h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
+ .h_filter_coef_data = DC_OVERLAY_H_FILTER_COEF_DATA,
+ .v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
+ .v_filter_coef_data = DC_OVERLAY_V_FILTER_COEF_DATA,
+ .init_offset = DC_OVERLAY_INIT_OFFSET,
+ .color_key = DC_OVERLAY_COLOR_KEY,
+ .color_key_high = DC_OVERLAY_COLOR_KEY_HIGH,
+ .clear_value = DC_OVERLAY_CLEAR_VALUE,
+ .color_table_index = DC_OVERLAY_COLOR_TABLE_INDEX,
+ .color_table_data = DC_OVERLAY_COLOR_TABLE_DATA,
+ .scale_config = DC_OVERLAY_SCALE_CONFIG,
+ .water_mark = DC_OVERLAY_WATER_MARK,
+ .degamma_index = DC_OVERLAY_DEGAMMA_INDEX,
+ .degamma_data = DC_OVERLAY_DEGAMMA_DATA,
+ .degamma_ex_data = DC_OVERLAY_DEGAMMA_EX_DATA,
+ .src_global_color = DC_OVERLAY_SRC_GLOBAL_COLOR,
+ .dst_global_color = DC_OVERLAY_DST_GLOBAL_COLOR,
+ .blend_config = DC_OVERLAY_BLEND_CONFIG,
+ .roi_origin = DC_OVERLAY_ROI_ORIGIN,
+ .roi_size = DC_OVERLAY_ROI_SIZE,
+ .yuv_to_rgb_coef0 = DC_OVERLAY_YUVTORGB_COEF0,
+ .yuv_to_rgb_coef1 = DC_OVERLAY_YUVTORGB_COEF1,
+ .yuv_to_rgb_coef2 = DC_OVERLAY_YUVTORGB_COEF2,
+ .yuv_to_rgb_coef3 = DC_OVERLAY_YUVTORGB_COEF3,
+ .yuv_to_rgb_coef4 = DC_OVERLAY_YUVTORGB_COEF4,
+ .yuv_to_rgb_coefd0 = DC_OVERLAY_YUVTORGB_COEFD0,
+ .yuv_to_rgb_coefd1 = DC_OVERLAY_YUVTORGB_COEFD1,
+ .yuv_to_rgb_coefd2 = DC_OVERLAY_YUVTORGB_COEFD2,
+ .y_clamp_bound = DC_OVERLAY_Y_CLAMP_BOUND,
+ .uv_clamp_bound = DC_OVERLAY_UV_CLAMP_BOUND,
+ .rgb_to_rgb_coef0 = DC_OVERLAY_RGBTORGB_COEF0,
+ .rgb_to_rgb_coef1 = DC_OVERLAY_RGBTORGB_COEF1,
+ .rgb_to_rgb_coef2 = DC_OVERLAY_RGBTORGB_COEF2,
+ .rgb_to_rgb_coef3 = DC_OVERLAY_RGBTORGB_COEF3,
+ .rgb_to_rgb_coef4 = DC_OVERLAY_RGBTORGB_COEF4,
+ },
+};
+
+static inline u32 hi_read(struct dc_hw *hw, u32 reg)
+{
+ return readl(hw->hi_base + reg);
+}
+
+static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
+{
+ writel(value, hw->hi_base + reg);
+}
+
+static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
+{
+ writel(value, hw->reg_base + reg - DC_REG_BASE);
+}
+
+static inline u32 dc_read(struct dc_hw *hw, u32 reg)
+{
+ u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
+
+ return value;
+}
+
+static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
+{
+ u32 value = dc_read(hw, reg);
+
+ value &= ~clear;
+ value |= set;
+ dc_write(hw, reg, value);
+}
+
+static void load_default_filter(struct dc_hw *hw,
+ const struct dc_hw_plane_reg *reg, u32 offset)
+{
+ u8 i;
+
+ dc_write(hw, reg->scale_config + offset, 0x33);
+ dc_write(hw, reg->init_offset + offset, 0x80008000);
+ dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
+ for (i = 0; i < H_COEF_SIZE; i++)
+ dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
+
+ dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
+ for (i = 0; i < V_COEF_SIZE; i++)
+ dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
+}
+
+static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
+ u32 offset, const u16 *table)
+{
+ dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
+ dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
+ dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
+ dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
+ dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
+}
+
+static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
+ u32 offset, const s32 *table)
+{
+ dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
+ (0xFFFF & table[0]) | (table[1] << 16));
+ dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
+ (0xFFFF & table[2]) | (table[3] << 16));
+ dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
+ (0xFFFF & table[4]) | (table[5] << 16));
+ dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
+ (0xFFFF & table[6]) | (table[7] << 16));
+ dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
+ dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
+ dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
+ dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
+ dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
+ dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
+}
+
+static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
+{
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
+ table[0] | (table[1] << 16));
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
+ table[2] | (table[3] << 16));
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
+ table[4] | (table[5] << 16));
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
+ table[6] | (table[7] << 16));
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
+ dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
+}
+
+static int update_vs_format(u32 drm_format)
+{
+ u8 f = FORMAT_A8R8G8B8;
+
+ switch (drm_format) {
+ case DRM_FORMAT_XRGB4444:
+ case DRM_FORMAT_RGBX4444:
+ case DRM_FORMAT_XBGR4444:
+ case DRM_FORMAT_BGRX4444:
+ f = FORMAT_X4R4G4B4;
+ break;
+ case DRM_FORMAT_ARGB4444:
+ case DRM_FORMAT_RGBA4444:
+ case DRM_FORMAT_ABGR4444:
+ case DRM_FORMAT_BGRA4444:
+ f = FORMAT_A4R4G4B4;
+ break;
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_RGBX5551:
+ case DRM_FORMAT_XBGR1555:
+ case DRM_FORMAT_BGRX5551:
+ f = FORMAT_X1R5G5B5;
+ break;
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_BGRA5551:
+ f = FORMAT_A1R5G5B5;
+ break;
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ f = FORMAT_R5G6B5;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_BGRX8888:
+ f = FORMAT_X8R8G8B8;
+ break;
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_BGRA8888:
+ f = FORMAT_A8R8G8B8;
+ break;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVYU:
+ f = FORMAT_YUY2;
+ break;
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ f = FORMAT_UYVY;
+ break;
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ f = FORMAT_YV12;
+ break;
+ case DRM_FORMAT_NV21:
+ f = FORMAT_NV12;
+ break;
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ f = FORMAT_NV16;
+ break;
+ case DRM_FORMAT_P010:
+ f = FORMAT_P010;
+ break;
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_BGRA1010102:
+ f = FORMAT_A2R10G10B10;
+ break;
+ case DRM_FORMAT_NV12:
+ f = FORMAT_NV12;
+ break;
+ case DRM_FORMAT_YUV444:
+ f = FORMAT_YUV444;
+ break;
+ default:
+ break;
+ }
+
+ return f;
+}
+
+int dc_hw_init(struct vs_dc *dc)
+{
+ u8 i, id, panel_num, layer_num;
+ struct dc_hw *hw = &dc->hw;
+ u32 offset;
+
+ layer_num = hw->info->layer_num;
+ for (i = 0; i < layer_num; i++) {
+ id = dc->planes[i].id;
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ hw->reg[i] = dc_plane_reg[0];
+ else
+ hw->reg[i] = dc_plane_reg[1];
+
+ load_default_filter(hw, &hw->reg[i], dc->planes[i].offset);
+ load_rgb_to_rgb(hw, &hw->reg[i], dc->planes[i].offset, RGB2RGB);
+ }
+
+ panel_num = hw->info->panel_num;
+ for (i = 0; i < panel_num; i++) {
+ offset = i << 2;
+
+ load_rgb_to_yuv(hw, offset, RGB2YUV);
+ dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
+
+ offset = i ? DC_CURSOR_OFFSET : 0;
+ dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
+ dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
+ }
+
+ return 0;
+}
+
+void dc_hw_disable_plane(struct vs_dc *dc, u8 id)
+{
+ struct dc_hw *hw = &dc->hw;
+
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + dc->planes[id].offset,
+ PRIMARY_EN(false), PRIMARY_EN_MASK);
+ else
+ dc_set_clear(hw, DC_OVERLAY_CONFIG + dc->planes[id].offset,
+ OVERLAY_FB_EN(false), OVERLAY_FB_EN_MASK);
+}
+
+static int update_cursor_size(uint32_t crtc_w)
+{
+ u8 size_type;
+
+ switch (crtc_w) {
+ case 32:
+ size_type = CURSOR_SIZE_32X32;
+ break;
+ case 64:
+ size_type = CURSOR_SIZE_64X64;
+ break;
+ default:
+ size_type = CURSOR_SIZE_32X32;
+ break;
+ }
+
+ return size_type;
+}
+
+void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr,
+ u32 crtc_w, u32 crtc_x, u32 crtc_y,
+ s32 hotspot_x, s32 hotspot_y)
+{
+ u32 offset, size;
+
+ offset = id ? DC_CURSOR_OFFSET : 0;
+ size = update_cursor_size(crtc_w);
+
+ dc_write(hw, DC_CURSOR_ADDRESS + offset,
+ dma_addr);
+ dc_write(hw, DC_CURSOR_LOCATION + offset,
+ X_LCOTION(crtc_x) |
+ Y_LCOTION(crtc_y));
+ dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
+ CURSOR_HOT_X(hotspot_x) |
+ CURSOR_HOT_y(hotspot_y) |
+ CURSOR_SIZE(size) |
+ CURSOR_VALID(1) |
+ CURSOR_TRIG_FETCH(1) |
+ CURSOR_FORMAT(CURSOR_FORMAT_A8R8G8B8),
+ CURSOR_HOT_X_MASK |
+ CURSOR_HOT_y_MASK |
+ CURSOR_SIZE_MASK |
+ CURSOR_VALID_MASK |
+ CURSOR_TRIG_FETCH_MASK |
+ CURSOR_FORMAT_MASK);
+}
+
+void dc_hw_disable_cursor(struct dc_hw *hw, u8 id)
+{
+ u32 offset = 0;
+
+ offset = id ? DC_CURSOR_OFFSET : 0;
+ dc_set_clear(hw, DC_CURSOR_CONFIG + offset, CURSOR_VALID(1), CURSOR_FORMAT_MASK);
+}
+
+void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
+ u16 r, u16 g, u16 b)
+{
+ if (index >= hw->info->gamma_size)
+ return;
+
+ hw->gamma[id].gamma[index][0] = r;
+ hw->gamma[id].gamma[index][1] = g;
+ hw->gamma[id].gamma[index][2] = b;
+}
+
+void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
+{
+ u32 value;
+
+ if (enable) {
+ dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (id << 2), 0x00);
+ for (int i = 0; i < GAMMA_EX_SIZE; i++) {
+ value = hw->gamma[id].gamma[i][2] |
+ (hw->gamma[id].gamma[i][1] << 12);
+ dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (id << 2), value);
+ dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (id << 2),
+ hw->gamma[id].gamma[i][0]);
+ }
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2), PANEL_GAMMA_EN, 0);
+ } else {
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2), 0, PANEL_GAMMA_EN);
+ }
+}
+
+void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode *mode,
+ u8 encoder_type, u32 output_fmt)
+{
+ u32 dp_cfg, dpi_cfg, offset = id << 2;
+ bool is_yuv = false;
+
+ if (encoder_type != DRM_MODE_ENCODER_DSI) {
+ switch (output_fmt) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ dp_cfg = 0;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ dp_cfg = 1;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ dp_cfg = 2;
+ break;
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ dp_cfg = 3;
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ dp_cfg = 2 << 4;
+ is_yuv = true;
+ break;
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ dp_cfg = 4 << 4;
+ is_yuv = true;
+ break;
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ dp_cfg = 8 << 4;
+ is_yuv = true;
+ break;
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ dp_cfg = 10 << 4;
+ is_yuv = true;
+ break;
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ dp_cfg = 12 << 4;
+ is_yuv = true;
+ break;
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ dp_cfg = 13 << 4;
+ is_yuv = true;
+ break;
+ default:
+ dp_cfg = 2;
+ break;
+ }
+ if (is_yuv)
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, PANEL_RGB2YUV_EN, 0);
+ else
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, PANEL_RGB2YUV_EN);
+ dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | DP_SELECT);
+ }
+
+ if (hw->out[id] == OUT_DPI)
+ dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT);
+
+ switch (output_fmt) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ dpi_cfg = 0;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ dpi_cfg = 3;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+ dpi_cfg = 4;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ dpi_cfg = 5;
+ break;
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ dpi_cfg = 6;
+ break;
+ default:
+ dpi_cfg = 5;
+ break;
+ }
+ dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
+
+ if (id == 0)
+ dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL0_EN | TWO_PANEL_EN);
+ else
+ dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL1_EN | TWO_PANEL_EN);
+
+ dc_write(hw, DC_DISPLAY_H + offset,
+ H_ACTIVE_LEN(mode->hdisplay) |
+ H_TOTAL_LEN(mode->htotal));
+
+ dc_write(hw, DC_DISPLAY_H_SYNC + offset,
+ H_SYNC_START_LEN(mode->hsync_start) |
+ H_SYNC_END_LEN(mode->hsync_end) |
+ H_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PHSYNC ? 0 : 1) |
+ H_PLUS_LEN(1));
+
+ dc_write(hw, DC_DISPLAY_V + offset,
+ V_ACTIVE_LEN(mode->vdisplay) |
+ V_TOTAL_LEN(mode->vtotal));
+
+ dc_write(hw, DC_DISPLAY_V_SYNC + offset,
+ V_SYNC_START_LEN(mode->vsync_start) |
+ V_SYNC_END_LEN(mode->vsync_end) |
+ V_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PVSYNC ? 0 : 1) |
+ V_PLUS_LEN(1));
+
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, PANEL_OUTPUT_EN, 0);
+ dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(id), SYNC_EN);
+}
+
+void dc_hw_disable(struct dc_hw *hw, int id)
+{
+ u32 offset = id << 2;
+
+ if (hw->out[id] == OUT_DPI)
+ dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT);
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, PANEL_OUTPUT_EN);
+ dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(id) | TWO_PANEL_EN);
+}
+
+void dc_hw_enable_interrupt(struct dc_hw *hw)
+{
+ hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
+}
+
+void dc_hw_disable_interrupt(struct dc_hw *hw)
+{
+ hi_write(hw, AQ_INTR_ENBL, 0);
+}
+
+u32 dc_hw_get_interrupt(struct dc_hw *hw)
+{
+ return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
+}
+
+void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable)
+{
+ u32 i, offset;
+ struct dc_hw *hw = &dc->hw;
+ u8 id, layer_num = hw->info->layer_num;
+ u8 panel_num = hw->info->panel_num;
+
+ for (i = 0; i < layer_num; i++) {
+ id = dc->planes[i].id;
+ offset = dc->planes[i].offset;
+ if (enable) {
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+ PRIMARY_SHADOW_EN, 0);
+ else
+ dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+ OVERLAY_SHADOW_EN, 0);
+ } else {
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+ 0, PRIMARY_SHADOW_EN);
+ else
+ dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+ 0, OVERLAY_SHADOW_EN);
+ }
+ }
+
+ for (i = 0; i < panel_num; i++) {
+ offset = i << 2;
+ if (enable)
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, PANEL_SHADOW_EN);
+ else
+ dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, PANEL_SHADOW_EN, 0);
+ }
+}
+
+void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
+{
+ if (out <= OUT_DP)
+ hw->out[id] = out;
+}
+
+static inline u8 to_vs_yuv_color_space(u32 color_space)
+{
+ u8 cs;
+
+ switch (color_space) {
+ case DRM_COLOR_YCBCR_BT601:
+ cs = COLOR_SPACE_601;
+ break;
+ case DRM_COLOR_YCBCR_BT709:
+ cs = COLOR_SPACE_709;
+ break;
+ case DRM_COLOR_YCBCR_BT2020:
+ cs = COLOR_SPACE_2020;
+ break;
+ default:
+ cs = COLOR_SPACE_601;
+ break;
+ }
+
+ return cs;
+}
+
+static inline u8 update_uv_swizzle(u32 format)
+{
+ u8 uv_swizzle = 0;
+
+ switch (format) {
+ case DRM_FORMAT_YVYU:
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV61:
+ uv_swizzle = 1;
+ break;
+ default:
+ break;
+ }
+
+ return uv_swizzle;
+}
+
+static inline u8 update_swizzle(u32 format)
+{
+ u8 swizzle = SWIZZLE_ARGB;
+
+ switch (format) {
+ case DRM_FORMAT_RGBX4444:
+ case DRM_FORMAT_RGBA4444:
+ case DRM_FORMAT_RGBX5551:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGBA1010102:
+ swizzle = SWIZZLE_RGBA;
+ break;
+ case DRM_FORMAT_XBGR4444:
+ case DRM_FORMAT_ABGR4444:
+ case DRM_FORMAT_XBGR1555:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_ABGR2101010:
+ swizzle = SWIZZLE_ABGR;
+ break;
+ case DRM_FORMAT_BGRX4444:
+ case DRM_FORMAT_BGRA4444:
+ case DRM_FORMAT_BGRX5551:
+ case DRM_FORMAT_BGRA5551:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_BGRA1010102:
+ swizzle = SWIZZLE_BGRA;
+ break;
+ default:
+ break;
+ }
+
+ return swizzle;
+}
+
+static inline u8 to_vs_rotation(unsigned int rotation)
+{
+ u8 rot;
+
+ switch (rotation & DRM_MODE_REFLECT_MASK) {
+ case DRM_MODE_REFLECT_X:
+ rot = FLIP_X;
+ return rot;
+ case DRM_MODE_REFLECT_Y:
+ rot = FLIP_Y;
+ return rot;
+ case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
+ rot = FLIP_XY;
+ return rot;
+ default:
+ break;
+ }
+
+ switch (rotation & DRM_MODE_ROTATE_MASK) {
+ case DRM_MODE_ROTATE_0:
+ rot = ROT_0;
+ break;
+ case DRM_MODE_ROTATE_90:
+ rot = ROT_90;
+ break;
+ case DRM_MODE_ROTATE_180:
+ rot = ROT_180;
+ break;
+ case DRM_MODE_ROTATE_270:
+ rot = ROT_270;
+ break;
+ default:
+ rot = ROT_0;
+ break;
+ }
+
+ return rot;
+}
+
+void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format,
+ enum drm_color_encoding encoding, u8 id, bool is_yuv)
+{
+ u32 offset = dc->planes[id].offset;
+ struct dc_hw *hw = &dc->hw;
+
+ if (is_yuv) {
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+ PRIMARY_YUVCLAMP_EN, PRIMARY_RGB2RGB_EN);
+ else
+ dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+ OVERLAY_CLAMP_EN, OVERLAY_RGB2RGB_EN);
+
+ switch (to_vs_yuv_color_space(encoding)) {
+ case COLOR_SPACE_601:
+ load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV601_2RGB);
+ break;
+ case COLOR_SPACE_709:
+ load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV709_2RGB);
+ break;
+ case COLOR_SPACE_2020:
+ load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV2020_2RGB);
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+ PRIMARY_RGB2RGB_EN, PRIMARY_YUVCLAMP_EN);
+ else
+ dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+ OVERLAY_RGB2RGB_EN, OVERLAY_CLAMP_EN);
+ }
+}
+
+void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format, dma_addr_t *dma_addr,
+ struct drm_framebuffer *drm_fb, struct drm_rect *src)
+{
+ u32 offset = dc->planes[id].offset;
+ struct dc_hw *hw = &dc->hw;
+
+ dc_write(hw, hw->reg[id].y_address + offset, dma_addr[0]);
+ dc_write(hw, hw->reg[id].u_address + offset,
+ format == DRM_FORMAT_YVU420 ?
+ dma_addr[2] : dma_addr[1]);
+ dc_write(hw, hw->reg[id].v_address + offset,
+ format == DRM_FORMAT_YVU420 ?
+ dma_addr[1] : dma_addr[2]);
+ dc_write(hw, hw->reg[id].y_stride + offset, drm_fb->pitches[0]);
+ dc_write(hw, hw->reg[id].u_stride + offset,
+ format == DRM_FORMAT_YVU420 ?
+ drm_fb->pitches[2] : drm_fb->pitches[1]);
+ dc_write(hw, hw->reg[id].v_stride + offset,
+ format == DRM_FORMAT_YVU420 ?
+ drm_fb->pitches[1] : drm_fb->pitches[2]);
+ dc_write(hw, hw->reg[id].size + offset,
+ FB_SIZE(drm_rect_width(src) >> 16, drm_rect_height(src) >> 16));
+}
+
+void plane_hw_update_format(struct vs_dc *dc, u32 format, enum drm_color_encoding encoding,
+ unsigned int rotation, bool visible, unsigned int zpos,
+ u8 id, u8 display_id)
+{
+ u32 offset = dc->planes[id].offset;
+ struct dc_hw *hw = &dc->hw;
+
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
+ PRIMARY_FORMAT(update_vs_format(format)) |
+ PRIMARY_UV_SWIZ(update_uv_swizzle(format)) |
+ PRIMARY_SWIZ(update_swizzle(format)) |
+ PRIMARY_TILE(DRM_FORMAT_MOD_LINEAR) |
+ PRIMARY_YUV_COLOR(to_vs_yuv_color_space(encoding)) |
+ PRIMARY_ROTATION(to_vs_rotation(rotation)),
+ PRIMARY_FORMAT_MASK |
+ PRIMARY_UV_SWIZ_MASK |
+ PRIMARY_SWIZ_MASK |
+ PRIMARY_TILE_MASK |
+ PRIMARY_YUV_COLOR_MASK |
+ PRIMARY_ROTATION_MASK |
+ PRIMARY_CLEAR_EN_MASK);
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+ PRIMARY_DECODER_EN(false) |
+ PRIMARY_EN(visible) |
+ PRIMARY_ZPOS(zpos) |
+ PRIMARY_CHANNEL(display_id),
+ PRIMARY_DECODER_EN_EN_MASK |
+ PRIMARY_EN_MASK |
+ PRIMARY_ZPOS_MASK |
+ PRIMARY_CHANNEL_MASK);
+ } else {
+ dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+ OVERLAY_FB_EN(visible) |
+ OVERLAY_FORMAT(update_vs_format(format)) |
+ OVERLAY_UV_SWIZ(update_uv_swizzle(format)) |
+ OVERLAY_SWIZ(update_swizzle(format)) |
+ OVERLAY_TILE(DRM_FORMAT_MOD_LINEAR) |
+ OVERLAY_YUV_COLOR(to_vs_yuv_color_space(encoding)) |
+ OVERLAY_ROTATION(to_vs_rotation(rotation)),
+ OVERLAY_DEC_EN_MASK |
+ OVERLAY_CLEAR_EN_MASK |
+ OVERLAY_FB_EN_MASK |
+ OVERLAY_FORMAT_MASK |
+ OVERLAY_UV_SWIZ_MASK |
+ OVERLAY_SWIZ_MASK |
+ OVERLAY_TILE_MASK |
+ OVERLAY_YUV_COLOR_MASK |
+ OVERLAY_ROTATION_MASK);
+
+ dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
+ OVERLAY_LAYER_SEL(zpos) |
+ OVERLAY_PANEL_SEL(display_id),
+ OVERLAY_LAYER_SEL_MASK |
+ OVERLAY_PANEL_SEL_MASK);
+ }
+}
+
+static u32 calc_factor(u32 src, u32 dest)
+{
+ u32 factor = 1 << 16;
+
+ if (src > 1 && dest > 1)
+ factor = ((src - 1) << 16) / (dest - 1);
+
+ return factor;
+}
+
+void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct drm_rect *dst,
+ u8 id, u8 display_id, unsigned int rotation)
+{
+ u32 offset = dc->planes[id].offset;
+ struct dc_hw *hw = &dc->hw;
+
+ int dst_w = drm_rect_width(dst);
+ int dst_h = drm_rect_height(dst);
+ int src_w, src_h, temp;
+ u32 scale_factor_x;
+ u32 scale_factor_y;
+ bool enable_scale = false;
+
+ src_w = drm_rect_width(src) >> 16;
+ src_h = drm_rect_height(src) >> 16;
+
+ if (drm_rotation_90_or_270(rotation)) {
+ temp = src_w;
+ src_w = src_h;
+ src_h = temp;
+ }
+
+ if (src_w != dst_w) {
+ scale_factor_x = calc_factor(src_w, dst_w);
+ enable_scale = true;
+ } else {
+ scale_factor_x = 1 << 16;
+ }
+ if (src_h != dst_h) {
+ scale_factor_y = calc_factor(src_h, dst_h);
+ enable_scale = true;
+ } else {
+ scale_factor_y = 1 << 16;
+ }
+ if (enable_scale) {
+ dc_write(hw, hw->reg[id].scale_factor_x + offset, scale_factor_x);
+ dc_write(hw, hw->reg[id].scale_factor_y + offset, scale_factor_y);
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, PRIMARY_SCALE_EN, 0);
+ else
+ dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset, OVERLAY_SCALE_EN, 0);
+ } else {
+ if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+ dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, 0, PRIMARY_SCALE_EN);
+ else
+ dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset, 0, OVERLAY_SCALE_EN);
+ }
+
+ dc_write(hw, hw->reg[id].top_left + offset, X_POS(dst->x1) | Y_POS(dst->y1));
+ dc_write(hw, hw->reg[id].bottom_right + offset, X_POS(dst->x2) | Y_POS(dst->y2));
+}
+
+void plane_hw_update_blend(struct vs_dc *dc, u16 alpha,
+ u16 pixel_blend_mode, u8 id, u8 display_id)
+{
+ u32 offset = dc->planes[id].offset;
+ struct dc_hw *hw = &dc->hw;
+
+ dc_write(hw, hw->reg[id].src_global_color + offset, PRIMARY_ALPHA_LEN(alpha >> 8));
+ dc_write(hw, hw->reg[id].dst_global_color + offset, PRIMARY_ALPHA_LEN(alpha >> 8));
+ switch (pixel_blend_mode) {
+ case DRM_MODE_BLEND_PREMULTI:
+ dc_write(hw, hw->reg[id].blend_config + offset, BLEND_PREMULTI);
+ break;
+ case DRM_MODE_BLEND_COVERAGE:
+ dc_write(hw, hw->reg[id].blend_config + offset, BLEND_COVERAGE);
+ break;
+ case DRM_MODE_BLEND_PIXEL_NONE:
+ dc_write(hw, hw->reg[id].blend_config + offset, BLEND_PIXEL_NONE);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
new file mode 100644
index 000000000000..63d8d153f57f
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
@@ -0,0 +1,493 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DC_HW_H__
+#define __VS_DC_HW_H__
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <drm/drm_atomic.h>
+
+#include "vs_type.h"
+
+#define UPDATE(x, h, l) FIELD_PREP(GENMASK(h, l), x)
+
+#define AQ_INTR_ACKNOWLEDGE 0x0010
+#define AQ_INTR_ENBL 0x0014
+#define DC_HW_REVISION 0x0024
+#define DC_HW_CHIP_CID 0x0030
+
+#define DC_REG_BASE 0x0800
+#define DC_REG_RANGE 0x2000
+#define DC_SEC_REG_OFFSET 0x100000
+
+#define DC_FRAMEBUFFER_CONFIG 0x1518
+# define PRIMARY_FORMAT(x) ((x) << 26)
+# define PRIMARY_FORMAT_MASK GENMASK(31, 26)
+# define PRIMARY_UV_SWIZ(x) ((x) << 25)
+# define PRIMARY_UV_SWIZ_MASK GENMASK(25, 25)
+# define PRIMARY_SWIZ(x) ((x) << 23)
+# define PRIMARY_SWIZ_MASK GENMASK(24, 23)
+# define PRIMARY_SCALE_EN BIT(12)
+# define PRIMARY_TILE(x) ((x) << 17)
+# define PRIMARY_TILE_MASK GENMASK(21, 17)
+# define PRIMARY_YUV_COLOR(x) ((x) << 14)
+# define PRIMARY_YUV_COLOR_MASK GENMASK(16, 14)
+# define PRIMARY_ROTATION(x) ((x) << 11)
+# define PRIMARY_ROTATION_MASK GENMASK(13, 11)
+# define PRIMARY_CLEAR_EN(x) ((x) << 8)
+# define PRIMARY_CLEAR_EN_MASK GENMASK(8, 8)
+
+#define DC_FRAMEBUFFER_CONFIG_EX 0x1CC0
+# define PRIMARY_CHANNEL(x) ((x) << 19)
+# define PRIMARY_CHANNEL_MASK GENMASK(19, 19)
+# define PRIMARY_ZPOS(x) ((x) << 16)
+# define PRIMARY_ZPOS_MASK GENMASK(18, 16)
+# define PRIMARY_EN(x) ((x) << 13)
+# define PRIMARY_EN_MASK GENMASK(13, 13)
+# define PRIMARY_SHADOW_EN BIT(12)
+# define PRIMARY_YUVCLAMP_EN BIT(8)
+# define PRIMARY_RGB2RGB_EN BIT(6)
+# define PRIMARY_SYNC1_EN BIT(4)
+# define PRIMARY_SYNC0_EN BIT(3)
+# define PRIMARY_DECODER_EN(x) ((x) << 1)
+# define PRIMARY_DECODER_EN_EN_MASK GENMASK(1, 1)
+
+#define DC_FRAMEBUFFER_SCALE_CONFIG 0x1520
+#define DC_FRAMEBUFFER_TOP_LEFT 0x24D8
+#define X_POS(x) (x)
+#define Y_POS(x) ((x) << 15)
+
+#define DC_FRAMEBUFFER_BOTTOM_RIGHT 0x24E0
+#define DC_FRAMEBUFFER_ADDRESS 0x1400
+#define DC_FRAMEBUFFER_U_ADDRESS 0x1530
+#define DC_FRAMEBUFFER_V_ADDRESS 0x1538
+#define DC_FRAMEBUFFER_STRIDE 0x1408
+#define DC_FRAMEBUFFER_U_STRIDE 0x1800
+#define DC_FRAMEBUFFER_V_STRIDE 0x1808
+#define DC_FRAMEBUFFER_SIZE 0x1810
+#define FB_SIZE(w, h) ((w) | ((h) << 15))
+
+#define DC_FRAMEBUFFER_SCALE_FACTOR_X 0x1828
+#define DC_FRAMEBUFFER_SCALE_FACTOR_Y 0x1830
+#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX 0x1838
+#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA 0x1A00
+#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX 0x1A08
+#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA 0x1A10
+#define DC_FRAMEBUFFER_INIT_OFFSET 0x1A20
+#define DC_FRAMEBUFFER_COLOR_KEY 0x1508
+#define DC_FRAMEBUFFER_COLOR_KEY_HIGH 0x1510
+#define DC_FRAMEBUFFER_CLEAR_VALUE 0x1A18
+#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX 0x1818
+#define DC_FRAMEBUFFER_COLOR_TABLE_DATA 0x1820
+#define DC_FRAMEBUFFER_BG_COLOR 0x1528
+#define DC_FRAMEBUFFER_ROI_ORIGIN 0x1CB0
+#define DC_FRAMEBUFFER_ROI_SIZE 0x1CB8
+#define DC_FRAMEBUFFER_WATER_MARK 0x1CE8
+#define DC_FRAMEBUFFER_DEGAMMA_INDEX 0x1D88
+#define DC_FRAMEBUFFER_DEGAMMA_DATA 0x1D90
+#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA 0x1D98
+#define DC_FRAMEBUFFER_YUVTORGB_COEF0 0x1DA0
+#define DC_FRAMEBUFFER_YUVTORGB_COEF1 0x1DA8
+#define DC_FRAMEBUFFER_YUVTORGB_COEF2 0x1DB0
+#define DC_FRAMEBUFFER_YUVTORGB_COEF3 0x1DB8
+#define DC_FRAMEBUFFER_YUVTORGB_COEF4 0x1E00
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD0 0x1E08
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD1 0x1E10
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD2 0x1E18
+#define DC_FRAMEBUFFER_Y_CLAMP_BOUND 0x1E88
+#define DC_FRAMEBUFFER_UV_CLAMP_BOUND 0x1E90
+#define DC_FRAMEBUFFER_RGBTORGB_COEF0 0x1E20
+#define DC_FRAMEBUFFER_RGBTORGB_COEF1 0x1E28
+#define DC_FRAMEBUFFER_RGBTORGB_COEF2 0x1E30
+#define DC_FRAMEBUFFER_RGBTORGB_COEF3 0x1E38
+#define DC_FRAMEBUFFER_RGBTORGB_COEF4 0x1E40
+#define DC_FRAMEBUFFER_BLEND_CONFIG 0x2510
+# define BLEND_PREMULTI 0x3450
+# define BLEND_COVERAGE 0x3950
+# define BLEND_PIXEL_NONE 0x3548
+
+#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR 0x2500
+# define PRIMARY_ALPHA_LEN(x) ((x) << 24)
+
+#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR 0x2508
+
+#define DC_OVERLAY_CONFIG 0x1540
+# define OVERLAY_SHADOW_EN BIT(31)
+# define OVERLAY_CLAMP_EN BIT(30)
+# define OVERLAY_RGB2RGB_EN BIT(29)
+# define OVERLAY_DEC_EN(x) ((x) << 27)
+# define OVERLAY_DEC_EN_MASK GENMASK(27, 27)
+# define OVERLAY_CLEAR_EN(x) ((x) << 25)
+# define OVERLAY_CLEAR_EN_MASK GENMASK(25, 25)
+# define OVERLAY_FB_EN(x) ((x) << 24)
+# define OVERLAY_FB_EN_MASK GENMASK(24, 24)
+# define OVERLAY_FORMAT(x) ((x) << 16)
+# define OVERLAY_FORMAT_MASK GENMASK(21, 16)
+# define OVERLAY_UV_SWIZ(x) ((x) << 15)
+# define OVERLAY_UV_SWIZ_MASK GENMASK(15, 15)
+# define OVERLAY_SWIZ(x) ((x) << 13)
+# define OVERLAY_SWIZ_MASK GENMASK(14, 13)
+# define OVERLAY_TILE(x) ((x) << 8)
+# define OVERLAY_TILE_MASK GENMASK(12, 8)
+# define OVERLAY_YUV_COLOR(x) ((x) << 5)
+# define OVERLAY_YUV_COLOR_MASK GENMASK(7, 5)
+# define OVERLAY_ROTATION(x) ((x) << 2)
+# define OVERLAY_ROTATION_MASK GENMASK(4, 2)
+
+#define DC_OVERLAY_CONFIG_EX 0x2540
+# define OVERLAY_LAYER_SEL(x) ((x) << 0)
+# define OVERLAY_LAYER_SEL_MASK GENMASK(2, 0)
+# define OVERLAY_PANEL_SEL(x) ((x) << 3)
+# define OVERLAY_PANEL_SEL_MASK GENMASK(3, 3)
+
+#define DC_OVERLAY_SCALE_CONFIG 0x1C00
+# define OVERLAY_SCALE_EN BIT(8)
+
+#define DC_OVERLAY_BLEND_CONFIG 0x1580
+#define DC_OVERLAY_TOP_LEFT 0x1640
+#define DC_OVERLAY_BOTTOM_RIGHT 0x1680
+#define DC_OVERLAY_ADDRESS 0x15C0
+#define DC_OVERLAY_U_ADDRESS 0x1840
+#define DC_OVERLAY_V_ADDRESS 0x1880
+#define DC_OVERLAY_STRIDE 0x1600
+#define DC_OVERLAY_U_STRIDE 0x18C0
+#define DC_OVERLAY_V_STRIDE 0x1900
+#define DC_OVERLAY_SIZE 0x17C0
+#define DC_OVERLAY_SCALE_FACTOR_X 0x1A40
+#define DC_OVERLAY_SCALE_FACTOR_Y 0x1A80
+#define DC_OVERLAY_H_FILTER_COEF_INDEX 0x1AC0
+#define DC_OVERLAY_H_FILTER_COEF_DATA 0x1B00
+#define DC_OVERLAY_V_FILTER_COEF_INDEX 0x1B40
+#define DC_OVERLAY_V_FILTER_COEF_DATA 0x1B80
+#define DC_OVERLAY_INIT_OFFSET 0x1BC0
+#define DC_OVERLAY_COLOR_KEY 0x1740
+#define DC_OVERLAY_COLOR_KEY_HIGH 0x1780
+#define DC_OVERLAY_CLEAR_VALUE 0x1940
+#define DC_OVERLAY_COLOR_TABLE_INDEX 0x1980
+#define DC_OVERLAY_COLOR_TABLE_DATA 0x19C0
+#define DC_OVERLAY_SRC_GLOBAL_COLOR 0x16C0
+# define OVERLAY_ALPHA_LEN(x) ((x) << 24)
+
+#define DC_OVERLAY_DST_GLOBAL_COLOR 0x1700
+#define DC_OVERLAY_ROI_ORIGIN 0x1D00
+#define DC_OVERLAY_ROI_SIZE 0x1D40
+#define DC_OVERLAY_WATER_MARK 0x1DC0
+#define DC_OVERLAY_DEGAMMA_INDEX 0x2200
+#define DC_OVERLAY_DEGAMMA_DATA 0x2240
+#define DC_OVERLAY_DEGAMMA_EX_DATA 0x2280
+#define DC_OVERLAY_YUVTORGB_COEF0 0x1EC0
+#define DC_OVERLAY_YUVTORGB_COEF1 0x1F00
+#define DC_OVERLAY_YUVTORGB_COEF2 0x1F40
+#define DC_OVERLAY_YUVTORGB_COEF3 0x1F80
+#define DC_OVERLAY_YUVTORGB_COEF4 0x1FC0
+#define DC_OVERLAY_YUVTORGB_COEFD0 0x2000
+#define DC_OVERLAY_YUVTORGB_COEFD1 0x2040
+#define DC_OVERLAY_YUVTORGB_COEFD2 0x2080
+#define DC_OVERLAY_Y_CLAMP_BOUND 0x22C0
+#define DC_OVERLAY_UV_CLAMP_BOUND 0x2300
+#define DC_OVERLAY_RGBTORGB_COEF0 0x20C0
+#define DC_OVERLAY_RGBTORGB_COEF1 0x2100
+#define DC_OVERLAY_RGBTORGB_COEF2 0x2140
+#define DC_OVERLAY_RGBTORGB_COEF3 0x2180
+#define DC_OVERLAY_RGBTORGB_COEF4 0x21C0
+
+#define DC_CURSOR_CONFIG 0x1468
+# define CURSOR_HOT_X(x) ((x) << 16)
+# define CURSOR_HOT_X_MASK GENMASK(23, 16)
+# define CURSOR_HOT_y(x) ((x) << 8)
+# define CURSOR_HOT_y_MASK GENMASK(15, 8)
+# define CURSOR_SIZE(x) ((x) << 5)
+# define CURSOR_SIZE_MASK GENMASK(7, 5)
+# define CURSOR_VALID(x) ((x) << 3)
+# define CURSOR_VALID_MASK GENMASK(3, 3)
+# define CURSOR_TRIG_FETCH(x) ((x) << 2)
+# define CURSOR_TRIG_FETCH_MASK GENMASK(2, 2)
+# define CURSOR_FORMAT(x) ((x) << 0)
+# define CURSOR_FORMAT_MASK GENMASK(1, 0)
+# define CURSOR_FORMAT_DISABLE 0
+# define CURSOR_FORMAT_MARK 1
+# define CURSOR_FORMAT_A8R8G8B8 2
+
+#define DC_CURSOR_ADDRESS 0x146C
+#define DC_CURSOR_LOCATION 0x1470
+# define X_LCOTION(x) (x)
+# define Y_LCOTION(x) ((x) << 16)
+
+#define DC_CURSOR_BACKGROUND 0x1474
+#define DC_CURSOR_FOREGROUND 0x1478
+#define DC_CURSOR_CLK_GATING 0x1484
+#define DC_CURSOR_CONFIG_EX 0x24E8
+#define DC_CURSOR_OFFSET 0x1080
+
+#define DC_DISPLAY_DITHER_CONFIG 0x1410
+#define DC_DISPLAY_PANEL_CONFIG 0x1418
+# define PANEL_RGB2YUV_EN BIT(16)
+# define PANEL_GAMMA_EN BIT(13)
+# define PANEL_OUTPUT_EN BIT(12)
+
+#define DC_DISPLAY_PANEL_CONFIG_EX 0x2518
+# define PANEL_SHADOW_EN BIT(0)
+
+#define DC_DISPLAY_DITHER_TABLE_LOW 0x1420
+#define DC_DISPLAY_DITHER_TABLE_HIGH 0x1428
+#define DC_DISPLAY_H 0x1430
+# define H_ACTIVE_LEN(x) (x)
+# define H_TOTAL_LEN(x) ((x) << 16)
+
+#define DC_DISPLAY_H_SYNC 0x1438
+# define H_SYNC_START_LEN(x) (x)
+# define H_SYNC_END_LEN(x) ((x) << 15)
+# define H_PLUS_LEN(x) ((x) << 30)
+# define H_POLARITY_LEN(x) ((x) << 31)
+
+#define DC_DISPLAY_V 0x1440
+# define V_ACTIVE_LEN(x) (x)
+# define V_TOTAL_LEN(x) ((x) << 16)
+
+#define DC_DISPLAY_V_SYNC 0x1448
+# define V_SYNC_START_LEN(x) (x)
+# define V_SYNC_END_LEN(x) ((x) << 15)
+# define V_PLUS_LEN(x) ((x) << 30)
+# define V_POLARITY_LEN(x) ((x) << 31)
+
+#define DC_DISPLAY_CURRENT_LOCATION 0x1450
+#define DC_DISPLAY_GAMMA_INDEX 0x1458
+#define DC_DISPLAY_GAMMA_DATA 0x1460
+#define DC_DISPLAY_INT 0x147C
+#define DC_DISPLAY_INT_ENABLE 0x1480
+#define DC_DISPLAY_DBI_CONFIG 0x1488
+#define DC_DISPLAY_GENERAL_CONFIG 0x14B0
+#define DC_DISPLAY_DPI_CONFIG 0x14B8
+#define DC_DISPLAY_PANEL_START 0x1CCC
+# define PANEL0_EN BIT(0)
+# define PANEL1_EN BIT(1)
+# define TWO_PANEL_EN BIT(2)
+# define SYNC_EN BIT(3)
+
+#define DC_DISPLAY_DEBUG_COUNTER_SELECT 0x14D0
+#define DC_DISPLAY_DEBUG_COUNTER_VALUE 0x14D8
+#define DC_DISPLAY_DP_CONFIG 0x1CD0
+# define DP_SELECT BIT(3)
+
+#define DC_DISPLAY_GAMMA_EX_INDEX 0x1CF0
+#define DC_DISPLAY_GAMMA_EX_DATA 0x1CF8
+#define DC_DISPLAY_GAMMA_EX_ONE_DATA 0x1D80
+#define DC_DISPLAY_RGBTOYUV_COEF0 0x1E48
+#define DC_DISPLAY_RGBTOYUV_COEF1 0x1E50
+#define DC_DISPLAY_RGBTOYUV_COEF2 0x1E58
+#define DC_DISPLAY_RGBTOYUV_COEF3 0x1E60
+#define DC_DISPLAY_RGBTOYUV_COEF4 0x1E68
+#define DC_DISPLAY_RGBTOYUV_COEFD0 0x1E70
+#define DC_DISPLAY_RGBTOYUV_COEFD1 0x1E78
+#define DC_DISPLAY_RGBTOYUV_COEFD2 0x1E80
+
+#define DC_CLK_GATTING 0x1A28
+#define DC_QOS_CONFIG 0x1A38
+
+#define DC_TRANSPARENCY_OPAQUE 0x00
+#define DC_TRANSPARENCY_KEY 0x02
+#define DC_DISPLAY_DITHERTABLE_LOW 0x7B48F3C0
+#define DC_DISPLAY_DITHERTABLE_HIGH 0x596AD1E2
+
+#define DC_TILE_MODE4X4 0x15
+
+#define GAMMA_SIZE 256
+#define GAMMA_EX_SIZE 300
+#define DEGAMMA_SIZE 260
+
+#define RGB_TO_RGB_TABLE_SIZE 9
+#define YUV_TO_RGB_TABLE_SIZE 16
+#define RGB_TO_YUV_TABLE_SIZE 12
+
+#define DC_LAYER_NUM 6
+#define DC_DISPLAY_NUM 2
+#define DC_CURSOR_NUM 2
+
+enum dc_hw_plane_id {
+ PRIMARY_PLANE_0,
+ OVERLAY_PLANE_0,
+ OVERLAY_PLANE_1,
+ PRIMARY_PLANE_1,
+ OVERLAY_PLANE_2,
+ OVERLAY_PLANE_3,
+ CURSOR_PLANE_0,
+ CURSOR_PLANE_1,
+ PLANE_NUM
+};
+
+enum dc_hw_color_format {
+ FORMAT_X4R4G4B4,
+ FORMAT_A4R4G4B4,
+ FORMAT_X1R5G5B5,
+ FORMAT_A1R5G5B5,
+ FORMAT_R5G6B5,
+ FORMAT_X8R8G8B8,
+ FORMAT_A8R8G8B8,
+ FORMAT_YUY2,
+ FORMAT_UYVY,
+ FORMAT_INDEX8,
+ FORMAT_MONOCHROME,
+ FORMAT_YV12 = 0xf,
+ FORMAT_A8,
+ FORMAT_NV12,
+ FORMAT_NV16,
+ FORMAT_RG16,
+ FORMAT_R8,
+ FORMAT_NV12_10BIT,
+ FORMAT_A2R10G10B10,
+ FORMAT_NV16_10BIT,
+ FORMAT_INDEX1,
+ FORMAT_INDEX2,
+ FORMAT_INDEX4,
+ FORMAT_P010,
+ FORMAT_YUV444,
+ FORMAT_YUV444_10BIT,
+};
+
+enum dc_hw_yuv_color_space {
+ COLOR_SPACE_601 = 0,
+ COLOR_SPACE_709 = 1,
+ COLOR_SPACE_2020 = 3,
+};
+
+enum dc_hw_rotation {
+ ROT_0 = 0,
+ ROT_90 = 4,
+ ROT_180 = 5,
+ ROT_270 = 6,
+ FLIP_X = 1,
+ FLIP_Y = 2,
+ FLIP_XY = 3,
+};
+
+enum dc_hw_swizzle {
+ SWIZZLE_ARGB = 0,
+ SWIZZLE_RGBA,
+ SWIZZLE_ABGR,
+ SWIZZLE_BGRA,
+};
+
+enum dc_hw_out {
+ OUT_DPI,
+ OUT_DP,
+};
+
+enum dc_hw_cursor_size {
+ CURSOR_SIZE_32X32 = 0,
+ CURSOR_SIZE_64X64,
+};
+
+struct dc_hw_plane_reg {
+ u32 y_address;
+ u32 u_address;
+ u32 v_address;
+ u32 y_stride;
+ u32 u_stride;
+ u32 v_stride;
+ u32 size;
+ u32 top_left;
+ u32 bottom_right;
+ u32 scale_factor_x;
+ u32 scale_factor_y;
+ u32 h_filter_coef_index;
+ u32 h_filter_coef_data;
+ u32 v_filter_coef_index;
+ u32 v_filter_coef_data;
+ u32 init_offset;
+ u32 color_key;
+ u32 color_key_high;
+ u32 clear_value;
+ u32 color_table_index;
+ u32 color_table_data;
+ u32 scale_config;
+ u32 water_mark;
+ u32 degamma_index;
+ u32 degamma_data;
+ u32 degamma_ex_data;
+ u32 src_global_color;
+ u32 dst_global_color;
+ u32 blend_config;
+ u32 roi_origin;
+ u32 roi_size;
+ u32 yuv_to_rgb_coef0;
+ u32 yuv_to_rgb_coef1;
+ u32 yuv_to_rgb_coef2;
+ u32 yuv_to_rgb_coef3;
+ u32 yuv_to_rgb_coef4;
+ u32 yuv_to_rgb_coefd0;
+ u32 yuv_to_rgb_coefd1;
+ u32 yuv_to_rgb_coefd2;
+ u32 y_clamp_bound;
+ u32 uv_clamp_bound;
+ u32 rgb_to_rgb_coef0;
+ u32 rgb_to_rgb_coef1;
+ u32 rgb_to_rgb_coef2;
+ u32 rgb_to_rgb_coef3;
+ u32 rgb_to_rgb_coef4;
+};
+
+struct dc_hw_gamma {
+ u16 gamma[GAMMA_EX_SIZE][3];
+};
+
+struct dc_hw_read {
+ u32 reg;
+ u32 value;
+};
+
+struct dc_hw {
+ enum dc_hw_out out[DC_DISPLAY_NUM];
+ void *hi_base;
+ void *reg_base;
+ struct dc_hw_plane_reg reg[DC_LAYER_NUM];
+
+ struct dc_hw_gamma gamma[DC_DISPLAY_NUM];
+ struct vs_dc_info *info;
+};
+
+struct vs_dc_plane {
+ enum dc_hw_plane_id id;
+ u32 offset;
+};
+
+struct vs_dc {
+ struct vs_crtc *crtc[DC_DISPLAY_NUM];
+ struct dc_hw hw;
+
+ struct vs_dc_plane planes[PLANE_NUM];
+};
+
+int dc_hw_init(struct vs_dc *dc);
+void dc_hw_disable_plane(struct vs_dc *dc, u8 id);
+void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr,
+ u32 crtc_w, u32 crtc_x, u32 crtc_y,
+ s32 hotspot_x, int32_t hotspot_y);
+void dc_hw_disable_cursor(struct dc_hw *hw, u8 id);
+void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
+ u16 r, u16 g, u16 b);
+void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
+void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode *mode,
+ u8 encoder_type, u32 output_fmt);
+void dc_hw_disable(struct dc_hw *hw, int id);
+void dc_hw_enable_interrupt(struct dc_hw *hw);
+void dc_hw_disable_interrupt(struct dc_hw *hw);
+u32 dc_hw_get_interrupt(struct dc_hw *hw);
+void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable);
+void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
+void dc_hw_commit(struct dc_hw *hw);
+void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format,
+ enum drm_color_encoding encoding, u8 id, bool is_yuv);
+void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format, dma_addr_t *dma_addr,
+ struct drm_framebuffer *drm_fb, struct drm_rect *src);
+void plane_hw_update_format(struct vs_dc *dc, u32 format, enum drm_color_encoding encoding,
+ unsigned int rotation, bool visible, unsigned int zpos,
+ u8 id, u8 display_id);
+void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct drm_rect *dst,
+ u8 id, u8 display_id, unsigned int rotation);
+void plane_hw_update_blend(struct vs_dc *dc, u16 alpha, u16 pixel_blend_mode,
+ u8 id, u8 display_id);
+
+#endif /* __VS_DC_HW_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
new file mode 100644
index 000000000000..30ccc2eda48b
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_type.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_TYPE_H__
+#define __VS_TYPE_H__
+
+#include <drm/drm_plane.h>
+
+struct vs_plane_primary_info {
+ u8 id;
+ unsigned int num_formats;
+ const u32 *formats;
+ u8 num_modifiers;
+ const u64 *modifiers;
+ unsigned int min_width;
+ unsigned int min_height;
+ unsigned int max_width;
+ unsigned int max_height;
+ unsigned int rotation;
+ unsigned int color_encoding;
+
+ int min_scale; /* 16.16 fixed point */
+ int max_scale; /* 16.16 fixed point */
+
+ u8 zpos;
+
+};
+
+struct vs_plane_overlay_info {
+ u8 id;
+ unsigned int num_formats;
+ const u32 *formats;
+ u8 num_modifiers;
+ const u64 *modifiers;
+ unsigned int min_width;
+ unsigned int min_height;
+ unsigned int max_width;
+ unsigned int max_height;
+ unsigned int rotation;
+ unsigned int color_encoding;
+
+ int min_scale; /* 16.16 fixed point */
+ int max_scale; /* 16.16 fixed point */
+
+ u8 zpos;
+
+};
+
+struct vs_plane_cursor_info {
+ u8 id;
+ unsigned int num_formats;
+ const u32 *formats;
+ unsigned int min_width;
+ unsigned int min_height;
+ unsigned int max_width;
+ unsigned int max_height;
+ u8 zpos;
+
+};
+
+struct vs_dc_info {
+ const char *name;
+
+ u8 panel_num;
+
+ /* planes */
+ u8 layer_num;
+ u8 primary_num;
+ u8 overlay_num;
+ u8 cursor_num;
+ const struct vs_plane_primary_info *primary;
+ const struct vs_plane_overlay_info *overlay;
+ const struct vs_plane_cursor_info *cursor;
+
+ /* 0 means no gamma LUT */
+ u16 gamma_size;
+ u8 gamma_bits;
+
+ u16 pitch_alignment;
+};
+
+#endif /* __VS_TYPE_H__ */
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 05/10] drm/vs: add vs mode config init
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (5 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 04/10] drm/vs: Add hardware funcs for vs keith
@ 2024-05-21 10:58 ` keith
2024-05-21 20:52 ` Dmitry Baryshkov
2024-05-21 10:58 ` [PATCH v4 06/10] drm/vs: add vs plane api keith
` (4 subsequent siblings)
11 siblings, 1 reply; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
add vs mode config base api
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
drivers/gpu/drm/verisilicon/Makefile | 3 +-
drivers/gpu/drm/verisilicon/vs_modeset.c | 36 ++++++++++++++++++++++++
drivers/gpu/drm/verisilicon/vs_modeset.h | 10 +++++++
3 files changed, 48 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.h
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 7da54b259940..536091f37378 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-vs_drm-objs := vs_dc_hw.o
+vs_drm-objs := vs_dc_hw.o \
+ vs_modeset.o
obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_modeset.c b/drivers/gpu/drm/verisilicon/vs_modeset.c
new file mode 100644
index 000000000000..c71fe0d32504
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_modeset.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+#include "vs_modeset.h"
+
+static const struct drm_mode_config_funcs vs_mode_config_funcs = {
+ .fb_create = drm_gem_fb_create,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static struct drm_mode_config_helper_funcs vs_mode_config_helpers = {
+ .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+};
+
+void vs_mode_config_init(struct drm_device *dev)
+{
+ int ret;
+
+ ret = drmm_mode_config_init(dev);
+ if (ret)
+ return;
+
+ dev->mode_config.min_width = 0;
+ dev->mode_config.min_height = 0;
+ dev->mode_config.max_width = 4096;
+ dev->mode_config.max_height = 4096;
+
+ dev->mode_config.funcs = &vs_mode_config_funcs;
+ dev->mode_config.helper_private = &vs_mode_config_helpers;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_modeset.h b/drivers/gpu/drm/verisilicon/vs_modeset.h
new file mode 100644
index 000000000000..bd04f81d2ad2
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_modeset.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_MODESET_H__
+#define __VS_MODESET_H__
+
+void vs_mode_config_init(struct drm_device *dev);
+#endif /* __VS_FB_H__ */
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 06/10] drm/vs: add vs plane api
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (6 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 05/10] drm/vs: add vs mode config init keith
@ 2024-05-21 10:58 ` keith
2024-05-21 20:39 ` kernel test robot
2024-05-21 21:06 ` Dmitry Baryshkov
2024-05-21 10:58 ` [PATCH v4 07/10] drm/vs: add ctrc fun keith
` (3 subsequent siblings)
11 siblings, 2 replies; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
add plane funs and helper funs
add vs drm common struct and funs
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
drivers/gpu/drm/verisilicon/Makefile | 3 +-
drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++
drivers/gpu/drm/verisilicon/vs_plane.c | 487 +++++++++++++++++++++++++
drivers/gpu/drm/verisilicon/vs_plane.h | 26 ++
4 files changed, 608 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 536091f37378..1c593b943261 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
vs_drm-objs := vs_dc_hw.o \
- vs_modeset.o
+ vs_modeset.o \
+ vs_plane.o
obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
new file mode 100644
index 000000000000..d9f6efa7c8f9
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_drv.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DRV_H__
+#define __VS_DRV_H__
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_managed.h>
+
+#include "vs_dc_hw.h"
+
+/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
+struct vs_drm_device {
+ struct drm_device base;
+ unsigned int pitch_alignment;
+ /* clocks */
+ unsigned int clk_count;
+ struct clk_bulk_data *clks;
+ struct reset_control *rsts;
+ struct vs_dc dc;
+ int irq;
+};
+
+static inline struct vs_drm_device *
+to_vs_drm_private(const struct drm_device *dev)
+{
+ return container_of(dev, struct vs_drm_device, base);
+}
+
+struct vs_crtc_state {
+ struct drm_crtc_state base;
+
+ u32 output_fmt;
+ u8 encoder_type;
+ u8 bpp;
+};
+
+struct vs_crtc {
+ struct drm_crtc base;
+ struct device *dev;
+};
+
+static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
+{
+ u8 panel_num = dc->hw.info->panel_num;
+ u32 index = drm_crtc_index(crtc);
+ int i;
+
+ for (i = 0; i < panel_num; i++) {
+ if (index == dc->crtc[i]->base.index)
+ return i;
+ }
+
+ return 0;
+}
+
+static inline struct vs_crtc_state *
+to_vs_crtc_state(struct drm_crtc_state *state)
+{
+ return container_of(state, struct vs_crtc_state, base);
+}
+
+struct vs_plane_state {
+ struct drm_plane_state base;
+ dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES];
+};
+
+struct vs_plane {
+ struct drm_plane base;
+ u8 id;
+};
+
+static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
+{
+ return container_of(plane, struct vs_plane, base);
+}
+
+static inline struct vs_plane_state *
+to_vs_plane_state(struct drm_plane_state *state)
+{
+ return container_of(state, struct vs_plane_state, base);
+}
+
+#endif /* __VS_DRV_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
new file mode 100644
index 000000000000..653f0ce72ed6
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_fb_dma_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+
+#include "vs_plane.h"
+
+static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
+
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(vs_plane_state);
+}
+
+static void vs_plane_reset(struct drm_plane *plane)
+{
+ struct vs_plane_state *state;
+ struct vs_plane *vs_plane = to_vs_plane(plane);
+
+ if (plane->state)
+ vs_plane_atomic_destroy_state(plane, plane->state);
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return;
+
+ state->base.zpos = vs_plane->id;
+ __drm_atomic_helper_plane_reset(plane, &state->base);
+}
+
+static struct drm_plane_state *
+vs_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+ struct vs_plane_state *state;
+
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+
+ return &state->base;
+}
+
+static bool vs_format_mod_supported(struct drm_plane *plane,
+ u32 format,
+ u64 modifier)
+{
+ int i;
+
+ /* We always have to allow these modifiers:
+ * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
+ * 2. Not passing any modifiers is the same as explicitly passing INVALID.
+ */
+ if (modifier == DRM_FORMAT_MOD_LINEAR)
+ return true;
+
+ /* Check that the modifier is on the list of the plane's supported modifiers. */
+ for (i = 0; i < plane->modifier_count; i++) {
+ if (modifier == plane->modifiers[i])
+ break;
+ }
+
+ if (i == plane->modifier_count)
+ return false;
+
+ return true;
+}
+
+const struct drm_plane_funcs vs_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .reset = vs_plane_reset,
+ .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
+ .atomic_destroy_state = vs_plane_atomic_destroy_state,
+ .format_mod_supported = vs_format_mod_supported,
+};
+
+static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
+{
+ const struct drm_format_info *info;
+
+ if (!fb)
+ return 0;
+
+ info = drm_format_info(fb->format->format);
+ if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
+ return 0;
+
+ return info->num_planes;
+}
+
+static bool vs_dc_mod_supported(const u64 *info_modifiers, u64 modifier)
+{
+ const u64 *mods;
+
+ if (!info_modifiers)
+ return false;
+
+ for (mods = info_modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
+ if (*mods == modifier)
+ return true;
+ }
+
+ return false;
+}
+
+static int vs_primary_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
+ struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
+ struct vs_dc *dc = &priv->dc;
+ struct drm_framebuffer *fb = new_state->fb;
+ const struct vs_plane_primary_info *primary_info;
+ struct drm_crtc_state *crtc_state;
+ int i;
+
+ if (!new_state->crtc || !new_state->fb)
+ return 0;
+ for (i = 0; i < dc->hw.info->primary_num; i++) {
+ primary_info = (struct vs_plane_primary_info *)&dc->hw.info->primary[i];
+ if (primary_info->id == to_vs_plane(plane)->id)
+ break;
+ }
+
+ primary_info = &dc->hw.info->primary[i];
+
+ if (fb->width < primary_info->min_width ||
+ fb->width > primary_info->max_width ||
+ fb->height < primary_info->min_height ||
+ fb->height > primary_info->max_height)
+ drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
+ to_vs_plane(plane)->id);
+
+ if (!vs_dc_mod_supported(primary_info->modifiers, fb->modifier)) {
+ drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id);
+ return -EINVAL;
+ }
+
+ crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc);
+ return drm_atomic_helper_check_plane_state(new_state, crtc_state,
+ primary_info->min_scale,
+ primary_info->max_scale,
+ true, true);
+}
+
+static int vs_overlay_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
+ struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
+ struct vs_dc *dc = &priv->dc;
+ struct drm_framebuffer *fb = new_state->fb;
+ const struct vs_plane_overlay_info *overlay_info;
+ struct drm_crtc_state *crtc_state;
+ int i;
+
+ if (!new_state->crtc || !new_state->fb)
+ return 0;
+
+ for (i = 0; i < dc->hw.info->overlay_num; i++) {
+ overlay_info = (struct vs_plane_overlay_info *)&dc->hw.info->overlay[i];
+ if (overlay_info->id == to_vs_plane(plane)->id)
+ break;
+ }
+
+ overlay_info = &dc->hw.info->overlay[i];
+
+ if (fb->width < overlay_info->min_width ||
+ fb->width > overlay_info->max_width ||
+ fb->height < overlay_info->min_height ||
+ fb->height > overlay_info->max_height)
+ drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
+ to_vs_plane(plane)->id);
+
+ if (!vs_dc_mod_supported(overlay_info->modifiers, fb->modifier)) {
+ drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id);
+ return -EINVAL;
+}
+
+ crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc);
+ return drm_atomic_helper_check_plane_state(new_state, crtc_state,
+ overlay_info->min_scale,
+ overlay_info->max_scale,
+ true, true);
+}
+
+static int vs_cursor_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
+ struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
+ struct vs_dc *dc = &priv->dc;
+ struct drm_framebuffer *fb = new_state->fb;
+ const struct vs_plane_cursor_info *cursor_info;
+ struct drm_crtc_state *crtc_state;
+ int i;
+
+ if (!new_state->crtc || !new_state->fb)
+ return 0;
+
+ for (i = 0; i < dc->hw.info->cursor_num; i++) {
+ cursor_info = (struct vs_plane_cursor_info *)&dc->hw.info->cursor[i];
+ if (cursor_info->id == to_vs_plane(plane)->id)
+ break;
+ }
+
+ cursor_info = &dc->hw.info->cursor[i];
+
+ if (fb->width < cursor_info->min_width ||
+ fb->width > cursor_info->max_width ||
+ fb->height < cursor_info->min_height ||
+ fb->height > cursor_info->max_height)
+ drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
+ to_vs_plane(plane)->id);
+
+ crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc);
+ return drm_atomic_helper_check_plane_state(new_state, crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ true, true);
+}
+
+static void vs_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+
+ unsigned char i, num_planes, display_id, id;
+ u32 format;
+ bool is_yuv;
+ struct vs_plane *vs_plane = to_vs_plane(plane);
+ struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
+ struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
+ struct vs_dc *dc = &priv->dc;
+
+ if (!new_state->fb || !new_state->crtc)
+ return;
+
+ drm_fb_dma_sync_non_coherent(plane->dev, old_state, new_state);
+
+ num_planes = vs_get_plane_number(new_state->fb);
+
+ for (i = 0; i < num_planes; i++) {
+ dma_addr_t dma_addr;
+
+ dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, i);
+ plane_state->dma_addr[i] = dma_addr;
+ }
+
+ display_id = to_vs_display_id(dc, new_state->crtc);
+ format = new_state->fb->format->format;
+ is_yuv = new_state->fb->format->is_yuv;
+ id = vs_plane->id;
+
+ plane_hw_update_format_colorspace(dc, format, new_state->color_encoding, id, is_yuv);
+ if (new_state->visible)
+ plane_hw_update_address(dc, id, format, plane_state->dma_addr,
+ new_state->fb, &new_state->src);
+ plane_hw_update_format(dc, format, new_state->color_encoding, new_state->rotation,
+ new_state->visible, new_state->zpos, id, display_id);
+ plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id,
+ display_id, new_state->rotation);
+ plane_hw_update_blend(dc, new_state->alpha, new_state->pixel_blend_mode,
+ id, display_id);
+}
+
+static void vs_cursor_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
+ plane);
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+ plane);
+ struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
+ struct vs_dc *dc = &priv->dc;
+ unsigned char display_id;
+ u32 crtc_w, crtc_x, crtc_y;
+ s32 hotspot_x, hotspot_y;
+ dma_addr_t dma_addr;
+
+ display_id = to_vs_display_id(dc, new_state->crtc);
+
+ if (!new_state->fb || !new_state->crtc)
+ return;
+
+ drm_fb_dma_sync_non_coherent(new_state->fb->dev, old_state, new_state);
+ dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, 0);
+ crtc_w = new_state->crtc_w;
+
+ if (new_state->crtc_x > 0) {
+ crtc_x = new_state->crtc_x;
+ hotspot_x = 0;
+ } else {
+ hotspot_x = -new_state->crtc_x;
+ crtc_x = 0;
+ }
+ if (new_state->crtc_y > 0) {
+ crtc_y = new_state->crtc_y;
+ hotspot_y = 0;
+ } else {
+ hotspot_y = -new_state->crtc_y;
+ crtc_y = 0;
+ }
+ dc_hw_update_cursor(&dc->hw, display_id, dma_addr, crtc_w, crtc_x,
+ crtc_y, hotspot_x, hotspot_y);
+}
+
+static void vs_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct vs_plane *vs_plane = to_vs_plane(plane);
+ struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
+ struct vs_dc *dc = &priv->dc;
+
+ dc_hw_disable_plane(dc, vs_plane->id);
+}
+
+static void vs_cursor_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+ struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
+ struct vs_dc *dc = &priv->dc;
+ unsigned char display_id;
+
+ display_id = to_vs_display_id(dc, old_state->crtc);
+ dc_hw_disable_cursor(&dc->hw, display_id);
+}
+
+const struct drm_plane_helper_funcs primary_plane_helpers = {
+ .atomic_check = vs_primary_plane_atomic_check,
+ .atomic_update = vs_plane_atomic_update,
+ .atomic_disable = vs_plane_atomic_disable,
+};
+
+const struct drm_plane_helper_funcs overlay_plane_helpers = {
+ .atomic_check = vs_overlay_plane_atomic_check,
+ .atomic_update = vs_plane_atomic_update,
+ .atomic_disable = vs_plane_atomic_disable,
+};
+
+const struct drm_plane_helper_funcs cursor_plane_helpers = {
+ .atomic_check = vs_cursor_plane_atomic_check,
+ .atomic_update = vs_cursor_plane_atomic_update,
+ .atomic_disable = vs_cursor_plane_atomic_disable,
+};
+
+struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev,
+ struct vs_plane_primary_info *info,
+ unsigned int layer_num,
+ unsigned int possible_crtcs)
+{
+ struct vs_plane *plane;
+ int ret;
+
+ if (!info)
+ return NULL;
+
+ plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
+ possible_crtcs,
+ &vs_plane_funcs,
+ info->formats, info->num_formats,
+ info->modifiers, DRM_PLANE_TYPE_PRIMARY,
+ NULL);
+ if (IS_ERR(plane))
+ return ERR_CAST(plane);
+
+ drm_plane_helper_add(&plane->base, &primary_plane_helpers);
+
+ drm_plane_create_alpha_property(&plane->base);
+ drm_plane_create_blend_mode_property(&plane->base,
+ BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+ BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE));
+
+ if (info->color_encoding) {
+ ret = drm_plane_create_color_properties(&plane->base, info->color_encoding,
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
+ DRM_COLOR_YCBCR_BT709,
+ DRM_COLOR_YCBCR_LIMITED_RANGE);
+ if (ret)
+ return NULL;
+ }
+
+ if (info->rotation) {
+ ret = drm_plane_create_rotation_property(&plane->base,
+ DRM_MODE_ROTATE_0,
+ info->rotation);
+ if (ret)
+ return NULL;
+ }
+
+ ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1);
+ if (ret)
+ return NULL;
+
+ return plane;
+}
+
+struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev,
+ struct vs_plane_overlay_info *info,
+ unsigned int layer_num,
+ unsigned int possible_crtcs)
+{
+ struct vs_plane *plane;
+ int ret;
+
+ if (!info)
+ return NULL;
+
+ plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
+ possible_crtcs,
+ &vs_plane_funcs,
+ info->formats, info->num_formats,
+ info->modifiers, DRM_PLANE_TYPE_OVERLAY,
+ NULL);
+ if (IS_ERR(plane))
+ return ERR_CAST(plane);
+
+ drm_plane_helper_add(&plane->base, &overlay_plane_helpers);
+
+ drm_plane_create_alpha_property(&plane->base);
+ drm_plane_create_blend_mode_property(&plane->base,
+ BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+ BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE));
+
+ if (info->color_encoding) {
+ ret = drm_plane_create_color_properties(&plane->base, info->color_encoding,
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
+ DRM_COLOR_YCBCR_BT709,
+ DRM_COLOR_YCBCR_LIMITED_RANGE);
+ if (ret)
+ return NULL;
+ }
+
+ if (info->rotation) {
+ ret = drm_plane_create_rotation_property(&plane->base,
+ DRM_MODE_ROTATE_0,
+ info->rotation);
+ if (ret)
+ return NULL;
+ }
+
+ ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1);
+ if (ret)
+ return NULL;
+
+ return plane;
+}
+
+struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev,
+ struct vs_plane_cursor_info *info,
+ unsigned int possible_crtcs)
+{
+ struct vs_plane *plane;
+ int ret;
+
+ if (!info)
+ return NULL;
+
+ plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
+ possible_crtcs,
+ &vs_plane_funcs,
+ info->formats, info->num_formats,
+ NULL, DRM_PLANE_TYPE_CURSOR,
+ NULL);
+ if (IS_ERR(plane))
+ return ERR_CAST(plane);
+
+ drm_plane_helper_add(&plane->base, &cursor_plane_helpers);
+
+ ret = drm_plane_create_zpos_immutable_property(&plane->base, info->zpos);
+ if (ret)
+ return NULL;
+
+ return plane;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
new file mode 100644
index 000000000000..0416146226a8
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_PLANE_H__
+#define __VS_PLANE_H__
+
+#include <drm/drm_plane_helper.h>
+
+#include "vs_drv.h"
+
+struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev,
+ struct vs_plane_primary_info *info,
+ unsigned int layer_num,
+ unsigned int possible_crtcs);
+
+struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev,
+ struct vs_plane_overlay_info *info,
+ unsigned int layer_num,
+ unsigned int possible_crtcs);
+
+struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev,
+ struct vs_plane_cursor_info *info,
+ unsigned int possible_crtcs);
+#endif /* __VS_PLANE_H__ */
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 07/10] drm/vs: add ctrc fun
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (7 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 06/10] drm/vs: add vs plane api keith
@ 2024-05-21 10:58 ` keith
2024-05-21 21:08 ` Dmitry Baryshkov
2024-05-21 10:58 ` [PATCH v4 08/10] drm/vs: add vs drm master driver keith
` (2 subsequent siblings)
11 siblings, 1 reply; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
add crtc funs and helper funs
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
drivers/gpu/drm/verisilicon/Makefile | 3 +-
drivers/gpu/drm/verisilicon/vs_crtc.c | 241 ++++++++++++++++++++++++++
drivers/gpu/drm/verisilicon/vs_crtc.h | 17 ++
3 files changed, 260 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 1c593b943261..26a43ca0fd36 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -2,6 +2,7 @@
vs_drm-objs := vs_dc_hw.o \
vs_modeset.o \
- vs_plane.o
+ vs_plane.o \
+ vs_crtc.o
obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
new file mode 100644
index 000000000000..ea7640a63c28
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ *
+ */
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "vs_crtc.h"
+
+static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ __drm_atomic_helper_crtc_destroy_state(state);
+ kfree(to_vs_crtc_state(state));
+}
+
+static void vs_crtc_reset(struct drm_crtc *crtc)
+{
+ struct vs_crtc_state *state;
+
+ if (crtc->state)
+ vs_crtc_atomic_destroy_state(crtc, crtc->state);
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return;
+
+ __drm_atomic_helper_crtc_reset(crtc, &state->base);
+}
+
+static struct drm_crtc_state *
+vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+ struct vs_crtc_state *old_state;
+ struct vs_crtc_state *state;
+
+ if (!crtc->state)
+ return NULL;
+
+ old_state = to_vs_crtc_state(crtc->state);
+
+ state = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+ return &state->base;
+}
+
+static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+ struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
+ struct vs_dc *dc = &priv->dc;
+
+ dc_hw_enable_interrupt(&dc->hw);
+
+ return 0;
+}
+
+static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+ struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
+ struct vs_dc *dc = &priv->dc;
+
+ dc_hw_disable_interrupt(&dc->hw);
+}
+
+static const struct drm_crtc_funcs vs_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = vs_crtc_reset,
+ .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
+ .atomic_destroy_state = vs_crtc_atomic_destroy_state,
+ .enable_vblank = vs_crtc_enable_vblank,
+ .disable_vblank = vs_crtc_disable_vblank,
+};
+
+static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
+ struct vs_dc *dc = &priv->dc;
+
+ struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ int id;
+
+ id = to_vs_display_id(dc, crtc);
+ if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
+ dc_hw_set_out(&dc->hw, OUT_DPI, id);
+ clk_set_rate(priv->clks[7].clk, mode->clock * 1000);
+ clk_set_parent(priv->clks[5].clk, priv->clks[7].clk);
+ } else {
+ dc_hw_set_out(&dc->hw, OUT_DP, id);
+ clk_set_parent(priv->clks[4].clk, priv->clks[6].clk);
+ }
+
+ dc_hw_enable(&dc->hw, id, mode, crtc_state->encoder_type, crtc_state->output_fmt);
+
+ enable_irq(priv->irq);
+
+ drm_crtc_vblank_on(crtc);
+}
+
+static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
+ struct vs_dc *dc = &priv->dc;
+ int id;
+
+ drm_crtc_vblank_off(crtc);
+
+ disable_irq(priv->irq);
+
+ id = to_vs_display_id(dc, crtc);
+ dc_hw_disable(&dc->hw, id);
+
+ if (crtc->state->event && !crtc->state->active) {
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ spin_unlock_irq(&crtc->dev->event_lock);
+ }
+}
+
+static void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
+ struct drm_color_lut *lut, unsigned int size)
+{
+ u16 i, r, g, b;
+ u8 bits, id;
+
+ if (size != dc->hw.info->gamma_size) {
+ drm_err(crtc->dev, "gamma size does not match!\n");
+ return;
+ }
+
+ id = to_vs_display_id(dc, crtc);
+
+ bits = dc->hw.info->gamma_bits;
+ for (i = 0; i < size; i++) {
+ r = drm_color_lut_extract(lut[i].red, bits);
+ g = drm_color_lut_extract(lut[i].green, bits);
+ b = drm_color_lut_extract(lut[i].blue, bits);
+ dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
+
+ if (i >= dc->hw.info->gamma_size)
+ return;
+
+ dc->hw.gamma[id].gamma[i][0] = r;
+ dc->hw.gamma[id].gamma[i][1] = g;
+ dc->hw.gamma[id].gamma[i][2] = b;
+ }
+}
+
+static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state,
+ crtc);
+
+ struct drm_property_blob *blob = new_state->gamma_lut;
+ struct drm_color_lut *lut;
+ struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
+ struct vs_dc *dc = &priv->dc;
+ u8 id;
+
+ id = to_vs_display_id(dc, crtc);
+ if (new_state->color_mgmt_changed) {
+ if (blob && blob->length) {
+ lut = blob->data;
+ vs_dc_set_gamma(dc, crtc, lut,
+ blob->length / sizeof(*lut));
+ dc_hw_enable_gamma(&dc->hw, id, true);
+ } else {
+ dc_hw_enable_gamma(&dc->hw, id, false);
+ }
+ }
+}
+
+static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct drm_pending_vblank_event *event = crtc->state->event;
+ struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
+ struct vs_dc *dc = &priv->dc;
+
+ dc_hw_enable_shadow_register(dc, false);
+
+ if (event) {
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_arm_vblank_event(crtc, event);
+ crtc->state->event = NULL;
+ spin_unlock_irq(&crtc->dev->event_lock);
+ }
+
+ dc_hw_enable_shadow_register(dc, true);
+}
+
+static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
+ .atomic_check = drm_crtc_helper_atomic_check,
+ .atomic_enable = vs_crtc_atomic_enable,
+ .atomic_disable = vs_crtc_atomic_disable,
+ .atomic_begin = vs_crtc_atomic_begin,
+ .atomic_flush = vs_crtc_atomic_flush,
+};
+
+struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
+ struct vs_dc_info *info)
+{
+ struct vs_crtc *crtc;
+ int ret;
+
+ if (!info)
+ return NULL;
+
+ crtc = drmm_crtc_alloc_with_planes(drm_dev, struct vs_crtc, base, NULL,
+ NULL, &vs_crtc_funcs,
+ info->name ? info->name : NULL);
+
+ drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
+
+ if (info->gamma_size) {
+ ret = drm_mode_crtc_set_gamma_size(&crtc->base,
+ info->gamma_size);
+ if (ret)
+ return NULL;
+
+ drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
+ info->gamma_size);
+ }
+
+ return crtc;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
new file mode 100644
index 000000000000..b1e588bb780d
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_CRTC_H__
+#define __VS_CRTC_H__
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "vs_drv.h"
+
+struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
+ struct vs_dc_info *info);
+
+#endif /* __VS_CRTC_H__ */
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 08/10] drm/vs: add vs drm master driver
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (8 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 07/10] drm/vs: add ctrc fun keith
@ 2024-05-21 10:58 ` keith
2024-05-21 21:14 ` Dmitry Baryshkov
2024-05-21 10:58 ` [PATCH v4 09/10] drm/vs: Innosilicon HDMI support keith
2024-05-21 10:58 ` [PATCH v4 10/10] drm/vs: add simple dsi encoder keith
11 siblings, 1 reply; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
Add vs DRM master driver for JH7110 SoC
ADD DMA GEM driver
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
drivers/gpu/drm/verisilicon/Makefile | 3 +-
drivers/gpu/drm/verisilicon/vs_drv.c | 718 +++++++++++++++++++++++++++
2 files changed, 720 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 26a43ca0fd36..88a07a308e31 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -3,6 +3,7 @@
vs_drm-objs := vs_dc_hw.o \
vs_modeset.o \
vs_plane.o \
- vs_crtc.o
+ vs_crtc.o \
+ vs_drv.o
obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
new file mode 100644
index 000000000000..c22fd2199fe2
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -0,0 +1,718 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+
+#include <drm/drm_aperture.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_file.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_module.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_blend.h>
+
+#include "vs_drv.h"
+#include "vs_crtc.h"
+#include "vs_plane.h"
+#include "vs_modeset.h"
+
+#define DRV_NAME "verisilicon"
+#define DRV_DESC "Verisilicon DRM driver"
+#define DRV_DATE "20230516"
+#define DRV_MAJOR 1
+#define DRV_MINOR 0
+
+#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
+
+static const u32 primary_overlay_format[] = {
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_XBGR4444,
+ DRM_FORMAT_RGBX4444,
+ DRM_FORMAT_BGRX4444,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_ABGR4444,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_BGRA4444,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_XBGR1555,
+ DRM_FORMAT_RGBX5551,
+ DRM_FORMAT_BGRX5551,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_RGBA5551,
+ DRM_FORMAT_BGRA5551,
+ DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_ABGR2101010,
+ DRM_FORMAT_RGBA1010102,
+ DRM_FORMAT_BGRA1010102,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_YVU420,
+ DRM_FORMAT_YUV420,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_P010,
+};
+
+static const u32 cursor_formats[] = {
+ DRM_FORMAT_ARGB8888
+};
+
+static const u64 format_modifier[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+static const u64 secondary_format_modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+static const struct vs_plane_primary_info dc_hw_planes_primary[2] = {
+ {
+ .id = PRIMARY_PLANE_0,
+ .num_formats = ARRAY_SIZE(primary_overlay_format),
+ .formats = primary_overlay_format,
+ .num_modifiers = ARRAY_SIZE(format_modifier),
+ .modifiers = format_modifier,
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 4096,
+ .max_height = 4096,
+ .min_scale = FRAC_16_16(1, 3),
+ .max_scale = FRAC_16_16(10, 1),
+ .rotation = DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_90 |
+ DRM_MODE_ROTATE_180 |
+ DRM_MODE_ROTATE_270 |
+ DRM_MODE_REFLECT_X |
+ DRM_MODE_REFLECT_Y,
+ .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
+ .zpos = 0,
+ },
+ {
+ .id = PRIMARY_PLANE_1,
+ .num_formats = ARRAY_SIZE(primary_overlay_format),
+ .formats = primary_overlay_format,
+ .num_modifiers = ARRAY_SIZE(format_modifier),
+ .modifiers = format_modifier,
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 4096,
+ .max_height = 4096,
+ .min_scale = FRAC_16_16(1, 3),
+ .max_scale = FRAC_16_16(10, 1),
+ .rotation = DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_90 |
+ DRM_MODE_ROTATE_180 |
+ DRM_MODE_ROTATE_270 |
+ DRM_MODE_REFLECT_X |
+ DRM_MODE_REFLECT_Y,
+ .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
+ .zpos = 3,
+ },
+};
+
+static const struct vs_plane_overlay_info dc_hw_planes_overlay[4] = {
+ {
+ .id = OVERLAY_PLANE_0,
+ .num_formats = ARRAY_SIZE(primary_overlay_format),
+ .formats = primary_overlay_format,
+ .num_modifiers = ARRAY_SIZE(format_modifier),
+ .modifiers = format_modifier,
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 4096,
+ .max_height = 4096,
+ .min_scale = FRAC_16_16(1, 3),
+ .max_scale = FRAC_16_16(10, 1),
+ .rotation = DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_90 |
+ DRM_MODE_ROTATE_180 |
+ DRM_MODE_ROTATE_270 |
+ DRM_MODE_REFLECT_X |
+ DRM_MODE_REFLECT_Y,
+ .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
+ .zpos = 1,
+ },
+ {
+ .id = OVERLAY_PLANE_1,
+ .num_formats = ARRAY_SIZE(primary_overlay_format),
+ .formats = primary_overlay_format,
+ .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+ .modifiers = secondary_format_modifiers,
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 4096,
+ .max_height = 4096,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .rotation = 0,
+ .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
+ .zpos = 2,
+ },
+ {
+ .id = OVERLAY_PLANE_2,
+ .num_formats = ARRAY_SIZE(primary_overlay_format),
+ .formats = primary_overlay_format,
+ .num_modifiers = ARRAY_SIZE(format_modifier),
+ .modifiers = format_modifier,
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 4096,
+ .max_height = 4096,
+ .min_scale = FRAC_16_16(1, 3),
+ .max_scale = FRAC_16_16(10, 1),
+ .rotation = DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_90 |
+ DRM_MODE_ROTATE_180 |
+ DRM_MODE_ROTATE_270 |
+ DRM_MODE_REFLECT_X |
+ DRM_MODE_REFLECT_Y,
+ .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
+ .zpos = 4,
+ },
+ {
+ .id = OVERLAY_PLANE_3,
+ .num_formats = ARRAY_SIZE(primary_overlay_format),
+ .formats = primary_overlay_format,
+ .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+ .modifiers = secondary_format_modifiers,
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 4096,
+ .max_height = 4096,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .rotation = 0,
+ .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
+ .zpos = 5,
+ },
+};
+
+static const struct vs_plane_cursor_info dc_hw_planes_cursor[2] = {
+ {
+ .id = CURSOR_PLANE_0,
+ .num_formats = ARRAY_SIZE(cursor_formats),
+ .formats = cursor_formats,
+ .min_width = 32,
+ .min_height = 32,
+ .max_width = 64,
+ .max_height = 64,
+ .zpos = 255,
+ },
+ {
+ .id = CURSOR_PLANE_1,
+ .num_formats = ARRAY_SIZE(cursor_formats),
+ .formats = cursor_formats,
+ .min_width = 32,
+ .min_height = 32,
+ .max_width = 64,
+ .max_height = 64,
+ .zpos = 255,
+ },
+};
+
+static const struct vs_dc_info dc8200_info = {
+ .name = "DC8200",
+ .panel_num = 2,
+ .primary_num = 2,
+ .overlay_num = 4,
+ .cursor_num = 2,
+ .primary = dc_hw_planes_primary,
+ .overlay = dc_hw_planes_overlay,
+ .cursor = dc_hw_planes_cursor,
+ .layer_num = 6,
+ .gamma_size = GAMMA_EX_SIZE,
+ .gamma_bits = 12,
+ .pitch_alignment = 128,
+};
+
+static int vs_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ struct vs_drm_device *priv = to_vs_drm_private(dev);
+ unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+ args->pitch = ALIGN(pitch, priv->pitch_alignment);
+ return drm_gem_dma_dumb_create_internal(file, dev, args);
+}
+
+DEFINE_DRM_GEM_FOPS(vs_drm_fops);
+
+static struct drm_driver vs_drm_driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
+
+ DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vs_gem_dumb_create),
+
+ .fops = &vs_drm_fops,
+ .name = DRV_NAME,
+ .desc = DRV_DESC,
+ .date = DRV_DATE,
+ .major = DRV_MAJOR,
+ .minor = DRV_MINOR,
+};
+
+static irqreturn_t vs_dc_isr(int irq, void *data)
+{
+ struct vs_drm_device *priv = data;
+ struct vs_dc *dc = &priv->dc;
+ struct vs_dc_info *dc_info = dc->hw.info;
+ u32 i;
+
+ dc_hw_get_interrupt(&dc->hw);
+
+ for (i = 0; i < dc_info->panel_num; i++)
+ drm_crtc_handle_vblank(&dc->crtc[i]->base);
+
+ return IRQ_HANDLED;
+}
+
+static int vs_drm_device_init_res(struct vs_drm_device *priv)
+{
+ struct device *dev = priv->base.dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ int ret;
+ struct vs_dc *dc;
+
+ dc = &priv->dc;
+ dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dc->hw.hi_base))
+ return PTR_ERR(dc->hw.hi_base);
+
+ dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(dc->hw.reg_base))
+ return PTR_ERR(dc->hw.reg_base);
+
+ dc->hw.info = (struct vs_dc_info *)of_device_get_match_data(dev);
+
+ ret = devm_clk_bulk_get_all(dev, &priv->clks);
+ if (ret < 0) {
+ dev_err(dev, "can't get vout clock, ret=%d\n", ret);
+ return ret;
+ }
+ priv->clk_count = ret;
+
+ priv->rsts = devm_reset_control_array_get_shared(dev);
+ if (IS_ERR(priv->rsts))
+ return PTR_ERR(priv->rsts);
+
+ priv->irq = platform_get_irq(pdev, 0);
+
+ /* do not autoenable, will be enabled later */
+ ret = devm_request_irq(dev, priv->irq, vs_dc_isr, IRQF_NO_AUTOEN, dev_name(dev), priv);
+ if (ret < 0) {
+ dev_err(dev, "Failed to install irq:%u.\n", priv->irq);
+ return ret;
+ }
+
+ return ret;
+}
+
+static u32 get_addr_offset(u32 id)
+{
+ u32 offset = 0;
+
+ switch (id) {
+ case PRIMARY_PLANE_1:
+ case OVERLAY_PLANE_1:
+ offset = 0x04;
+ break;
+ case OVERLAY_PLANE_2:
+ offset = 0x08;
+ break;
+ case OVERLAY_PLANE_3:
+ offset = 0x0C;
+ break;
+ default:
+ break;
+ }
+
+ return offset;
+}
+
+static int vs_drm_device_crtc_plane_create(struct vs_drm_device *priv)
+{
+ struct vs_dc *dc;
+ struct drm_device *drm_dev;
+ int i, ret;
+ struct device_node *port;
+ struct vs_crtc *crtc;
+ struct vs_dc_info *dc_info;
+ struct vs_plane *plane;
+ struct vs_plane_primary_info *primary_info;
+ struct vs_plane_overlay_info *overlay_info;
+ struct vs_plane_cursor_info *cursor_info;
+
+ struct device *dev = priv->base.dev;
+ u32 max_width = 0, max_height = 0;
+ u32 min_width = 0xffff, min_heigth = 0xffff;
+ u32 possible_crtc = 0;
+
+ dc = &priv->dc;
+ dc_info = dc->hw.info;
+ drm_dev = &priv->base;
+
+ for (i = 0; i < dc_info->panel_num; i++) {
+ crtc = vs_crtc_create(drm_dev, dc_info);
+ if (!crtc) {
+ drm_err(drm_dev, "Failed to create CRTC.\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+ crtc->dev = drm_dev->dev;
+
+ port = of_graph_get_port_by_id(crtc->dev->of_node, i);
+ if (!port) {
+ drm_err(drm_dev, "no port node found for crtc_port%d\n", i);
+ return -ENOENT;
+ }
+
+ crtc->base.port = port;
+ dc->crtc[i] = crtc;
+
+ of_node_put(port);
+ }
+
+ if (!dc->crtc[0]->base.port || !dc->crtc[1]->base.port) {
+ drm_err(drm_dev, "no port no crtc mask, fail to create plane\n");
+ return -ENOENT;
+ }
+
+ for (i = 0; i < dc_info->primary_num; i++) {
+ primary_info = (struct vs_plane_primary_info *)&dc_info->primary[i];
+
+ if (primary_info->id == PRIMARY_PLANE_0)
+ possible_crtc = drm_crtc_mask(&dc->crtc[0]->base);
+ else
+ possible_crtc = drm_crtc_mask(&dc->crtc[1]->base);
+
+ plane = vs_plane_primary_create(drm_dev, primary_info,
+ dc_info->layer_num, possible_crtc);
+ if (IS_ERR(plane)) {
+ dev_err(dev, "failed to construct plane\n");
+ return PTR_ERR(plane);
+ }
+
+ plane->id = primary_info->id;
+ dc->planes[plane->id].id = primary_info->id;
+ dc->planes[plane->id].offset = get_addr_offset(primary_info->id);
+
+ if (primary_info->id == PRIMARY_PLANE_0)
+ dc->crtc[0]->base.primary = &plane->base;
+ else
+ dc->crtc[1]->base.primary = &plane->base;
+
+ min_width = min_t(u32, min_width, primary_info->min_width);
+ min_heigth = min_t(u32, min_heigth, primary_info->min_height);
+ /*
+ * Note: these values are used for multiple independent things:
+ * hw display mode filtering, plane buffer sizes ...
+ * Use the combined maximum values here to cover all use cases,
+ * and do more specific checking in the respective code paths.
+ */
+ max_width = max_t(u32, max_width, primary_info->max_width);
+ max_height = max_t(u32, max_height, primary_info->max_height);
+ }
+
+ for (i = 0; i < dc_info->overlay_num; i++) {
+ overlay_info = (struct vs_plane_overlay_info *)&dc_info->overlay[i];
+
+ possible_crtc = drm_crtc_mask(&dc->crtc[0]->base) |
+ drm_crtc_mask(&dc->crtc[1]->base);
+
+ plane = vs_plane_overlay_create(drm_dev, overlay_info,
+ dc_info->layer_num, possible_crtc);
+ if (IS_ERR(plane)) {
+ dev_err(dev, "failed to construct plane\n");
+ return PTR_ERR(plane);
+ }
+
+ plane->id = overlay_info->id;
+ dc->planes[plane->id].id = overlay_info->id;
+ dc->planes[plane->id].offset = get_addr_offset(overlay_info->id);
+ }
+
+ for (i = 0; i < dc_info->cursor_num; i++) {
+ cursor_info = (struct vs_plane_cursor_info *)&dc_info->cursor[i];
+
+ if (cursor_info->id == CURSOR_PLANE_0)
+ possible_crtc = drm_crtc_mask(&dc->crtc[0]->base);
+ else
+ possible_crtc = drm_crtc_mask(&dc->crtc[1]->base);
+
+ plane = vs_plane_cursor_create(drm_dev, cursor_info, possible_crtc);
+ if (IS_ERR(plane)) {
+ dev_err(dev, "failed to construct plane\n");
+ return PTR_ERR(plane);
+ }
+
+ plane->id = cursor_info->id;
+ dc->planes[plane->id].id = cursor_info->id;
+ dc->planes[plane->id].offset = get_addr_offset(cursor_info->id);
+
+ if (cursor_info->id == CURSOR_PLANE_0)
+ dc->crtc[0]->base.cursor = &plane->base;
+ else
+ dc->crtc[1]->base.cursor = &plane->base;
+ drm_dev->mode_config.cursor_width =
+ max_t(u32, drm_dev->mode_config.cursor_width,
+ cursor_info->max_width);
+ drm_dev->mode_config.cursor_height =
+ max_t(u32, drm_dev->mode_config.cursor_height,
+ cursor_info->max_height);
+ }
+
+ drm_dev->mode_config.min_width = min_width;
+ drm_dev->mode_config.min_height = min_heigth;
+ drm_dev->mode_config.max_width = max_width;
+ drm_dev->mode_config.max_height = max_height;
+
+ if (dc_info->pitch_alignment > priv->pitch_alignment)
+ priv->pitch_alignment = dc_info->pitch_alignment;
+
+ return 0;
+}
+
+static int vs_load(struct vs_drm_device *priv)
+{
+ int ret;
+
+ ret = clk_bulk_prepare_enable(priv->clk_count, priv->clks);
+ if (ret)
+ return ret;
+
+ reset_control_deassert(priv->rsts);
+
+ ret = dc_hw_init(&priv->dc);
+ if (ret) {
+ DRM_ERROR("failed to init DC HW\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int vs_drm_bind(struct device *dev)
+{
+ struct vs_drm_device *priv;
+ int ret;
+ struct drm_device *drm_dev;
+
+ priv = devm_drm_dev_alloc(dev, &vs_drm_driver, struct vs_drm_device, base);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ priv->pitch_alignment = 64;
+ drm_dev = &priv->base;
+ dev_set_drvdata(dev, drm_dev);
+
+ ret = dma_set_coherent_mask(drm_dev->dev, DMA_BIT_MASK(40));
+ if (ret)
+ return ret;
+
+ ret = vs_drm_device_init_res(priv);
+ if (ret)
+ return ret;
+
+ vs_mode_config_init(drm_dev);
+
+ /* Remove existing drivers that may own the framebuffer memory. */
+ ret = drm_aperture_remove_framebuffers(&vs_drm_driver);
+ if (ret)
+ return ret;
+
+ ret = vs_drm_device_crtc_plane_create(priv);
+ if (ret) {
+ DRM_ERROR("Failed to create ctrc and plane\n");
+ return ret;
+ }
+
+ ret = vs_load(priv);
+ if (ret)
+ return ret;
+
+ /* Now try and bind all our sub-components */
+ ret = component_bind_all(dev, drm_dev);
+ if (ret) {
+ ret = -EPROBE_DEFER;
+ goto unload;
+ }
+ ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
+ if (ret)
+ goto err_unbind_all;
+
+ drm_mode_config_reset(drm_dev);
+
+ ret = drmm_kms_helper_poll_init(drm_dev);
+ if (ret)
+ goto err_unbind_all;
+
+ ret = drm_dev_register(drm_dev, 0);
+ if (ret)
+ goto err_unbind_all;
+
+ drm_fbdev_generic_setup(drm_dev, 32);
+
+ return 0;
+
+err_unbind_all:
+ component_unbind_all(drm_dev->dev, drm_dev);
+unload:
+ reset_control_assert(priv->rsts);
+ clk_bulk_disable_unprepare(priv->clk_count, priv->clks);
+ return ret;
+
+}
+
+static void vs_drm_unbind(struct device *dev)
+{
+ struct drm_device *drm_dev = dev_get_drvdata(dev);
+ struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
+
+ reset_control_assert(priv->rsts);
+ clk_bulk_disable_unprepare(priv->clk_count, priv->clks);
+
+ drm_dev_unregister(drm_dev);
+ drm_atomic_helper_shutdown(drm_dev);
+ component_unbind_all(drm_dev->dev, drm_dev);
+}
+
+static const struct component_master_ops vs_drm_ops = {
+ .bind = vs_drm_bind,
+ .unbind = vs_drm_unbind,
+};
+
+static struct platform_driver *drm_sub_drivers[] = {
+
+};
+
+static struct component_match *vs_add_external_components(struct device *dev)
+{
+ struct component_match *match = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(drm_sub_drivers); ++i) {
+ struct platform_driver *drv = drm_sub_drivers[i];
+ struct device *p = NULL, *d;
+
+ while ((d = platform_find_device_by_driver(p, &drv->driver))) {
+ put_device(p);
+
+ drm_of_component_match_add(dev, &match, component_compare_of,
+ d->of_node);
+ p = d;
+ }
+ put_device(p);
+ }
+
+ return match ? match : ERR_PTR(-ENODEV);
+}
+
+static int vs_drm_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct component_match *match;
+
+ /* all the planes and CRTC would be created in this platform device
+ * , so external components are encoder + connector or self-defined
+ * encoder.
+ */
+ match = vs_add_external_components(dev);
+ if (IS_ERR(match))
+ return PTR_ERR(match);
+
+ return component_master_add_with_match(dev, &vs_drm_ops, match);
+}
+
+static int vs_drm_platform_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &vs_drm_ops);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vs_drm_suspend(struct device *dev)
+{
+ return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
+}
+
+static int vs_drm_resume(struct device *dev)
+{
+ drm_mode_config_helper_resume(dev_get_drvdata(dev));
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
+
+static const struct of_device_id vs_drm_dt_ids[] = {
+ { .compatible = "starfive,jh7110-dc8200", .data = &dc8200_info,},
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
+
+static struct platform_driver vs_drm_platform_driver = {
+ .probe = vs_drm_platform_probe,
+ .remove = vs_drm_platform_remove,
+
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = vs_drm_dt_ids,
+ .pm = &vs_drm_pm_ops,
+ },
+};
+
+static int __init vs_drm_init(void)
+{
+ int ret;
+
+ ret = platform_register_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers));
+ if (ret)
+ return ret;
+
+ ret = drm_platform_driver_register(&vs_drm_platform_driver);
+ if (ret)
+ platform_unregister_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers));
+
+ return ret;
+}
+
+static void __exit vs_drm_fini(void)
+{
+ platform_driver_unregister(&vs_drm_platform_driver);
+ platform_unregister_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers));
+}
+
+late_initcall_sync(vs_drm_init);
+module_exit(vs_drm_fini);
+
+MODULE_DESCRIPTION("VeriSilicon DRM Driver");
+MODULE_LICENSE("GPL");
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 09/10] drm/vs: Innosilicon HDMI support
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (9 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 08/10] drm/vs: add vs drm master driver keith
@ 2024-05-21 10:58 ` keith
2024-05-21 9:31 ` Krzysztof Kozlowski
2024-05-21 10:58 ` [PATCH v4 10/10] drm/vs: add simple dsi encoder keith
11 siblings, 1 reply; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
add inno hdmi driver which binds to vs display controller
and this driver uses the commom api from the inno hdmi
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
drivers/gpu/drm/verisilicon/Kconfig | 10 +
drivers/gpu/drm/verisilicon/Makefile | 1 +
.../gpu/drm/verisilicon/inno_hdmi-starfive.c | 481 ++++++++++++++++++
.../gpu/drm/verisilicon/inno_hdmi-starfive.h | 152 ++++++
drivers/gpu/drm/verisilicon/vs_drv.c | 4 +-
drivers/gpu/drm/verisilicon/vs_drv.h | 4 +
6 files changed, 651 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c
create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h
diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig
index 2d733f93439e..228732d21e40 100644
--- a/drivers/gpu/drm/verisilicon/Kconfig
+++ b/drivers/gpu/drm/verisilicon/Kconfig
@@ -11,3 +11,13 @@ config DRM_VERISILICON_DC8200
This driver provides VeriSilicon kernel mode
setting and buffer management. It does not
provide 2D or 3D acceleration.
+
+if DRM_VERISILICON_DC8200
+config DRM_INNO_STARFIVE_HDMI
+ bool "Starfive JH7110 specific extensions for Innosilicon HDMI"
+ select DRM_INNO_HDMI
+ help
+ This selects support for StarFive SoC specific extensions
+ for the Innosilicon HDMI driver. If you want to enable
+ HDMI on JH7110 based SoC, you should select this option.
+endif
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 88a07a308e31..2d02b4a3a567 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -6,4 +6,5 @@ vs_drm-objs := vs_dc_hw.o \
vs_crtc.o \
vs_drv.o
+vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o
obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c
new file mode 100644
index 000000000000..f27b04ef5690
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c
@@ -0,0 +1,481 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/component.h>
+#include <linux/i2c.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_of.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/bridge/inno_hdmi.h>
+#include <sound/hdmi-codec.h>
+
+#include "vs_drv.h"
+#include "inno_hdmi-starfive.h"
+
+enum hdmi_clk {
+ CLK_SYS = 0,
+ CLK_M,
+ CLK_B,
+ CLK_HDMI_NUM
+};
+
+struct pre_pll_config {
+ unsigned long pixclock;
+ unsigned long tmdsclock;
+ u8 prediv;
+ u16 fbdiv;
+ u8 tmds_div_a;
+ u8 tmds_div_b;
+ u8 tmds_div_c;
+ u8 pclk_div_a;
+ u8 pclk_div_b;
+ u8 pclk_div_c;
+ u8 pclk_div_d;
+ u8 vco_div_5_en;
+ u32 fracdiv;
+};
+
+struct post_pll_config {
+ unsigned long tmdsclock;
+ u8 prediv;
+ u16 fbdiv;
+ u8 postdiv;
+ u8 post_div_en;
+ u8 version;
+};
+
+struct stf_inno_hdmi {
+ struct drm_encoder encoder;
+ struct inno_hdmi inno_hdmi;
+ struct clk_bulk_data clk_hdmi[CLK_HDMI_NUM];
+ struct reset_control *tx_rst;
+ int nclks;
+ unsigned long tmds_rate;
+ struct pre_pll_config pre_cfg;
+ const struct post_pll_config *post_cfg;
+};
+
+static inline struct stf_inno_hdmi *to_starfive_inno_hdmi(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct stf_inno_hdmi, encoder);
+}
+
+static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder)
+{
+ struct stf_inno_hdmi *stf_hdmi = to_starfive_inno_hdmi(encoder);
+
+ return &stf_hdmi->inno_hdmi;
+}
+
+static const struct post_pll_config post_pll_cfg_table[] = {
+ {25200000, 1, 80, 13, 3, 1},
+ {27000000, 1, 40, 11, 3, 1},
+ {33750000, 1, 40, 11, 3, 1},
+ {49000000, 1, 20, 1, 3, 3},
+ {241700000, 1, 20, 1, 3, 3},
+ {297000000, 4, 20, 0, 0, 3},
+ { /* sentinel */ }
+};
+
+static int starfive_hdmi_enable_clk_rst(struct device *dev, struct stf_inno_hdmi *stf_inno_hdmi)
+{
+ int ret;
+
+ ret = clk_bulk_prepare_enable(stf_inno_hdmi->nclks, stf_inno_hdmi->clk_hdmi);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks\n");
+ return ret;
+ }
+
+ ret = reset_control_deassert(stf_inno_hdmi->tx_rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to deassert tx_rst\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void starfive_hdmi_disable_clk_rst(struct device *dev, struct stf_inno_hdmi *stf_inno_hdmi)
+{
+ int ret;
+
+ ret = reset_control_assert(stf_inno_hdmi->tx_rst);
+ if (ret < 0)
+ dev_err(dev, "failed to assert tx_rst\n");
+
+ clk_bulk_disable_unprepare(stf_inno_hdmi->nclks, stf_inno_hdmi->clk_hdmi);
+}
+
+static void starfive_hdmi_config_pll(struct stf_inno_hdmi *stf_inno_hdmi)
+{
+ u32 val;
+ struct inno_hdmi *hdmi;
+
+ hdmi = &stf_inno_hdmi->inno_hdmi;
+ u8 reg_1ad_value = stf_inno_hdmi->post_cfg->post_div_en ?
+ stf_inno_hdmi->post_cfg->postdiv : 0x00;
+ u8 reg_1aa_value = stf_inno_hdmi->post_cfg->post_div_en ?
+ 0x0e : 0x02;
+
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_CONTROL, STF_INNO_PRE_PLL_POWER_DOWN);
+ hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_1,
+ STF_INNO_POST_PLL_POST_DIV_ENABLE |
+ STF_INNO_POST_PLL_REFCLK_SEL_TMDS |
+ STF_INNO_POST_PLL_POWER_DOWN);
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_1,
+ STF_INNO_PRE_PLL_PRE_DIV(stf_inno_hdmi->pre_cfg.prediv));
+
+ val = STF_INNO_SPREAD_SPECTRUM_MOD_DISABLE | STF_INNO_SPREAD_SPECTRUM_MOD_DOWN;
+ if (!stf_inno_hdmi->pre_cfg.fracdiv)
+ val |= STF_INNO_PRE_PLL_FRAC_DIV_DISABLE;
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_2,
+ STF_INNO_PRE_PLL_FB_DIV_11_8(stf_inno_hdmi->pre_cfg.fbdiv) | val);
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_3,
+ STF_INNO_PRE_PLL_FB_DIV_7_0(stf_inno_hdmi->pre_cfg.fbdiv));
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_4,
+ STF_INNO_PRE_PLL_TMDSCLK_DIV_C(stf_inno_hdmi->pre_cfg.tmds_div_c) |
+ STF_INNO_PRE_PLL_TMDSCLK_DIV_A(stf_inno_hdmi->pre_cfg.tmds_div_a) |
+ STF_INNO_PRE_PLL_TMDSCLK_DIV_B(stf_inno_hdmi->pre_cfg.tmds_div_b));
+
+ if (stf_inno_hdmi->pre_cfg.fracdiv) {
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_FRAC_DIV_L,
+ STF_INNO_PRE_PLL_FRAC_DIV_7_0(stf_inno_hdmi->pre_cfg.fracdiv));
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_FRAC_DIV_M,
+ STF_INNO_PRE_PLL_FRAC_DIV_15_8(stf_inno_hdmi->pre_cfg.fracdiv));
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_FRAC_DIV_H,
+ STF_INNO_PRE_PLL_FRAC_DIV_23_16(stf_inno_hdmi->pre_cfg.fracdiv));
+ }
+
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_5,
+ STF_INNO_PRE_PLL_PCLK_DIV_A(stf_inno_hdmi->pre_cfg.pclk_div_a) |
+ STF_INNO_PRE_PLL_PCLK_DIV_B(stf_inno_hdmi->pre_cfg.pclk_div_b));
+ hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_6,
+ STF_INNO_PRE_PLL_PCLK_DIV_C(stf_inno_hdmi->pre_cfg.pclk_div_c) |
+ STF_INNO_PRE_PLL_PCLK_DIV_D(stf_inno_hdmi->pre_cfg.pclk_div_d));
+
+ /*pre-pll power down*/
+ hdmi_modb(hdmi, STF_INNO_PRE_PLL_CONTROL, STF_INNO_PRE_PLL_POWER_DOWN, 0);
+
+ hdmi_modb(hdmi, STF_INNO_POST_PLL_DIV_2, STF_INNO_POST_PLL_Pre_DIV_MASK,
+ STF_INNO_POST_PLL_PRE_DIV(stf_inno_hdmi->post_cfg->prediv));
+ hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_3, stf_inno_hdmi->post_cfg->fbdiv & 0xff);
+ hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_4, reg_1ad_value);
+ hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_1, reg_1aa_value);
+}
+
+static void starfive_hdmi_tmds_driver_on(struct inno_hdmi *hdmi)
+{
+ hdmi_modb(hdmi, STF_INNO_TMDS_CONTROL,
+ STF_INNO_TMDS_DRIVER_ENABLE, STF_INNO_TMDS_DRIVER_ENABLE);
+}
+
+static void starfive_hdmi_sync_tmds(struct inno_hdmi *hdmi)
+{
+ /*first send 0 to this bit, then send 1 and keep 1 into this bit*/
+ hdmi_writeb(hdmi, HDMI_SYNC, 0x0);
+ hdmi_writeb(hdmi, HDMI_SYNC, 0x1);
+}
+
+static void starfive_hdmi_phy_get_pre_pll_cfg(struct stf_inno_hdmi *hdmi)
+{
+ if (hdmi->tmds_rate > 30000000) {
+ hdmi->pre_cfg.pixclock = hdmi->tmds_rate;
+ hdmi->pre_cfg.tmdsclock = hdmi->tmds_rate;
+ hdmi->pre_cfg.prediv = 1;
+ hdmi->pre_cfg.fbdiv = hdmi->tmds_rate / 3000000;
+ hdmi->pre_cfg.tmds_div_a = 0;
+ hdmi->pre_cfg.tmds_div_b = 1;
+ hdmi->pre_cfg.tmds_div_c = 1;
+ hdmi->pre_cfg.pclk_div_a = 1;
+ hdmi->pre_cfg.pclk_div_b = 0;
+ hdmi->pre_cfg.pclk_div_c = 2;
+ hdmi->pre_cfg.pclk_div_d = 2;
+ hdmi->pre_cfg.vco_div_5_en = hdmi->tmds_rate % 3000000 ? 1 : 0;
+
+ if (hdmi->pre_cfg.vco_div_5_en) {
+ hdmi->pre_cfg.fracdiv = (hdmi->tmds_rate % 3000000) *
+ 0xffffff / 1000000;
+ }
+ } else {
+ hdmi->pre_cfg.pixclock = hdmi->tmds_rate;
+ hdmi->pre_cfg.tmdsclock = hdmi->tmds_rate;
+ hdmi->pre_cfg.prediv = 1;
+ hdmi->pre_cfg.fbdiv = hdmi->tmds_rate / 1000000;
+ hdmi->pre_cfg.tmds_div_a = 2;
+ hdmi->pre_cfg.tmds_div_b = 1;
+ hdmi->pre_cfg.tmds_div_c = 1;
+ hdmi->pre_cfg.pclk_div_a = 3;
+ hdmi->pre_cfg.pclk_div_b = 0;
+ hdmi->pre_cfg.pclk_div_c = 3;
+ hdmi->pre_cfg.pclk_div_d = 4;
+ hdmi->pre_cfg.vco_div_5_en = hdmi->tmds_rate % 1000000 ? 1 : 0;
+
+ if (hdmi->pre_cfg.vco_div_5_en) {
+ hdmi->pre_cfg.fracdiv = (hdmi->tmds_rate % 1000000) *
+ 0xffffff / 1000000;
+ }
+ }
+}
+
+static int starfive_hdmi_phy_clk_set_rate(struct stf_inno_hdmi *stf_inno_hdmi)
+{
+ stf_inno_hdmi->post_cfg = post_pll_cfg_table;
+
+ starfive_hdmi_phy_get_pre_pll_cfg(stf_inno_hdmi);
+
+ for (; stf_inno_hdmi->post_cfg->tmdsclock != 0; stf_inno_hdmi->post_cfg++)
+ if (stf_inno_hdmi->tmds_rate <= stf_inno_hdmi->post_cfg->tmdsclock)
+ break;
+
+ starfive_hdmi_config_pll(stf_inno_hdmi);
+
+ return 0;
+}
+
+static int starfive_hdmi_setup(struct inno_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ struct stf_inno_hdmi *stf_inno_hdmi = dev_get_drvdata(hdmi->dev);
+ struct drm_display_info *display = &hdmi->connector.display_info;
+ int ret;
+ u32 val;
+
+ hdmi_modb(hdmi, STF_INNO_BIAS_CONTROL, STF_INNO_BIAS_ENABLE, STF_INNO_BIAS_ENABLE);
+ hdmi_writeb(hdmi, STF_INNO_RX_CONTROL, STF_INNO_RX_ENABLE);
+
+ stf_inno_hdmi->tmds_rate = mode->clock * 1000;
+ starfive_hdmi_phy_clk_set_rate(stf_inno_hdmi);
+
+ ret = readx_poll_timeout(readl_relaxed,
+ hdmi->regs + (STF_INNO_PRE_PLL_LOCK_STATUS) * 0x04,
+ val, val & 0x1, 1000, 100000);
+ if (ret < 0) {
+ dev_err(hdmi->dev, "failed to wait pre-pll lock\n");
+ return ret;
+ }
+
+ ret = readx_poll_timeout(readl_relaxed,
+ hdmi->regs + (STF_INNO_POST_PLL_LOCK_STATUS) * 0x04,
+ val, val & 0x1, 1000, 100000);
+ if (ret < 0) {
+ dev_err(hdmi->dev, "failed to wait post-pll lock\n");
+ return ret;
+ }
+
+ /*turn on LDO*/
+ hdmi_writeb(hdmi, STF_INNO_LDO_CONTROL, STF_INNO_LDO_ENABLE);
+ /*turn on serializer*/
+ hdmi_writeb(hdmi, STF_INNO_SERIALIER_CONTROL, STF_INNO_SERIALIER_ENABLE);
+
+ if (display->is_hdmi)
+ inno_hdmi_config_video_avi(hdmi, mode);
+
+ inno_hdmi_sys_power(hdmi, false);
+ inno_hdmi_config_video_timing(hdmi, mode);
+ inno_hdmi_sys_power(hdmi, true);
+
+ starfive_hdmi_tmds_driver_on(hdmi);
+ starfive_hdmi_sync_tmds(hdmi);
+
+ return 0;
+}
+
+static enum drm_mode_status
+starfive_hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+{
+ int pclk = mode->clock * 1000;
+ bool valid = false;
+
+ if (pclk <= PIXCLOCK_4K_30FPS)
+ valid = true;
+
+ return (valid) ? MODE_OK : MODE_BAD;
+}
+
+static void starfive_hdmi_encoder_enable(struct drm_encoder *encoder,
+ struct drm_atomic_state *state)
+{
+ struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+
+ conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector);
+ if (WARN_ON(!conn_state))
+ return;
+
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ if (WARN_ON(!crtc_state))
+ return;
+
+ starfive_hdmi_setup(hdmi, &crtc_state->adjusted_mode);
+}
+
+static void starfive_hdmi_encoder_disable(struct drm_encoder *encoder,
+ struct drm_atomic_state *state)
+{
+ struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
+
+ inno_hdmi_sys_power(hdmi, false);
+}
+
+static int
+starfive_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+ u8 vic = drm_match_cea_mode(mode);
+ struct inno_hdmi_connector_state *inno_conn_state = to_inno_hdmi_conn_state(conn_state);
+
+ struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state);
+
+ vs_crtc_state->encoder_type = encoder->encoder_type;
+ vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
+
+ if (vic == 6 || vic == 7 || vic == 21 || vic == 22 ||
+ vic == 2 || vic == 3 || vic == 17 || vic == 18)
+ inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601;
+ else
+ inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709;
+
+ inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB;
+ inno_conn_state->rgb_limited_range =
+ drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED;
+
+ return starfive_hdmi_connector_mode_valid(conn_state->connector,
+ &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL;
+}
+
+static const struct drm_encoder_helper_funcs stf_inno_encoder_helper_funcs = {
+ .atomic_check = starfive_hdmi_encoder_atomic_check,
+ .atomic_enable = starfive_hdmi_encoder_enable,
+ .atomic_disable = starfive_hdmi_encoder_disable,
+};
+
+static int starfive_hdmi_get_clk_rst(struct device *dev, struct stf_inno_hdmi *stf_hdmi)
+{
+ int ret;
+
+ stf_hdmi->nclks = ARRAY_SIZE(stf_hdmi->clk_hdmi);
+
+ ret = devm_clk_bulk_get(dev, stf_hdmi->nclks, stf_hdmi->clk_hdmi);
+ if (ret) {
+ dev_err(dev, "Failed to get clk controls\n");
+ return ret;
+ }
+
+ stf_hdmi->tx_rst = devm_reset_control_get_by_index(dev, 0);
+ if (IS_ERR(stf_hdmi->tx_rst)) {
+ dev_err(dev, "failed to get tx_rst reset\n");
+ return PTR_ERR(stf_hdmi->tx_rst);
+ }
+
+ return 0;
+}
+
+static int starfive_hdmi_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct stf_inno_hdmi *stf_hdmi;
+ struct inno_hdmi *hdmi;
+ struct resource *iores;
+
+ int ret;
+ unsigned long long rate;
+
+ stf_hdmi = drmm_simple_encoder_alloc(drm, struct stf_inno_hdmi,
+ encoder, DRM_MODE_ENCODER_TMDS);
+ hdmi = &stf_hdmi->inno_hdmi;
+
+ hdmi->dev = dev;
+ hdmi->plat_data = (struct inno_hdmi_plat_data *)of_device_get_match_data(dev);
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdmi->regs = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs))
+ return PTR_ERR(hdmi->regs);
+
+ ret = starfive_hdmi_get_clk_rst(dev, stf_hdmi);
+ if (ret < 0)
+ return ret;
+
+ ret = starfive_hdmi_enable_clk_rst(dev, stf_hdmi);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(stf_hdmi->clk_hdmi[CLK_SYS].clk);
+ inno_hdmi_i2c_init(hdmi, rate);
+
+ ret = inno_hdmi_bind(drm, hdmi, &stf_hdmi->encoder);
+ if (ret)
+ goto err_disable_clk;
+
+ dev_set_drvdata(dev, stf_hdmi);
+
+ return 0;
+
+err_disable_clk:
+ starfive_hdmi_disable_clk_rst(dev, stf_hdmi);
+ return ret;
+}
+
+static void starfive_hdmi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct stf_inno_hdmi *stf_hdmi = dev_get_drvdata(dev);
+
+ struct inno_hdmi *hdmi = &stf_hdmi->inno_hdmi;
+
+ i2c_put_adapter(hdmi->ddc);
+ starfive_hdmi_disable_clk_rst(dev, stf_hdmi);
+}
+
+static const struct component_ops starfive_hdmi_ops = {
+ .bind = starfive_hdmi_bind,
+ .unbind = starfive_hdmi_unbind,
+};
+
+static int starfive_hdmi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &starfive_hdmi_ops);
+}
+
+static int starfive_hdmi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &starfive_hdmi_ops);
+
+ return 0;
+}
+
+static const struct inno_hdmi_plat_data stf_inno_info = {
+ .soc_type = STARFIVE_HDMI,
+ .mode_valid = starfive_hdmi_connector_mode_valid,
+ .helper_private = &stf_inno_encoder_helper_funcs,
+};
+
+static const struct of_device_id starfive_hdmi_dt_ids[] = {
+ { .compatible = "starfive,jh7110-inno-hdmi", .data = &stf_inno_info,},
+ {},
+};
+MODULE_DEVICE_TABLE(of, starfive_hdmi_dt_ids);
+
+struct platform_driver starfive_hdmi_driver = {
+ .probe = starfive_hdmi_probe,
+ .remove = starfive_hdmi_remove,
+ .driver = {
+ .name = "starfive-hdmi",
+ .of_match_table = starfive_hdmi_dt_ids,
+ },
+};
+
+MODULE_AUTHOR("StarFive Corporation");
+MODULE_DESCRIPTION("Starfive Specific INNO-HDMI Driver");
diff --git a/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h
new file mode 100644
index 000000000000..c64374208b58
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef __STARFIVE_HDMI_H__
+#define __STARFIVE_HDMI_H__
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+
+#define HDMI_SYNC 0xce
+
+#define UPDATE(x, h, l) FIELD_PREP(GENMASK(h, l), x)
+
+/* REG: 0x1a0 */
+#define STF_INNO_PRE_PLL_CONTROL 0x1a0
+#define STF_INNO_PCLK_VCO_DIV_5_MASK BIT(1)
+#define STF_INNO_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1)
+#define STF_INNO_PRE_PLL_POWER_DOWN BIT(0)
+
+/* REG: 0x1a1 */
+#define STF_INNO_PRE_PLL_DIV_1 0x1a1
+#define STF_INNO_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0)
+#define STF_INNO_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0)
+
+/* REG: 0x1a2 */
+#define STF_INNO_PRE_PLL_DIV_2 0x1a2
+#define STF_INNO_SPREAD_SPECTRUM_MOD_DOWN BIT(7)
+#define STF_INNO_SPREAD_SPECTRUM_MOD_DISABLE BIT(6)
+#define STF_INNO_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4)
+#define STF_INNO_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0)
+#define STF_INNO_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0)
+
+/* REG: 0x1a3 */
+#define STF_INNO_PRE_PLL_DIV_3 0x1a3
+#define STF_INNO_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0)
+
+/* REG: 0x1a4*/
+#define STF_INNO_PRE_PLL_DIV_4 0x1a4
+#define STF_INNO_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0)
+#define STF_INNO_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0)
+#define STF_INNO_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2)
+#define STF_INNO_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2)
+#define STF_INNO_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4)
+#define STF_INNO_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4)
+
+/* REG: 0x1a5 */
+#define STF_INNO_PRE_PLL_DIV_5 0x1a5
+#define STF_INNO_PRE_PLL_PCLK_DIV_B_SHIFT 5
+#define STF_INNO_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5)
+#define STF_INNO_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5)
+#define STF_INNO_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0)
+#define STF_INNO_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0)
+
+/* REG: 0x1a6 */
+#define STF_INNO_PRE_PLL_DIV_6 0x1a6
+#define STF_INNO_PRE_PLL_PCLK_DIV_C_SHIFT 5
+#define STF_INNO_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5)
+#define STF_INNO_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5)
+#define STF_INNO_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0)
+#define STF_INNO_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0)
+
+/* REG: 0x1a9 */
+#define STF_INNO_PRE_PLL_LOCK_STATUS 0x1a9
+
+/* REG: 0x1aa */
+#define STF_INNO_POST_PLL_DIV_1 0x1aa
+#define STF_INNO_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2)
+#define STF_INNO_POST_PLL_REFCLK_SEL_TMDS BIT(1)
+#define STF_INNO_POST_PLL_POWER_DOWN BIT(0)
+#define STF_INNO_POST_PLL_FB_DIV_8(x) UPDATE(((x) >> 8) << 4, 4, 4)
+
+/* REG:0x1ab */
+#define STF_INNO_POST_PLL_DIV_2 0x1ab
+#define STF_INNO_POST_PLL_Pre_DIV_MASK GENMASK(5, 0)
+#define STF_INNO_POST_PLL_PRE_DIV(x) UPDATE(x, 5, 0)
+
+/* REG: 0x1ac */
+#define STF_INNO_POST_PLL_DIV_3 0x1ac
+#define STF_INNO_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0)
+
+/* REG: 0x1ad */
+#define STF_INNO_POST_PLL_DIV_4 0x1ad
+#define STF_INNO_POST_PLL_POST_DIV_MASK GENMASK(2, 0)
+#define STF_INNO_POST_PLL_POST_DIV_2 0x0
+#define STF_INNO_POST_PLL_POST_DIV_4 0x1
+#define STF_INNO_POST_PLL_POST_DIV_8 0x3
+
+/* REG: 0x1af */
+#define STF_INNO_POST_PLL_LOCK_STATUS 0x1af
+
+/* REG: 0x1b0 */
+#define STF_INNO_BIAS_CONTROL 0x1b0
+#define STF_INNO_BIAS_ENABLE BIT(2)
+
+/* REG: 0x1b2 */
+#define STF_INNO_TMDS_CONTROL 0x1b2
+#define STF_INNO_TMDS_CLK_DRIVER_EN BIT(3)
+#define STF_INNO_TMDS_D2_DRIVER_EN BIT(2)
+#define STF_INNO_TMDS_D1_DRIVER_EN BIT(1)
+#define STF_INNO_TMDS_D0_DRIVER_EN BIT(0)
+#define STF_INNO_TMDS_DRIVER_ENABLE (STF_INNO_TMDS_CLK_DRIVER_EN | \
+ STF_INNO_TMDS_D2_DRIVER_EN | \
+ STF_INNO_TMDS_D1_DRIVER_EN | \
+ STF_INNO_TMDS_D0_DRIVER_EN)
+
+/* REG: 0x1b4 */
+#define STF_INNO_LDO_CONTROL 0x1b4
+#define STF_INNO_LDO_D2_EN BIT(2)
+#define STF_INNO_LDO_D1_EN BIT(1)
+#define STF_INNO_LDO_D0_EN BIT(0)
+#define STF_INNO_LDO_ENABLE (STF_INNO_LDO_D2_EN | \
+ STF_INNO_LDO_D1_EN | \
+ STF_INNO_LDO_D0_EN)
+
+/* REG: 0x1be */
+#define STF_INNO_SERIALIER_CONTROL 0x1be
+#define STF_INNO_SERIALIER_D2_EN BIT(6)
+#define STF_INNO_SERIALIER_D1_EN BIT(5)
+#define STF_INNO_SERIALIER_D0_EN BIT(4)
+#define STF_INNO_SERIALIER_EN BIT(0)
+
+#define STF_INNO_SERIALIER_ENABLE (STF_INNO_SERIALIER_D2_EN | \
+ STF_INNO_SERIALIER_D1_EN | \
+ STF_INNO_SERIALIER_D0_EN | \
+ STF_INNO_SERIALIER_EN)
+
+/* REG: 0x1cc */
+#define STF_INNO_RX_CONTROL 0x1cc
+#define STF_INNO_RX_EN BIT(3)
+#define STF_INNO_RX_CHANNEL_2_EN BIT(2)
+#define STF_INNO_RX_CHANNEL_1_EN BIT(1)
+#define STF_INNO_RX_CHANNEL_0_EN BIT(0)
+#define STF_INNO_RX_ENABLE (STF_INNO_RX_EN | \
+ STF_INNO_RX_CHANNEL_2_EN | \
+ STF_INNO_RX_CHANNEL_1_EN | \
+ STF_INNO_RX_CHANNEL_0_EN)
+
+/* REG: 0x1d1 */
+#define STF_INNO_PRE_PLL_FRAC_DIV_H 0x1d1
+#define STF_INNO_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0)
+/* REG: 0x1d2 */
+#define STF_INNO_PRE_PLL_FRAC_DIV_M 0x1d2
+#define STF_INNO_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0)
+/* REG: 0x1d3 */
+#define STF_INNO_PRE_PLL_FRAC_DIV_L 0x1d3
+#define STF_INNO_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0)
+
+#define PIXCLOCK_4K_30FPS 297000000
+
+#endif /* __STARFIVE_HDMI_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
index c22fd2199fe2..6f04102b05b3 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.c
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -609,7 +609,9 @@ static const struct component_master_ops vs_drm_ops = {
};
static struct platform_driver *drm_sub_drivers[] = {
-
+#ifdef CONFIG_DRM_INNO_STARFIVE_HDMI
+ &starfive_hdmi_driver,
+#endif
};
static struct component_match *vs_add_external_components(struct device *dev)
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
index d9f6efa7c8f9..c3c08ed5f8ac 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.h
+++ b/drivers/gpu/drm/verisilicon/vs_drv.h
@@ -90,4 +90,8 @@ to_vs_plane_state(struct drm_plane_state *state)
return container_of(state, struct vs_plane_state, base);
}
+#ifdef CONFIG_DRM_INNO_STARFIVE_HDMI
+extern struct platform_driver starfive_hdmi_driver;
+#endif
+
#endif /* __VS_DRV_H__ */
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v4 10/10] drm/vs: add simple dsi encoder
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
` (10 preceding siblings ...)
2024-05-21 10:58 ` [PATCH v4 09/10] drm/vs: Innosilicon HDMI support keith
@ 2024-05-21 10:58 ` keith
2024-05-21 15:25 ` Dmitry Baryshkov
2024-05-22 7:29 ` Maxime Ripard
11 siblings, 2 replies; 53+ messages in thread
From: keith @ 2024-05-21 10:58 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel, keith.zhao
add encoder to match cdns dsi driver
Signed-off-by: keith <keith.zhao@starfivetech.com>
---
drivers/gpu/drm/verisilicon/Makefile | 3 +-
drivers/gpu/drm/verisilicon/vs_drv.c | 1 +
drivers/gpu/drm/verisilicon/vs_drv.h | 1 +
drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 ++++++++++++++++++++
drivers/gpu/drm/verisilicon/vs_simple_enc.h | 25 +++
5 files changed, 219 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c
create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 2d02b4a3a567..c35ba9bd6f81 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -4,7 +4,8 @@ vs_drm-objs := vs_dc_hw.o \
vs_modeset.o \
vs_plane.o \
vs_crtc.o \
- vs_drv.o
+ vs_drv.o \
+ vs_simple_enc.o
vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o
obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
index 6f04102b05b3..2748d48f2c7e 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.c
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -612,6 +612,7 @@ static struct platform_driver *drm_sub_drivers[] = {
#ifdef CONFIG_DRM_INNO_STARFIVE_HDMI
&starfive_hdmi_driver,
#endif
+ &simple_encoder_driver,
};
static struct component_match *vs_add_external_components(struct device *dev)
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
index c3c08ed5f8ac..f3f0f170777d 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.h
+++ b/drivers/gpu/drm/verisilicon/vs_drv.h
@@ -17,6 +17,7 @@
#include <drm/drm_managed.h>
#include "vs_dc_hw.h"
+#include "vs_simple_enc.h"
/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
struct vs_drm_device {
diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.c b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
new file mode 100644
index 000000000000..d0b1755d77d2
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
+ */
+#include <linux/component.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
+
+#include "vs_crtc.h"
+#include "vs_simple_enc.h"
+
+static const struct simple_encoder_priv dsi_priv = {
+ .encoder_type = DRM_MODE_ENCODER_DSI
+};
+
+static inline struct vs_simple_encoder *to_simple_encoder(struct drm_encoder *enc)
+{
+ return container_of(enc, struct vs_simple_encoder, encoder);
+}
+
+static int encoder_parse_dt(struct device *dev)
+{
+ struct vs_simple_encoder *simple = dev_get_drvdata(dev);
+ unsigned int args[2];
+
+ simple->dss_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
+ "starfive,syscon",
+ 2, args);
+
+ if (IS_ERR(simple->dss_regmap)) {
+ return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
+ "getting the regmap failed\n");
+ }
+
+ simple->offset = args[0];
+ simple->mask = args[1];
+
+ return 0;
+}
+
+static void vs_encoder_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
+{
+ struct vs_simple_encoder *simple = to_simple_encoder(encoder);
+
+ regmap_update_bits(simple->dss_regmap, simple->offset, simple->mask, simple->mask);
+}
+
+static int vs_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state);
+ struct drm_connector *connector = conn_state->connector;
+ int ret = 0;
+
+ vs_crtc_state->encoder_type = encoder->encoder_type;
+ if (connector->display_info.num_bus_formats)
+ vs_crtc_state->output_fmt = connector->display_info.bus_formats[0];
+ else
+ vs_crtc_state->output_fmt = MEDIA_BUS_FMT_FIXED;
+
+ switch (vs_crtc_state->output_fmt) {
+ case MEDIA_BUS_FMT_FIXED:
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ /* If MEDIA_BUS_FMT_FIXED, set it to default value */
+ if (vs_crtc_state->output_fmt == MEDIA_BUS_FMT_FIXED)
+ vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
+
+ return ret;
+}
+
+static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+ .atomic_check = vs_encoder_atomic_check,
+ .atomic_enable = vs_encoder_atomic_enable,
+};
+
+static int vs_encoder_bind(struct device *dev, struct device *master, void *data)
+{
+ struct drm_device *drm_dev = data;
+ struct vs_simple_encoder *simple = dev_get_drvdata(dev);
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+ int ret;
+
+ encoder = &simple->encoder;
+
+ ret = drmm_encoder_init(drm_dev, encoder, NULL, simple->priv->encoder_type, NULL);
+ if (ret)
+ return ret;
+
+ drm_encoder_helper_add(encoder, &encoder_helper_funcs);
+
+ encoder->possible_crtcs =
+ drm_of_find_possible_crtcs(drm_dev, dev->of_node);
+
+ /* output port is port1*/
+ bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+ if (IS_ERR(bridge)) {
+ if (PTR_ERR(bridge) == -ENODEV) {
+ bridge = NULL;
+ return 0;
+ }
+
+ return PTR_ERR(bridge);
+ }
+
+ return drm_bridge_attach(encoder, bridge, NULL, 0);
+}
+
+static const struct component_ops encoder_component_ops = {
+ .bind = vs_encoder_bind,
+};
+
+static int vs_encoder_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct vs_simple_encoder *simple;
+ int ret;
+
+ simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
+ if (!simple)
+ return -ENOMEM;
+
+ simple->priv = of_device_get_match_data(dev);
+
+ simple->dev = dev;
+
+ dev_set_drvdata(dev, simple);
+
+ ret = encoder_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ return component_add(dev, &encoder_component_ops);
+}
+
+static int vs_encoder_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_del(dev, &encoder_component_ops);
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id simple_encoder_dt_match[] = {
+ { .compatible = "starfive,dsi-encoder", .data = &dsi_priv},
+ {},
+};
+MODULE_DEVICE_TABLE(of, simple_encoder_dt_match);
+
+struct platform_driver simple_encoder_driver = {
+ .probe = vs_encoder_probe,
+ .remove = vs_encoder_remove,
+ .driver = {
+ .name = "vs-simple-encoder",
+ .of_match_table = of_match_ptr(simple_encoder_dt_match),
+ },
+};
+
+MODULE_DESCRIPTION("Simple Encoder Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.h b/drivers/gpu/drm/verisilicon/vs_simple_enc.h
new file mode 100644
index 000000000000..73e356bfeb2c
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_SIMPLE_ENC_H_
+#define __VS_SIMPLE_ENC_H_
+
+#include <drm/drm_encoder.h>
+
+struct simple_encoder_priv {
+ unsigned char encoder_type;
+};
+
+struct vs_simple_encoder {
+ struct drm_encoder encoder;
+ struct device *dev;
+ const struct simple_encoder_priv *priv;
+ struct regmap *dss_regmap;
+ unsigned int offset;
+ unsigned int mask;
+};
+
+extern struct platform_driver simple_encoder_driver;
+#endif /* __VS_SIMPLE_ENC_H_ */
--
2.27.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* Re: [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi
2024-05-21 8:03 ` Heiko Stübner
@ 2024-05-21 14:55 ` Alex Bee
0 siblings, 0 replies; 53+ messages in thread
From: Alex Bee @ 2024-05-21 14:55 UTC (permalink / raw)
To: Heiko Stübner, andrzej.hajda, neil.armstrong, rfoss,
Laurent.pinchart, jonas, jernej.skrabec, maarten.lankhorst,
mripard, tzimmermann, airlied, daniel, robh, krzk+dt, conor+dt,
hjc, andy.yan, xingyu.wu, p.zabel, jack.zhu, shengyang.chen,
keith
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel
Hi Heiko,
Am 21.05.24 um 10:03 schrieb Heiko Stübner:
> Hi Alex,
>
> Am Dienstag, 21. Mai 2024, 12:58:07 CEST schrieb keith:
>> Verisilicon/DC8200 display controller IP has 2 display pipes and each
>> pipe support a primary plane and a cursor plane .
>> In addition, there are four overlay planes as two display pipes common resources.
>>
>> The first display pipe is bound to the inno HDMI encoder.
>> The second display pipe is bound to a simple encoder, which is used to
>> find dsi bridge by dts node.
>>
>> Patch 1 adds YAML schema for JH7110 display pipeline.
>>
>> Patches 2 to 3 add inno common api and match the ROCKCHIP inno hdmi driver
>> by calling the common api.
>> The collating public interface is based on ROCKCHIP inno hdmi,
>> and it can be resused by JH7110 inno hdmi.
>> Those common api are tested on rk-3128 SDK, which kernel version is 4.x.
> as you were working on the rk3128-inno-hdmi variant recently
> and I don't really have a rk3036 or rk3128 in working condition
> right now, could you give this series a try.
Sure, I'm going to check this soon.
Regards,
Alex
> For reference, the full series is at lore:
> https://lore.kernel.org/dri-devel/20240521105817.3301-1-keith.zhao@starfivetech.com/
>
> and generalizes the inno-hdmi driver into the bridge model we
> have in a number of other places already.
>
>
> Thanks
> Heiko
>
>
>
>> step1, make sure the process is consistent with the latest kernel version.
>> step2, just remove the interface and add a common interface.
>>
>> Patches 4 to 8 add kms driver for dc8200 display controller.
>>
>> Patch 9 adds inno hdmi support for JH7110 display pipeline.
>>
>> Patch 10 adds a simple encoder.
>>
>> This patchset should be applied on next branch.
>>
>> V1:
>> Changes since v1:
>> - Further standardize the yaml file.
>> - Dts naming convention improved.
>> - Fix the problem of compiling and loading ko files.
>> - Use drm new api to automatically manage resources.
>> - Drop vs_crtc_funcs&vs_plane_funcs, subdivide the plane's help interface.
>> - Reduce the modifiers unused.
>> - Optimize the hdmi driver code
>>
>> V2:
>> Changes since v2:
>> - fix the error about checking the yaml file.
>> - match drm driver GEM DMA API.
>> - Delete the custom crtc property .
>> - hdmi use drmm_ new api to automatically manage resources.
>> - update the modifiers comments.
>> - enabling KASAN, fix the error during removing module
>>
>> V3:
>> Changes since v3:
>> - Delete the custom plane property.
>> - Delete the custom fourcc modifiers.
>> - Adjust the calculation mode of hdmi pixclock.
>> - Add match data for dc8200 driver.
>> - Adjust some magic values.
>> - Add a simple encoder for dsi output.
>>
>> V4:
>> Changes since v4:
>> - Delete the display subsystem module as all crtcs and planes are a driver.
>> - Delete the custom struct, directly use the drm struct data.
>> - Tidy up the inno hdmi public interface.
>> - Add a simple encoder for dsi output.
>>
>> keith (10):
>> dt-bindings: display: Add YAML schema for JH7110 display pipeline
>> drm/bridge: add common api for inno hdmi
>> drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver
>> drm/vs: Add hardware funcs for vs.
>> drm/vs: add vs mode config init
>> drm/vs: add vs plane api
>> drm/vs: add ctrc fun
>> drm/vs: add vs drm master driver
>> drm/vs: Innosilicon HDMI support
>> drm/vs: add simple dsi encoder
>>
>> .../display/bridge/innosilicon,inno-hdmi.yaml | 49 +
>> .../display/rockchip/rockchip,inno-hdmi.yaml | 27 +-
>> .../starfive/starfive,dsi-encoder.yaml | 92 ++
>> .../starfive/starfive,jh7110-dc8200.yaml | 169 +++
>> .../starfive/starfive,jh7110-inno-hdmi.yaml | 75 ++
>> .../soc/starfive/starfive,jh7110-syscon.yaml | 1 +
>> MAINTAINERS | 11 +
>> drivers/gpu/drm/Kconfig | 2 +
>> drivers/gpu/drm/Makefile | 1 +
>> drivers/gpu/drm/bridge/Kconfig | 2 +
>> drivers/gpu/drm/bridge/Makefile | 1 +
>> drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
>> drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
>> .../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 +++++++++
>> .../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 ++
>> drivers/gpu/drm/rockchip/Kconfig | 1 +
>> drivers/gpu/drm/rockchip/Makefile | 2 +-
>> drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++
>> .../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 -
>> drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 -----------------
>> drivers/gpu/drm/verisilicon/Kconfig | 23 +
>> drivers/gpu/drm/verisilicon/Makefile | 11 +
>> .../gpu/drm/verisilicon/inno_hdmi-starfive.c | 481 ++++++++
>> .../gpu/drm/verisilicon/inno_hdmi-starfive.h | 152 +++
>> drivers/gpu/drm/verisilicon/vs_crtc.c | 241 ++++
>> drivers/gpu/drm/verisilicon/vs_crtc.h | 17 +
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1060 ++++++++++++++++
>> drivers/gpu/drm/verisilicon/vs_dc_hw.h | 493 ++++++++
>> drivers/gpu/drm/verisilicon/vs_drv.c | 721 +++++++++++
>> drivers/gpu/drm/verisilicon/vs_drv.h | 98 ++
>> drivers/gpu/drm/verisilicon/vs_modeset.c | 36 +
>> drivers/gpu/drm/verisilicon/vs_modeset.h | 10 +
>> drivers/gpu/drm/verisilicon/vs_plane.c | 487 ++++++++
>> drivers/gpu/drm/verisilicon/vs_plane.h | 26 +
>> drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 +++
>> drivers/gpu/drm/verisilicon/vs_simple_enc.h | 25 +
>> drivers/gpu/drm/verisilicon/vs_type.h | 84 ++
>> include/drm/bridge/inno_hdmi.h | 69 ++
>> 38 files changed, 5840 insertions(+), 1144 deletions(-)
>> create mode 100644 Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
>> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml
>> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml
>> create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml
>> create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
>> create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
>> create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
>> create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
>> create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
>> rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h} (85%)
>> delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
>> create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
>> create mode 100644 drivers/gpu/drm/verisilicon/Makefile
>> create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c
>> create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.c
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.h
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
>> create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
>> create mode 100644 include/drm/bridge/inno_hdmi.h
>>
>>
>
>
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder
2024-05-21 10:58 ` [PATCH v4 10/10] drm/vs: add simple dsi encoder keith
@ 2024-05-21 15:25 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
2024-05-22 7:29 ` Maxime Ripard
1 sibling, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-05-21 15:25 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
On Tue, May 21, 2024 at 06:58:17PM +0800, keith wrote:
> add encoder to match cdns dsi driver
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
Please fix your git configuration to include your full name into the
S-o-B and Author fields.
> ---
> drivers/gpu/drm/verisilicon/Makefile | 3 +-
> drivers/gpu/drm/verisilicon/vs_drv.c | 1 +
> drivers/gpu/drm/verisilicon/vs_drv.h | 1 +
> drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 ++++++++++++++++++++
> drivers/gpu/drm/verisilicon/vs_simple_enc.h | 25 +++
> 5 files changed, 219 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
>
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 2d02b4a3a567..c35ba9bd6f81 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -4,7 +4,8 @@ vs_drm-objs := vs_dc_hw.o \
> vs_modeset.o \
> vs_plane.o \
> vs_crtc.o \
> - vs_drv.o
> + vs_drv.o \
> + vs_simple_enc.o
>
> vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o
> obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> index 6f04102b05b3..2748d48f2c7e 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -612,6 +612,7 @@ static struct platform_driver *drm_sub_drivers[] = {
> #ifdef CONFIG_DRM_INNO_STARFIVE_HDMI
> &starfive_hdmi_driver,
> #endif
> + &simple_encoder_driver,
> };
>
> static struct component_match *vs_add_external_components(struct device *dev)
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
> index c3c08ed5f8ac..f3f0f170777d 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.h
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> @@ -17,6 +17,7 @@
> #include <drm/drm_managed.h>
>
> #include "vs_dc_hw.h"
> +#include "vs_simple_enc.h"
>
> /*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
> struct vs_drm_device {
> diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.c b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> new file mode 100644
> index 000000000000..d0b1755d77d2
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> @@ -0,0 +1,190 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
Now it is 2024, so the copyright should probably cover the range.
> + */
> +#include <linux/component.h>
> +#include <linux/of_device.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/media-bus-format.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_of.h>
> +
> +#include "vs_crtc.h"
> +#include "vs_simple_enc.h"
> +
> +static const struct simple_encoder_priv dsi_priv = {
> + .encoder_type = DRM_MODE_ENCODER_DSI
So, is it 'simple' aka something generic or DSI? In the latter case,
please rename it accordingly.
> +};
> +
> +static inline struct vs_simple_encoder *to_simple_encoder(struct drm_encoder *enc)
> +{
> + return container_of(enc, struct vs_simple_encoder, encoder);
> +}
> +
> +static int encoder_parse_dt(struct device *dev)
> +{
> + struct vs_simple_encoder *simple = dev_get_drvdata(dev);
> + unsigned int args[2];
> +
> + simple->dss_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
> + "starfive,syscon",
> + 2, args);
> +
> + if (IS_ERR(simple->dss_regmap)) {
> + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
> + "getting the regmap failed\n");
> + }
> +
> + simple->offset = args[0];
> + simple->mask = args[1];
Is the value that you've read platform dependent or use case dependent?
What is the actual value being written? Why are you using syscon for it?
> +
> + return 0;
> +}
> +
> +static void vs_encoder_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
> +{
> + struct vs_simple_encoder *simple = to_simple_encoder(encoder);
> +
> + regmap_update_bits(simple->dss_regmap, simple->offset, simple->mask, simple->mask);
A purist in me would ask to have separate mask and value to write.
> +}
Is it necessary to clear those bits when stopping the stream?
[skipped the rest]
> +
> +
> +struct platform_driver simple_encoder_driver = {
> + .probe = vs_encoder_probe,
> + .remove = vs_encoder_remove,
> + .driver = {
> + .name = "vs-simple-encoder",
> + .of_match_table = of_match_ptr(simple_encoder_dt_match),
> + },
> +};
> +
> +MODULE_DESCRIPTION("Simple Encoder Driver");
VeriSilicon DSI Encoder
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.h b/drivers/gpu/drm/verisilicon/vs_simple_enc.h
> new file mode 100644
> index 000000000000..73e356bfeb2c
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2022 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_SIMPLE_ENC_H_
> +#define __VS_SIMPLE_ENC_H_
> +
> +#include <drm/drm_encoder.h>
> +
> +struct simple_encoder_priv {
> + unsigned char encoder_type;
> +};
> +
> +struct vs_simple_encoder {
> + struct drm_encoder encoder;
> + struct device *dev;
> + const struct simple_encoder_priv *priv;
> + struct regmap *dss_regmap;
> + unsigned int offset;
> + unsigned int mask;
> +};
Is there a need for aheader for the encoder? Can you move the
definitions to the source file?
> +
> +extern struct platform_driver simple_encoder_driver;
> +#endif /* __VS_SIMPLE_ENC_H_ */
> --
> 2.27.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
2024-05-21 10:58 ` [PATCH v4 02/10] drm/bridge: add common api for inno hdmi keith
2024-05-21 9:30 ` Krzysztof Kozlowski
@ 2024-05-21 15:36 ` Alex Bee
2024-05-21 15:42 ` Laurent Pinchart
2024-06-23 18:42 ` Markus Elfring
2 siblings, 1 reply; 53+ messages in thread
From: Alex Bee @ 2024-05-21 15:36 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel
Hi Keith,
thanks a lot for working on this. See some general remarks below
Am 21.05.24 um 12:58 schrieb keith:
> Add INNO common api so that it can be used by vendor
> drivers which implement vendor specific extensions to Innosilicon HDMI.
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> MAINTAINERS | 2 +
> drivers/gpu/drm/bridge/Kconfig | 2 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
> drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
> .../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 ++++++++++++++++++
> .../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 +++
> include/drm/bridge/inno_hdmi.h | 69 ++
> 8 files changed, 766 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
> create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
> create mode 100644 include/drm/bridge/inno_hdmi.h
>
....
> + drm_encoder_helper_add(encoder, pdata->helper_private);
> +
> + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
> +
> + drm_connector_helper_add(&hdmi->connector,
> + &inno_hdmi_connector_helper_funcs);
> +
> + drmm_connector_init(drm, &hdmi->connector,
> + &inno_hdmi_connector_funcs,
> + DRM_MODE_CONNECTOR_HDMIA,
> + hdmi->ddc);
> +
I really don't want to anticipate bridge maintainer's feedback, but new
bridge drivers must not contain connector creation. That must happen
somewhere else.
Also I'm neither seeing any drm_brige struct nor drm_bridge_funcs, which
are both essential for a bridge driver. I don't think moving a part of a
driver to .../drm/bridge/ makes it a bridge driver.
Regeards,
Alex
> + drm_connector_attach_encoder(&hdmi->connector, encoder);
> +
> + return 0;
> +}
> +
....
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
2024-05-21 15:36 ` Alex Bee
@ 2024-05-21 15:42 ` Laurent Pinchart
2024-05-22 5:58 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Laurent Pinchart @ 2024-05-21 15:42 UTC (permalink / raw)
To: Alex Bee
Cc: keith, andrzej.hajda, neil.armstrong, rfoss, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
On Tue, May 21, 2024 at 05:36:43PM +0200, Alex Bee wrote:
> Hi Keith,
>
> thanks a lot for working on this. See some general remarks below
>
> Am 21.05.24 um 12:58 schrieb keith:
> > Add INNO common api so that it can be used by vendor
> > drivers which implement vendor specific extensions to Innosilicon HDMI.
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > ---
> > MAINTAINERS | 2 +
> > drivers/gpu/drm/bridge/Kconfig | 2 +
> > drivers/gpu/drm/bridge/Makefile | 1 +
> > drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
> > drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
> > .../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 ++++++++++++++++++
> > .../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 +++
> > include/drm/bridge/inno_hdmi.h | 69 ++
> > 8 files changed, 766 insertions(+)
> > create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
> > create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
> > create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
> > create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
> > create mode 100644 include/drm/bridge/inno_hdmi.h
> >
> ....
>
> > + drm_encoder_helper_add(encoder, pdata->helper_private);
> > +
> > + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
> > +
> > + drm_connector_helper_add(&hdmi->connector,
> > + &inno_hdmi_connector_helper_funcs);
> > +
> > + drmm_connector_init(drm, &hdmi->connector,
> > + &inno_hdmi_connector_funcs,
> > + DRM_MODE_CONNECTOR_HDMIA,
> > + hdmi->ddc);
> > +
>
> I really don't want to anticipate bridge maintainer's feedback, but new
> bridge drivers must not contain connector creation. That must happen
> somewhere else.
You're absolutely right :-) Connector creation should be handled by the
drm_bridge_connector helper. The HDMI bridge driver should focus on the
HDMI bridge itself.
> Also I'm neither seeing any drm_brige struct nor drm_bridge_funcs, which
> are both essential for a bridge driver. I don't think moving a part of a
> driver to .../drm/bridge/ makes it a bridge driver.
>
> > + drm_connector_attach_encoder(&hdmi->connector, encoder);
> > +
> > + return 0;
> > +}
> > +
> ....
>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 06/10] drm/vs: add vs plane api
2024-05-21 10:58 ` [PATCH v4 06/10] drm/vs: add vs plane api keith
@ 2024-05-21 20:39 ` kernel test robot
2024-05-21 21:06 ` Dmitry Baryshkov
1 sibling, 0 replies; 53+ messages in thread
From: kernel test robot @ 2024-05-21 20:39 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: oe-kbuild-all, dri-devel, devicetree, linux-kernel,
linux-arm-kernel, keith.zhao
Hi keith,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master next-20240521]
[cannot apply to robh/for-next rockchip/for-next v6.9]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/keith/dt-bindings-display-Add-YAML-schema-for-JH7110-display-pipeline/20240521-110316
base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link: https://lore.kernel.org/r/20240521105817.3301-7-keith.zhao%40starfivetech.com
patch subject: [PATCH v4 06/10] drm/vs: add vs plane api
config: m68k-randconfig-r133-20240522 (https://download.01.org/0day-ci/archive/20240522/202405220419.2XNzWyBP-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20240522/202405220419.2XNzWyBP-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405220419.2XNzWyBP-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/verisilicon/vs_plane.c:83:30: sparse: sparse: symbol 'vs_plane_funcs' was not declared. Should it be static?
>> drivers/gpu/drm/verisilicon/vs_plane.c:339:37: sparse: sparse: symbol 'primary_plane_helpers' was not declared. Should it be static?
>> drivers/gpu/drm/verisilicon/vs_plane.c:345:37: sparse: sparse: symbol 'overlay_plane_helpers' was not declared. Should it be static?
>> drivers/gpu/drm/verisilicon/vs_plane.c:351:37: sparse: sparse: symbol 'cursor_plane_helpers' was not declared. Should it be static?
vim +/vs_plane_funcs +83 drivers/gpu/drm/verisilicon/vs_plane.c
82
> 83 const struct drm_plane_funcs vs_plane_funcs = {
84 .update_plane = drm_atomic_helper_update_plane,
85 .disable_plane = drm_atomic_helper_disable_plane,
86 .reset = vs_plane_reset,
87 .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
88 .atomic_destroy_state = vs_plane_atomic_destroy_state,
89 .format_mod_supported = vs_format_mod_supported,
90 };
91
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-05-21 10:58 ` [PATCH v4 04/10] drm/vs: Add hardware funcs for vs keith
@ 2024-05-21 20:50 ` kernel test robot
2024-05-21 20:50 ` Dmitry Baryshkov
` (2 subsequent siblings)
3 siblings, 0 replies; 53+ messages in thread
From: kernel test robot @ 2024-05-21 20:50 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: Paul Gazzillo, Necip Fazil Yildiran, oe-kbuild-all, dri-devel,
devicetree, linux-kernel, linux-arm-kernel, keith.zhao
Hi keith,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master next-20240521]
[cannot apply to robh/for-next rockchip/for-next v6.9]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/keith/dt-bindings-display-Add-YAML-schema-for-JH7110-display-pipeline/20240521-110316
base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link: https://lore.kernel.org/r/20240521105817.3301-5-keith.zhao%40starfivetech.com
patch subject: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
config: arc-kismet-CONFIG_DMA_CMA-CONFIG_DRM_VERISILICON_DC8200-0-0 (https://download.01.org/0day-ci/archive/20240522/202405220427.loHTDi8t-lkp@intel.com/config)
reproduce: (https://download.01.org/0day-ci/archive/20240522/202405220427.loHTDi8t-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405220427.loHTDi8t-lkp@intel.com/
kismet warnings: (new ones prefixed by >>)
>> kismet: WARNING: unmet direct dependencies detected for DMA_CMA when selected by DRM_VERISILICON_DC8200
WARNING: unmet direct dependencies detected for DMA_CMA
Depends on [n]: HAVE_DMA_CONTIGUOUS [=n] && CMA [=y]
Selected by [y]:
- DRM_VERISILICON_DC8200 [=y] && HAS_IOMEM [=y] && DRM [=y]
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-05-21 10:58 ` [PATCH v4 04/10] drm/vs: Add hardware funcs for vs keith
2024-05-21 20:50 ` kernel test robot
@ 2024-05-21 20:50 ` Dmitry Baryshkov
2024-06-23 7:16 ` Keith Zhao
2024-05-21 21:01 ` kernel test robot
2024-05-22 1:34 ` kernel test robot
3 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-05-21 20:50 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
On Tue, May 21, 2024 at 06:58:11PM +0800, keith wrote:
> add hardware base api for vs drm
Commit message is nearly missing. Please describe your hardware.
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
Full name please
> ---
> MAINTAINERS | 1 +
> drivers/gpu/drm/Kconfig | 2 +
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/verisilicon/Kconfig | 13 +
> drivers/gpu/drm/verisilicon/Makefile | 5 +
> drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1060 ++++++++++++++++++++++++
> drivers/gpu/drm/verisilicon/vs_dc_hw.h | 493 +++++++++++
> drivers/gpu/drm/verisilicon/vs_type.h | 84 ++
> 8 files changed, 1659 insertions(+)
> create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
> create mode 100644 drivers/gpu/drm/verisilicon/Makefile
> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index cf2d66f88a83..9cb376f76f74 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7156,6 +7156,7 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
> F: Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml
> F: Documentation/devicetree/bindings/display/starfive/
> F: drivers/gpu/drm/bridge/innosilicon/
> +F: drivers/gpu/drm/verisilicon
> F: include/drm/bridge/inno_hdmi.h
>
> DRM DRIVER FOR SYNAPTICS R63353 PANELS
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 026444eeb5c6..5413d87ef1d6 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -423,6 +423,8 @@ source "drivers/gpu/drm/sprd/Kconfig"
>
> source "drivers/gpu/drm/imagination/Kconfig"
>
> +source "drivers/gpu/drm/verisilicon/Kconfig"
> +
> config DRM_HYPERV
> tristate "DRM Support for Hyper-V synthetic video device"
> depends on DRM && PCI && MMU && HYPERV
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index f9ca4f8fa6c5..cb27092b1672 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -219,3 +219,4 @@ obj-y += solomon/
> obj-$(CONFIG_DRM_SPRD) += sprd/
> obj-$(CONFIG_DRM_LOONGSON) += loongson/
> obj-$(CONFIG_DRM_POWERVR) += imagination/
> +obj-$(CONFIG_DRM_VERISILICON_DC8200) += verisilicon/
> diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig
> new file mode 100644
> index 000000000000..2d733f93439e
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/Kconfig
> @@ -0,0 +1,13 @@
> +# SPDX-License-Identifier: GPL-2.0
> +config DRM_VERISILICON_DC8200
> + tristate "DRM Support for VeriSilicon DC8200"
> + depends on DRM
> + select DRM_KMS_HELPER
> + select DRM_GEM_DMA_HELPER
> + select CMA
> + select DMA_CMA
> + help
> + Choose this option if you have a VeriSilicon DC8200 chipset.
> + This driver provides VeriSilicon kernel mode
> + setting and buffer management. It does not
> + provide 2D or 3D acceleration.
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> new file mode 100644
> index 000000000000..7da54b259940
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +vs_drm-objs := vs_dc_hw.o
> +
> +obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> new file mode 100644
> index 000000000000..69f020f8352f
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> @@ -0,0 +1,1060 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
No changes in 2024?
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/io.h>
> +#include <linux/media-bus-format.h>
> +//#include <drm/drm_atomic_helper.h>
Either uncomment or drop.
> +#include <drm/drm_blend.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_framebuffer.h>
> +#include <drm/drm_fb_dma_helper.h>
> +
> +#include "vs_dc_hw.h"
> +
> +static const u32 horkernel[] = {
> + 0x00000000, 0x20000000, 0x00002000, 0x00000000,
> + 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> + 0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> + 0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> + 0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> + 0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> + 0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> + 0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> + 0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> + 0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> + 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> + 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> + 0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> + 0x00000000, 0x00000000, 0x00000000, 0x01470000,
> + 0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> + 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> + 0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> + 0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> + 0x00000000, 0x00000000, 0x00004000, 0x00000000,
> + 0x00000000, 0x00000000, 0x20002000, 0x00000000,
> + 0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
> + 0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
> + 0x00000000, 0x00000000, 0x00000000, 0x14680000,
> + 0x00002b98, 0x00000000, 0x00000000, 0x00000000,
> + 0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
> + 0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
> + 0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
> + 0x00000000, 0x087f0000, 0x00003781, 0x00000000,
> + 0x00000000, 0x00000000, 0x399a0666, 0x00000000,
> + 0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
> + 0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
> + 0x00000000, 0x00000000, 0x00000000, 0x021f0000,
> +};
> +
> +#define H_COEF_SIZE ARRAY_SIZE(horkernel)
> +
> +static const u32 verkernel[] = {
> + 0x00000000, 0x20000000, 0x00002000, 0x00000000,
> + 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> + 0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> + 0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> + 0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> + 0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> + 0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> + 0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> + 0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> + 0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> + 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> + 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> + 0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> + 0x00000000, 0x00000000, 0x00000000, 0x01470000,
> + 0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> + 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> + 0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> + 0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> + 0x00000000, 0x00000000, 0x00004000, 0x00000000,
> + 0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
> + 0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
> + 0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +};
> +
> +#define V_COEF_SIZE ARRAY_SIZE(verkernel)
> +
> +/*
> + * RGB 709->2020 conversion parameters
> + */
> +static const u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
> + 10279, 5395, 709,
> + 1132, 15065, 187,
> + 269, 1442, 14674
> +};
> +
> +/*
> + * YUV601 to RGB conversion parameters
> + * YUV2RGB[0] - [8] : C0 - C8;
> + * YUV2RGB[9] - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static const s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> + 1196, 0, 1640, 1196,
> + -404, -836, 1196, 2076,
> + 0, -916224, 558336, -1202944,
> + 64, 940, 64, 960
> +};
> +
> +/*
> + * YUV709 to RGB conversion parameters
> + * YUV2RGB[0] - [8] : C0 - C8;
> + * YUV2RGB[9] - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> + 1196, 0, 1844, 1196,
> + -220, -548, 1196, 2172,
> + 0, -1020672, 316672, -1188608,
> + 64, 940, 64, 960
> +};
> +
> +/*
> + * YUV2020 to RGB conversion parameters
> + * YUV2RGB[0] - [8] : C0 - C8;
> + * YUV2RGB[9] - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> + 1196, 0, 1724, 1196,
> + -192, -668, 1196, 2200,
> + 0, -959232, 363776, -1202944,
> + 64, 940, 64, 960
> +};
> +
> +/*
> + * RGB to YUV2020 conversion parameters
> + * RGB2YUV[0] - [8] : C0 - C8;
> + * RGB2YUV[9] - [11]: D0 - D2;
> + */
> +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
> + 230, 594, 52,
> + -125, -323, 448,
> + 448, -412, -36,
> + 64, 512, 512
Please fix spaces vs tabs here.
> +};
> +
> +/* one is for primary plane and the other is for all overlay planes */
> +static const struct dc_hw_plane_reg dc_plane_reg[] = {
> + {
> + .y_address = DC_FRAMEBUFFER_ADDRESS,
> + .u_address = DC_FRAMEBUFFER_U_ADDRESS,
> + .v_address = DC_FRAMEBUFFER_V_ADDRESS,
> + .y_stride = DC_FRAMEBUFFER_STRIDE,
> + .u_stride = DC_FRAMEBUFFER_U_STRIDE,
> + .v_stride = DC_FRAMEBUFFER_V_STRIDE,
> + .size = DC_FRAMEBUFFER_SIZE,
> + .top_left = DC_FRAMEBUFFER_TOP_LEFT,
> + .bottom_right = DC_FRAMEBUFFER_BOTTOM_RIGHT,
> + .scale_factor_x = DC_FRAMEBUFFER_SCALE_FACTOR_X,
> + .scale_factor_y = DC_FRAMEBUFFER_SCALE_FACTOR_Y,
> + .h_filter_coef_index = DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
> + .h_filter_coef_data = DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
> + .v_filter_coef_index = DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
> + .v_filter_coef_data = DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
> + .init_offset = DC_FRAMEBUFFER_INIT_OFFSET,
> + .color_key = DC_FRAMEBUFFER_COLOR_KEY,
> + .color_key_high = DC_FRAMEBUFFER_COLOR_KEY_HIGH,
> + .clear_value = DC_FRAMEBUFFER_CLEAR_VALUE,
> + .color_table_index = DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
> + .color_table_data = DC_FRAMEBUFFER_COLOR_TABLE_DATA,
> + .scale_config = DC_FRAMEBUFFER_SCALE_CONFIG,
> + .water_mark = DC_FRAMEBUFFER_WATER_MARK,
> + .degamma_index = DC_FRAMEBUFFER_DEGAMMA_INDEX,
> + .degamma_data = DC_FRAMEBUFFER_DEGAMMA_DATA,
> + .degamma_ex_data = DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
> + .src_global_color = DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
> + .dst_global_color = DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
> + .blend_config = DC_FRAMEBUFFER_BLEND_CONFIG,
> + .roi_origin = DC_FRAMEBUFFER_ROI_ORIGIN,
> + .roi_size = DC_FRAMEBUFFER_ROI_SIZE,
> + .yuv_to_rgb_coef0 = DC_FRAMEBUFFER_YUVTORGB_COEF0,
> + .yuv_to_rgb_coef1 = DC_FRAMEBUFFER_YUVTORGB_COEF1,
> + .yuv_to_rgb_coef2 = DC_FRAMEBUFFER_YUVTORGB_COEF2,
> + .yuv_to_rgb_coef3 = DC_FRAMEBUFFER_YUVTORGB_COEF3,
> + .yuv_to_rgb_coef4 = DC_FRAMEBUFFER_YUVTORGB_COEF4,
> + .yuv_to_rgb_coefd0 = DC_FRAMEBUFFER_YUVTORGB_COEFD0,
> + .yuv_to_rgb_coefd1 = DC_FRAMEBUFFER_YUVTORGB_COEFD1,
> + .yuv_to_rgb_coefd2 = DC_FRAMEBUFFER_YUVTORGB_COEFD2,
> + .y_clamp_bound = DC_FRAMEBUFFER_Y_CLAMP_BOUND,
> + .uv_clamp_bound = DC_FRAMEBUFFER_UV_CLAMP_BOUND,
> + .rgb_to_rgb_coef0 = DC_FRAMEBUFFER_RGBTORGB_COEF0,
> + .rgb_to_rgb_coef1 = DC_FRAMEBUFFER_RGBTORGB_COEF1,
> + .rgb_to_rgb_coef2 = DC_FRAMEBUFFER_RGBTORGB_COEF2,
> + .rgb_to_rgb_coef3 = DC_FRAMEBUFFER_RGBTORGB_COEF3,
> + .rgb_to_rgb_coef4 = DC_FRAMEBUFFER_RGBTORGB_COEF4,
> + },
> + {
> + .y_address = DC_OVERLAY_ADDRESS,
> + .u_address = DC_OVERLAY_U_ADDRESS,
> + .v_address = DC_OVERLAY_V_ADDRESS,
> + .y_stride = DC_OVERLAY_STRIDE,
> + .u_stride = DC_OVERLAY_U_STRIDE,
> + .v_stride = DC_OVERLAY_V_STRIDE,
> + .size = DC_OVERLAY_SIZE,
> + .top_left = DC_OVERLAY_TOP_LEFT,
> + .bottom_right = DC_OVERLAY_BOTTOM_RIGHT,
> + .scale_factor_x = DC_OVERLAY_SCALE_FACTOR_X,
> + .scale_factor_y = DC_OVERLAY_SCALE_FACTOR_Y,
> + .h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
> + .h_filter_coef_data = DC_OVERLAY_H_FILTER_COEF_DATA,
> + .v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
> + .v_filter_coef_data = DC_OVERLAY_V_FILTER_COEF_DATA,
> + .init_offset = DC_OVERLAY_INIT_OFFSET,
> + .color_key = DC_OVERLAY_COLOR_KEY,
> + .color_key_high = DC_OVERLAY_COLOR_KEY_HIGH,
> + .clear_value = DC_OVERLAY_CLEAR_VALUE,
> + .color_table_index = DC_OVERLAY_COLOR_TABLE_INDEX,
> + .color_table_data = DC_OVERLAY_COLOR_TABLE_DATA,
> + .scale_config = DC_OVERLAY_SCALE_CONFIG,
> + .water_mark = DC_OVERLAY_WATER_MARK,
> + .degamma_index = DC_OVERLAY_DEGAMMA_INDEX,
> + .degamma_data = DC_OVERLAY_DEGAMMA_DATA,
> + .degamma_ex_data = DC_OVERLAY_DEGAMMA_EX_DATA,
> + .src_global_color = DC_OVERLAY_SRC_GLOBAL_COLOR,
> + .dst_global_color = DC_OVERLAY_DST_GLOBAL_COLOR,
> + .blend_config = DC_OVERLAY_BLEND_CONFIG,
> + .roi_origin = DC_OVERLAY_ROI_ORIGIN,
> + .roi_size = DC_OVERLAY_ROI_SIZE,
> + .yuv_to_rgb_coef0 = DC_OVERLAY_YUVTORGB_COEF0,
> + .yuv_to_rgb_coef1 = DC_OVERLAY_YUVTORGB_COEF1,
> + .yuv_to_rgb_coef2 = DC_OVERLAY_YUVTORGB_COEF2,
> + .yuv_to_rgb_coef3 = DC_OVERLAY_YUVTORGB_COEF3,
> + .yuv_to_rgb_coef4 = DC_OVERLAY_YUVTORGB_COEF4,
> + .yuv_to_rgb_coefd0 = DC_OVERLAY_YUVTORGB_COEFD0,
> + .yuv_to_rgb_coefd1 = DC_OVERLAY_YUVTORGB_COEFD1,
> + .yuv_to_rgb_coefd2 = DC_OVERLAY_YUVTORGB_COEFD2,
> + .y_clamp_bound = DC_OVERLAY_Y_CLAMP_BOUND,
> + .uv_clamp_bound = DC_OVERLAY_UV_CLAMP_BOUND,
> + .rgb_to_rgb_coef0 = DC_OVERLAY_RGBTORGB_COEF0,
> + .rgb_to_rgb_coef1 = DC_OVERLAY_RGBTORGB_COEF1,
> + .rgb_to_rgb_coef2 = DC_OVERLAY_RGBTORGB_COEF2,
> + .rgb_to_rgb_coef3 = DC_OVERLAY_RGBTORGB_COEF3,
> + .rgb_to_rgb_coef4 = DC_OVERLAY_RGBTORGB_COEF4,
> + },
> +};
> +
> +static inline u32 hi_read(struct dc_hw *hw, u32 reg)
> +{
> + return readl(hw->hi_base + reg);
> +}
> +
> +static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
> +{
> + writel(value, hw->hi_base + reg);
> +}
> +
> +static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
> +{
> + writel(value, hw->reg_base + reg - DC_REG_BASE);
> +}
> +
> +static inline u32 dc_read(struct dc_hw *hw, u32 reg)
> +{
> + u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
> +
> + return value;
just return readl(...)
> +}
> +
> +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
> +{
> + u32 value = dc_read(hw, reg);
> +
> + value &= ~clear;
> + value |= set;
> + dc_write(hw, reg, value);
regmap_update_bits?
> +}
> +
> +static void load_default_filter(struct dc_hw *hw,
> + const struct dc_hw_plane_reg *reg, u32 offset)
> +{
> + u8 i;
> +
> + dc_write(hw, reg->scale_config + offset, 0x33);
> + dc_write(hw, reg->init_offset + offset, 0x80008000);
> + dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
> + for (i = 0; i < H_COEF_SIZE; i++)
> + dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
> +
> + dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
> + for (i = 0; i < V_COEF_SIZE; i++)
> + dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
> +}
> +
> +static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
> + u32 offset, const u16 *table)
> +{
> + dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
> + dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
> + dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
> + dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
> + dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
> +}
> +
> +static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
> + u32 offset, const s32 *table)
> +{
> + dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
> + (0xFFFF & table[0]) | (table[1] << 16));
> + dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
> + (0xFFFF & table[2]) | (table[3] << 16));
> + dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
> + (0xFFFF & table[4]) | (table[5] << 16));
> + dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
> + (0xFFFF & table[6]) | (table[7] << 16));
> + dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
> + dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
> + dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
> + dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
> + dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
> + dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
> +}
> +
> +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
Is there any reason why load_rgb_to_yuv differs from two other
functions?
> +{
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
> + table[0] | (table[1] << 16));
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
> + table[2] | (table[3] << 16));
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
> + table[4] | (table[5] << 16));
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
> + table[6] | (table[7] << 16));
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
> + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
> +}
> +
> +static int update_vs_format(u32 drm_format)
> +{
> + u8 f = FORMAT_A8R8G8B8;
> +
> + switch (drm_format) {
> + case DRM_FORMAT_XRGB4444:
> + case DRM_FORMAT_RGBX4444:
> + case DRM_FORMAT_XBGR4444:
> + case DRM_FORMAT_BGRX4444:
> + f = FORMAT_X4R4G4B4;
> + break;
> + case DRM_FORMAT_ARGB4444:
> + case DRM_FORMAT_RGBA4444:
> + case DRM_FORMAT_ABGR4444:
> + case DRM_FORMAT_BGRA4444:
> + f = FORMAT_A4R4G4B4;
> + break;
> + case DRM_FORMAT_XRGB1555:
> + case DRM_FORMAT_RGBX5551:
> + case DRM_FORMAT_XBGR1555:
> + case DRM_FORMAT_BGRX5551:
> + f = FORMAT_X1R5G5B5;
> + break;
> + case DRM_FORMAT_ARGB1555:
> + case DRM_FORMAT_RGBA5551:
> + case DRM_FORMAT_ABGR1555:
> + case DRM_FORMAT_BGRA5551:
> + f = FORMAT_A1R5G5B5;
> + break;
> + case DRM_FORMAT_RGB565:
> + case DRM_FORMAT_BGR565:
> + f = FORMAT_R5G6B5;
> + break;
> + case DRM_FORMAT_XRGB8888:
> + case DRM_FORMAT_RGBX8888:
> + case DRM_FORMAT_XBGR8888:
> + case DRM_FORMAT_BGRX8888:
> + f = FORMAT_X8R8G8B8;
> + break;
> + case DRM_FORMAT_ARGB8888:
> + case DRM_FORMAT_RGBA8888:
> + case DRM_FORMAT_ABGR8888:
> + case DRM_FORMAT_BGRA8888:
> + f = FORMAT_A8R8G8B8;
> + break;
> + case DRM_FORMAT_YUYV:
> + case DRM_FORMAT_YVYU:
> + f = FORMAT_YUY2;
> + break;
> + case DRM_FORMAT_UYVY:
> + case DRM_FORMAT_VYUY:
> + f = FORMAT_UYVY;
> + break;
> + case DRM_FORMAT_YUV420:
> + case DRM_FORMAT_YVU420:
> + f = FORMAT_YV12;
> + break;
> + case DRM_FORMAT_NV21:
> + f = FORMAT_NV12;
> + break;
> + case DRM_FORMAT_NV16:
> + case DRM_FORMAT_NV61:
> + f = FORMAT_NV16;
> + break;
> + case DRM_FORMAT_P010:
> + f = FORMAT_P010;
> + break;
> + case DRM_FORMAT_ARGB2101010:
> + case DRM_FORMAT_RGBA1010102:
> + case DRM_FORMAT_ABGR2101010:
> + case DRM_FORMAT_BGRA1010102:
> + f = FORMAT_A2R10G10B10;
> + break;
> + case DRM_FORMAT_NV12:
> + f = FORMAT_NV12;
> + break;
> + case DRM_FORMAT_YUV444:
> + f = FORMAT_YUV444;
s/f = /return /g all over the place.
> + break;
> + default:
return -EINVAL;
> + break;
> + }
> +
> + return f;
> +}
> +
> +int dc_hw_init(struct vs_dc *dc)
> +{
> + u8 i, id, panel_num, layer_num;
> + struct dc_hw *hw = &dc->hw;
> + u32 offset;
> +
> + layer_num = hw->info->layer_num;
> + for (i = 0; i < layer_num; i++) {
> + id = dc->planes[i].id;
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + hw->reg[i] = dc_plane_reg[0];
> + else
> + hw->reg[i] = dc_plane_reg[1];
> +
> + load_default_filter(hw, &hw->reg[i], dc->planes[i].offset);
> + load_rgb_to_rgb(hw, &hw->reg[i], dc->planes[i].offset, RGB2RGB);
> + }
> +
> + panel_num = hw->info->panel_num;
> + for (i = 0; i < panel_num; i++) {
> + offset = i << 2;
> +
> + load_rgb_to_yuv(hw, offset, RGB2YUV);
> + dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
> +
> + offset = i ? DC_CURSOR_OFFSET : 0;
> + dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
> + dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
> + }
> +
> + return 0;
> +}
> +
> +void dc_hw_disable_plane(struct vs_dc *dc, u8 id)
> +{
> + struct dc_hw *hw = &dc->hw;
> +
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + dc->planes[id].offset,
> + PRIMARY_EN(false), PRIMARY_EN_MASK);
> + else
> + dc_set_clear(hw, DC_OVERLAY_CONFIG + dc->planes[id].offset,
> + OVERLAY_FB_EN(false), OVERLAY_FB_EN_MASK);
> +}
> +
> +static int update_cursor_size(uint32_t crtc_w)
get_cursor_size()
> +{
> + u8 size_type;
> +
> + switch (crtc_w) {
> + case 32:
> + size_type = CURSOR_SIZE_32X32;
> + break;
> + case 64:
> + size_type = CURSOR_SIZE_64X64;
> + break;
> + default:
> + size_type = CURSOR_SIZE_32X32;
> + break;
> + }
> +
> + return size_type;
Same comment. Return directly without extra variable assignments.
> +}
> +
> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr,
> + u32 crtc_w, u32 crtc_x, u32 crtc_y,
> + s32 hotspot_x, s32 hotspot_y)
> +{
> + u32 offset, size;
> +
> + offset = id ? DC_CURSOR_OFFSET : 0;
> + size = update_cursor_size(crtc_w);
> +
> + dc_write(hw, DC_CURSOR_ADDRESS + offset,
> + dma_addr);
> + dc_write(hw, DC_CURSOR_LOCATION + offset,
> + X_LCOTION(crtc_x) |
> + Y_LCOTION(crtc_y));
> + dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
> + CURSOR_HOT_X(hotspot_x) |
> + CURSOR_HOT_y(hotspot_y) |
> + CURSOR_SIZE(size) |
> + CURSOR_VALID(1) |
> + CURSOR_TRIG_FETCH(1) |
> + CURSOR_FORMAT(CURSOR_FORMAT_A8R8G8B8),
> + CURSOR_HOT_X_MASK |
> + CURSOR_HOT_y_MASK |
> + CURSOR_SIZE_MASK |
> + CURSOR_VALID_MASK |
> + CURSOR_TRIG_FETCH_MASK |
> + CURSOR_FORMAT_MASK);
> +}
> +
> +void dc_hw_disable_cursor(struct dc_hw *hw, u8 id)
> +{
> + u32 offset = 0;
> +
> + offset = id ? DC_CURSOR_OFFSET : 0;
> + dc_set_clear(hw, DC_CURSOR_CONFIG + offset, CURSOR_VALID(1), CURSOR_FORMAT_MASK);
> +}
> +
> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> + u16 r, u16 g, u16 b)
> +{
> + if (index >= hw->info->gamma_size)
> + return;
> +
> + hw->gamma[id].gamma[index][0] = r;
> + hw->gamma[id].gamma[index][1] = g;
> + hw->gamma[id].gamma[index][2] = b;
> +}
> +
> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
> +{
> + u32 value;
> +
> + if (enable) {
> + dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (id << 2), 0x00);
> + for (int i = 0; i < GAMMA_EX_SIZE; i++) {
> + value = hw->gamma[id].gamma[i][2] |
> + (hw->gamma[id].gamma[i][1] << 12);
> + dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (id << 2), value);
> + dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (id << 2),
> + hw->gamma[id].gamma[i][0]);
> + }
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2), PANEL_GAMMA_EN, 0);
> + } else {
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2), 0, PANEL_GAMMA_EN);
> + }
> +}
> +
> +void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode *mode,
> + u8 encoder_type, u32 output_fmt)
> +{
> + u32 dp_cfg, dpi_cfg, offset = id << 2;
> + bool is_yuv = false;
> +
> + if (encoder_type != DRM_MODE_ENCODER_DSI) {
> + switch (output_fmt) {
> + case MEDIA_BUS_FMT_RGB565_1X16:
> + dp_cfg = 0;
> + break;
> + case MEDIA_BUS_FMT_RGB666_1X18:
> + dp_cfg = 1;
> + break;
> + case MEDIA_BUS_FMT_RGB888_1X24:
> + dp_cfg = 2;
> + break;
> + case MEDIA_BUS_FMT_RGB101010_1X30:
> + dp_cfg = 3;
> + break;
> + case MEDIA_BUS_FMT_UYVY8_1X16:
> + dp_cfg = 2 << 4;
> + is_yuv = true;
> + break;
> + case MEDIA_BUS_FMT_YUV8_1X24:
> + dp_cfg = 4 << 4;
> + is_yuv = true;
> + break;
> + case MEDIA_BUS_FMT_UYVY10_1X20:
> + dp_cfg = 8 << 4;
> + is_yuv = true;
> + break;
> + case MEDIA_BUS_FMT_YUV10_1X30:
> + dp_cfg = 10 << 4;
> + is_yuv = true;
> + break;
> + case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> + dp_cfg = 12 << 4;
> + is_yuv = true;
> + break;
> + case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> + dp_cfg = 13 << 4;
> + is_yuv = true;
> + break;
> + default:
> + dp_cfg = 2;
> + break;
> + }
> + if (is_yuv)
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, PANEL_RGB2YUV_EN, 0);
> + else
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, PANEL_RGB2YUV_EN);
> + dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | DP_SELECT);
> + }
> +
> + if (hw->out[id] == OUT_DPI)
> + dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT);
> +
> + switch (output_fmt) {
> + case MEDIA_BUS_FMT_RGB565_1X16:
> + dpi_cfg = 0;
> + break;
> + case MEDIA_BUS_FMT_RGB666_1X18:
> + dpi_cfg = 3;
> + break;
> + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> + dpi_cfg = 4;
> + break;
> + case MEDIA_BUS_FMT_RGB888_1X24:
> + dpi_cfg = 5;
> + break;
> + case MEDIA_BUS_FMT_RGB101010_1X30:
> + dpi_cfg = 6;
> + break;
> + default:
> + dpi_cfg = 5;
> + break;
> + }
> + dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
> +
> + if (id == 0)
> + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL0_EN | TWO_PANEL_EN);
> + else
> + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL1_EN | TWO_PANEL_EN);
> +
> + dc_write(hw, DC_DISPLAY_H + offset,
> + H_ACTIVE_LEN(mode->hdisplay) |
> + H_TOTAL_LEN(mode->htotal));
> +
> + dc_write(hw, DC_DISPLAY_H_SYNC + offset,
> + H_SYNC_START_LEN(mode->hsync_start) |
> + H_SYNC_END_LEN(mode->hsync_end) |
> + H_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PHSYNC ? 0 : 1) |
> + H_PLUS_LEN(1));
> +
> + dc_write(hw, DC_DISPLAY_V + offset,
> + V_ACTIVE_LEN(mode->vdisplay) |
> + V_TOTAL_LEN(mode->vtotal));
> +
> + dc_write(hw, DC_DISPLAY_V_SYNC + offset,
> + V_SYNC_START_LEN(mode->vsync_start) |
> + V_SYNC_END_LEN(mode->vsync_end) |
> + V_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PVSYNC ? 0 : 1) |
> + V_PLUS_LEN(1));
> +
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, PANEL_OUTPUT_EN, 0);
> + dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(id), SYNC_EN);
> +}
> +
> +void dc_hw_disable(struct dc_hw *hw, int id)
> +{
> + u32 offset = id << 2;
> +
> + if (hw->out[id] == OUT_DPI)
> + dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT);
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, PANEL_OUTPUT_EN);
> + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(id) | TWO_PANEL_EN);
> +}
> +
> +void dc_hw_enable_interrupt(struct dc_hw *hw)
> +{
> + hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
> +}
> +
> +void dc_hw_disable_interrupt(struct dc_hw *hw)
> +{
> + hi_write(hw, AQ_INTR_ENBL, 0);
> +}
> +
> +u32 dc_hw_get_interrupt(struct dc_hw *hw)
> +{
> + return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
> +}
> +
> +void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable)
> +{
> + u32 i, offset;
> + struct dc_hw *hw = &dc->hw;
> + u8 id, layer_num = hw->info->layer_num;
> + u8 panel_num = hw->info->panel_num;
> +
> + for (i = 0; i < layer_num; i++) {
> + id = dc->planes[i].id;
> + offset = dc->planes[i].offset;
> + if (enable) {
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> + PRIMARY_SHADOW_EN, 0);
> + else
> + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> + OVERLAY_SHADOW_EN, 0);
> + } else {
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> + 0, PRIMARY_SHADOW_EN);
> + else
> + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> + 0, OVERLAY_SHADOW_EN);
> + }
> + }
> +
> + for (i = 0; i < panel_num; i++) {
> + offset = i << 2;
> + if (enable)
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, PANEL_SHADOW_EN);
> + else
> + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, PANEL_SHADOW_EN, 0);
> + }
> +}
> +
> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
> +{
> + if (out <= OUT_DP)
This doesn't scale if you add another output type. Please either add
OUT_MAX or consider something which doesn't make OUT_DP special.
> + hw->out[id] = out;
> +}
> +
> +static inline u8 to_vs_yuv_color_space(u32 color_space)
> +{
> + u8 cs;
> +
> + switch (color_space) {
> + case DRM_COLOR_YCBCR_BT601:
> + cs = COLOR_SPACE_601;
> + break;
> + case DRM_COLOR_YCBCR_BT709:
> + cs = COLOR_SPACE_709;
> + break;
> + case DRM_COLOR_YCBCR_BT2020:
> + cs = COLOR_SPACE_2020;
> + break;
> + default:
> + cs = COLOR_SPACE_601;
> + break;
> + }
> +
> + return cs;
> +}
> +
> +static inline u8 update_uv_swizzle(u32 format)
> +{
> + u8 uv_swizzle = 0;
> +
> + switch (format) {
> + case DRM_FORMAT_YVYU:
> + case DRM_FORMAT_VYUY:
> + case DRM_FORMAT_NV21:
> + case DRM_FORMAT_NV61:
> + uv_swizzle = 1;
> + break;
> + default:
> + break;
> + }
> +
> + return uv_swizzle;
> +}
> +
> +static inline u8 update_swizzle(u32 format)
> +{
> + u8 swizzle = SWIZZLE_ARGB;
> +
> + switch (format) {
> + case DRM_FORMAT_RGBX4444:
> + case DRM_FORMAT_RGBA4444:
> + case DRM_FORMAT_RGBX5551:
> + case DRM_FORMAT_RGBA5551:
> + case DRM_FORMAT_RGBX8888:
> + case DRM_FORMAT_RGBA8888:
> + case DRM_FORMAT_RGBA1010102:
> + swizzle = SWIZZLE_RGBA;
> + break;
> + case DRM_FORMAT_XBGR4444:
> + case DRM_FORMAT_ABGR4444:
> + case DRM_FORMAT_XBGR1555:
> + case DRM_FORMAT_ABGR1555:
> + case DRM_FORMAT_BGR565:
> + case DRM_FORMAT_XBGR8888:
> + case DRM_FORMAT_ABGR8888:
> + case DRM_FORMAT_ABGR2101010:
> + swizzle = SWIZZLE_ABGR;
> + break;
> + case DRM_FORMAT_BGRX4444:
> + case DRM_FORMAT_BGRA4444:
> + case DRM_FORMAT_BGRX5551:
> + case DRM_FORMAT_BGRA5551:
> + case DRM_FORMAT_BGRX8888:
> + case DRM_FORMAT_BGRA8888:
> + case DRM_FORMAT_BGRA1010102:
> + swizzle = SWIZZLE_BGRA;
> + break;
> + default:
> + break;
> + }
> +
> + return swizzle;
> +}
> +
> +static inline u8 to_vs_rotation(unsigned int rotation)
> +{
> + u8 rot;
> +
> + switch (rotation & DRM_MODE_REFLECT_MASK) {
> + case DRM_MODE_REFLECT_X:
> + rot = FLIP_X;
> + return rot;
> + case DRM_MODE_REFLECT_Y:
> + rot = FLIP_Y;
> + return rot;
> + case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
> + rot = FLIP_XY;
> + return rot;
> + default:
> + break;
> + }
> +
> + switch (rotation & DRM_MODE_ROTATE_MASK) {
> + case DRM_MODE_ROTATE_0:
> + rot = ROT_0;
> + break;
> + case DRM_MODE_ROTATE_90:
> + rot = ROT_90;
> + break;
> + case DRM_MODE_ROTATE_180:
> + rot = ROT_180;
> + break;
> + case DRM_MODE_ROTATE_270:
> + rot = ROT_270;
> + break;
> + default:
> + rot = ROT_0;
> + break;
> + }
> +
> + return rot;
> +}
> +
> +void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format,
> + enum drm_color_encoding encoding, u8 id, bool is_yuv)
> +{
> + u32 offset = dc->planes[id].offset;
> + struct dc_hw *hw = &dc->hw;
> +
> + if (is_yuv) {
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> + PRIMARY_YUVCLAMP_EN, PRIMARY_RGB2RGB_EN);
> + else
> + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> + OVERLAY_CLAMP_EN, OVERLAY_RGB2RGB_EN);
> +
> + switch (to_vs_yuv_color_space(encoding)) {
> + case COLOR_SPACE_601:
> + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV601_2RGB);
> + break;
> + case COLOR_SPACE_709:
> + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV709_2RGB);
> + break;
> + case COLOR_SPACE_2020:
> + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV2020_2RGB);
> + break;
> + default:
> + break;
> + }
> + } else {
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> + PRIMARY_RGB2RGB_EN, PRIMARY_YUVCLAMP_EN);
> + else
> + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> + OVERLAY_RGB2RGB_EN, OVERLAY_CLAMP_EN);
> + }
> +}
> +
> +void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format, dma_addr_t *dma_addr,
> + struct drm_framebuffer *drm_fb, struct drm_rect *src)
> +{
> + u32 offset = dc->planes[id].offset;
> + struct dc_hw *hw = &dc->hw;
> +
> + dc_write(hw, hw->reg[id].y_address + offset, dma_addr[0]);
> + dc_write(hw, hw->reg[id].u_address + offset,
> + format == DRM_FORMAT_YVU420 ?
> + dma_addr[2] : dma_addr[1]);
> + dc_write(hw, hw->reg[id].v_address + offset,
> + format == DRM_FORMAT_YVU420 ?
> + dma_addr[1] : dma_addr[2]);
> + dc_write(hw, hw->reg[id].y_stride + offset, drm_fb->pitches[0]);
> + dc_write(hw, hw->reg[id].u_stride + offset,
> + format == DRM_FORMAT_YVU420 ?
> + drm_fb->pitches[2] : drm_fb->pitches[1]);
> + dc_write(hw, hw->reg[id].v_stride + offset,
> + format == DRM_FORMAT_YVU420 ?
> + drm_fb->pitches[1] : drm_fb->pitches[2]);
> + dc_write(hw, hw->reg[id].size + offset,
> + FB_SIZE(drm_rect_width(src) >> 16, drm_rect_height(src) >> 16));
> +}
> +
> +void plane_hw_update_format(struct vs_dc *dc, u32 format, enum drm_color_encoding encoding,
> + unsigned int rotation, bool visible, unsigned int zpos,
> + u8 id, u8 display_id)
> +{
> + u32 offset = dc->planes[id].offset;
> + struct dc_hw *hw = &dc->hw;
> +
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
> + PRIMARY_FORMAT(update_vs_format(format)) |
> + PRIMARY_UV_SWIZ(update_uv_swizzle(format)) |
> + PRIMARY_SWIZ(update_swizzle(format)) |
> + PRIMARY_TILE(DRM_FORMAT_MOD_LINEAR) |
> + PRIMARY_YUV_COLOR(to_vs_yuv_color_space(encoding)) |
> + PRIMARY_ROTATION(to_vs_rotation(rotation)),
> + PRIMARY_FORMAT_MASK |
> + PRIMARY_UV_SWIZ_MASK |
> + PRIMARY_SWIZ_MASK |
> + PRIMARY_TILE_MASK |
> + PRIMARY_YUV_COLOR_MASK |
> + PRIMARY_ROTATION_MASK |
> + PRIMARY_CLEAR_EN_MASK);
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> + PRIMARY_DECODER_EN(false) |
> + PRIMARY_EN(visible) |
> + PRIMARY_ZPOS(zpos) |
> + PRIMARY_CHANNEL(display_id),
> + PRIMARY_DECODER_EN_EN_MASK |
> + PRIMARY_EN_MASK |
> + PRIMARY_ZPOS_MASK |
> + PRIMARY_CHANNEL_MASK);
> + } else {
> + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> + OVERLAY_FB_EN(visible) |
> + OVERLAY_FORMAT(update_vs_format(format)) |
> + OVERLAY_UV_SWIZ(update_uv_swizzle(format)) |
> + OVERLAY_SWIZ(update_swizzle(format)) |
> + OVERLAY_TILE(DRM_FORMAT_MOD_LINEAR) |
> + OVERLAY_YUV_COLOR(to_vs_yuv_color_space(encoding)) |
> + OVERLAY_ROTATION(to_vs_rotation(rotation)),
> + OVERLAY_DEC_EN_MASK |
> + OVERLAY_CLEAR_EN_MASK |
> + OVERLAY_FB_EN_MASK |
> + OVERLAY_FORMAT_MASK |
> + OVERLAY_UV_SWIZ_MASK |
> + OVERLAY_SWIZ_MASK |
> + OVERLAY_TILE_MASK |
> + OVERLAY_YUV_COLOR_MASK |
> + OVERLAY_ROTATION_MASK);
> +
> + dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
> + OVERLAY_LAYER_SEL(zpos) |
> + OVERLAY_PANEL_SEL(display_id),
> + OVERLAY_LAYER_SEL_MASK |
> + OVERLAY_PANEL_SEL_MASK);
> + }
> +}
> +
> +static u32 calc_factor(u32 src, u32 dest)
A comment is appreciated.
> +{
> + u32 factor = 1 << 16;
> +
> + if (src > 1 && dest > 1)
> + factor = ((src - 1) << 16) / (dest - 1);
> +
> + return factor;
> +}
> +
> +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct drm_rect *dst,
> + u8 id, u8 display_id, unsigned int rotation)
> +{
> + u32 offset = dc->planes[id].offset;
> + struct dc_hw *hw = &dc->hw;
> +
> + int dst_w = drm_rect_width(dst);
> + int dst_h = drm_rect_height(dst);
> + int src_w, src_h, temp;
> + u32 scale_factor_x;
> + u32 scale_factor_y;
> + bool enable_scale = false;
> +
> + src_w = drm_rect_width(src) >> 16;
> + src_h = drm_rect_height(src) >> 16;
> +
> + if (drm_rotation_90_or_270(rotation)) {
> + temp = src_w;
> + src_w = src_h;
> + src_h = temp;
> + }
> +
> + if (src_w != dst_w) {
> + scale_factor_x = calc_factor(src_w, dst_w);
> + enable_scale = true;
> + } else {
> + scale_factor_x = 1 << 16;
> + }
> + if (src_h != dst_h) {
> + scale_factor_y = calc_factor(src_h, dst_h);
> + enable_scale = true;
> + } else {
> + scale_factor_y = 1 << 16;
> + }
> + if (enable_scale) {
> + dc_write(hw, hw->reg[id].scale_factor_x + offset, scale_factor_x);
> + dc_write(hw, hw->reg[id].scale_factor_y + offset, scale_factor_y);
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, PRIMARY_SCALE_EN, 0);
> + else
> + dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset, OVERLAY_SCALE_EN, 0);
> + } else {
> + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, 0, PRIMARY_SCALE_EN);
> + else
> + dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset, 0, OVERLAY_SCALE_EN);
> + }
> +
> + dc_write(hw, hw->reg[id].top_left + offset, X_POS(dst->x1) | Y_POS(dst->y1));
> + dc_write(hw, hw->reg[id].bottom_right + offset, X_POS(dst->x2) | Y_POS(dst->y2));
> +}
> +
> +void plane_hw_update_blend(struct vs_dc *dc, u16 alpha,
> + u16 pixel_blend_mode, u8 id, u8 display_id)
> +{
> + u32 offset = dc->planes[id].offset;
> + struct dc_hw *hw = &dc->hw;
> +
> + dc_write(hw, hw->reg[id].src_global_color + offset, PRIMARY_ALPHA_LEN(alpha >> 8));
> + dc_write(hw, hw->reg[id].dst_global_color + offset, PRIMARY_ALPHA_LEN(alpha >> 8));
> + switch (pixel_blend_mode) {
> + case DRM_MODE_BLEND_PREMULTI:
> + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_PREMULTI);
> + break;
> + case DRM_MODE_BLEND_COVERAGE:
> + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_COVERAGE);
> + break;
> + case DRM_MODE_BLEND_PIXEL_NONE:
> + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_PIXEL_NONE);
> + break;
> + default:
> + break;
> + }
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> new file mode 100644
> index 000000000000..63d8d153f57f
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> @@ -0,0 +1,493 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_DC_HW_H__
> +#define __VS_DC_HW_H__
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <drm/drm_atomic.h>
> +
> +#include "vs_type.h"
> +
> +#define UPDATE(x, h, l) FIELD_PREP(GENMASK(h, l), x)
> +
> +#define AQ_INTR_ACKNOWLEDGE 0x0010
> +#define AQ_INTR_ENBL 0x0014
> +#define DC_HW_REVISION 0x0024
> +#define DC_HW_CHIP_CID 0x0030
> +
> +#define DC_REG_BASE 0x0800
> +#define DC_REG_RANGE 0x2000
> +#define DC_SEC_REG_OFFSET 0x100000
> +
> +#define DC_FRAMEBUFFER_CONFIG 0x1518
> +# define PRIMARY_FORMAT(x) ((x) << 26)
> +# define PRIMARY_FORMAT_MASK GENMASK(31, 26)
> +# define PRIMARY_UV_SWIZ(x) ((x) << 25)
> +# define PRIMARY_UV_SWIZ_MASK GENMASK(25, 25)
> +# define PRIMARY_SWIZ(x) ((x) << 23)
> +# define PRIMARY_SWIZ_MASK GENMASK(24, 23)
> +# define PRIMARY_SCALE_EN BIT(12)
> +# define PRIMARY_TILE(x) ((x) << 17)
> +# define PRIMARY_TILE_MASK GENMASK(21, 17)
> +# define PRIMARY_YUV_COLOR(x) ((x) << 14)
> +# define PRIMARY_YUV_COLOR_MASK GENMASK(16, 14)
> +# define PRIMARY_ROTATION(x) ((x) << 11)
> +# define PRIMARY_ROTATION_MASK GENMASK(13, 11)
> +# define PRIMARY_CLEAR_EN(x) ((x) << 8)
> +# define PRIMARY_CLEAR_EN_MASK GENMASK(8, 8)
> +
> +#define DC_FRAMEBUFFER_CONFIG_EX 0x1CC0
> +# define PRIMARY_CHANNEL(x) ((x) << 19)
> +# define PRIMARY_CHANNEL_MASK GENMASK(19, 19)
> +# define PRIMARY_ZPOS(x) ((x) << 16)
> +# define PRIMARY_ZPOS_MASK GENMASK(18, 16)
> +# define PRIMARY_EN(x) ((x) << 13)
> +# define PRIMARY_EN_MASK GENMASK(13, 13)
> +# define PRIMARY_SHADOW_EN BIT(12)
> +# define PRIMARY_YUVCLAMP_EN BIT(8)
> +# define PRIMARY_RGB2RGB_EN BIT(6)
> +# define PRIMARY_SYNC1_EN BIT(4)
> +# define PRIMARY_SYNC0_EN BIT(3)
> +# define PRIMARY_DECODER_EN(x) ((x) << 1)
> +# define PRIMARY_DECODER_EN_EN_MASK GENMASK(1, 1)
> +
> +#define DC_FRAMEBUFFER_SCALE_CONFIG 0x1520
> +#define DC_FRAMEBUFFER_TOP_LEFT 0x24D8
> +#define X_POS(x) (x)
> +#define Y_POS(x) ((x) << 15)
> +
> +#define DC_FRAMEBUFFER_BOTTOM_RIGHT 0x24E0
> +#define DC_FRAMEBUFFER_ADDRESS 0x1400
> +#define DC_FRAMEBUFFER_U_ADDRESS 0x1530
> +#define DC_FRAMEBUFFER_V_ADDRESS 0x1538
> +#define DC_FRAMEBUFFER_STRIDE 0x1408
> +#define DC_FRAMEBUFFER_U_STRIDE 0x1800
> +#define DC_FRAMEBUFFER_V_STRIDE 0x1808
> +#define DC_FRAMEBUFFER_SIZE 0x1810
> +#define FB_SIZE(w, h) ((w) | ((h) << 15))
> +
> +#define DC_FRAMEBUFFER_SCALE_FACTOR_X 0x1828
> +#define DC_FRAMEBUFFER_SCALE_FACTOR_Y 0x1830
> +#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX 0x1838
> +#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA 0x1A00
> +#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX 0x1A08
> +#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA 0x1A10
> +#define DC_FRAMEBUFFER_INIT_OFFSET 0x1A20
> +#define DC_FRAMEBUFFER_COLOR_KEY 0x1508
> +#define DC_FRAMEBUFFER_COLOR_KEY_HIGH 0x1510
> +#define DC_FRAMEBUFFER_CLEAR_VALUE 0x1A18
> +#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX 0x1818
> +#define DC_FRAMEBUFFER_COLOR_TABLE_DATA 0x1820
> +#define DC_FRAMEBUFFER_BG_COLOR 0x1528
> +#define DC_FRAMEBUFFER_ROI_ORIGIN 0x1CB0
> +#define DC_FRAMEBUFFER_ROI_SIZE 0x1CB8
> +#define DC_FRAMEBUFFER_WATER_MARK 0x1CE8
> +#define DC_FRAMEBUFFER_DEGAMMA_INDEX 0x1D88
> +#define DC_FRAMEBUFFER_DEGAMMA_DATA 0x1D90
> +#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA 0x1D98
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF0 0x1DA0
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF1 0x1DA8
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF2 0x1DB0
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF3 0x1DB8
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF4 0x1E00
> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD0 0x1E08
> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD1 0x1E10
> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD2 0x1E18
> +#define DC_FRAMEBUFFER_Y_CLAMP_BOUND 0x1E88
> +#define DC_FRAMEBUFFER_UV_CLAMP_BOUND 0x1E90
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF0 0x1E20
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF1 0x1E28
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF2 0x1E30
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF3 0x1E38
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF4 0x1E40
> +#define DC_FRAMEBUFFER_BLEND_CONFIG 0x2510
> +# define BLEND_PREMULTI 0x3450
> +# define BLEND_COVERAGE 0x3950
> +# define BLEND_PIXEL_NONE 0x3548
> +
> +#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR 0x2500
> +# define PRIMARY_ALPHA_LEN(x) ((x) << 24)
> +
> +#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR 0x2508
> +
> +#define DC_OVERLAY_CONFIG 0x1540
> +# define OVERLAY_SHADOW_EN BIT(31)
> +# define OVERLAY_CLAMP_EN BIT(30)
> +# define OVERLAY_RGB2RGB_EN BIT(29)
> +# define OVERLAY_DEC_EN(x) ((x) << 27)
> +# define OVERLAY_DEC_EN_MASK GENMASK(27, 27)
> +# define OVERLAY_CLEAR_EN(x) ((x) << 25)
> +# define OVERLAY_CLEAR_EN_MASK GENMASK(25, 25)
> +# define OVERLAY_FB_EN(x) ((x) << 24)
> +# define OVERLAY_FB_EN_MASK GENMASK(24, 24)
> +# define OVERLAY_FORMAT(x) ((x) << 16)
> +# define OVERLAY_FORMAT_MASK GENMASK(21, 16)
> +# define OVERLAY_UV_SWIZ(x) ((x) << 15)
> +# define OVERLAY_UV_SWIZ_MASK GENMASK(15, 15)
> +# define OVERLAY_SWIZ(x) ((x) << 13)
> +# define OVERLAY_SWIZ_MASK GENMASK(14, 13)
> +# define OVERLAY_TILE(x) ((x) << 8)
> +# define OVERLAY_TILE_MASK GENMASK(12, 8)
> +# define OVERLAY_YUV_COLOR(x) ((x) << 5)
> +# define OVERLAY_YUV_COLOR_MASK GENMASK(7, 5)
> +# define OVERLAY_ROTATION(x) ((x) << 2)
> +# define OVERLAY_ROTATION_MASK GENMASK(4, 2)
> +
> +#define DC_OVERLAY_CONFIG_EX 0x2540
> +# define OVERLAY_LAYER_SEL(x) ((x) << 0)
> +# define OVERLAY_LAYER_SEL_MASK GENMASK(2, 0)
> +# define OVERLAY_PANEL_SEL(x) ((x) << 3)
> +# define OVERLAY_PANEL_SEL_MASK GENMASK(3, 3)
> +
> +#define DC_OVERLAY_SCALE_CONFIG 0x1C00
> +# define OVERLAY_SCALE_EN BIT(8)
> +
> +#define DC_OVERLAY_BLEND_CONFIG 0x1580
> +#define DC_OVERLAY_TOP_LEFT 0x1640
> +#define DC_OVERLAY_BOTTOM_RIGHT 0x1680
> +#define DC_OVERLAY_ADDRESS 0x15C0
> +#define DC_OVERLAY_U_ADDRESS 0x1840
> +#define DC_OVERLAY_V_ADDRESS 0x1880
> +#define DC_OVERLAY_STRIDE 0x1600
> +#define DC_OVERLAY_U_STRIDE 0x18C0
> +#define DC_OVERLAY_V_STRIDE 0x1900
> +#define DC_OVERLAY_SIZE 0x17C0
> +#define DC_OVERLAY_SCALE_FACTOR_X 0x1A40
> +#define DC_OVERLAY_SCALE_FACTOR_Y 0x1A80
> +#define DC_OVERLAY_H_FILTER_COEF_INDEX 0x1AC0
> +#define DC_OVERLAY_H_FILTER_COEF_DATA 0x1B00
> +#define DC_OVERLAY_V_FILTER_COEF_INDEX 0x1B40
> +#define DC_OVERLAY_V_FILTER_COEF_DATA 0x1B80
> +#define DC_OVERLAY_INIT_OFFSET 0x1BC0
> +#define DC_OVERLAY_COLOR_KEY 0x1740
> +#define DC_OVERLAY_COLOR_KEY_HIGH 0x1780
> +#define DC_OVERLAY_CLEAR_VALUE 0x1940
> +#define DC_OVERLAY_COLOR_TABLE_INDEX 0x1980
> +#define DC_OVERLAY_COLOR_TABLE_DATA 0x19C0
> +#define DC_OVERLAY_SRC_GLOBAL_COLOR 0x16C0
> +# define OVERLAY_ALPHA_LEN(x) ((x) << 24)
> +
> +#define DC_OVERLAY_DST_GLOBAL_COLOR 0x1700
> +#define DC_OVERLAY_ROI_ORIGIN 0x1D00
> +#define DC_OVERLAY_ROI_SIZE 0x1D40
> +#define DC_OVERLAY_WATER_MARK 0x1DC0
> +#define DC_OVERLAY_DEGAMMA_INDEX 0x2200
> +#define DC_OVERLAY_DEGAMMA_DATA 0x2240
> +#define DC_OVERLAY_DEGAMMA_EX_DATA 0x2280
> +#define DC_OVERLAY_YUVTORGB_COEF0 0x1EC0
> +#define DC_OVERLAY_YUVTORGB_COEF1 0x1F00
> +#define DC_OVERLAY_YUVTORGB_COEF2 0x1F40
> +#define DC_OVERLAY_YUVTORGB_COEF3 0x1F80
> +#define DC_OVERLAY_YUVTORGB_COEF4 0x1FC0
> +#define DC_OVERLAY_YUVTORGB_COEFD0 0x2000
> +#define DC_OVERLAY_YUVTORGB_COEFD1 0x2040
> +#define DC_OVERLAY_YUVTORGB_COEFD2 0x2080
> +#define DC_OVERLAY_Y_CLAMP_BOUND 0x22C0
> +#define DC_OVERLAY_UV_CLAMP_BOUND 0x2300
> +#define DC_OVERLAY_RGBTORGB_COEF0 0x20C0
> +#define DC_OVERLAY_RGBTORGB_COEF1 0x2100
> +#define DC_OVERLAY_RGBTORGB_COEF2 0x2140
> +#define DC_OVERLAY_RGBTORGB_COEF3 0x2180
> +#define DC_OVERLAY_RGBTORGB_COEF4 0x21C0
> +
> +#define DC_CURSOR_CONFIG 0x1468
> +# define CURSOR_HOT_X(x) ((x) << 16)
> +# define CURSOR_HOT_X_MASK GENMASK(23, 16)
> +# define CURSOR_HOT_y(x) ((x) << 8)
> +# define CURSOR_HOT_y_MASK GENMASK(15, 8)
> +# define CURSOR_SIZE(x) ((x) << 5)
> +# define CURSOR_SIZE_MASK GENMASK(7, 5)
> +# define CURSOR_VALID(x) ((x) << 3)
> +# define CURSOR_VALID_MASK GENMASK(3, 3)
> +# define CURSOR_TRIG_FETCH(x) ((x) << 2)
> +# define CURSOR_TRIG_FETCH_MASK GENMASK(2, 2)
> +# define CURSOR_FORMAT(x) ((x) << 0)
> +# define CURSOR_FORMAT_MASK GENMASK(1, 0)
> +# define CURSOR_FORMAT_DISABLE 0
> +# define CURSOR_FORMAT_MARK 1
> +# define CURSOR_FORMAT_A8R8G8B8 2
> +
> +#define DC_CURSOR_ADDRESS 0x146C
> +#define DC_CURSOR_LOCATION 0x1470
> +# define X_LCOTION(x) (x)
> +# define Y_LCOTION(x) ((x) << 16)
> +
> +#define DC_CURSOR_BACKGROUND 0x1474
> +#define DC_CURSOR_FOREGROUND 0x1478
> +#define DC_CURSOR_CLK_GATING 0x1484
> +#define DC_CURSOR_CONFIG_EX 0x24E8
> +#define DC_CURSOR_OFFSET 0x1080
> +
> +#define DC_DISPLAY_DITHER_CONFIG 0x1410
> +#define DC_DISPLAY_PANEL_CONFIG 0x1418
> +# define PANEL_RGB2YUV_EN BIT(16)
> +# define PANEL_GAMMA_EN BIT(13)
> +# define PANEL_OUTPUT_EN BIT(12)
> +
> +#define DC_DISPLAY_PANEL_CONFIG_EX 0x2518
> +# define PANEL_SHADOW_EN BIT(0)
> +
> +#define DC_DISPLAY_DITHER_TABLE_LOW 0x1420
> +#define DC_DISPLAY_DITHER_TABLE_HIGH 0x1428
> +#define DC_DISPLAY_H 0x1430
> +# define H_ACTIVE_LEN(x) (x)
> +# define H_TOTAL_LEN(x) ((x) << 16)
> +
> +#define DC_DISPLAY_H_SYNC 0x1438
> +# define H_SYNC_START_LEN(x) (x)
> +# define H_SYNC_END_LEN(x) ((x) << 15)
> +# define H_PLUS_LEN(x) ((x) << 30)
> +# define H_POLARITY_LEN(x) ((x) << 31)
> +
> +#define DC_DISPLAY_V 0x1440
> +# define V_ACTIVE_LEN(x) (x)
> +# define V_TOTAL_LEN(x) ((x) << 16)
> +
> +#define DC_DISPLAY_V_SYNC 0x1448
> +# define V_SYNC_START_LEN(x) (x)
> +# define V_SYNC_END_LEN(x) ((x) << 15)
> +# define V_PLUS_LEN(x) ((x) << 30)
> +# define V_POLARITY_LEN(x) ((x) << 31)
> +
> +#define DC_DISPLAY_CURRENT_LOCATION 0x1450
> +#define DC_DISPLAY_GAMMA_INDEX 0x1458
> +#define DC_DISPLAY_GAMMA_DATA 0x1460
> +#define DC_DISPLAY_INT 0x147C
> +#define DC_DISPLAY_INT_ENABLE 0x1480
> +#define DC_DISPLAY_DBI_CONFIG 0x1488
> +#define DC_DISPLAY_GENERAL_CONFIG 0x14B0
> +#define DC_DISPLAY_DPI_CONFIG 0x14B8
> +#define DC_DISPLAY_PANEL_START 0x1CCC
> +# define PANEL0_EN BIT(0)
> +# define PANEL1_EN BIT(1)
> +# define TWO_PANEL_EN BIT(2)
> +# define SYNC_EN BIT(3)
> +
> +#define DC_DISPLAY_DEBUG_COUNTER_SELECT 0x14D0
> +#define DC_DISPLAY_DEBUG_COUNTER_VALUE 0x14D8
> +#define DC_DISPLAY_DP_CONFIG 0x1CD0
> +# define DP_SELECT BIT(3)
> +
> +#define DC_DISPLAY_GAMMA_EX_INDEX 0x1CF0
> +#define DC_DISPLAY_GAMMA_EX_DATA 0x1CF8
> +#define DC_DISPLAY_GAMMA_EX_ONE_DATA 0x1D80
> +#define DC_DISPLAY_RGBTOYUV_COEF0 0x1E48
> +#define DC_DISPLAY_RGBTOYUV_COEF1 0x1E50
> +#define DC_DISPLAY_RGBTOYUV_COEF2 0x1E58
> +#define DC_DISPLAY_RGBTOYUV_COEF3 0x1E60
> +#define DC_DISPLAY_RGBTOYUV_COEF4 0x1E68
> +#define DC_DISPLAY_RGBTOYUV_COEFD0 0x1E70
> +#define DC_DISPLAY_RGBTOYUV_COEFD1 0x1E78
> +#define DC_DISPLAY_RGBTOYUV_COEFD2 0x1E80
> +
> +#define DC_CLK_GATTING 0x1A28
> +#define DC_QOS_CONFIG 0x1A38
> +
> +#define DC_TRANSPARENCY_OPAQUE 0x00
> +#define DC_TRANSPARENCY_KEY 0x02
> +#define DC_DISPLAY_DITHERTABLE_LOW 0x7B48F3C0
> +#define DC_DISPLAY_DITHERTABLE_HIGH 0x596AD1E2
> +
> +#define DC_TILE_MODE4X4 0x15
> +
> +#define GAMMA_SIZE 256
> +#define GAMMA_EX_SIZE 300
> +#define DEGAMMA_SIZE 260
> +
> +#define RGB_TO_RGB_TABLE_SIZE 9
> +#define YUV_TO_RGB_TABLE_SIZE 16
> +#define RGB_TO_YUV_TABLE_SIZE 12
> +
> +#define DC_LAYER_NUM 6
> +#define DC_DISPLAY_NUM 2
> +#define DC_CURSOR_NUM 2
> +
> +enum dc_hw_plane_id {
> + PRIMARY_PLANE_0,
> + OVERLAY_PLANE_0,
> + OVERLAY_PLANE_1,
> + PRIMARY_PLANE_1,
> + OVERLAY_PLANE_2,
> + OVERLAY_PLANE_3,
> + CURSOR_PLANE_0,
> + CURSOR_PLANE_1,
> + PLANE_NUM
> +};
> +
> +enum dc_hw_color_format {
> + FORMAT_X4R4G4B4,
> + FORMAT_A4R4G4B4,
> + FORMAT_X1R5G5B5,
> + FORMAT_A1R5G5B5,
> + FORMAT_R5G6B5,
> + FORMAT_X8R8G8B8,
> + FORMAT_A8R8G8B8,
> + FORMAT_YUY2,
> + FORMAT_UYVY,
> + FORMAT_INDEX8,
> + FORMAT_MONOCHROME,
> + FORMAT_YV12 = 0xf,
> + FORMAT_A8,
> + FORMAT_NV12,
> + FORMAT_NV16,
> + FORMAT_RG16,
> + FORMAT_R8,
> + FORMAT_NV12_10BIT,
> + FORMAT_A2R10G10B10,
> + FORMAT_NV16_10BIT,
> + FORMAT_INDEX1,
> + FORMAT_INDEX2,
> + FORMAT_INDEX4,
> + FORMAT_P010,
> + FORMAT_YUV444,
> + FORMAT_YUV444_10BIT,
> +};
> +
> +enum dc_hw_yuv_color_space {
> + COLOR_SPACE_601 = 0,
> + COLOR_SPACE_709 = 1,
> + COLOR_SPACE_2020 = 3,
> +};
> +
> +enum dc_hw_rotation {
> + ROT_0 = 0,
> + ROT_90 = 4,
> + ROT_180 = 5,
> + ROT_270 = 6,
> + FLIP_X = 1,
> + FLIP_Y = 2,
> + FLIP_XY = 3,
> +};
> +
> +enum dc_hw_swizzle {
> + SWIZZLE_ARGB = 0,
> + SWIZZLE_RGBA,
> + SWIZZLE_ABGR,
> + SWIZZLE_BGRA,
> +};
> +
> +enum dc_hw_out {
> + OUT_DPI,
> + OUT_DP,
> +};
> +
> +enum dc_hw_cursor_size {
> + CURSOR_SIZE_32X32 = 0,
> + CURSOR_SIZE_64X64,
> +};
> +
> +struct dc_hw_plane_reg {
> + u32 y_address;
> + u32 u_address;
> + u32 v_address;
> + u32 y_stride;
> + u32 u_stride;
> + u32 v_stride;
> + u32 size;
> + u32 top_left;
> + u32 bottom_right;
> + u32 scale_factor_x;
> + u32 scale_factor_y;
> + u32 h_filter_coef_index;
> + u32 h_filter_coef_data;
> + u32 v_filter_coef_index;
> + u32 v_filter_coef_data;
> + u32 init_offset;
> + u32 color_key;
> + u32 color_key_high;
> + u32 clear_value;
> + u32 color_table_index;
> + u32 color_table_data;
> + u32 scale_config;
> + u32 water_mark;
> + u32 degamma_index;
> + u32 degamma_data;
> + u32 degamma_ex_data;
> + u32 src_global_color;
> + u32 dst_global_color;
> + u32 blend_config;
> + u32 roi_origin;
> + u32 roi_size;
> + u32 yuv_to_rgb_coef0;
> + u32 yuv_to_rgb_coef1;
> + u32 yuv_to_rgb_coef2;
> + u32 yuv_to_rgb_coef3;
> + u32 yuv_to_rgb_coef4;
> + u32 yuv_to_rgb_coefd0;
> + u32 yuv_to_rgb_coefd1;
> + u32 yuv_to_rgb_coefd2;
> + u32 y_clamp_bound;
> + u32 uv_clamp_bound;
> + u32 rgb_to_rgb_coef0;
> + u32 rgb_to_rgb_coef1;
> + u32 rgb_to_rgb_coef2;
> + u32 rgb_to_rgb_coef3;
> + u32 rgb_to_rgb_coef4;
> +};
> +
> +struct dc_hw_gamma {
> + u16 gamma[GAMMA_EX_SIZE][3];
> +};
> +
> +struct dc_hw_read {
Not used, please drop.
> + u32 reg;
> + u32 value;
> +};
> +
> +struct dc_hw {
> + enum dc_hw_out out[DC_DISPLAY_NUM];
> + void *hi_base;
> + void *reg_base;
> + struct dc_hw_plane_reg reg[DC_LAYER_NUM];
> +
> + struct dc_hw_gamma gamma[DC_DISPLAY_NUM];
> + struct vs_dc_info *info;
> +};
> +
> +struct vs_dc_plane {
> + enum dc_hw_plane_id id;
> + u32 offset;
> +};
> +
> +struct vs_dc {
> + struct vs_crtc *crtc[DC_DISPLAY_NUM];
Not defined here. Please drop and add when it is actually defined.
> + struct dc_hw hw;
> +
> + struct vs_dc_plane planes[PLANE_NUM];
> +};
> +
> +int dc_hw_init(struct vs_dc *dc);
> +void dc_hw_disable_plane(struct vs_dc *dc, u8 id);
> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr,
> + u32 crtc_w, u32 crtc_x, u32 crtc_y,
> + s32 hotspot_x, int32_t hotspot_y);
> +void dc_hw_disable_cursor(struct dc_hw *hw, u8 id);
> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> + u16 r, u16 g, u16 b);
> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
> +void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode *mode,
> + u8 encoder_type, u32 output_fmt);
> +void dc_hw_disable(struct dc_hw *hw, int id);
> +void dc_hw_enable_interrupt(struct dc_hw *hw);
> +void dc_hw_disable_interrupt(struct dc_hw *hw);
> +u32 dc_hw_get_interrupt(struct dc_hw *hw);
> +void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable);
> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
> +void dc_hw_commit(struct dc_hw *hw);
> +void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format,
> + enum drm_color_encoding encoding, u8 id, bool is_yuv);
> +void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format, dma_addr_t *dma_addr,
> + struct drm_framebuffer *drm_fb, struct drm_rect *src);
> +void plane_hw_update_format(struct vs_dc *dc, u32 format, enum drm_color_encoding encoding,
> + unsigned int rotation, bool visible, unsigned int zpos,
> + u8 id, u8 display_id);
> +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct drm_rect *dst,
> + u8 id, u8 display_id, unsigned int rotation);
> +void plane_hw_update_blend(struct vs_dc *dc, u16 alpha, u16 pixel_blend_mode,
> + u8 id, u8 display_id);
Could you please settle on a single prefix for all your function names?
Ideally it should be close to the driver name. It's hard to understand
that the function comes from the verisilicon driver if its name starts
from dc_ or especially with plane_.
I'd strongly suggest to stop defining anything outside of the selected
vs_ namespace.
> +
> +#endif /* __VS_DC_HW_H__ */
> diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
> new file mode 100644
> index 000000000000..30ccc2eda48b
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_type.h
> @@ -0,0 +1,84 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_TYPE_H__
> +#define __VS_TYPE_H__
> +
> +#include <drm/drm_plane.h>
These types are largely unused within this patch. Please drop all the
unused parts and add them later, when required.
> +
> +struct vs_plane_primary_info {
> + u8 id;
> + unsigned int num_formats;
> + const u32 *formats;
> + u8 num_modifiers;
> + const u64 *modifiers;
> + unsigned int min_width;
> + unsigned int min_height;
> + unsigned int max_width;
> + unsigned int max_height;
> + unsigned int rotation;
> + unsigned int color_encoding;
> +
> + int min_scale; /* 16.16 fixed point */
> + int max_scale; /* 16.16 fixed point */
> +
> + u8 zpos;
> +
> +};
> +
> +struct vs_plane_overlay_info {
> + u8 id;
> + unsigned int num_formats;
> + const u32 *formats;
> + u8 num_modifiers;
> + const u64 *modifiers;
> + unsigned int min_width;
> + unsigned int min_height;
> + unsigned int max_width;
> + unsigned int max_height;
> + unsigned int rotation;
> + unsigned int color_encoding;
> +
> + int min_scale; /* 16.16 fixed point */
> + int max_scale; /* 16.16 fixed point */
> +
> + u8 zpos;
> +
> +};
> +
> +struct vs_plane_cursor_info {
> + u8 id;
> + unsigned int num_formats;
> + const u32 *formats;
> + unsigned int min_width;
> + unsigned int min_height;
> + unsigned int max_width;
> + unsigned int max_height;
> + u8 zpos;
> +
> +};
> +
> +struct vs_dc_info {
> + const char *name;
> +
> + u8 panel_num;
> +
> + /* planes */
> + u8 layer_num;
> + u8 primary_num;
> + u8 overlay_num;
> + u8 cursor_num;
> + const struct vs_plane_primary_info *primary;
> + const struct vs_plane_overlay_info *overlay;
> + const struct vs_plane_cursor_info *cursor;
> +
> + /* 0 means no gamma LUT */
> + u16 gamma_size;
> + u8 gamma_bits;
> +
> + u16 pitch_alignment;
> +};
> +
> +#endif /* __VS_TYPE_H__ */
> --
> 2.27.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 05/10] drm/vs: add vs mode config init
2024-05-21 10:58 ` [PATCH v4 05/10] drm/vs: add vs mode config init keith
@ 2024-05-21 20:52 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-05-21 20:52 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
On Tue, May 21, 2024 at 06:58:12PM +0800, keith wrote:
> add vs mode config base api
Commit message? Please describe e.g. why are you using
drm_atomic_helper_commit_tail_rpm() instead of
drm_atomic_helper_commit_tail().
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
Name
> ---
> drivers/gpu/drm/verisilicon/Makefile | 3 +-
> drivers/gpu/drm/verisilicon/vs_modeset.c | 36 ++++++++++++++++++++++++
> drivers/gpu/drm/verisilicon/vs_modeset.h | 10 +++++++
> 3 files changed, 48 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.h
>
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 7da54b259940..536091f37378 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -1,5 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0
>
> -vs_drm-objs := vs_dc_hw.o
> +vs_drm-objs := vs_dc_hw.o \
> + vs_modeset.o
>
> obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_modeset.c b/drivers/gpu/drm/verisilicon/vs_modeset.c
> new file mode 100644
> index 000000000000..c71fe0d32504
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_modeset.c
> @@ -0,0 +1,36 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +#include <drm/drm_damage_helper.h>
I don't see anything concerning damage helpers being used here.
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +
> +#include "vs_modeset.h"
> +
> +static const struct drm_mode_config_funcs vs_mode_config_funcs = {
> + .fb_create = drm_gem_fb_create,
> + .atomic_check = drm_atomic_helper_check,
> + .atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static struct drm_mode_config_helper_funcs vs_mode_config_helpers = {
> + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
> +};
> +
> +void vs_mode_config_init(struct drm_device *dev)
> +{
> + int ret;
> +
> + ret = drmm_mode_config_init(dev);
> + if (ret)
> + return;
> +
> + dev->mode_config.min_width = 0;
> + dev->mode_config.min_height = 0;
> + dev->mode_config.max_width = 4096;
> + dev->mode_config.max_height = 4096;
> +
> + dev->mode_config.funcs = &vs_mode_config_funcs;
> + dev->mode_config.helper_private = &vs_mode_config_helpers;
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_modeset.h b/drivers/gpu/drm/verisilicon/vs_modeset.h
> new file mode 100644
> index 000000000000..bd04f81d2ad2
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_modeset.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_MODESET_H__
> +#define __VS_MODESET_H__
> +
> +void vs_mode_config_init(struct drm_device *dev);
> +#endif /* __VS_FB_H__ */
> --
> 2.27.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-05-21 10:58 ` [PATCH v4 04/10] drm/vs: Add hardware funcs for vs keith
2024-05-21 20:50 ` kernel test robot
2024-05-21 20:50 ` Dmitry Baryshkov
@ 2024-05-21 21:01 ` kernel test robot
2024-05-22 1:34 ` kernel test robot
3 siblings, 0 replies; 53+ messages in thread
From: kernel test robot @ 2024-05-21 21:01 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: oe-kbuild-all, dri-devel, devicetree, linux-kernel,
linux-arm-kernel, keith.zhao
Hi keith,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master next-20240521]
[cannot apply to robh/for-next rockchip/for-next v6.9]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/keith/dt-bindings-display-Add-YAML-schema-for-JH7110-display-pipeline/20240521-110316
base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link: https://lore.kernel.org/r/20240521105817.3301-5-keith.zhao%40starfivetech.com
patch subject: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
config: arc-randconfig-r123-20240522 (https://download.01.org/0day-ci/archive/20240522/202405220449.sjkbwf6F-lkp@intel.com/config)
compiler: arc-elf-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20240522/202405220449.sjkbwf6F-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405220449.sjkbwf6F-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
drivers/gpu/drm/verisilicon/vs_dc_hw.c: note: in included file (through include/linux/mmzone.h, include/linux/gfp.h, include/linux/stackdepot.h, ...):
include/linux/page-flags.h:241:46: sparse: sparse: self-comparison always evaluates to false
include/linux/page-flags.h:241:46: sparse: sparse: self-comparison always evaluates to false
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
drivers/gpu/drm/verisilicon/vs_dc_hw.c:261:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:261:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:261:9: sparse: got void *
drivers/gpu/drm/verisilicon/vs_dc_hw.c:261:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:261:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:261:9: sparse: got void *
drivers/gpu/drm/verisilicon/vs_dc_hw.c:256:16: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:256:16: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:256:16: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: expected void const volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:271:21: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
>> drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void * @@
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/gpu/drm/verisilicon/vs_dc_hw.c:266:9: sparse: got void *
vim +266 drivers/gpu/drm/verisilicon/vs_dc_hw.c
263
264 static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
265 {
> 266 writel(value, hw->reg_base + reg - DC_REG_BASE);
267 }
268
269 static inline u32 dc_read(struct dc_hw *hw, u32 reg)
270 {
> 271 u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
272
273 return value;
274 }
275
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 06/10] drm/vs: add vs plane api
2024-05-21 10:58 ` [PATCH v4 06/10] drm/vs: add vs plane api keith
2024-05-21 20:39 ` kernel test robot
@ 2024-05-21 21:06 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
1 sibling, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-05-21 21:06 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
On Tue, May 21, 2024 at 06:58:13PM +0800, keith wrote:
> add plane funs and helper funs
> add vs drm common struct and funs
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> drivers/gpu/drm/verisilicon/Makefile | 3 +-
> drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++
> drivers/gpu/drm/verisilicon/vs_plane.c | 487 +++++++++++++++++++++++++
> drivers/gpu/drm/verisilicon/vs_plane.h | 26 ++
> 4 files changed, 608 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
>
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 536091f37378..1c593b943261 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -1,6 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0
>
> vs_drm-objs := vs_dc_hw.o \
> - vs_modeset.o
> + vs_modeset.o \
> + vs_plane.o
>
> obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
> new file mode 100644
> index 000000000000..d9f6efa7c8f9
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> @@ -0,0 +1,93 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_DRV_H__
> +#define __VS_DRV_H__
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_managed.h>
> +
> +#include "vs_dc_hw.h"
> +
> +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
Is that all the docs you want to add?
> +struct vs_drm_device {
> + struct drm_device base;
> + unsigned int pitch_alignment;
> + /* clocks */
> + unsigned int clk_count;
> + struct clk_bulk_data *clks;
> + struct reset_control *rsts;
> + struct vs_dc dc;
> + int irq;
As usual, please drop unused fields and add them when required.
> +};
> +
> +static inline struct vs_drm_device *
> +to_vs_drm_private(const struct drm_device *dev)
> +{
> + return container_of(dev, struct vs_drm_device, base);
> +}
> +
> +struct vs_crtc_state {
> + struct drm_crtc_state base;
> +
> + u32 output_fmt;
> + u8 encoder_type;
> + u8 bpp;
> +};
Not used here, drop.
> +
> +struct vs_crtc {
> + struct drm_crtc base;
> + struct device *dev;
> +};
> +
> +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
> +{
> + u8 panel_num = dc->hw.info->panel_num;
> + u32 index = drm_crtc_index(crtc);
> + int i;
> +
> + for (i = 0; i < panel_num; i++) {
> + if (index == dc->crtc[i]->base.index)
> + return i;
> + }
> +
> + return 0;
> +}
> +
> +static inline struct vs_crtc_state *
> +to_vs_crtc_state(struct drm_crtc_state *state)
> +{
> + return container_of(state, struct vs_crtc_state, base);
> +}
> +
> +struct vs_plane_state {
> + struct drm_plane_state base;
> + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES];
> +};
> +
> +struct vs_plane {
> + struct drm_plane base;
> + u8 id;
> +};
> +
> +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
> +{
> + return container_of(plane, struct vs_plane, base);
> +}
> +
> +static inline struct vs_plane_state *
> +to_vs_plane_state(struct drm_plane_state *state)
> +{
> + return container_of(state, struct vs_plane_state, base);
> +}
> +
> +#endif /* __VS_DRV_H__ */
> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
> new file mode 100644
> index 000000000000..653f0ce72ed6
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_plane.c
> @@ -0,0 +1,487 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_blend.h>
> +#include <drm/drm_gem_dma_helper.h>
> +#include <drm/drm_fb_dma_helper.h>
> +#include <drm/drm_framebuffer.h>
> +#include <drm/drm_plane.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "vs_plane.h"
> +
> +static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
> + struct drm_plane_state *state)
> +{
> + struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
> +
> + __drm_atomic_helper_plane_destroy_state(state);
> + kfree(vs_plane_state);
> +}
> +
> +static void vs_plane_reset(struct drm_plane *plane)
> +{
> + struct vs_plane_state *state;
> + struct vs_plane *vs_plane = to_vs_plane(plane);
> +
> + if (plane->state)
> + vs_plane_atomic_destroy_state(plane, plane->state);
> +
> + state = kzalloc(sizeof(*state), GFP_KERNEL);
> + if (!state)
> + return;
> +
> + state->base.zpos = vs_plane->id;
> + __drm_atomic_helper_plane_reset(plane, &state->base);
> +}
> +
> +static struct drm_plane_state *
> +vs_plane_atomic_duplicate_state(struct drm_plane *plane)
> +{
> + struct vs_plane_state *state;
> +
> + if (WARN_ON(!plane->state))
> + return NULL;
> +
> + state = kzalloc(sizeof(*state), GFP_KERNEL);
> + if (!state)
> + return NULL;
> +
> + __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
> +
> + return &state->base;
> +}
> +
> +static bool vs_format_mod_supported(struct drm_plane *plane,
> + u32 format,
> + u64 modifier)
> +{
> + int i;
> +
> + /* We always have to allow these modifiers:
> + * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
> + * 2. Not passing any modifiers is the same as explicitly passing INVALID.
> + */
> + if (modifier == DRM_FORMAT_MOD_LINEAR)
> + return true;
> +
> + /* Check that the modifier is on the list of the plane's supported modifiers. */
> + for (i = 0; i < plane->modifier_count; i++) {
> + if (modifier == plane->modifiers[i])
> + break;
> + }
> +
> + if (i == plane->modifier_count)
> + return false;
> +
> + return true;
> +}
> +
> +const struct drm_plane_funcs vs_plane_funcs = {
> + .update_plane = drm_atomic_helper_update_plane,
> + .disable_plane = drm_atomic_helper_disable_plane,
> + .reset = vs_plane_reset,
> + .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
> + .atomic_destroy_state = vs_plane_atomic_destroy_state,
> + .format_mod_supported = vs_format_mod_supported,
> +};
> +
> +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
> +{
> + const struct drm_format_info *info;
> +
> + if (!fb)
> + return 0;
> +
> + info = drm_format_info(fb->format->format);
> + if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
> + return 0;
> +
> + return info->num_planes;
> +}
> +
> +static bool vs_dc_mod_supported(const u64 *info_modifiers, u64 modifier)
> +{
> + const u64 *mods;
> +
> + if (!info_modifiers)
> + return false;
> +
> + for (mods = info_modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
> + if (*mods == modifier)
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static int vs_primary_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
> + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> + struct vs_dc *dc = &priv->dc;
> + struct drm_framebuffer *fb = new_state->fb;
> + const struct vs_plane_primary_info *primary_info;
> + struct drm_crtc_state *crtc_state;
> + int i;
> +
> + if (!new_state->crtc || !new_state->fb)
> + return 0;
> + for (i = 0; i < dc->hw.info->primary_num; i++) {
> + primary_info = (struct vs_plane_primary_info *)&dc->hw.info->primary[i];
> + if (primary_info->id == to_vs_plane(plane)->id)
> + break;
> + }
> +
> + primary_info = &dc->hw.info->primary[i];
> +
> + if (fb->width < primary_info->min_width ||
> + fb->width > primary_info->max_width ||
> + fb->height < primary_info->min_height ||
> + fb->height > primary_info->max_height)
> + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
> + to_vs_plane(plane)->id);
> +
> + if (!vs_dc_mod_supported(primary_info->modifiers, fb->modifier)) {
> + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id);
> + return -EINVAL;
> + }
> +
> + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc);
> + return drm_atomic_helper_check_plane_state(new_state, crtc_state,
> + primary_info->min_scale,
> + primary_info->max_scale,
> + true, true);
> +}
> +
> +static int vs_overlay_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
> + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> + struct vs_dc *dc = &priv->dc;
> + struct drm_framebuffer *fb = new_state->fb;
> + const struct vs_plane_overlay_info *overlay_info;
> + struct drm_crtc_state *crtc_state;
> + int i;
> +
> + if (!new_state->crtc || !new_state->fb)
> + return 0;
> +
> + for (i = 0; i < dc->hw.info->overlay_num; i++) {
> + overlay_info = (struct vs_plane_overlay_info *)&dc->hw.info->overlay[i];
> + if (overlay_info->id == to_vs_plane(plane)->id)
> + break;
> + }
> +
> + overlay_info = &dc->hw.info->overlay[i];
> +
> + if (fb->width < overlay_info->min_width ||
> + fb->width > overlay_info->max_width ||
> + fb->height < overlay_info->min_height ||
> + fb->height > overlay_info->max_height)
> + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
> + to_vs_plane(plane)->id);
> +
> + if (!vs_dc_mod_supported(overlay_info->modifiers, fb->modifier)) {
> + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id);
> + return -EINVAL;
> +}
> +
> + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc);
> + return drm_atomic_helper_check_plane_state(new_state, crtc_state,
> + overlay_info->min_scale,
> + overlay_info->max_scale,
> + true, true);
> +}
> +
> +static int vs_cursor_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
> + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> + struct vs_dc *dc = &priv->dc;
> + struct drm_framebuffer *fb = new_state->fb;
> + const struct vs_plane_cursor_info *cursor_info;
> + struct drm_crtc_state *crtc_state;
> + int i;
> +
> + if (!new_state->crtc || !new_state->fb)
> + return 0;
> +
> + for (i = 0; i < dc->hw.info->cursor_num; i++) {
> + cursor_info = (struct vs_plane_cursor_info *)&dc->hw.info->cursor[i];
> + if (cursor_info->id == to_vs_plane(plane)->id)
> + break;
> + }
> +
> + cursor_info = &dc->hw.info->cursor[i];
> +
> + if (fb->width < cursor_info->min_width ||
> + fb->width > cursor_info->max_width ||
> + fb->height < cursor_info->min_height ||
> + fb->height > cursor_info->max_height)
> + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
> + to_vs_plane(plane)->id);
> +
> + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc);
> + return drm_atomic_helper_check_plane_state(new_state, crtc_state,
> + DRM_PLANE_NO_SCALING,
> + DRM_PLANE_NO_SCALING,
> + true, true);
Looking at these three functions:
- Define a common struct for plane info;
- Define a single function handling common case;
- Extend it as necessary for primary / overlay cases (or just skip the
corresponding check for cursor plane type).
> +}
> +
> +static void vs_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
> + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
> +
> + unsigned char i, num_planes, display_id, id;
> + u32 format;
> + bool is_yuv;
> + struct vs_plane *vs_plane = to_vs_plane(plane);
> + struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
> + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> + struct vs_dc *dc = &priv->dc;
> +
> + if (!new_state->fb || !new_state->crtc)
> + return;
> +
> + drm_fb_dma_sync_non_coherent(plane->dev, old_state, new_state);
> +
> + num_planes = vs_get_plane_number(new_state->fb);
> +
> + for (i = 0; i < num_planes; i++) {
> + dma_addr_t dma_addr;
> +
> + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, i);
> + plane_state->dma_addr[i] = dma_addr;
> + }
> +
> + display_id = to_vs_display_id(dc, new_state->crtc);
> + format = new_state->fb->format->format;
> + is_yuv = new_state->fb->format->is_yuv;
> + id = vs_plane->id;
> +
> + plane_hw_update_format_colorspace(dc, format, new_state->color_encoding, id, is_yuv);
> + if (new_state->visible)
> + plane_hw_update_address(dc, id, format, plane_state->dma_addr,
> + new_state->fb, &new_state->src);
> + plane_hw_update_format(dc, format, new_state->color_encoding, new_state->rotation,
> + new_state->visible, new_state->zpos, id, display_id);
> + plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id,
> + display_id, new_state->rotation);
> + plane_hw_update_blend(dc, new_state->alpha, new_state->pixel_blend_mode,
> + id, display_id);
> +}
> +
> +static void vs_cursor_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> + plane);
> + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
> + plane);
> + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> + struct vs_dc *dc = &priv->dc;
> + unsigned char display_id;
> + u32 crtc_w, crtc_x, crtc_y;
> + s32 hotspot_x, hotspot_y;
> + dma_addr_t dma_addr;
> +
> + display_id = to_vs_display_id(dc, new_state->crtc);
> +
> + if (!new_state->fb || !new_state->crtc)
> + return;
> +
> + drm_fb_dma_sync_non_coherent(new_state->fb->dev, old_state, new_state);
> + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, 0);
> + crtc_w = new_state->crtc_w;
> +
> + if (new_state->crtc_x > 0) {
> + crtc_x = new_state->crtc_x;
> + hotspot_x = 0;
> + } else {
> + hotspot_x = -new_state->crtc_x;
> + crtc_x = 0;
> + }
> + if (new_state->crtc_y > 0) {
> + crtc_y = new_state->crtc_y;
> + hotspot_y = 0;
> + } else {
> + hotspot_y = -new_state->crtc_y;
> + crtc_y = 0;
> + }
> + dc_hw_update_cursor(&dc->hw, display_id, dma_addr, crtc_w, crtc_x,
> + crtc_y, hotspot_x, hotspot_y);
> +}
> +
> +static void vs_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state)
> +{
> + struct vs_plane *vs_plane = to_vs_plane(plane);
> + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> + struct vs_dc *dc = &priv->dc;
> +
> + dc_hw_disable_plane(dc, vs_plane->id);
> +}
> +
> +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
> + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> + struct vs_dc *dc = &priv->dc;
> + unsigned char display_id;
> +
> + display_id = to_vs_display_id(dc, old_state->crtc);
> + dc_hw_disable_cursor(&dc->hw, display_id);
> +}
> +
> +const struct drm_plane_helper_funcs primary_plane_helpers = {
> + .atomic_check = vs_primary_plane_atomic_check,
> + .atomic_update = vs_plane_atomic_update,
> + .atomic_disable = vs_plane_atomic_disable,
> +};
> +
> +const struct drm_plane_helper_funcs overlay_plane_helpers = {
> + .atomic_check = vs_overlay_plane_atomic_check,
> + .atomic_update = vs_plane_atomic_update,
> + .atomic_disable = vs_plane_atomic_disable,
> +};
> +
> +const struct drm_plane_helper_funcs cursor_plane_helpers = {
> + .atomic_check = vs_cursor_plane_atomic_check,
> + .atomic_update = vs_cursor_plane_atomic_update,
> + .atomic_disable = vs_cursor_plane_atomic_disable,
> +};
> +
> +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev,
> + struct vs_plane_primary_info *info,
> + unsigned int layer_num,
> + unsigned int possible_crtcs)
> +{
> + struct vs_plane *plane;
> + int ret;
> +
> + if (!info)
> + return NULL;
> +
> + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
> + possible_crtcs,
> + &vs_plane_funcs,
> + info->formats, info->num_formats,
> + info->modifiers, DRM_PLANE_TYPE_PRIMARY,
> + NULL);
> + if (IS_ERR(plane))
> + return ERR_CAST(plane);
> +
> + drm_plane_helper_add(&plane->base, &primary_plane_helpers);
> +
> + drm_plane_create_alpha_property(&plane->base);
> + drm_plane_create_blend_mode_property(&plane->base,
> + BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> + BIT(DRM_MODE_BLEND_PREMULTI) |
> + BIT(DRM_MODE_BLEND_COVERAGE));
> +
> + if (info->color_encoding) {
> + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding,
> + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
> + DRM_COLOR_YCBCR_BT709,
> + DRM_COLOR_YCBCR_LIMITED_RANGE);
> + if (ret)
> + return NULL;
> + }
> +
> + if (info->rotation) {
> + ret = drm_plane_create_rotation_property(&plane->base,
> + DRM_MODE_ROTATE_0,
> + info->rotation);
> + if (ret)
> + return NULL;
> + }
> +
> + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1);
> + if (ret)
> + return NULL;
> +
> + return plane;
> +}
> +
> +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev,
> + struct vs_plane_overlay_info *info,
> + unsigned int layer_num,
> + unsigned int possible_crtcs)
This looks almost like a previous function. Consider merging them.
> +{
> + struct vs_plane *plane;
> + int ret;
> +
> + if (!info)
> + return NULL;
> +
> + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
> + possible_crtcs,
> + &vs_plane_funcs,
> + info->formats, info->num_formats,
> + info->modifiers, DRM_PLANE_TYPE_OVERLAY,
> + NULL);
> + if (IS_ERR(plane))
> + return ERR_CAST(plane);
> +
> + drm_plane_helper_add(&plane->base, &overlay_plane_helpers);
> +
> + drm_plane_create_alpha_property(&plane->base);
> + drm_plane_create_blend_mode_property(&plane->base,
> + BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> + BIT(DRM_MODE_BLEND_PREMULTI) |
> + BIT(DRM_MODE_BLEND_COVERAGE));
> +
> + if (info->color_encoding) {
> + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding,
> + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
> + DRM_COLOR_YCBCR_BT709,
> + DRM_COLOR_YCBCR_LIMITED_RANGE);
> + if (ret)
> + return NULL;
> + }
> +
> + if (info->rotation) {
> + ret = drm_plane_create_rotation_property(&plane->base,
> + DRM_MODE_ROTATE_0,
> + info->rotation);
> + if (ret)
> + return NULL;
> + }
> +
> + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1);
> + if (ret)
> + return NULL;
> +
> + return plane;
> +}
> +
> +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev,
> + struct vs_plane_cursor_info *info,
> + unsigned int possible_crtcs)
> +{
> + struct vs_plane *plane;
> + int ret;
> +
> + if (!info)
> + return NULL;
> +
> + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
> + possible_crtcs,
> + &vs_plane_funcs,
> + info->formats, info->num_formats,
> + NULL, DRM_PLANE_TYPE_CURSOR,
> + NULL);
> + if (IS_ERR(plane))
> + return ERR_CAST(plane);
> +
> + drm_plane_helper_add(&plane->base, &cursor_plane_helpers);
> +
> + ret = drm_plane_create_zpos_immutable_property(&plane->base, info->zpos);
> + if (ret)
> + return NULL;
> +
> + return plane;
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
> new file mode 100644
> index 000000000000..0416146226a8
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_plane.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_PLANE_H__
> +#define __VS_PLANE_H__
> +
> +#include <drm/drm_plane_helper.h>
> +
> +#include "vs_drv.h"
> +
> +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev,
> + struct vs_plane_primary_info *info,
> + unsigned int layer_num,
> + unsigned int possible_crtcs);
> +
> +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev,
> + struct vs_plane_overlay_info *info,
> + unsigned int layer_num,
> + unsigned int possible_crtcs);
> +
> +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev,
> + struct vs_plane_cursor_info *info,
> + unsigned int possible_crtcs);
> +#endif /* __VS_PLANE_H__ */
> --
> 2.27.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 07/10] drm/vs: add ctrc fun
2024-05-21 10:58 ` [PATCH v4 07/10] drm/vs: add ctrc fun keith
@ 2024-05-21 21:08 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-05-21 21:08 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
On Tue, May 21, 2024 at 06:58:14PM +0800, keith wrote:
> add crtc funs and helper funs
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> drivers/gpu/drm/verisilicon/Makefile | 3 +-
> drivers/gpu/drm/verisilicon/vs_crtc.c | 241 ++++++++++++++++++++++++++
> drivers/gpu/drm/verisilicon/vs_crtc.h | 17 ++
> 3 files changed, 260 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
>
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 1c593b943261..26a43ca0fd36 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -2,6 +2,7 @@
>
> vs_drm-objs := vs_dc_hw.o \
> vs_modeset.o \
> - vs_plane.o
> + vs_plane.o \
> + vs_crtc.o
>
> obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
> new file mode 100644
> index 000000000000..ea7640a63c28
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
> @@ -0,0 +1,241 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + *
> + */
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_gem_atomic_helper.h>
> +#include <drm/drm_vblank.h>
> +
> +#include "vs_crtc.h"
> +
> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *state)
> +{
> + __drm_atomic_helper_crtc_destroy_state(state);
> + kfree(to_vs_crtc_state(state));
> +}
> +
> +static void vs_crtc_reset(struct drm_crtc *crtc)
> +{
> + struct vs_crtc_state *state;
> +
> + if (crtc->state)
> + vs_crtc_atomic_destroy_state(crtc, crtc->state);
> +
> + state = kzalloc(sizeof(*state), GFP_KERNEL);
> + if (!state)
> + return;
> +
> + __drm_atomic_helper_crtc_reset(crtc, &state->base);
> +}
> +
> +static struct drm_crtc_state *
> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
> +{
> + struct vs_crtc_state *old_state;
> + struct vs_crtc_state *state;
> +
> + if (!crtc->state)
> + return NULL;
> +
> + old_state = to_vs_crtc_state(crtc->state);
> +
> + state = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);
> + if (!state)
> + return NULL;
> +
> + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
> +
> + return &state->base;
> +}
> +
> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
> +{
> + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> + struct vs_dc *dc = &priv->dc;
> +
> + dc_hw_enable_interrupt(&dc->hw);
> +
> + return 0;
> +}
> +
> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
> +{
> + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> + struct vs_dc *dc = &priv->dc;
> +
> + dc_hw_disable_interrupt(&dc->hw);
> +}
> +
> +static const struct drm_crtc_funcs vs_crtc_funcs = {
> + .set_config = drm_atomic_helper_set_config,
> + .page_flip = drm_atomic_helper_page_flip,
> + .reset = vs_crtc_reset,
> + .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
> + .atomic_destroy_state = vs_crtc_atomic_destroy_state,
> + .enable_vblank = vs_crtc_enable_vblank,
> + .disable_vblank = vs_crtc_disable_vblank,
> +};
> +
> +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
> + struct drm_atomic_state *state)
> +{
> + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> + struct vs_dc *dc = &priv->dc;
> +
> + struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
> + struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> + int id;
> +
> + id = to_vs_display_id(dc, crtc);
> + if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
> + dc_hw_set_out(&dc->hw, OUT_DPI, id);
> + clk_set_rate(priv->clks[7].clk, mode->clock * 1000);
> + clk_set_parent(priv->clks[5].clk, priv->clks[7].clk);
> + } else {
> + dc_hw_set_out(&dc->hw, OUT_DP, id);
> + clk_set_parent(priv->clks[4].clk, priv->clks[6].clk);
> + }
> +
> + dc_hw_enable(&dc->hw, id, mode, crtc_state->encoder_type, crtc_state->output_fmt);
> +
> + enable_irq(priv->irq);
> +
> + drm_crtc_vblank_on(crtc);
> +}
> +
> +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
> + struct drm_atomic_state *state)
> +{
> + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> + struct vs_dc *dc = &priv->dc;
> + int id;
> +
> + drm_crtc_vblank_off(crtc);
> +
> + disable_irq(priv->irq);
> +
> + id = to_vs_display_id(dc, crtc);
> + dc_hw_disable(&dc->hw, id);
> +
> + if (crtc->state->event && !crtc->state->active) {
> + spin_lock_irq(&crtc->dev->event_lock);
> + drm_crtc_send_vblank_event(crtc, crtc->state->event);
> + crtc->state->event = NULL;
> + spin_unlock_irq(&crtc->dev->event_lock);
> + }
> +}
> +
> +static void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> + struct drm_color_lut *lut, unsigned int size)
> +{
> + u16 i, r, g, b;
> + u8 bits, id;
> +
> + if (size != dc->hw.info->gamma_size) {
> + drm_err(crtc->dev, "gamma size does not match!\n");
> + return;
> + }
> +
> + id = to_vs_display_id(dc, crtc);
> +
> + bits = dc->hw.info->gamma_bits;
> + for (i = 0; i < size; i++) {
> + r = drm_color_lut_extract(lut[i].red, bits);
> + g = drm_color_lut_extract(lut[i].green, bits);
> + b = drm_color_lut_extract(lut[i].blue, bits);
> + dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
> +
> + if (i >= dc->hw.info->gamma_size)
> + return;
> +
> + dc->hw.gamma[id].gamma[i][0] = r;
> + dc->hw.gamma[id].gamma[i][1] = g;
> + dc->hw.gamma[id].gamma[i][2] = b;
> + }
> +}
> +
> +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
> + struct drm_atomic_state *state)
> +{
> + struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state,
> + crtc);
> +
> + struct drm_property_blob *blob = new_state->gamma_lut;
> + struct drm_color_lut *lut;
> + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> + struct vs_dc *dc = &priv->dc;
> + u8 id;
> +
> + id = to_vs_display_id(dc, crtc);
> + if (new_state->color_mgmt_changed) {
> + if (blob && blob->length) {
> + lut = blob->data;
> + vs_dc_set_gamma(dc, crtc, lut,
> + blob->length / sizeof(*lut));
> + dc_hw_enable_gamma(&dc->hw, id, true);
> + } else {
> + dc_hw_enable_gamma(&dc->hw, id, false);
> + }
> + }
> +}
> +
> +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
> + struct drm_atomic_state *state)
> +{
> + struct drm_pending_vblank_event *event = crtc->state->event;
> + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> + struct vs_dc *dc = &priv->dc;
> +
> + dc_hw_enable_shadow_register(dc, false);
> +
> + if (event) {
> + WARN_ON(drm_crtc_vblank_get(crtc) != 0);
> +
> + spin_lock_irq(&crtc->dev->event_lock);
> + drm_crtc_arm_vblank_event(crtc, event);
> + crtc->state->event = NULL;
> + spin_unlock_irq(&crtc->dev->event_lock);
> + }
> +
> + dc_hw_enable_shadow_register(dc, true);
> +}
> +
> +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
> + .atomic_check = drm_crtc_helper_atomic_check,
> + .atomic_enable = vs_crtc_atomic_enable,
> + .atomic_disable = vs_crtc_atomic_disable,
> + .atomic_begin = vs_crtc_atomic_begin,
> + .atomic_flush = vs_crtc_atomic_flush,
> +};
> +
> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> + struct vs_dc_info *info)
> +{
> + struct vs_crtc *crtc;
> + int ret;
> +
> + if (!info)
> + return NULL;
> +
> + crtc = drmm_crtc_alloc_with_planes(drm_dev, struct vs_crtc, base, NULL,
> + NULL, &vs_crtc_funcs,
> + info->name ? info->name : NULL);
> +
> + drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
> +
> + if (info->gamma_size) {
> + ret = drm_mode_crtc_set_gamma_size(&crtc->base,
> + info->gamma_size);
> + if (ret)
> + return NULL;
> +
> + drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
> + info->gamma_size);
> + }
> +
> + return crtc;
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
> new file mode 100644
> index 000000000000..b1e588bb780d
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_CRTC_H__
> +#define __VS_CRTC_H__
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
Do you really need to include them here?
> +
> +#include "vs_drv.h"
> +
> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> + struct vs_dc_info *info);
> +
> +#endif /* __VS_CRTC_H__ */
> --
> 2.27.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 08/10] drm/vs: add vs drm master driver
2024-05-21 10:58 ` [PATCH v4 08/10] drm/vs: add vs drm master driver keith
@ 2024-05-21 21:14 ` Dmitry Baryshkov
2024-06-23 7:16 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-05-21 21:14 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu,
p.zabel, jack.zhu, shengyang.chen, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
On Tue, May 21, 2024 at 06:58:15PM +0800, keith wrote:
> Add vs DRM master driver for JH7110 SoC
> ADD DMA GEM driver
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> drivers/gpu/drm/verisilicon/Makefile | 3 +-
> drivers/gpu/drm/verisilicon/vs_drv.c | 718 +++++++++++++++++++++++++++
> 2 files changed, 720 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
>
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 26a43ca0fd36..88a07a308e31 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -3,6 +3,7 @@
> vs_drm-objs := vs_dc_hw.o \
> vs_modeset.o \
> vs_plane.o \
> - vs_crtc.o
> + vs_crtc.o \
> + vs_drv.o
>
> obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> new file mode 100644
> index 000000000000..c22fd2199fe2
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -0,0 +1,718 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/of_clk.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of_device.h>
> +
> +#include <drm/drm_aperture.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_fbdev_generic.h>
> +#include <drm/drm_file.h>
> +#include <drm/drm_gem_dma_helper.h>
> +#include <drm/drm_module.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/drm_blend.h>
> +
> +#include "vs_drv.h"
> +#include "vs_crtc.h"
> +#include "vs_plane.h"
> +#include "vs_modeset.h"
> +
> +#define DRV_NAME "verisilicon"
> +#define DRV_DESC "Verisilicon DRM driver"
> +#define DRV_DATE "20230516"
> +#define DRV_MAJOR 1
> +#define DRV_MINOR 0
> +
> +#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
> +
> +static const u32 primary_overlay_format[] = {
> + DRM_FORMAT_RGB565,
> + DRM_FORMAT_BGR565,
> + DRM_FORMAT_XRGB8888,
> + DRM_FORMAT_XBGR8888,
> + DRM_FORMAT_RGBX8888,
> + DRM_FORMAT_BGRX8888,
> + DRM_FORMAT_ARGB8888,
> + DRM_FORMAT_ABGR8888,
> + DRM_FORMAT_RGBA8888,
> + DRM_FORMAT_BGRA8888,
> + DRM_FORMAT_XRGB4444,
> + DRM_FORMAT_XBGR4444,
> + DRM_FORMAT_RGBX4444,
> + DRM_FORMAT_BGRX4444,
> + DRM_FORMAT_ARGB4444,
> + DRM_FORMAT_ABGR4444,
> + DRM_FORMAT_RGBA4444,
> + DRM_FORMAT_BGRA4444,
> + DRM_FORMAT_XRGB1555,
> + DRM_FORMAT_XBGR1555,
> + DRM_FORMAT_RGBX5551,
> + DRM_FORMAT_BGRX5551,
> + DRM_FORMAT_ARGB1555,
> + DRM_FORMAT_ABGR1555,
> + DRM_FORMAT_RGBA5551,
> + DRM_FORMAT_BGRA5551,
> + DRM_FORMAT_ARGB2101010,
> + DRM_FORMAT_ABGR2101010,
> + DRM_FORMAT_RGBA1010102,
> + DRM_FORMAT_BGRA1010102,
> + DRM_FORMAT_YUYV,
> + DRM_FORMAT_YVYU,
> + DRM_FORMAT_UYVY,
> + DRM_FORMAT_VYUY,
> + DRM_FORMAT_YVU420,
> + DRM_FORMAT_YUV420,
> + DRM_FORMAT_NV12,
> + DRM_FORMAT_NV21,
> + DRM_FORMAT_NV16,
> + DRM_FORMAT_NV61,
> + DRM_FORMAT_P010,
> +};
> +
> +static const u32 cursor_formats[] = {
> + DRM_FORMAT_ARGB8888
> +};
> +
> +static const u64 format_modifier[] = {
> + DRM_FORMAT_MOD_LINEAR,
> + DRM_FORMAT_MOD_INVALID
> +};
> +
> +static const u64 secondary_format_modifiers[] = {
> + DRM_FORMAT_MOD_LINEAR,
> + DRM_FORMAT_MOD_INVALID
> +};
> +
> +static const struct vs_plane_primary_info dc_hw_planes_primary[2] = {
> + {
> + .id = PRIMARY_PLANE_0,
> + .num_formats = ARRAY_SIZE(primary_overlay_format),
> + .formats = primary_overlay_format,
> + .num_modifiers = ARRAY_SIZE(format_modifier),
> + .modifiers = format_modifier,
> + .min_width = 0,
> + .min_height = 0,
> + .max_width = 4096,
> + .max_height = 4096,
> + .min_scale = FRAC_16_16(1, 3),
> + .max_scale = FRAC_16_16(10, 1),
> + .rotation = DRM_MODE_ROTATE_0 |
> + DRM_MODE_ROTATE_90 |
> + DRM_MODE_ROTATE_180 |
> + DRM_MODE_ROTATE_270 |
> + DRM_MODE_REFLECT_X |
> + DRM_MODE_REFLECT_Y,
> + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
> + .zpos = 0,
How are these zpos related to the zpos from drm_plane_state?
> + },
> + {
> + .id = PRIMARY_PLANE_1,
> + .num_formats = ARRAY_SIZE(primary_overlay_format),
> + .formats = primary_overlay_format,
> + .num_modifiers = ARRAY_SIZE(format_modifier),
> + .modifiers = format_modifier,
> + .min_width = 0,
> + .min_height = 0,
> + .max_width = 4096,
> + .max_height = 4096,
> + .min_scale = FRAC_16_16(1, 3),
> + .max_scale = FRAC_16_16(10, 1),
> + .rotation = DRM_MODE_ROTATE_0 |
> + DRM_MODE_ROTATE_90 |
> + DRM_MODE_ROTATE_180 |
> + DRM_MODE_ROTATE_270 |
> + DRM_MODE_REFLECT_X |
> + DRM_MODE_REFLECT_Y,
> + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
> + .zpos = 3,
> + },
> +};
> +
> +static const struct vs_plane_overlay_info dc_hw_planes_overlay[4] = {
> + {
> + .id = OVERLAY_PLANE_0,
> + .num_formats = ARRAY_SIZE(primary_overlay_format),
> + .formats = primary_overlay_format,
> + .num_modifiers = ARRAY_SIZE(format_modifier),
> + .modifiers = format_modifier,
> + .min_width = 0,
> + .min_height = 0,
> + .max_width = 4096,
> + .max_height = 4096,
> + .min_scale = FRAC_16_16(1, 3),
> + .max_scale = FRAC_16_16(10, 1),
> + .rotation = DRM_MODE_ROTATE_0 |
> + DRM_MODE_ROTATE_90 |
> + DRM_MODE_ROTATE_180 |
> + DRM_MODE_ROTATE_270 |
> + DRM_MODE_REFLECT_X |
> + DRM_MODE_REFLECT_Y,
> + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
> + .zpos = 1,
> + },
> + {
> + .id = OVERLAY_PLANE_1,
> + .num_formats = ARRAY_SIZE(primary_overlay_format),
> + .formats = primary_overlay_format,
> + .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> + .modifiers = secondary_format_modifiers,
> + .min_width = 0,
> + .min_height = 0,
> + .max_width = 4096,
> + .max_height = 4096,
> + .min_scale = DRM_PLANE_NO_SCALING,
> + .max_scale = DRM_PLANE_NO_SCALING,
> + .rotation = 0,
> + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
> + .zpos = 2,
> + },
> + {
> + .id = OVERLAY_PLANE_2,
> + .num_formats = ARRAY_SIZE(primary_overlay_format),
> + .formats = primary_overlay_format,
> + .num_modifiers = ARRAY_SIZE(format_modifier),
> + .modifiers = format_modifier,
> + .min_width = 0,
> + .min_height = 0,
> + .max_width = 4096,
> + .max_height = 4096,
> + .min_scale = FRAC_16_16(1, 3),
> + .max_scale = FRAC_16_16(10, 1),
> + .rotation = DRM_MODE_ROTATE_0 |
> + DRM_MODE_ROTATE_90 |
> + DRM_MODE_ROTATE_180 |
> + DRM_MODE_ROTATE_270 |
> + DRM_MODE_REFLECT_X |
> + DRM_MODE_REFLECT_Y,
> + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
> + .zpos = 4,
> + },
> + {
> + .id = OVERLAY_PLANE_3,
> + .num_formats = ARRAY_SIZE(primary_overlay_format),
> + .formats = primary_overlay_format,
> + .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> + .modifiers = secondary_format_modifiers,
> + .min_width = 0,
> + .min_height = 0,
> + .max_width = 4096,
> + .max_height = 4096,
> + .min_scale = DRM_PLANE_NO_SCALING,
> + .max_scale = DRM_PLANE_NO_SCALING,
> + .rotation = 0,
> + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020),
> + .zpos = 5,
> + },
> +};
> +
> +static const struct vs_plane_cursor_info dc_hw_planes_cursor[2] = {
> + {
> + .id = CURSOR_PLANE_0,
> + .num_formats = ARRAY_SIZE(cursor_formats),
> + .formats = cursor_formats,
> + .min_width = 32,
> + .min_height = 32,
> + .max_width = 64,
> + .max_height = 64,
> + .zpos = 255,
> + },
> + {
> + .id = CURSOR_PLANE_1,
> + .num_formats = ARRAY_SIZE(cursor_formats),
> + .formats = cursor_formats,
> + .min_width = 32,
> + .min_height = 32,
> + .max_width = 64,
> + .max_height = 64,
> + .zpos = 255,
> + },
> +};
> +
> +static const struct vs_dc_info dc8200_info = {
> + .name = "DC8200",
> + .panel_num = 2,
> + .primary_num = 2,
> + .overlay_num = 4,
> + .cursor_num = 2,
ARRAY_SIZE would have been better.
> + .primary = dc_hw_planes_primary,
> + .overlay = dc_hw_planes_overlay,
> + .cursor = dc_hw_planes_cursor,
> + .layer_num = 6,
> + .gamma_size = GAMMA_EX_SIZE,
> + .gamma_bits = 12,
> + .pitch_alignment = 128,
> +};
> +
> +static int vs_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
> + struct drm_mode_create_dumb *args)
> +{
> + struct vs_drm_device *priv = to_vs_drm_private(dev);
> + unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
> +
> + args->pitch = ALIGN(pitch, priv->pitch_alignment);
> + return drm_gem_dma_dumb_create_internal(file, dev, args);
> +}
> +
> +DEFINE_DRM_GEM_FOPS(vs_drm_fops);
> +
> +static struct drm_driver vs_drm_driver = {
> + .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
> +
> + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vs_gem_dumb_create),
> +
> + .fops = &vs_drm_fops,
> + .name = DRV_NAME,
> + .desc = DRV_DESC,
> + .date = DRV_DATE,
> + .major = DRV_MAJOR,
> + .minor = DRV_MINOR,
> +};
> +
> +static irqreturn_t vs_dc_isr(int irq, void *data)
> +{
> + struct vs_drm_device *priv = data;
> + struct vs_dc *dc = &priv->dc;
> + struct vs_dc_info *dc_info = dc->hw.info;
> + u32 i;
> +
> + dc_hw_get_interrupt(&dc->hw);
> +
> + for (i = 0; i < dc_info->panel_num; i++)
> + drm_crtc_handle_vblank(&dc->crtc[i]->base);
Is it true that all CRTCs have vblank at the same time?
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int vs_drm_device_init_res(struct vs_drm_device *priv)
> +{
> + struct device *dev = priv->base.dev;
> + struct platform_device *pdev = to_platform_device(dev);
> + int ret;
> + struct vs_dc *dc;
> +
> + dc = &priv->dc;
> + dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(dc->hw.hi_base))
> + return PTR_ERR(dc->hw.hi_base);
> +
> + dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
> + if (IS_ERR(dc->hw.reg_base))
> + return PTR_ERR(dc->hw.reg_base);
> +
> + dc->hw.info = (struct vs_dc_info *)of_device_get_match_data(dev);
> +
> + ret = devm_clk_bulk_get_all(dev, &priv->clks);
> + if (ret < 0) {
> + dev_err(dev, "can't get vout clock, ret=%d\n", ret);
> + return ret;
> + }
> + priv->clk_count = ret;
> +
> + priv->rsts = devm_reset_control_array_get_shared(dev);
> + if (IS_ERR(priv->rsts))
> + return PTR_ERR(priv->rsts);
> +
> + priv->irq = platform_get_irq(pdev, 0);
> +
> + /* do not autoenable, will be enabled later */
> + ret = devm_request_irq(dev, priv->irq, vs_dc_isr, IRQF_NO_AUTOEN, dev_name(dev), priv);
> + if (ret < 0) {
> + dev_err(dev, "Failed to install irq:%u.\n", priv->irq);
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> +static u32 get_addr_offset(u32 id)
> +{
> + u32 offset = 0;
> +
> + switch (id) {
> + case PRIMARY_PLANE_1:
> + case OVERLAY_PLANE_1:
> + offset = 0x04;
> + break;
> + case OVERLAY_PLANE_2:
> + offset = 0x08;
> + break;
> + case OVERLAY_PLANE_3:
> + offset = 0x0C;
> + break;
> + default:
> + break;
> + }
> +
> + return offset;
> +}
> +
> +static int vs_drm_device_crtc_plane_create(struct vs_drm_device *priv)
> +{
> + struct vs_dc *dc;
> + struct drm_device *drm_dev;
> + int i, ret;
> + struct device_node *port;
> + struct vs_crtc *crtc;
> + struct vs_dc_info *dc_info;
> + struct vs_plane *plane;
> + struct vs_plane_primary_info *primary_info;
> + struct vs_plane_overlay_info *overlay_info;
> + struct vs_plane_cursor_info *cursor_info;
> +
> + struct device *dev = priv->base.dev;
> + u32 max_width = 0, max_height = 0;
> + u32 min_width = 0xffff, min_heigth = 0xffff;
> + u32 possible_crtc = 0;
> +
> + dc = &priv->dc;
> + dc_info = dc->hw.info;
> + drm_dev = &priv->base;
> +
> + for (i = 0; i < dc_info->panel_num; i++) {
> + crtc = vs_crtc_create(drm_dev, dc_info);
> + if (!crtc) {
> + drm_err(drm_dev, "Failed to create CRTC.\n");
> + ret = -ENOMEM;
> + return ret;
> + }
> + crtc->dev = drm_dev->dev;
> +
> + port = of_graph_get_port_by_id(crtc->dev->of_node, i);
> + if (!port) {
> + drm_err(drm_dev, "no port node found for crtc_port%d\n", i);
> + return -ENOENT;
> + }
> +
> + crtc->base.port = port;
> + dc->crtc[i] = crtc;
> +
> + of_node_put(port);
> + }
> +
> + if (!dc->crtc[0]->base.port || !dc->crtc[1]->base.port) {
> + drm_err(drm_dev, "no port no crtc mask, fail to create plane\n");
> + return -ENOENT;
> + }
> +
> + for (i = 0; i < dc_info->primary_num; i++) {
> + primary_info = (struct vs_plane_primary_info *)&dc_info->primary[i];
> +
> + if (primary_info->id == PRIMARY_PLANE_0)
> + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base);
> + else
> + possible_crtc = drm_crtc_mask(&dc->crtc[1]->base);
> +
> + plane = vs_plane_primary_create(drm_dev, primary_info,
> + dc_info->layer_num, possible_crtc);
> + if (IS_ERR(plane)) {
> + dev_err(dev, "failed to construct plane\n");
> + return PTR_ERR(plane);
> + }
> +
> + plane->id = primary_info->id;
> + dc->planes[plane->id].id = primary_info->id;
> + dc->planes[plane->id].offset = get_addr_offset(primary_info->id);
> +
> + if (primary_info->id == PRIMARY_PLANE_0)
> + dc->crtc[0]->base.primary = &plane->base;
> + else
> + dc->crtc[1]->base.primary = &plane->base;
> +
> + min_width = min_t(u32, min_width, primary_info->min_width);
> + min_heigth = min_t(u32, min_heigth, primary_info->min_height);
> + /*
> + * Note: these values are used for multiple independent things:
> + * hw display mode filtering, plane buffer sizes ...
> + * Use the combined maximum values here to cover all use cases,
> + * and do more specific checking in the respective code paths.
> + */
> + max_width = max_t(u32, max_width, primary_info->max_width);
> + max_height = max_t(u32, max_height, primary_info->max_height);
> + }
> +
> + for (i = 0; i < dc_info->overlay_num; i++) {
> + overlay_info = (struct vs_plane_overlay_info *)&dc_info->overlay[i];
> +
> + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base) |
> + drm_crtc_mask(&dc->crtc[1]->base);
> +
> + plane = vs_plane_overlay_create(drm_dev, overlay_info,
> + dc_info->layer_num, possible_crtc);
> + if (IS_ERR(plane)) {
> + dev_err(dev, "failed to construct plane\n");
> + return PTR_ERR(plane);
> + }
> +
> + plane->id = overlay_info->id;
> + dc->planes[plane->id].id = overlay_info->id;
> + dc->planes[plane->id].offset = get_addr_offset(overlay_info->id);
> + }
> +
> + for (i = 0; i < dc_info->cursor_num; i++) {
> + cursor_info = (struct vs_plane_cursor_info *)&dc_info->cursor[i];
> +
> + if (cursor_info->id == CURSOR_PLANE_0)
> + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base);
> + else
> + possible_crtc = drm_crtc_mask(&dc->crtc[1]->base);
> +
> + plane = vs_plane_cursor_create(drm_dev, cursor_info, possible_crtc);
> + if (IS_ERR(plane)) {
> + dev_err(dev, "failed to construct plane\n");
> + return PTR_ERR(plane);
> + }
> +
> + plane->id = cursor_info->id;
> + dc->planes[plane->id].id = cursor_info->id;
> + dc->planes[plane->id].offset = get_addr_offset(cursor_info->id);
> +
> + if (cursor_info->id == CURSOR_PLANE_0)
> + dc->crtc[0]->base.cursor = &plane->base;
> + else
> + dc->crtc[1]->base.cursor = &plane->base;
> + drm_dev->mode_config.cursor_width =
> + max_t(u32, drm_dev->mode_config.cursor_width,
> + cursor_info->max_width);
> + drm_dev->mode_config.cursor_height =
> + max_t(u32, drm_dev->mode_config.cursor_height,
> + cursor_info->max_height);
> + }
> +
> + drm_dev->mode_config.min_width = min_width;
> + drm_dev->mode_config.min_height = min_heigth;
> + drm_dev->mode_config.max_width = max_width;
> + drm_dev->mode_config.max_height = max_height;
I thought that I saw mode_config.min/max being initialized.
> +
> + if (dc_info->pitch_alignment > priv->pitch_alignment)
> + priv->pitch_alignment = dc_info->pitch_alignment;
> +
> + return 0;
> +}
> +
> +static int vs_load(struct vs_drm_device *priv)
> +{
> + int ret;
> +
> + ret = clk_bulk_prepare_enable(priv->clk_count, priv->clks);
> + if (ret)
> + return ret;
> +
> + reset_control_deassert(priv->rsts);
> +
> + ret = dc_hw_init(&priv->dc);
> + if (ret) {
> + DRM_ERROR("failed to init DC HW\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int vs_drm_bind(struct device *dev)
> +{
> + struct vs_drm_device *priv;
> + int ret;
> + struct drm_device *drm_dev;
> +
> + priv = devm_drm_dev_alloc(dev, &vs_drm_driver, struct vs_drm_device, base);
> + if (IS_ERR(priv))
> + return PTR_ERR(priv);
> +
> + priv->pitch_alignment = 64;
> + drm_dev = &priv->base;
> + dev_set_drvdata(dev, drm_dev);
> +
> + ret = dma_set_coherent_mask(drm_dev->dev, DMA_BIT_MASK(40));
> + if (ret)
> + return ret;
> +
> + ret = vs_drm_device_init_res(priv);
> + if (ret)
> + return ret;
> +
> + vs_mode_config_init(drm_dev);
> +
> + /* Remove existing drivers that may own the framebuffer memory. */
> + ret = drm_aperture_remove_framebuffers(&vs_drm_driver);
> + if (ret)
> + return ret;
> +
> + ret = vs_drm_device_crtc_plane_create(priv);
> + if (ret) {
> + DRM_ERROR("Failed to create ctrc and plane\n");
> + return ret;
> + }
> +
> + ret = vs_load(priv);
> + if (ret)
> + return ret;
> +
> + /* Now try and bind all our sub-components */
> + ret = component_bind_all(dev, drm_dev);
> + if (ret) {
> + ret = -EPROBE_DEFER;
> + goto unload;
> + }
> + ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
> + if (ret)
> + goto err_unbind_all;
> +
> + drm_mode_config_reset(drm_dev);
> +
> + ret = drmm_kms_helper_poll_init(drm_dev);
> + if (ret)
> + goto err_unbind_all;
> +
> + ret = drm_dev_register(drm_dev, 0);
> + if (ret)
> + goto err_unbind_all;
> +
> + drm_fbdev_generic_setup(drm_dev, 32);
> +
> + return 0;
> +
> +err_unbind_all:
> + component_unbind_all(drm_dev->dev, drm_dev);
> +unload:
> + reset_control_assert(priv->rsts);
> + clk_bulk_disable_unprepare(priv->clk_count, priv->clks);
> + return ret;
> +
> +}
> +
> +static void vs_drm_unbind(struct device *dev)
> +{
> + struct drm_device *drm_dev = dev_get_drvdata(dev);
> + struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
> +
> + reset_control_assert(priv->rsts);
> + clk_bulk_disable_unprepare(priv->clk_count, priv->clks);
> +
> + drm_dev_unregister(drm_dev);
> + drm_atomic_helper_shutdown(drm_dev);
> + component_unbind_all(drm_dev->dev, drm_dev);
> +}
> +
> +static const struct component_master_ops vs_drm_ops = {
> + .bind = vs_drm_bind,
> + .unbind = vs_drm_unbind,
> +};
> +
> +static struct platform_driver *drm_sub_drivers[] = {
> +
> +};
> +
> +static struct component_match *vs_add_external_components(struct device *dev)
> +{
> + struct component_match *match = NULL;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(drm_sub_drivers); ++i) {
> + struct platform_driver *drv = drm_sub_drivers[i];
> + struct device *p = NULL, *d;
> +
> + while ((d = platform_find_device_by_driver(p, &drv->driver))) {
> + put_device(p);
> +
> + drm_of_component_match_add(dev, &match, component_compare_of,
> + d->of_node);
> + p = d;
> + }
> + put_device(p);
What about just going through the graph connections instead and adding
them?
> + }
> +
> + return match ? match : ERR_PTR(-ENODEV);
> +}
> +
> +static int vs_drm_platform_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct component_match *match;
> +
> + /* all the planes and CRTC would be created in this platform device
> + * , so external components are encoder + connector or self-defined
Comma should go to the previous line.
> + * encoder.
> + */
> + match = vs_add_external_components(dev);
> + if (IS_ERR(match))
> + return PTR_ERR(match);
> +
> + return component_master_add_with_match(dev, &vs_drm_ops, match);
> +}
> +
> +static int vs_drm_platform_remove(struct platform_device *pdev)
> +{
> + component_master_del(&pdev->dev, &vs_drm_ops);
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int vs_drm_suspend(struct device *dev)
> +{
> + return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
> +}
> +
> +static int vs_drm_resume(struct device *dev)
> +{
> + drm_mode_config_helper_resume(dev_get_drvdata(dev));
> +
> + return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
> +
> +static const struct of_device_id vs_drm_dt_ids[] = {
> + { .compatible = "starfive,jh7110-dc8200", .data = &dc8200_info,},
> + { },
> +};
> +
> +MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
> +
> +static struct platform_driver vs_drm_platform_driver = {
> + .probe = vs_drm_platform_probe,
> + .remove = vs_drm_platform_remove,
> +
> + .driver = {
> + .name = DRV_NAME,
> + .of_match_table = vs_drm_dt_ids,
> + .pm = &vs_drm_pm_ops,
> + },
> +};
> +
> +static int __init vs_drm_init(void)
> +{
> + int ret;
> +
> + ret = platform_register_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers));
> + if (ret)
> + return ret;
> +
> + ret = drm_platform_driver_register(&vs_drm_platform_driver);
> + if (ret)
> + platform_unregister_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers));
> +
> + return ret;
> +}
> +
> +static void __exit vs_drm_fini(void)
> +{
> + platform_driver_unregister(&vs_drm_platform_driver);
> + platform_unregister_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers));
> +}
> +
> +late_initcall_sync(vs_drm_init);
Why _sync?
> +module_exit(vs_drm_fini);
> +
> +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
> +MODULE_LICENSE("GPL");
> --
> 2.27.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-05-21 10:58 ` [PATCH v4 04/10] drm/vs: Add hardware funcs for vs keith
` (2 preceding siblings ...)
2024-05-21 21:01 ` kernel test robot
@ 2024-05-22 1:34 ` kernel test robot
3 siblings, 0 replies; 53+ messages in thread
From: kernel test robot @ 2024-05-22 1:34 UTC (permalink / raw)
To: keith, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh, krzk+dt, conor+dt, hjc, heiko, andy.yan,
xingyu.wu, p.zabel, jack.zhu, shengyang.chen
Cc: Paul Gazzillo, Necip Fazil Yildiran, oe-kbuild-all, dri-devel,
devicetree, linux-kernel, linux-arm-kernel, keith.zhao
Hi keith,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master next-20240521]
[cannot apply to robh/for-next rockchip/for-next v6.9]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/keith/dt-bindings-display-Add-YAML-schema-for-JH7110-display-pipeline/20240521-110316
base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link: https://lore.kernel.org/r/20240521105817.3301-5-keith.zhao%40starfivetech.com
patch subject: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
config: arm-kismet-CONFIG_CMA-CONFIG_DRM_VERISILICON_DC8200-0-0 (https://download.01.org/0day-ci/archive/20240522/202405220946.U4oQ9BG2-lkp@intel.com/config)
reproduce: (https://download.01.org/0day-ci/archive/20240522/202405220946.U4oQ9BG2-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405220946.U4oQ9BG2-lkp@intel.com/
kismet warnings: (new ones prefixed by >>)
>> kismet: WARNING: unmet direct dependencies detected for CMA when selected by DRM_VERISILICON_DC8200
WARNING: unmet direct dependencies detected for CMA
Depends on [n]: MMU [=n]
Selected by [y]:
- DRM_VERISILICON_DC8200 [=y] && HAS_IOMEM [=y] && DRM [=y]
WARNING: unmet direct dependencies detected for DMA_CMA
Depends on [n]: HAVE_DMA_CONTIGUOUS [=n] && CMA [=y]
Selected by [y]:
- DRM_VERISILICON_DC8200 [=y] && HAS_IOMEM [=y] && DRM [=y]
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
2024-05-21 15:42 ` Laurent Pinchart
@ 2024-05-22 5:58 ` Keith Zhao
2024-05-22 7:32 ` Laurent Pinchart
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-05-22 5:58 UTC (permalink / raw)
To: Laurent Pinchart, Alex Bee
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Alex, Laurent:
I want to make as few changes as possible on the current basis, and add bridge_fun,
> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: 2024年5月21日 23:42
> To: Alex Bee <knaerzche@gmail.com>
> Cc: Keith Zhao <keith.zhao@starfivetech.com>; andrzej.hajda@intel.com;
> neil.armstrong@linaro.org; rfoss@kernel.org; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
>
> On Tue, May 21, 2024 at 05:36:43PM +0200, Alex Bee wrote:
> > Hi Keith,
> >
> > thanks a lot for working on this. See some general remarks below
> >
> > Am 21.05.24 um 12:58 schrieb keith:
> > > Add INNO common api so that it can be used by vendor drivers which
> > > implement vendor specific extensions to Innosilicon HDMI.
> > >
> > > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > > ---
> > > MAINTAINERS | 2 +
> > > drivers/gpu/drm/bridge/Kconfig | 2 +
> > > drivers/gpu/drm/bridge/Makefile | 1 +
> > > drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
> > > drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
> > > .../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587
> ++++++++++++++++++
> > > .../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 +++
> > > include/drm/bridge/inno_hdmi.h | 69 ++
> > > 8 files changed, 766 insertions(+)
> > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
> > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
> > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
> > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
> > > create mode 100644 include/drm/bridge/inno_hdmi.h
> > >
> > ....
> >
> > > + drm_encoder_helper_add(encoder, pdata->helper_private);
> > > +
> > > + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
> > > +
> > > + drm_connector_helper_add(&hdmi->connector,
> > > + &inno_hdmi_connector_helper_funcs);
> > > +
> > > + drmm_connector_init(drm, &hdmi->connector,
> > > + &inno_hdmi_connector_funcs,
> > > + DRM_MODE_CONNECTOR_HDMIA,
> > > + hdmi->ddc);
> > > +
> >
> > I really don't want to anticipate bridge maintainer's feedback, but
> > new bridge drivers must not contain connector creation. That must
> > happen somewhere else.
>
> You're absolutely right :-) Connector creation should be handled by the
> drm_bridge_connector helper. The HDMI bridge driver should focus on the
> HDMI bridge itself.
static int inno_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct inno_hdmi *hdmi = bridge_to_inno(bridge);
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
DRM_ERROR("Fix bridge driver to make connector optional!");
return -EINVAL;
}
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
&inno_hdmi_connector_helper_funcs);
drmm_connector_init(drm, &hdmi->connector,
&inno_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
hdmi->ddc);
drm_connector_attach_encoder(&hdmi->connector, encoder);
}
static const struct drm_bridge_funcs inno_bridge_attach = {
.attach = inno_bridge_attach,
};
Connector creation is handled by the drm_bridge_funcs ->attach.
Is it ok?
Regards
Keith
>
> > Also I'm neither seeing any drm_brige struct nor drm_bridge_funcs,
> > which are both essential for a bridge driver. I don't think moving a
> > part of a driver to .../drm/bridge/ makes it a bridge driver.
> >
> > > + drm_connector_attach_encoder(&hdmi->connector, encoder);
> > > +
> > > + return 0;
> > > +}
> > > +
> > ....
> >
>
> --
> Regards,
>
> Laurent Pinchart
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver
2024-05-21 10:58 ` [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver keith
@ 2024-05-22 7:24 ` Maxime Ripard
2024-06-23 7:17 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Maxime Ripard @ 2024-05-22 7:24 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, daniel,
robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu, p.zabel,
jack.zhu, shengyang.chen, dri-devel, devicetree, linux-kernel,
linux-arm-kernel
[-- Attachment #1: Type: text/plain, Size: 11862 bytes --]
Hi,
On Tue, May 21, 2024 at 06:58:10PM GMT, keith wrote:
> Add the ROCKCHIP inno hdmi driver that uses the Inno DesignWare
> HDMI TX bridge and remove the old separate one.
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> drivers/gpu/drm/rockchip/Kconfig | 1 +
> drivers/gpu/drm/rockchip/Makefile | 2 +-
> drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++
> .../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 -
> drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 -----------------
> 5 files changed, 519 insertions(+), 1119 deletions(-)
> create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h} (85%)
> delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
>
> diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
> index 1bf3e2829cd0..cc6cfd5a30d6 100644
> --- a/drivers/gpu/drm/rockchip/Kconfig
> +++ b/drivers/gpu/drm/rockchip/Kconfig
> @@ -74,6 +74,7 @@ config ROCKCHIP_DW_MIPI_DSI
>
> config ROCKCHIP_INNO_HDMI
> bool "Rockchip specific extensions for Innosilicon HDMI"
> + select DRM_INNO_HDMI
> help
> This selects support for Rockchip SoC specific extensions
> for the Innosilicon HDMI driver. If you want to enable
> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
> index 3ff7b21c0414..4b2d0cba8db3 100644
> --- a/drivers/gpu/drm/rockchip/Makefile
> +++ b/drivers/gpu/drm/rockchip/Makefile
> @@ -12,7 +12,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
> rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
> rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
> rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
> -rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
> +rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi-rockchip.o
> rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
> rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
> rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o
> diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> new file mode 100644
> index 000000000000..69d0e913e13b
> --- /dev/null
> +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> @@ -0,0 +1,517 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> + * Zheng Yang <zhengyang@rock-chips.com>
> + * Yakir Yang <ykk@rock-chips.com>
> + */
> +
> +#include <linux/irq.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/hdmi.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +
> +#include <drm/bridge/inno_hdmi.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_simple_kms_helper.h>
> +
> +#include "rockchip_drm_drv.h"
> +
> +#include "inno_hdmi-rockchip.h"
> +
> +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
> +
> +struct rk_inno_hdmi {
> + struct rockchip_encoder encoder;
> + struct inno_hdmi inno_hdmi;
> + struct clk *pclk;
> + struct clk *refclk;
> +};
> +
> +static struct inno_hdmi *rk_encoder_to_inno_hdmi(struct drm_encoder *encoder)
> +{
> + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
> + struct rk_inno_hdmi *rk_hdmi = container_of(rkencoder, struct rk_inno_hdmi, encoder);
> +
> + return &rk_hdmi->inno_hdmi;
> +}
> +
> +enum {
> + CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
> + CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
> + CSC_RGB_0_255_TO_RGB_16_235_8BIT,
> +};
> +
> +static const char coeff_csc[][24] = {
> + /*
> + * RGB2YUV:601 SD mode:
> + * Cb = -0.291G - 0.148R + 0.439B + 128
> + * Y = 0.504G + 0.257R + 0.098B + 16
> + * Cr = -0.368G + 0.439R - 0.071B + 128
> + */
> + {
> + 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
> + 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
> + 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
> + },
> + /*
> + * RGB2YUV:709 HD mode:
> + * Cb = - 0.338G - 0.101R + 0.439B + 128
> + * Y = 0.614G + 0.183R + 0.062B + 16
> + * Cr = - 0.399G + 0.439R - 0.040B + 128
> + */
> + {
> + 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
> + 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
> + 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
> + },
> + /*
> + * RGB[0:255]2RGB[16:235]:
> + * R' = R x (235-16)/255 + 16;
> + * G' = G x (235-16)/255 + 16;
> + * B' = B x (235-16)/255 + 16;
> + */
> + {
> + 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
> + 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
> + 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
> + },
> +};
> +
> +static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
> + { 74250000, 0x3f, 0xbb },
> + { 165000000, 0x6f, 0xbb },
> + { ~0UL, 0x00, 0x00 }
> +};
> +
> +static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = {
> + { 74250000, 0x3f, 0xaa },
> + { 165000000, 0x5f, 0xaa },
> + { ~0UL, 0x00, 0x00 }
> +};
> +
> +static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi,
> + unsigned long pixelclk)
> +{
> + const struct inno_hdmi_phy_config *phy_configs = hdmi->plat_data->phy_configs;
> + int i;
> +
> + for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) {
> + if (pixelclk <= phy_configs[i].pixelclock)
> + return i;
> + }
> +
> + DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n",
> + pixelclk);
> +
> + return -EINVAL;
> +}
> +
> +static void inno_hdmi_standby(struct inno_hdmi *hdmi)
> +{
> + inno_hdmi_sys_power(hdmi, false);
> +
> + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
> + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
> + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
> + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
> +};
> +
> +static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
> + unsigned long mpixelclock)
> +{
> + struct inno_hdmi_phy_config *phy_config;
> + int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock);
> +
> + if (ret < 0) {
> + phy_config = hdmi->plat_data->default_phy_config;
> + DRM_DEV_ERROR(hdmi->dev,
> + "Using default phy configuration for TMDS rate %lu",
> + mpixelclock);
> + } else {
> + phy_config = &hdmi->plat_data->phy_configs[ret];
> + }
> +
> + inno_hdmi_sys_power(hdmi, false);
> +
> + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis);
> + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control);
> + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
> + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
> + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
> + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
> + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
> + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
> +
> + inno_hdmi_sys_power(hdmi, true);
> +};
> +
> +static void inno_hdmi_reset(struct inno_hdmi *hdmi)
> +{
> + u32 val;
> + u32 msk;
> +
> + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
> + udelay(100);
> +
> + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
> + udelay(100);
> +
> + msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
> + val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
> + hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
> +
> + inno_hdmi_standby(hdmi);
> +}
> +
> +static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
> +{
> + struct drm_connector *connector = &hdmi->connector;
> + struct drm_connector_state *conn_state = connector->state;
> + struct inno_hdmi_connector_state *inno_conn_state =
> + to_inno_hdmi_conn_state(conn_state);
> + int c0_c2_change = 0;
> + int csc_enable = 0;
> + int csc_mode = 0;
> + int auto_csc = 0;
> + int value;
> + int i;
> +
> + /* Input video mode is SDR RGB24bit, data enable signal from external */
> + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
> + v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
> +
> + /* Input color hardcode to RGB, and output color hardcode to RGB888 */
> + value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
> + v_VIDEO_OUTPUT_COLOR(0) |
> + v_VIDEO_INPUT_CSP(0);
> + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
> +
> + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
> + if (inno_conn_state->rgb_limited_range) {
> + csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT;
> + auto_csc = AUTO_CSC_DISABLE;
> + c0_c2_change = C0_C2_CHANGE_DISABLE;
> + csc_enable = v_CSC_ENABLE;
> +
> + } else {
> + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
> + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
> +
> + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
> + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
> + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
> + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
> + return 0;
> + }
> + } else {
> + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) {
> + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
> + csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
> + auto_csc = AUTO_CSC_DISABLE;
> + c0_c2_change = C0_C2_CHANGE_DISABLE;
> + csc_enable = v_CSC_ENABLE;
> + }
> + } else {
> + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
> + csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
> + auto_csc = AUTO_CSC_DISABLE;
> + c0_c2_change = C0_C2_CHANGE_DISABLE;
> + csc_enable = v_CSC_ENABLE;
> + }
> + }
> + }
> +
> + for (i = 0; i < 24; i++)
> + hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
> + coeff_csc[csc_mode][i]);
> +
> + value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1);
> + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
> + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
> + m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
> + v_VIDEO_C0_C2_SWAP(c0_c2_change));
> +
> + return 0;
> +}
> +
> +static int inno_hdmi_setup(struct inno_hdmi *hdmi,
> + struct drm_display_mode *mode)
> +{
> + struct drm_display_info *display = &hdmi->connector.display_info;
> + unsigned long mpixelclock = mode->clock * 1000;
> +
> + /* Mute video and audio output */
> + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
> + v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
> +
> + /* Set HDMI Mode */
> + hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
> + v_HDMI_DVI(display->is_hdmi));
> +
> + inno_hdmi_config_video_timing(hdmi, mode);
> +
> + inno_hdmi_config_video_csc(hdmi);
> +
> + if (display->is_hdmi)
> + inno_hdmi_config_video_avi(hdmi, mode);
> +
> + /*
> + * When IP controller have configured to an accurate video
> + * timing, then the TMDS clock source would be switched to
> + * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
> + * clock rate, and reconfigure the DDC clock.
> + */
> + inno_hdmi_i2c_init(hdmi, mpixelclock);
> +
> + /* Unmute video and audio output */
> + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
> + v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
> +
> + inno_hdmi_power_up(hdmi, mpixelclock);
> +
> + return 0;
> +}
>
It's kind of a general comment, but I don't think that's the right
abstraction. You should create a inno_hdmi bridge that allows to
supplement some of the atomic hooks, but not reimplement them entirely
each time.
You can have a look at how dw-hdmi does it for example. Also, why do you
still need the encoder and connectors?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder
2024-05-21 10:58 ` [PATCH v4 10/10] drm/vs: add simple dsi encoder keith
2024-05-21 15:25 ` Dmitry Baryshkov
@ 2024-05-22 7:29 ` Maxime Ripard
1 sibling, 0 replies; 53+ messages in thread
From: Maxime Ripard @ 2024-05-22 7:29 UTC (permalink / raw)
To: keith
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, daniel,
robh, krzk+dt, conor+dt, hjc, heiko, andy.yan, xingyu.wu, p.zabel,
jack.zhu, shengyang.chen, dri-devel, devicetree, linux-kernel,
linux-arm-kernel
[-- Attachment #1: Type: text/plain, Size: 7877 bytes --]
Hi,
On Tue, May 21, 2024 at 06:58:17PM GMT, keith wrote:
> add encoder to match cdns dsi driver
>
> Signed-off-by: keith <keith.zhao@starfivetech.com>
> ---
> drivers/gpu/drm/verisilicon/Makefile | 3 +-
> drivers/gpu/drm/verisilicon/vs_drv.c | 1 +
> drivers/gpu/drm/verisilicon/vs_drv.h | 1 +
> drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 ++++++++++++++++++++
> drivers/gpu/drm/verisilicon/vs_simple_enc.h | 25 +++
> 5 files changed, 219 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c
> create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
>
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 2d02b4a3a567..c35ba9bd6f81 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -4,7 +4,8 @@ vs_drm-objs := vs_dc_hw.o \
> vs_modeset.o \
> vs_plane.o \
> vs_crtc.o \
> - vs_drv.o
> + vs_drv.o \
> + vs_simple_enc.o
>
> vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o
> obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> index 6f04102b05b3..2748d48f2c7e 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -612,6 +612,7 @@ static struct platform_driver *drm_sub_drivers[] = {
> #ifdef CONFIG_DRM_INNO_STARFIVE_HDMI
> &starfive_hdmi_driver,
> #endif
> + &simple_encoder_driver,
> };
>
> static struct component_match *vs_add_external_components(struct device *dev)
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
> index c3c08ed5f8ac..f3f0f170777d 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.h
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> @@ -17,6 +17,7 @@
> #include <drm/drm_managed.h>
>
> #include "vs_dc_hw.h"
> +#include "vs_simple_enc.h"
>
> /*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
> struct vs_drm_device {
> diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.c b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> new file mode 100644
> index 000000000000..d0b1755d77d2
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> @@ -0,0 +1,190 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
> + */
> +#include <linux/component.h>
> +#include <linux/of_device.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/media-bus-format.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_of.h>
> +
> +#include "vs_crtc.h"
> +#include "vs_simple_enc.h"
> +
> +static const struct simple_encoder_priv dsi_priv = {
> + .encoder_type = DRM_MODE_ENCODER_DSI
> +};
A simple encoder is a thing in KMS, and it's not what you are doing /
using. Please use a different name.
> +static inline struct vs_simple_encoder *to_simple_encoder(struct drm_encoder *enc)
> +{
> + return container_of(enc, struct vs_simple_encoder, encoder);
> +}
> +
> +static int encoder_parse_dt(struct device *dev)
> +{
> + struct vs_simple_encoder *simple = dev_get_drvdata(dev);
> + unsigned int args[2];
> +
> + simple->dss_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
> + "starfive,syscon",
> + 2, args);
> +
> + if (IS_ERR(simple->dss_regmap)) {
> + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
> + "getting the regmap failed\n");
> + }
> +
> + simple->offset = args[0];
> + simple->mask = args[1];
> +
> + return 0;
> +}
> +
> +static void vs_encoder_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
> +{
> + struct vs_simple_encoder *simple = to_simple_encoder(encoder);
> +
> + regmap_update_bits(simple->dss_regmap, simple->offset, simple->mask, simple->mask);
> +}
That should be handled through cdns_dsi_platform_ops.enable.
> +static int vs_encoder_atomic_check(struct drm_encoder *encoder,
> + struct drm_crtc_state *crtc_state,
> + struct drm_connector_state *conn_state)
> +{
> + struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state);
> + struct drm_connector *connector = conn_state->connector;
> + int ret = 0;
> +
> + vs_crtc_state->encoder_type = encoder->encoder_type;
> + if (connector->display_info.num_bus_formats)
> + vs_crtc_state->output_fmt = connector->display_info.bus_formats[0];
> + else
> + vs_crtc_state->output_fmt = MEDIA_BUS_FMT_FIXED;
> +
> + switch (vs_crtc_state->output_fmt) {
> + case MEDIA_BUS_FMT_FIXED:
> + case MEDIA_BUS_FMT_RGB565_1X16:
> + case MEDIA_BUS_FMT_RGB666_1X18:
> + case MEDIA_BUS_FMT_RGB888_1X24:
> + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> + case MEDIA_BUS_FMT_RGB101010_1X30:
> + case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> + case MEDIA_BUS_FMT_UYVY8_1X16:
> + case MEDIA_BUS_FMT_YUV8_1X24:
> + case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> + case MEDIA_BUS_FMT_UYVY10_1X20:
> + case MEDIA_BUS_FMT_YUV10_1X30:
> + ret = 0;
> + break;
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + /* If MEDIA_BUS_FMT_FIXED, set it to default value */
> + if (vs_crtc_state->output_fmt == MEDIA_BUS_FMT_FIXED)
> + vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
> +
> + return ret;
> +}
And that should be handled by the core cdns-dsi driver.
Maxime
> +static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
> + .atomic_check = vs_encoder_atomic_check,
> + .atomic_enable = vs_encoder_atomic_enable,
> +};
> +
> +static int vs_encoder_bind(struct device *dev, struct device *master, void *data)
> +{
> + struct drm_device *drm_dev = data;
> + struct vs_simple_encoder *simple = dev_get_drvdata(dev);
> + struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> + int ret;
> +
> + encoder = &simple->encoder;
> +
> + ret = drmm_encoder_init(drm_dev, encoder, NULL, simple->priv->encoder_type, NULL);
> + if (ret)
> + return ret;
> +
> + drm_encoder_helper_add(encoder, &encoder_helper_funcs);
> +
> + encoder->possible_crtcs =
> + drm_of_find_possible_crtcs(drm_dev, dev->of_node);
> +
> + /* output port is port1*/
> + bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
> + if (IS_ERR(bridge)) {
> + if (PTR_ERR(bridge) == -ENODEV) {
> + bridge = NULL;
> + return 0;
> + }
> +
> + return PTR_ERR(bridge);
> + }
> +
> + return drm_bridge_attach(encoder, bridge, NULL, 0);
> +}
> +
> +static const struct component_ops encoder_component_ops = {
> + .bind = vs_encoder_bind,
> +};
> +
> +static int vs_encoder_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct vs_simple_encoder *simple;
> + int ret;
> +
> + simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
> + if (!simple)
> + return -ENOMEM;
> +
> + simple->priv = of_device_get_match_data(dev);
> +
> + simple->dev = dev;
> +
> + dev_set_drvdata(dev, simple);
> +
> + ret = encoder_parse_dt(dev);
> + if (ret)
> + return ret;
> +
> + return component_add(dev, &encoder_component_ops);
> +}
> +
> +static int vs_encoder_remove(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> +
> + component_del(dev, &encoder_component_ops);
> + dev_set_drvdata(dev, NULL);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id simple_encoder_dt_match[] = {
> + { .compatible = "starfive,dsi-encoder", .data = &dsi_priv},
> + {},
> +};
You also don't need a specific compatible here, just reuse cdns,dsi.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
2024-05-22 5:58 ` Keith Zhao
@ 2024-05-22 7:32 ` Laurent Pinchart
0 siblings, 0 replies; 53+ messages in thread
From: Laurent Pinchart @ 2024-05-22 7:32 UTC (permalink / raw)
To: Keith Zhao
Cc: Alex Bee, andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Keith,
On Wed, May 22, 2024 at 05:58:00AM +0000, Keith Zhao wrote:
> Hi Alex, Laurent:
>
> I want to make as few changes as possible on the current basis, and add bridge_fun,
>
> On 2024年5月21日 23:42, Laurent Pinchart wrote:
> > On Tue, May 21, 2024 at 05:36:43PM +0200, Alex Bee wrote:
> > > Hi Keith,
> > >
> > > thanks a lot for working on this. See some general remarks below
> > >
> > > Am 21.05.24 um 12:58 schrieb keith:
> > > > Add INNO common api so that it can be used by vendor drivers which
> > > > implement vendor specific extensions to Innosilicon HDMI.
> > > >
> > > > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > > > ---
> > > > MAINTAINERS | 2 +
> > > > drivers/gpu/drm/bridge/Kconfig | 2 +
> > > > drivers/gpu/drm/bridge/Makefile | 1 +
> > > > drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 +
> > > > drivers/gpu/drm/bridge/innosilicon/Makefile | 2 +
> > > > .../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 ++++++++++++++++++
> > > > .../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 +++
> > > > include/drm/bridge/inno_hdmi.h | 69 ++
> > > > 8 files changed, 766 insertions(+)
> > > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig
> > > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile
> > > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
> > > > create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h
> > > > create mode 100644 include/drm/bridge/inno_hdmi.h
> > > >
> > > ....
> > >
> > > > + drm_encoder_helper_add(encoder, pdata->helper_private);
> > > > +
> > > > + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
> > > > +
> > > > + drm_connector_helper_add(&hdmi->connector,
> > > > + &inno_hdmi_connector_helper_funcs);
> > > > +
> > > > + drmm_connector_init(drm, &hdmi->connector,
> > > > + &inno_hdmi_connector_funcs,
> > > > + DRM_MODE_CONNECTOR_HDMIA,
> > > > + hdmi->ddc);
> > > > +
> > >
> > > I really don't want to anticipate bridge maintainer's feedback, but
> > > new bridge drivers must not contain connector creation. That must
> > > happen somewhere else.
> >
> > You're absolutely right :-) Connector creation should be handled by the
> > drm_bridge_connector helper. The HDMI bridge driver should focus on the
> > HDMI bridge itself.
>
> static int inno_bridge_attach(struct drm_bridge *bridge,
> enum drm_bridge_attach_flags flags)
> {
> struct inno_hdmi *hdmi = bridge_to_inno(bridge);
>
> if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
> DRM_ERROR("Fix bridge driver to make connector optional!");
> return -EINVAL;
> }
This kind of code was added to existing bridge drivers when we
transitioned to the new model where bridges don't create the connectors,
because we couldn't fix all the existing bridges in one go. New bridges
must do the opposite. See imx8qxp-pixel-link.c for instance, it has this
code instead in its attach function:
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
DRM_DEV_ERROR(pl->dev,
"do not support creating a drm_connector\n");
return -EINVAL;
}
(I would personally drop the DRM_DEV_ERROR message)
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> &inno_hdmi_connector_helper_funcs);
>
> drmm_connector_init(drm, &hdmi->connector,
> &inno_hdmi_connector_funcs,
> DRM_MODE_CONNECTOR_HDMIA,
> hdmi->ddc);
>
> drm_connector_attach_encoder(&hdmi->connector, encoder);
> }
>
> static const struct drm_bridge_funcs inno_bridge_attach = {
> .attach = inno_bridge_attach,
> };
>
> Connector creation is handled by the drm_bridge_funcs ->attach.
> Is it ok?
No, the connector should be created by the display controller driver by
calling drm_brige_connector_init(). It should not be created by the
bridge driver. The bridge driver should provide the bridge functions
(drm_bridge_funcs), but not create any connector.
> > > Also I'm neither seeing any drm_brige struct nor drm_bridge_funcs,
> > > which are both essential for a bridge driver. I don't think moving a
> > > part of a driver to .../drm/bridge/ makes it a bridge driver.
> > >
> > > > + drm_connector_attach_encoder(&hdmi->connector, encoder);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > ....
> > >
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-05-21 20:50 ` Dmitry Baryshkov
@ 2024-06-23 7:16 ` Keith Zhao
2024-06-23 20:51 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-23 7:16 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Dmitry:
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年5月22日 4:51
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
>
> On Tue, May 21, 2024 at 06:58:11PM +0800, keith wrote:
> > add hardware base api for vs drm
>
>
> Commit message is nearly missing. Please describe your hardware.
Ok it will be modified next
>
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
>
> Full name please
>
Ok it will be modified next
> > ---
> > MAINTAINERS | 1 +
> > drivers/gpu/drm/Kconfig | 2 +
> > drivers/gpu/drm/Makefile | 1 +
> > drivers/gpu/drm/verisilicon/Kconfig | 13 +
> > drivers/gpu/drm/verisilicon/Makefile | 5 +
> > drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1060
> ++++++++++++++++++++++++
> > drivers/gpu/drm/verisilicon/vs_dc_hw.h | 493 +++++++++++
> > drivers/gpu/drm/verisilicon/vs_type.h | 84 ++
> > 8 files changed, 1659 insertions(+)
> > create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
> > create mode 100644 drivers/gpu/drm/verisilicon/Makefile
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index cf2d66f88a83..9cb376f76f74 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -7156,6 +7156,7 @@ T: git
> https://gitlab.freedesktop.org/drm/misc/kernel.git
> > F:
> Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.y
> aml
> > F: Documentation/devicetree/bindings/display/starfive/
> > F: drivers/gpu/drm/bridge/innosilicon/
> > +F: drivers/gpu/drm/verisilicon
> > F: include/drm/bridge/inno_hdmi.h
> >
> > DRM DRIVER FOR SYNAPTICS R63353 PANELS
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index 026444eeb5c6..5413d87ef1d6 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -423,6 +423,8 @@ source "drivers/gpu/drm/sprd/Kconfig"
> >
> > source "drivers/gpu/drm/imagination/Kconfig"
> >
> > +source "drivers/gpu/drm/verisilicon/Kconfig"
> > +
> > config DRM_HYPERV
> > tristate "DRM Support for Hyper-V synthetic video device"
> > depends on DRM && PCI && MMU && HYPERV
> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > index f9ca4f8fa6c5..cb27092b1672 100644
> > --- a/drivers/gpu/drm/Makefile
> > +++ b/drivers/gpu/drm/Makefile
> > @@ -219,3 +219,4 @@ obj-y += solomon/
> > obj-$(CONFIG_DRM_SPRD) += sprd/
> > obj-$(CONFIG_DRM_LOONGSON) += loongson/
> > obj-$(CONFIG_DRM_POWERVR) += imagination/
> > +obj-$(CONFIG_DRM_VERISILICON_DC8200) += verisilicon/
> > diff --git a/drivers/gpu/drm/verisilicon/Kconfig
> b/drivers/gpu/drm/verisilicon/Kconfig
> > new file mode 100644
> > index 000000000000..2d733f93439e
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/Kconfig
> > @@ -0,0 +1,13 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +config DRM_VERISILICON_DC8200
> > + tristate "DRM Support for VeriSilicon DC8200"
> > + depends on DRM
> > + select DRM_KMS_HELPER
> > + select DRM_GEM_DMA_HELPER
> > + select CMA
> > + select DMA_CMA
> > + help
> > + Choose this option if you have a VeriSilicon DC8200 chipset.
> > + This driver provides VeriSilicon kernel mode
> > + setting and buffer management. It does not
> > + provide 2D or 3D acceleration.
> > diff --git a/drivers/gpu/drm/verisilicon/Makefile
> b/drivers/gpu/drm/verisilicon/Makefile
> > new file mode 100644
> > index 000000000000..7da54b259940
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > @@ -0,0 +1,5 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +vs_drm-objs := vs_dc_hw.o
> > +
> > +obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> > diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> > new file mode 100644
> > index 000000000000..69f020f8352f
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> > @@ -0,0 +1,1060 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>
> No changes in 2024?
>
it will be updated to 2024 next
> > + */
> > +
> > +#include <linux/bits.h>
> > +#include <linux/io.h>
> > +#include <linux/media-bus-format.h>
> > +//#include <drm/drm_atomic_helper.h>
>
> Either uncomment or drop.
Ok it will be modified next
>
> > +#include <drm/drm_blend.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_framebuffer.h>
> > +#include <drm/drm_fb_dma_helper.h>
> > +
> > +#include "vs_dc_hw.h"
> > +
> > +static const u32 horkernel[] = {
> > + 0x00000000, 0x20000000, 0x00002000, 0x00000000,
> > + 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> > + 0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> > + 0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> > + 0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> > + 0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> > + 0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> > + 0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> > + 0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> > + 0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> > + 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> > + 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> > + 0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> > + 0x00000000, 0x00000000, 0x00000000, 0x01470000,
> > + 0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> > + 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> > + 0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> > + 0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> > + 0x00000000, 0x00000000, 0x00004000, 0x00000000,
> > + 0x00000000, 0x00000000, 0x20002000, 0x00000000,
> > + 0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
> > + 0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
> > + 0x00000000, 0x00000000, 0x00000000, 0x14680000,
> > + 0x00002b98, 0x00000000, 0x00000000, 0x00000000,
> > + 0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
> > + 0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
> > + 0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
> > + 0x00000000, 0x087f0000, 0x00003781, 0x00000000,
> > + 0x00000000, 0x00000000, 0x399a0666, 0x00000000,
> > + 0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
> > + 0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
> > + 0x00000000, 0x00000000, 0x00000000, 0x021f0000,
> > +};
> > +
> > +#define H_COEF_SIZE ARRAY_SIZE(horkernel)
> > +
> > +static const u32 verkernel[] = {
> > + 0x00000000, 0x20000000, 0x00002000, 0x00000000,
> > + 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> > + 0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> > + 0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> > + 0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> > + 0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> > + 0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> > + 0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> > + 0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> > + 0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> > + 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> > + 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> > + 0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> > + 0x00000000, 0x00000000, 0x00000000, 0x01470000,
> > + 0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> > + 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> > + 0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> > + 0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> > + 0x00000000, 0x00000000, 0x00004000, 0x00000000,
> > + 0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
> > + 0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
> > + 0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> > +};
> > +
> > +#define V_COEF_SIZE ARRAY_SIZE(verkernel)
> > +
> > +/*
> > + * RGB 709->2020 conversion parameters
> > + */
> > +static const u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
> > + 10279, 5395, 709,
> > + 1132, 15065, 187,
> > + 269, 1442, 14674
> > +};
> > +
> > +/*
> > + * YUV601 to RGB conversion parameters
> > + * YUV2RGB[0] - [8] : C0 - C8;
> > + * YUV2RGB[9] - [11]: D0 - D2;
> > + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> > + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> > + */
> > +static const s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> > + 1196, 0, 1640, 1196,
> > + -404, -836, 1196, 2076,
> > + 0, -916224, 558336, -1202944,
> > + 64, 940, 64, 960
> > +};
> > +
> > +/*
> > + * YUV709 to RGB conversion parameters
> > + * YUV2RGB[0] - [8] : C0 - C8;
> > + * YUV2RGB[9] - [11]: D0 - D2;
> > + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> > + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> > + */
> > +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> > + 1196, 0, 1844, 1196,
> > + -220, -548, 1196, 2172,
> > + 0, -1020672, 316672, -1188608,
> > + 64, 940, 64, 960
> > +};
> > +
> > +/*
> > + * YUV2020 to RGB conversion parameters
> > + * YUV2RGB[0] - [8] : C0 - C8;
> > + * YUV2RGB[9] - [11]: D0 - D2;
> > + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> > + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> > + */
> > +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> > + 1196, 0, 1724, 1196,
> > + -192, -668, 1196, 2200,
> > + 0, -959232, 363776, -1202944,
> > + 64, 940, 64, 960
> > +};
> > +
> > +/*
> > + * RGB to YUV2020 conversion parameters
> > + * RGB2YUV[0] - [8] : C0 - C8;
> > + * RGB2YUV[9] - [11]: D0 - D2;
> > + */
> > +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
> > + 230, 594, 52,
> > + -125, -323, 448,
> > + 448, -412, -36,
> > + 64, 512, 512
>
> Please fix spaces vs tabs here.
Ok it will be modified next
>
> > +};
> > +
> > +/* one is for primary plane and the other is for all overlay planes */
> > +static const struct dc_hw_plane_reg dc_plane_reg[] = {
> > + {
> > + .y_address = DC_FRAMEBUFFER_ADDRESS,
> > + .u_address = DC_FRAMEBUFFER_U_ADDRESS,
> > + .v_address = DC_FRAMEBUFFER_V_ADDRESS,
> > + .y_stride = DC_FRAMEBUFFER_STRIDE,
> > + .u_stride = DC_FRAMEBUFFER_U_STRIDE,
> > + .v_stride = DC_FRAMEBUFFER_V_STRIDE,
> > + .size = DC_FRAMEBUFFER_SIZE,
> > + .top_left = DC_FRAMEBUFFER_TOP_LEFT,
> > + .bottom_right = DC_FRAMEBUFFER_BOTTOM_RIGHT,
> > + .scale_factor_x =
> DC_FRAMEBUFFER_SCALE_FACTOR_X,
> > + .scale_factor_y =
> DC_FRAMEBUFFER_SCALE_FACTOR_Y,
> > + .h_filter_coef_index =
> DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
> > + .h_filter_coef_data = DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
> > + .v_filter_coef_index =
> DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
> > + .v_filter_coef_data = DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
> > + .init_offset = DC_FRAMEBUFFER_INIT_OFFSET,
> > + .color_key = DC_FRAMEBUFFER_COLOR_KEY,
> > + .color_key_high =
> DC_FRAMEBUFFER_COLOR_KEY_HIGH,
> > + .clear_value = DC_FRAMEBUFFER_CLEAR_VALUE,
> > + .color_table_index = DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
> > + .color_table_data = DC_FRAMEBUFFER_COLOR_TABLE_DATA,
> > + .scale_config = DC_FRAMEBUFFER_SCALE_CONFIG,
> > + .water_mark = DC_FRAMEBUFFER_WATER_MARK,
> > + .degamma_index =
> DC_FRAMEBUFFER_DEGAMMA_INDEX,
> > + .degamma_data =
> DC_FRAMEBUFFER_DEGAMMA_DATA,
> > + .degamma_ex_data =
> DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
> > + .src_global_color = DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
> > + .dst_global_color = DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
> > + .blend_config = DC_FRAMEBUFFER_BLEND_CONFIG,
> > + .roi_origin = DC_FRAMEBUFFER_ROI_ORIGIN,
> > + .roi_size = DC_FRAMEBUFFER_ROI_SIZE,
> > + .yuv_to_rgb_coef0 =
> DC_FRAMEBUFFER_YUVTORGB_COEF0,
> > + .yuv_to_rgb_coef1 =
> DC_FRAMEBUFFER_YUVTORGB_COEF1,
> > + .yuv_to_rgb_coef2 =
> DC_FRAMEBUFFER_YUVTORGB_COEF2,
> > + .yuv_to_rgb_coef3 =
> DC_FRAMEBUFFER_YUVTORGB_COEF3,
> > + .yuv_to_rgb_coef4 =
> DC_FRAMEBUFFER_YUVTORGB_COEF4,
> > + .yuv_to_rgb_coefd0 =
> DC_FRAMEBUFFER_YUVTORGB_COEFD0,
> > + .yuv_to_rgb_coefd1 =
> DC_FRAMEBUFFER_YUVTORGB_COEFD1,
> > + .yuv_to_rgb_coefd2 =
> DC_FRAMEBUFFER_YUVTORGB_COEFD2,
> > + .y_clamp_bound =
> DC_FRAMEBUFFER_Y_CLAMP_BOUND,
> > + .uv_clamp_bound =
> DC_FRAMEBUFFER_UV_CLAMP_BOUND,
> > + .rgb_to_rgb_coef0 =
> DC_FRAMEBUFFER_RGBTORGB_COEF0,
> > + .rgb_to_rgb_coef1 =
> DC_FRAMEBUFFER_RGBTORGB_COEF1,
> > + .rgb_to_rgb_coef2 =
> DC_FRAMEBUFFER_RGBTORGB_COEF2,
> > + .rgb_to_rgb_coef3 =
> DC_FRAMEBUFFER_RGBTORGB_COEF3,
> > + .rgb_to_rgb_coef4 =
> DC_FRAMEBUFFER_RGBTORGB_COEF4,
> > + },
> > + {
> > + .y_address = DC_OVERLAY_ADDRESS,
> > + .u_address = DC_OVERLAY_U_ADDRESS,
> > + .v_address = DC_OVERLAY_V_ADDRESS,
> > + .y_stride = DC_OVERLAY_STRIDE,
> > + .u_stride = DC_OVERLAY_U_STRIDE,
> > + .v_stride = DC_OVERLAY_V_STRIDE,
> > + .size = DC_OVERLAY_SIZE,
> > + .top_left = DC_OVERLAY_TOP_LEFT,
> > + .bottom_right = DC_OVERLAY_BOTTOM_RIGHT,
> > + .scale_factor_x = DC_OVERLAY_SCALE_FACTOR_X,
> > + .scale_factor_y = DC_OVERLAY_SCALE_FACTOR_Y,
> > + .h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
> > + .h_filter_coef_data = DC_OVERLAY_H_FILTER_COEF_DATA,
> > + .v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
> > + .v_filter_coef_data = DC_OVERLAY_V_FILTER_COEF_DATA,
> > + .init_offset = DC_OVERLAY_INIT_OFFSET,
> > + .color_key = DC_OVERLAY_COLOR_KEY,
> > + .color_key_high = DC_OVERLAY_COLOR_KEY_HIGH,
> > + .clear_value = DC_OVERLAY_CLEAR_VALUE,
> > + .color_table_index = DC_OVERLAY_COLOR_TABLE_INDEX,
> > + .color_table_data = DC_OVERLAY_COLOR_TABLE_DATA,
> > + .scale_config = DC_OVERLAY_SCALE_CONFIG,
> > + .water_mark = DC_OVERLAY_WATER_MARK,
> > + .degamma_index = DC_OVERLAY_DEGAMMA_INDEX,
> > + .degamma_data = DC_OVERLAY_DEGAMMA_DATA,
> > + .degamma_ex_data = DC_OVERLAY_DEGAMMA_EX_DATA,
> > + .src_global_color = DC_OVERLAY_SRC_GLOBAL_COLOR,
> > + .dst_global_color = DC_OVERLAY_DST_GLOBAL_COLOR,
> > + .blend_config = DC_OVERLAY_BLEND_CONFIG,
> > + .roi_origin = DC_OVERLAY_ROI_ORIGIN,
> > + .roi_size = DC_OVERLAY_ROI_SIZE,
> > + .yuv_to_rgb_coef0 = DC_OVERLAY_YUVTORGB_COEF0,
> > + .yuv_to_rgb_coef1 = DC_OVERLAY_YUVTORGB_COEF1,
> > + .yuv_to_rgb_coef2 = DC_OVERLAY_YUVTORGB_COEF2,
> > + .yuv_to_rgb_coef3 = DC_OVERLAY_YUVTORGB_COEF3,
> > + .yuv_to_rgb_coef4 = DC_OVERLAY_YUVTORGB_COEF4,
> > + .yuv_to_rgb_coefd0 =
> DC_OVERLAY_YUVTORGB_COEFD0,
> > + .yuv_to_rgb_coefd1 =
> DC_OVERLAY_YUVTORGB_COEFD1,
> > + .yuv_to_rgb_coefd2 =
> DC_OVERLAY_YUVTORGB_COEFD2,
> > + .y_clamp_bound = DC_OVERLAY_Y_CLAMP_BOUND,
> > + .uv_clamp_bound = DC_OVERLAY_UV_CLAMP_BOUND,
> > + .rgb_to_rgb_coef0 = DC_OVERLAY_RGBTORGB_COEF0,
> > + .rgb_to_rgb_coef1 = DC_OVERLAY_RGBTORGB_COEF1,
> > + .rgb_to_rgb_coef2 = DC_OVERLAY_RGBTORGB_COEF2,
> > + .rgb_to_rgb_coef3 = DC_OVERLAY_RGBTORGB_COEF3,
> > + .rgb_to_rgb_coef4 = DC_OVERLAY_RGBTORGB_COEF4,
> > + },
> > +};
> > +
> > +static inline u32 hi_read(struct dc_hw *hw, u32 reg)
> > +{
> > + return readl(hw->hi_base + reg);
> > +}
> > +
> > +static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
> > +{
> > + writel(value, hw->hi_base + reg);
> > +}
> > +
> > +static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
> > +{
> > + writel(value, hw->reg_base + reg - DC_REG_BASE);
> > +}
> > +
> > +static inline u32 dc_read(struct dc_hw *hw, u32 reg)
> > +{
> > + u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
> > +
> > + return value;
>
> just return readl(...)
Ok it will be modified next , good idea!
>
> > +}
> > +
> > +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
> > +{
> > + u32 value = dc_read(hw, reg);
> > +
> > + value &= ~clear;
> > + value |= set;
> > + dc_write(hw, reg, value);
>
> regmap_update_bits?
regmap_update_bits follows 4 steps:
1、ret = _regmap_read(map, reg, &orig);
.........
2、tmp = orig & ~mask;
3、tmp |= val & mask;
......
4、ret = _regmap_write(map, reg, tmp);
If the value out of mask range
It will just clear the mask bir
dc_set_clear will do clear and set without limit.
Maybe the name should be dc_clear_set
}
>
> > +}
> > +
> > +static void load_default_filter(struct dc_hw *hw,
> > + const struct dc_hw_plane_reg *reg, u32 offset)
> > +{
> > + u8 i;
> > +
> > + dc_write(hw, reg->scale_config + offset, 0x33);
> > + dc_write(hw, reg->init_offset + offset, 0x80008000);
> > + dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
> > + for (i = 0; i < H_COEF_SIZE; i++)
> > + dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
> > +
> > + dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
> > + for (i = 0; i < V_COEF_SIZE; i++)
> > + dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
> > +}
> > +
> > +static void load_rgb_to_rgb(struct dc_hw *hw, const struct
> dc_hw_plane_reg *reg,
> > + u32 offset, const u16 *table)
> > +{
> > + dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
> > + dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
> > + dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
> > + dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
> > + dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
> > +}
> > +
> > +static void load_yuv_to_rgb(struct dc_hw *hw, const struct
> dc_hw_plane_reg *reg,
> > + u32 offset, const s32 *table)
> > +{
> > + dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
> > + (0xFFFF & table[0]) | (table[1] << 16));
> > + dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
> > + (0xFFFF & table[2]) | (table[3] << 16));
> > + dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
> > + (0xFFFF & table[4]) | (table[5] << 16));
> > + dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
> > + (0xFFFF & table[6]) | (table[7] << 16));
> > + dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
> > + dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
> > + dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
> > + dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
> > + dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
> > + dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
> > +}
> > +
> > +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
>
> Is there any reason why load_rgb_to_yuv differs from two other
> functions?
>
load_rgb_to_yuv matches crtcs
load_yuv_to_rgb matches planes
load_rgb_to_rgb matches planes
the coefficient(table) is diff between load_rgb_to_yuv and load_yuv_to_rgb
> > +{
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
> > + table[0] | (table[1] << 16));
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
> > + table[2] | (table[3] << 16));
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
> > + table[4] | (table[5] << 16));
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
> > + table[6] | (table[7] << 16));
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
> > + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
> > +}
> > +
> > +static int update_vs_format(u32 drm_format)
> > +{
> > + u8 f = FORMAT_A8R8G8B8;
> > +
> > + switch (drm_format) {
> > + case DRM_FORMAT_XRGB4444:
> > + case DRM_FORMAT_RGBX4444:
> > + case DRM_FORMAT_XBGR4444:
> > + case DRM_FORMAT_BGRX4444:
> > + f = FORMAT_X4R4G4B4;
> > + break;
> > + case DRM_FORMAT_ARGB4444:
> > + case DRM_FORMAT_RGBA4444:
> > + case DRM_FORMAT_ABGR4444:
> > + case DRM_FORMAT_BGRA4444:
> > + f = FORMAT_A4R4G4B4;
> > + break;
> > + case DRM_FORMAT_XRGB1555:
> > + case DRM_FORMAT_RGBX5551:
> > + case DRM_FORMAT_XBGR1555:
> > + case DRM_FORMAT_BGRX5551:
> > + f = FORMAT_X1R5G5B5;
> > + break;
> > + case DRM_FORMAT_ARGB1555:
> > + case DRM_FORMAT_RGBA5551:
> > + case DRM_FORMAT_ABGR1555:
> > + case DRM_FORMAT_BGRA5551:
> > + f = FORMAT_A1R5G5B5;
> > + break;
> > + case DRM_FORMAT_RGB565:
> > + case DRM_FORMAT_BGR565:
> > + f = FORMAT_R5G6B5;
> > + break;
> > + case DRM_FORMAT_XRGB8888:
> > + case DRM_FORMAT_RGBX8888:
> > + case DRM_FORMAT_XBGR8888:
> > + case DRM_FORMAT_BGRX8888:
> > + f = FORMAT_X8R8G8B8;
> > + break;
> > + case DRM_FORMAT_ARGB8888:
> > + case DRM_FORMAT_RGBA8888:
> > + case DRM_FORMAT_ABGR8888:
> > + case DRM_FORMAT_BGRA8888:
> > + f = FORMAT_A8R8G8B8;
> > + break;
> > + case DRM_FORMAT_YUYV:
> > + case DRM_FORMAT_YVYU:
> > + f = FORMAT_YUY2;
> > + break;
> > + case DRM_FORMAT_UYVY:
> > + case DRM_FORMAT_VYUY:
> > + f = FORMAT_UYVY;
> > + break;
> > + case DRM_FORMAT_YUV420:
> > + case DRM_FORMAT_YVU420:
> > + f = FORMAT_YV12;
> > + break;
> > + case DRM_FORMAT_NV21:
> > + f = FORMAT_NV12;
> > + break;
> > + case DRM_FORMAT_NV16:
> > + case DRM_FORMAT_NV61:
> > + f = FORMAT_NV16;
> > + break;
> > + case DRM_FORMAT_P010:
> > + f = FORMAT_P010;
> > + break;
> > + case DRM_FORMAT_ARGB2101010:
> > + case DRM_FORMAT_RGBA1010102:
> > + case DRM_FORMAT_ABGR2101010:
> > + case DRM_FORMAT_BGRA1010102:
> > + f = FORMAT_A2R10G10B10;
> > + break;
> > + case DRM_FORMAT_NV12:
> > + f = FORMAT_NV12;
> > + break;
> > + case DRM_FORMAT_YUV444:
> > + f = FORMAT_YUV444;
>
> s/f = /return /g all over the place.
it will be modified next
>
> > + break;
> > + default:
>
> return -EINVAL;
>
> > + break;
> > + }
> > +
> > + return f;
> > +}
> > +
> > +int dc_hw_init(struct vs_dc *dc)
> > +{
> > + u8 i, id, panel_num, layer_num;
> > + struct dc_hw *hw = &dc->hw;
> > + u32 offset;
> > +
> > + layer_num = hw->info->layer_num;
> > + for (i = 0; i < layer_num; i++) {
> > + id = dc->planes[i].id;
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + hw->reg[i] = dc_plane_reg[0];
> > + else
> > + hw->reg[i] = dc_plane_reg[1];
> > +
> > + load_default_filter(hw, &hw->reg[i], dc->planes[i].offset);
> > + load_rgb_to_rgb(hw, &hw->reg[i], dc->planes[i].offset, RGB2RGB);
> > + }
> > +
> > + panel_num = hw->info->panel_num;
> > + for (i = 0; i < panel_num; i++) {
> > + offset = i << 2;
> > +
> > + load_rgb_to_yuv(hw, offset, RGB2YUV);
> > + dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
> > +
> > + offset = i ? DC_CURSOR_OFFSET : 0;
> > + dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
> > + dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +void dc_hw_disable_plane(struct vs_dc *dc, u8 id)
> > +{
> > + struct dc_hw *hw = &dc->hw;
> > +
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX +
> dc->planes[id].offset,
> > + PRIMARY_EN(false), PRIMARY_EN_MASK);
> > + else
> > + dc_set_clear(hw, DC_OVERLAY_CONFIG + dc->planes[id].offset,
> > + OVERLAY_FB_EN(false), OVERLAY_FB_EN_MASK);
> > +}
> > +
> > +static int update_cursor_size(uint32_t crtc_w)
>
> get_cursor_size()
>
> > +{
> > + u8 size_type;
> > +
> > + switch (crtc_w) {
> > + case 32:
> > + size_type = CURSOR_SIZE_32X32;
> > + break;
> > + case 64:
> > + size_type = CURSOR_SIZE_64X64;
> > + break;
> > + default:
> > + size_type = CURSOR_SIZE_32X32;
> > + break;
> > + }
> > +
> > + return size_type;
>
> Same comment. Return directly without extra variable assignments.
it will be modified next
>
> > +}
> > +
> > +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr,
> > + u32 crtc_w, u32 crtc_x, u32 crtc_y,
> > + s32 hotspot_x, s32 hotspot_y)
> > +{
> > + u32 offset, size;
> > +
> > + offset = id ? DC_CURSOR_OFFSET : 0;
> > + size = update_cursor_size(crtc_w);
> > +
> > + dc_write(hw, DC_CURSOR_ADDRESS + offset,
> > + dma_addr);
> > + dc_write(hw, DC_CURSOR_LOCATION + offset,
> > + X_LCOTION(crtc_x) |
> > + Y_LCOTION(crtc_y));
> > + dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
> > + CURSOR_HOT_X(hotspot_x) |
> > + CURSOR_HOT_y(hotspot_y) |
> > + CURSOR_SIZE(size) |
> > + CURSOR_VALID(1) |
> > + CURSOR_TRIG_FETCH(1) |
> > + CURSOR_FORMAT(CURSOR_FORMAT_A8R8G8B8),
> > + CURSOR_HOT_X_MASK |
> > + CURSOR_HOT_y_MASK |
> > + CURSOR_SIZE_MASK |
> > + CURSOR_VALID_MASK |
> > + CURSOR_TRIG_FETCH_MASK |
> > + CURSOR_FORMAT_MASK);
> > +}
> > +
> > +void dc_hw_disable_cursor(struct dc_hw *hw, u8 id)
> > +{
> > + u32 offset = 0;
> > +
> > + offset = id ? DC_CURSOR_OFFSET : 0;
> > + dc_set_clear(hw, DC_CURSOR_CONFIG + offset, CURSOR_VALID(1),
> CURSOR_FORMAT_MASK);
> > +}
> > +
> > +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> > + u16 r, u16 g, u16 b)
> > +{
> > + if (index >= hw->info->gamma_size)
> > + return;
> > +
> > + hw->gamma[id].gamma[index][0] = r;
> > + hw->gamma[id].gamma[index][1] = g;
> > + hw->gamma[id].gamma[index][2] = b;
> > +}
> > +
> > +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
> > +{
> > + u32 value;
> > +
> > + if (enable) {
> > + dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (id << 2), 0x00);
> > + for (int i = 0; i < GAMMA_EX_SIZE; i++) {
> > + value = hw->gamma[id].gamma[i][2] |
> > + (hw->gamma[id].gamma[i][1] << 12);
> > + dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (id << 2), value);
> > + dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (id << 2),
> > + hw->gamma[id].gamma[i][0]);
> > + }
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2),
> PANEL_GAMMA_EN, 0);
> > + } else {
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2), 0,
> PANEL_GAMMA_EN);
> > + }
> > +}
> > +
> > +void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode
> *mode,
> > + u8 encoder_type, u32 output_fmt)
> > +{
> > + u32 dp_cfg, dpi_cfg, offset = id << 2;
> > + bool is_yuv = false;
> > +
> > + if (encoder_type != DRM_MODE_ENCODER_DSI) {
> > + switch (output_fmt) {
> > + case MEDIA_BUS_FMT_RGB565_1X16:
> > + dp_cfg = 0;
> > + break;
> > + case MEDIA_BUS_FMT_RGB666_1X18:
> > + dp_cfg = 1;
> > + break;
> > + case MEDIA_BUS_FMT_RGB888_1X24:
> > + dp_cfg = 2;
> > + break;
> > + case MEDIA_BUS_FMT_RGB101010_1X30:
> > + dp_cfg = 3;
> > + break;
> > + case MEDIA_BUS_FMT_UYVY8_1X16:
> > + dp_cfg = 2 << 4;
> > + is_yuv = true;
> > + break;
> > + case MEDIA_BUS_FMT_YUV8_1X24:
> > + dp_cfg = 4 << 4;
> > + is_yuv = true;
> > + break;
> > + case MEDIA_BUS_FMT_UYVY10_1X20:
> > + dp_cfg = 8 << 4;
> > + is_yuv = true;
> > + break;
> > + case MEDIA_BUS_FMT_YUV10_1X30:
> > + dp_cfg = 10 << 4;
> > + is_yuv = true;
> > + break;
> > + case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> > + dp_cfg = 12 << 4;
> > + is_yuv = true;
> > + break;
> > + case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> > + dp_cfg = 13 << 4;
> > + is_yuv = true;
> > + break;
> > + default:
> > + dp_cfg = 2;
> > + break;
> > + }
> > + if (is_yuv)
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset,
> PANEL_RGB2YUV_EN, 0);
> > + else
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0,
> PANEL_RGB2YUV_EN);
> > + dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | DP_SELECT);
> > + }
> > +
> > + if (hw->out[id] == OUT_DPI)
> > + dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT);
> > +
> > + switch (output_fmt) {
> > + case MEDIA_BUS_FMT_RGB565_1X16:
> > + dpi_cfg = 0;
> > + break;
> > + case MEDIA_BUS_FMT_RGB666_1X18:
> > + dpi_cfg = 3;
> > + break;
> > + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> > + dpi_cfg = 4;
> > + break;
> > + case MEDIA_BUS_FMT_RGB888_1X24:
> > + dpi_cfg = 5;
> > + break;
> > + case MEDIA_BUS_FMT_RGB101010_1X30:
> > + dpi_cfg = 6;
> > + break;
> > + default:
> > + dpi_cfg = 5;
> > + break;
> > + }
> > + dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
> > +
> > + if (id == 0)
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL0_EN |
> TWO_PANEL_EN);
> > + else
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL1_EN |
> TWO_PANEL_EN);
> > +
> > + dc_write(hw, DC_DISPLAY_H + offset,
> > + H_ACTIVE_LEN(mode->hdisplay) |
> > + H_TOTAL_LEN(mode->htotal));
> > +
> > + dc_write(hw, DC_DISPLAY_H_SYNC + offset,
> > + H_SYNC_START_LEN(mode->hsync_start) |
> > + H_SYNC_END_LEN(mode->hsync_end) |
> > + H_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PHSYNC ? 0 :
> 1) |
> > + H_PLUS_LEN(1));
> > +
> > + dc_write(hw, DC_DISPLAY_V + offset,
> > + V_ACTIVE_LEN(mode->vdisplay) |
> > + V_TOTAL_LEN(mode->vtotal));
> > +
> > + dc_write(hw, DC_DISPLAY_V_SYNC + offset,
> > + V_SYNC_START_LEN(mode->vsync_start) |
> > + V_SYNC_END_LEN(mode->vsync_end) |
> > + V_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PVSYNC ? 0 : 1)
> |
> > + V_PLUS_LEN(1));
> > +
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset,
> PANEL_OUTPUT_EN, 0);
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(id), SYNC_EN);
> > +}
> > +
> > +void dc_hw_disable(struct dc_hw *hw, int id)
> > +{
> > + u32 offset = id << 2;
> > +
> > + if (hw->out[id] == OUT_DPI)
> > + dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT);
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0,
> PANEL_OUTPUT_EN);
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(id) | TWO_PANEL_EN);
> > +}
> > +
> > +void dc_hw_enable_interrupt(struct dc_hw *hw)
> > +{
> > + hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
> > +}
> > +
> > +void dc_hw_disable_interrupt(struct dc_hw *hw)
> > +{
> > + hi_write(hw, AQ_INTR_ENBL, 0);
> > +}
> > +
> > +u32 dc_hw_get_interrupt(struct dc_hw *hw)
> > +{
> > + return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
> > +}
> > +
> > +void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable)
> > +{
> > + u32 i, offset;
> > + struct dc_hw *hw = &dc->hw;
> > + u8 id, layer_num = hw->info->layer_num;
> > + u8 panel_num = hw->info->panel_num;
> > +
> > + for (i = 0; i < layer_num; i++) {
> > + id = dc->planes[i].id;
> > + offset = dc->planes[i].offset;
> > + if (enable) {
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> > + PRIMARY_SHADOW_EN, 0);
> > + else
> > + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> > + OVERLAY_SHADOW_EN, 0);
> > + } else {
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> > + 0, PRIMARY_SHADOW_EN);
> > + else
> > + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> > + 0, OVERLAY_SHADOW_EN);
> > + }
> > + }
> > +
> > + for (i = 0; i < panel_num; i++) {
> > + offset = i << 2;
> > + if (enable)
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0,
> PANEL_SHADOW_EN);
> > + else
> > + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset,
> PANEL_SHADOW_EN, 0);
> > + }
> > +}
> > +
> > +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
> > +{
> > + if (out <= OUT_DP)
>
> This doesn't scale if you add another output type. Please either add
> OUT_MAX or consider something which doesn't make OUT_DP special.
>
> > + hw->out[id] = out;
> > +}
> > +
> > +static inline u8 to_vs_yuv_color_space(u32 color_space)
> > +{
> > + u8 cs;
> > +
> > + switch (color_space) {
> > + case DRM_COLOR_YCBCR_BT601:
> > + cs = COLOR_SPACE_601;
> > + break;
> > + case DRM_COLOR_YCBCR_BT709:
> > + cs = COLOR_SPACE_709;
> > + break;
> > + case DRM_COLOR_YCBCR_BT2020:
> > + cs = COLOR_SPACE_2020;
> > + break;
> > + default:
> > + cs = COLOR_SPACE_601;
> > + break;
> > + }
> > +
> > + return cs;
> > +}
> > +
> > +static inline u8 update_uv_swizzle(u32 format)
> > +{
> > + u8 uv_swizzle = 0;
> > +
> > + switch (format) {
> > + case DRM_FORMAT_YVYU:
> > + case DRM_FORMAT_VYUY:
> > + case DRM_FORMAT_NV21:
> > + case DRM_FORMAT_NV61:
> > + uv_swizzle = 1;
> > + break;
> > + default:
> > + break;
> > + }
> > +
> > + return uv_swizzle;
> > +}
> > +
> > +static inline u8 update_swizzle(u32 format)
> > +{
> > + u8 swizzle = SWIZZLE_ARGB;
> > +
> > + switch (format) {
> > + case DRM_FORMAT_RGBX4444:
> > + case DRM_FORMAT_RGBA4444:
> > + case DRM_FORMAT_RGBX5551:
> > + case DRM_FORMAT_RGBA5551:
> > + case DRM_FORMAT_RGBX8888:
> > + case DRM_FORMAT_RGBA8888:
> > + case DRM_FORMAT_RGBA1010102:
> > + swizzle = SWIZZLE_RGBA;
> > + break;
> > + case DRM_FORMAT_XBGR4444:
> > + case DRM_FORMAT_ABGR4444:
> > + case DRM_FORMAT_XBGR1555:
> > + case DRM_FORMAT_ABGR1555:
> > + case DRM_FORMAT_BGR565:
> > + case DRM_FORMAT_XBGR8888:
> > + case DRM_FORMAT_ABGR8888:
> > + case DRM_FORMAT_ABGR2101010:
> > + swizzle = SWIZZLE_ABGR;
> > + break;
> > + case DRM_FORMAT_BGRX4444:
> > + case DRM_FORMAT_BGRA4444:
> > + case DRM_FORMAT_BGRX5551:
> > + case DRM_FORMAT_BGRA5551:
> > + case DRM_FORMAT_BGRX8888:
> > + case DRM_FORMAT_BGRA8888:
> > + case DRM_FORMAT_BGRA1010102:
> > + swizzle = SWIZZLE_BGRA;
> > + break;
> > + default:
> > + break;
> > + }
> > +
> > + return swizzle;
> > +}
> > +
> > +static inline u8 to_vs_rotation(unsigned int rotation)
> > +{
> > + u8 rot;
> > +
> > + switch (rotation & DRM_MODE_REFLECT_MASK) {
> > + case DRM_MODE_REFLECT_X:
> > + rot = FLIP_X;
> > + return rot;
> > + case DRM_MODE_REFLECT_Y:
> > + rot = FLIP_Y;
> > + return rot;
> > + case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
> > + rot = FLIP_XY;
> > + return rot;
> > + default:
> > + break;
> > + }
> > +
> > + switch (rotation & DRM_MODE_ROTATE_MASK) {
> > + case DRM_MODE_ROTATE_0:
> > + rot = ROT_0;
> > + break;
> > + case DRM_MODE_ROTATE_90:
> > + rot = ROT_90;
> > + break;
> > + case DRM_MODE_ROTATE_180:
> > + rot = ROT_180;
> > + break;
> > + case DRM_MODE_ROTATE_270:
> > + rot = ROT_270;
> > + break;
> > + default:
> > + rot = ROT_0;
> > + break;
> > + }
> > +
> > + return rot;
> > +}
> > +
> > +void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format,
> > + enum drm_color_encoding encoding, u8 id, bool
> is_yuv)
> > +{
> > + u32 offset = dc->planes[id].offset;
> > + struct dc_hw *hw = &dc->hw;
> > +
> > + if (is_yuv) {
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> > + PRIMARY_YUVCLAMP_EN, PRIMARY_RGB2RGB_EN);
> > + else
> > + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> > + OVERLAY_CLAMP_EN, OVERLAY_RGB2RGB_EN);
> > +
> > + switch (to_vs_yuv_color_space(encoding)) {
> > + case COLOR_SPACE_601:
> > + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV601_2RGB);
> > + break;
> > + case COLOR_SPACE_709:
> > + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV709_2RGB);
> > + break;
> > + case COLOR_SPACE_2020:
> > + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV2020_2RGB);
> > + break;
> > + default:
> > + break;
> > + }
> > + } else {
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> > + PRIMARY_RGB2RGB_EN, PRIMARY_YUVCLAMP_EN);
> > + else
> > + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> > + OVERLAY_RGB2RGB_EN, OVERLAY_CLAMP_EN);
> > + }
> > +}
> > +
> > +void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format,
> dma_addr_t *dma_addr,
> > + struct drm_framebuffer *drm_fb, struct drm_rect *src)
> > +{
> > + u32 offset = dc->planes[id].offset;
> > + struct dc_hw *hw = &dc->hw;
> > +
> > + dc_write(hw, hw->reg[id].y_address + offset, dma_addr[0]);
> > + dc_write(hw, hw->reg[id].u_address + offset,
> > + format == DRM_FORMAT_YVU420 ?
> > + dma_addr[2] : dma_addr[1]);
> > + dc_write(hw, hw->reg[id].v_address + offset,
> > + format == DRM_FORMAT_YVU420 ?
> > + dma_addr[1] : dma_addr[2]);
> > + dc_write(hw, hw->reg[id].y_stride + offset, drm_fb->pitches[0]);
> > + dc_write(hw, hw->reg[id].u_stride + offset,
> > + format == DRM_FORMAT_YVU420 ?
> > + drm_fb->pitches[2] : drm_fb->pitches[1]);
> > + dc_write(hw, hw->reg[id].v_stride + offset,
> > + format == DRM_FORMAT_YVU420 ?
> > + drm_fb->pitches[1] : drm_fb->pitches[2]);
> > + dc_write(hw, hw->reg[id].size + offset,
> > + FB_SIZE(drm_rect_width(src) >> 16, drm_rect_height(src) >> 16));
> > +}
> > +
> > +void plane_hw_update_format(struct vs_dc *dc, u32 format, enum
> drm_color_encoding encoding,
> > + unsigned int rotation, bool visible, unsigned int zpos,
> > + u8 id, u8 display_id)
> > +{
> > + u32 offset = dc->planes[id].offset;
> > + struct dc_hw *hw = &dc->hw;
> > +
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
> > + PRIMARY_FORMAT(update_vs_format(format)) |
> > + PRIMARY_UV_SWIZ(update_uv_swizzle(format)) |
> > + PRIMARY_SWIZ(update_swizzle(format)) |
> > + PRIMARY_TILE(DRM_FORMAT_MOD_LINEAR) |
> > + PRIMARY_YUV_COLOR(to_vs_yuv_color_space(encoding))
> |
> > + PRIMARY_ROTATION(to_vs_rotation(rotation)),
> > + PRIMARY_FORMAT_MASK |
> > + PRIMARY_UV_SWIZ_MASK |
> > + PRIMARY_SWIZ_MASK |
> > + PRIMARY_TILE_MASK |
> > + PRIMARY_YUV_COLOR_MASK |
> > + PRIMARY_ROTATION_MASK |
> > + PRIMARY_CLEAR_EN_MASK);
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> > + PRIMARY_DECODER_EN(false) |
> > + PRIMARY_EN(visible) |
> > + PRIMARY_ZPOS(zpos) |
> > + PRIMARY_CHANNEL(display_id),
> > + PRIMARY_DECODER_EN_EN_MASK |
> > + PRIMARY_EN_MASK |
> > + PRIMARY_ZPOS_MASK |
> > + PRIMARY_CHANNEL_MASK);
> > + } else {
> > + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> > + OVERLAY_FB_EN(visible) |
> > + OVERLAY_FORMAT(update_vs_format(format)) |
> > + OVERLAY_UV_SWIZ(update_uv_swizzle(format)) |
> > + OVERLAY_SWIZ(update_swizzle(format)) |
> > + OVERLAY_TILE(DRM_FORMAT_MOD_LINEAR) |
> > + OVERLAY_YUV_COLOR(to_vs_yuv_color_space(encoding))
> |
> > + OVERLAY_ROTATION(to_vs_rotation(rotation)),
> > + OVERLAY_DEC_EN_MASK |
> > + OVERLAY_CLEAR_EN_MASK |
> > + OVERLAY_FB_EN_MASK |
> > + OVERLAY_FORMAT_MASK |
> > + OVERLAY_UV_SWIZ_MASK |
> > + OVERLAY_SWIZ_MASK |
> > + OVERLAY_TILE_MASK |
> > + OVERLAY_YUV_COLOR_MASK |
> > + OVERLAY_ROTATION_MASK);
> > +
> > + dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
> > + OVERLAY_LAYER_SEL(zpos) |
> > + OVERLAY_PANEL_SEL(display_id),
> > + OVERLAY_LAYER_SEL_MASK |
> > + OVERLAY_PANEL_SEL_MASK);
> > + }
> > +}
> > +
> > +static u32 calc_factor(u32 src, u32 dest)
>
> A comment is appreciated.
>
> > +{
> > + u32 factor = 1 << 16;
> > +
> > + if (src > 1 && dest > 1)
> > + factor = ((src - 1) << 16) / (dest - 1);
> > +
> > + return factor;
> > +}
> > +
> > +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct
> drm_rect *dst,
> > + u8 id, u8 display_id, unsigned int rotation)
> > +{
> > + u32 offset = dc->planes[id].offset;
> > + struct dc_hw *hw = &dc->hw;
> > +
> > + int dst_w = drm_rect_width(dst);
> > + int dst_h = drm_rect_height(dst);
> > + int src_w, src_h, temp;
> > + u32 scale_factor_x;
> > + u32 scale_factor_y;
> > + bool enable_scale = false;
> > +
> > + src_w = drm_rect_width(src) >> 16;
> > + src_h = drm_rect_height(src) >> 16;
> > +
> > + if (drm_rotation_90_or_270(rotation)) {
> > + temp = src_w;
> > + src_w = src_h;
> > + src_h = temp;
> > + }
> > +
> > + if (src_w != dst_w) {
> > + scale_factor_x = calc_factor(src_w, dst_w);
> > + enable_scale = true;
> > + } else {
> > + scale_factor_x = 1 << 16;
> > + }
> > + if (src_h != dst_h) {
> > + scale_factor_y = calc_factor(src_h, dst_h);
> > + enable_scale = true;
> > + } else {
> > + scale_factor_y = 1 << 16;
> > + }
> > + if (enable_scale) {
> > + dc_write(hw, hw->reg[id].scale_factor_x + offset, scale_factor_x);
> > + dc_write(hw, hw->reg[id].scale_factor_y + offset, scale_factor_y);
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
> PRIMARY_SCALE_EN, 0);
> > + else
> > + dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset,
> OVERLAY_SCALE_EN, 0);
> > + } else {
> > + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> > + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, 0,
> PRIMARY_SCALE_EN);
> > + else
> > + dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset, 0,
> OVERLAY_SCALE_EN);
> > + }
> > +
> > + dc_write(hw, hw->reg[id].top_left + offset, X_POS(dst->x1) |
> Y_POS(dst->y1));
> > + dc_write(hw, hw->reg[id].bottom_right + offset, X_POS(dst->x2) |
> Y_POS(dst->y2));
> > +}
> > +
> > +void plane_hw_update_blend(struct vs_dc *dc, u16 alpha,
> > + u16 pixel_blend_mode, u8 id, u8 display_id)
> > +{
> > + u32 offset = dc->planes[id].offset;
> > + struct dc_hw *hw = &dc->hw;
> > +
> > + dc_write(hw, hw->reg[id].src_global_color + offset,
> PRIMARY_ALPHA_LEN(alpha >> 8));
> > + dc_write(hw, hw->reg[id].dst_global_color + offset,
> PRIMARY_ALPHA_LEN(alpha >> 8));
> > + switch (pixel_blend_mode) {
> > + case DRM_MODE_BLEND_PREMULTI:
> > + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_PREMULTI);
> > + break;
> > + case DRM_MODE_BLEND_COVERAGE:
> > + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_COVERAGE);
> > + break;
> > + case DRM_MODE_BLEND_PIXEL_NONE:
> > + dc_write(hw, hw->reg[id].blend_config + offset,
> BLEND_PIXEL_NONE);
> > + break;
> > + default:
> > + break;
> > + }
> > +}
> > diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> > new file mode 100644
> > index 000000000000..63d8d153f57f
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> > @@ -0,0 +1,493 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_DC_HW_H__
> > +#define __VS_DC_HW_H__
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/bits.h>
> > +#include <drm/drm_atomic.h>
> > +
> > +#include "vs_type.h"
> > +
> > +#define UPDATE(x, h, l) FIELD_PREP(GENMASK(h, l), x)
> > +
> > +#define AQ_INTR_ACKNOWLEDGE 0x0010
> > +#define AQ_INTR_ENBL 0x0014
> > +#define DC_HW_REVISION 0x0024
> > +#define DC_HW_CHIP_CID 0x0030
> > +
> > +#define DC_REG_BASE 0x0800
> > +#define DC_REG_RANGE 0x2000
> > +#define DC_SEC_REG_OFFSET 0x100000
> > +
> > +#define DC_FRAMEBUFFER_CONFIG 0x1518
> > +# define PRIMARY_FORMAT(x) ((x) << 26)
> > +# define PRIMARY_FORMAT_MASK GENMASK(31, 26)
> > +# define PRIMARY_UV_SWIZ(x) ((x) << 25)
> > +# define PRIMARY_UV_SWIZ_MASK GENMASK(25, 25)
> > +# define PRIMARY_SWIZ(x) ((x) << 23)
> > +# define PRIMARY_SWIZ_MASK GENMASK(24, 23)
> > +# define PRIMARY_SCALE_EN BIT(12)
> > +# define PRIMARY_TILE(x) ((x) << 17)
> > +# define PRIMARY_TILE_MASK GENMASK(21, 17)
> > +# define PRIMARY_YUV_COLOR(x) ((x) << 14)
> > +# define PRIMARY_YUV_COLOR_MASK GENMASK(16, 14)
> > +# define PRIMARY_ROTATION(x) ((x) << 11)
> > +# define PRIMARY_ROTATION_MASK GENMASK(13, 11)
> > +# define PRIMARY_CLEAR_EN(x) ((x) << 8)
> > +# define PRIMARY_CLEAR_EN_MASK GENMASK(8, 8)
> > +
> > +#define DC_FRAMEBUFFER_CONFIG_EX 0x1CC0
> > +# define PRIMARY_CHANNEL(x) ((x) << 19)
> > +# define PRIMARY_CHANNEL_MASK GENMASK(19, 19)
> > +# define PRIMARY_ZPOS(x) ((x) << 16)
> > +# define PRIMARY_ZPOS_MASK GENMASK(18, 16)
> > +# define PRIMARY_EN(x) ((x) << 13)
> > +# define PRIMARY_EN_MASK GENMASK(13, 13)
> > +# define PRIMARY_SHADOW_EN BIT(12)
> > +# define PRIMARY_YUVCLAMP_EN BIT(8)
> > +# define PRIMARY_RGB2RGB_EN BIT(6)
> > +# define PRIMARY_SYNC1_EN BIT(4)
> > +# define PRIMARY_SYNC0_EN BIT(3)
> > +# define PRIMARY_DECODER_EN(x) ((x) << 1)
> > +# define PRIMARY_DECODER_EN_EN_MASK GENMASK(1, 1)
> > +
> > +#define DC_FRAMEBUFFER_SCALE_CONFIG 0x1520
> > +#define DC_FRAMEBUFFER_TOP_LEFT 0x24D8
> > +#define X_POS(x) (x)
> > +#define Y_POS(x) ((x) << 15)
> > +
> > +#define DC_FRAMEBUFFER_BOTTOM_RIGHT 0x24E0
> > +#define DC_FRAMEBUFFER_ADDRESS 0x1400
> > +#define DC_FRAMEBUFFER_U_ADDRESS 0x1530
> > +#define DC_FRAMEBUFFER_V_ADDRESS 0x1538
> > +#define DC_FRAMEBUFFER_STRIDE 0x1408
> > +#define DC_FRAMEBUFFER_U_STRIDE 0x1800
> > +#define DC_FRAMEBUFFER_V_STRIDE 0x1808
> > +#define DC_FRAMEBUFFER_SIZE 0x1810
> > +#define FB_SIZE(w, h) ((w) | ((h) << 15))
> > +
> > +#define DC_FRAMEBUFFER_SCALE_FACTOR_X 0x1828
> > +#define DC_FRAMEBUFFER_SCALE_FACTOR_Y 0x1830
> > +#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX 0x1838
> > +#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA 0x1A00
> > +#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX 0x1A08
> > +#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA 0x1A10
> > +#define DC_FRAMEBUFFER_INIT_OFFSET 0x1A20
> > +#define DC_FRAMEBUFFER_COLOR_KEY 0x1508
> > +#define DC_FRAMEBUFFER_COLOR_KEY_HIGH 0x1510
> > +#define DC_FRAMEBUFFER_CLEAR_VALUE 0x1A18
> > +#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX 0x1818
> > +#define DC_FRAMEBUFFER_COLOR_TABLE_DATA 0x1820
> > +#define DC_FRAMEBUFFER_BG_COLOR 0x1528
> > +#define DC_FRAMEBUFFER_ROI_ORIGIN 0x1CB0
> > +#define DC_FRAMEBUFFER_ROI_SIZE 0x1CB8
> > +#define DC_FRAMEBUFFER_WATER_MARK 0x1CE8
> > +#define DC_FRAMEBUFFER_DEGAMMA_INDEX 0x1D88
> > +#define DC_FRAMEBUFFER_DEGAMMA_DATA 0x1D90
> > +#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA 0x1D98
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEF0 0x1DA0
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEF1 0x1DA8
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEF2 0x1DB0
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEF3 0x1DB8
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEF4 0x1E00
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEFD0 0x1E08
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEFD1 0x1E10
> > +#define DC_FRAMEBUFFER_YUVTORGB_COEFD2 0x1E18
> > +#define DC_FRAMEBUFFER_Y_CLAMP_BOUND 0x1E88
> > +#define DC_FRAMEBUFFER_UV_CLAMP_BOUND 0x1E90
> > +#define DC_FRAMEBUFFER_RGBTORGB_COEF0 0x1E20
> > +#define DC_FRAMEBUFFER_RGBTORGB_COEF1 0x1E28
> > +#define DC_FRAMEBUFFER_RGBTORGB_COEF2 0x1E30
> > +#define DC_FRAMEBUFFER_RGBTORGB_COEF3 0x1E38
> > +#define DC_FRAMEBUFFER_RGBTORGB_COEF4 0x1E40
> > +#define DC_FRAMEBUFFER_BLEND_CONFIG 0x2510
> > +# define BLEND_PREMULTI 0x3450
> > +# define BLEND_COVERAGE 0x3950
> > +# define BLEND_PIXEL_NONE 0x3548
> > +
> > +#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR 0x2500
> > +# define PRIMARY_ALPHA_LEN(x) ((x) << 24)
> > +
> > +#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR 0x2508
> > +
> > +#define DC_OVERLAY_CONFIG 0x1540
> > +# define OVERLAY_SHADOW_EN BIT(31)
> > +# define OVERLAY_CLAMP_EN BIT(30)
> > +# define OVERLAY_RGB2RGB_EN BIT(29)
> > +# define OVERLAY_DEC_EN(x) ((x) << 27)
> > +# define OVERLAY_DEC_EN_MASK GENMASK(27, 27)
> > +# define OVERLAY_CLEAR_EN(x) ((x) << 25)
> > +# define OVERLAY_CLEAR_EN_MASK GENMASK(25, 25)
> > +# define OVERLAY_FB_EN(x) ((x) << 24)
> > +# define OVERLAY_FB_EN_MASK GENMASK(24, 24)
> > +# define OVERLAY_FORMAT(x) ((x) << 16)
> > +# define OVERLAY_FORMAT_MASK GENMASK(21, 16)
> > +# define OVERLAY_UV_SWIZ(x) ((x) << 15)
> > +# define OVERLAY_UV_SWIZ_MASK GENMASK(15, 15)
> > +# define OVERLAY_SWIZ(x) ((x) << 13)
> > +# define OVERLAY_SWIZ_MASK GENMASK(14, 13)
> > +# define OVERLAY_TILE(x) ((x) << 8)
> > +# define OVERLAY_TILE_MASK GENMASK(12, 8)
> > +# define OVERLAY_YUV_COLOR(x) ((x) << 5)
> > +# define OVERLAY_YUV_COLOR_MASK GENMASK(7, 5)
> > +# define OVERLAY_ROTATION(x) ((x) << 2)
> > +# define OVERLAY_ROTATION_MASK GENMASK(4, 2)
> > +
> > +#define DC_OVERLAY_CONFIG_EX 0x2540
> > +# define OVERLAY_LAYER_SEL(x) ((x) << 0)
> > +# define OVERLAY_LAYER_SEL_MASK GENMASK(2, 0)
> > +# define OVERLAY_PANEL_SEL(x) ((x) << 3)
> > +# define OVERLAY_PANEL_SEL_MASK GENMASK(3, 3)
> > +
> > +#define DC_OVERLAY_SCALE_CONFIG 0x1C00
> > +# define OVERLAY_SCALE_EN BIT(8)
> > +
> > +#define DC_OVERLAY_BLEND_CONFIG 0x1580
> > +#define DC_OVERLAY_TOP_LEFT 0x1640
> > +#define DC_OVERLAY_BOTTOM_RIGHT 0x1680
> > +#define DC_OVERLAY_ADDRESS 0x15C0
> > +#define DC_OVERLAY_U_ADDRESS 0x1840
> > +#define DC_OVERLAY_V_ADDRESS 0x1880
> > +#define DC_OVERLAY_STRIDE 0x1600
> > +#define DC_OVERLAY_U_STRIDE 0x18C0
> > +#define DC_OVERLAY_V_STRIDE 0x1900
> > +#define DC_OVERLAY_SIZE 0x17C0
> > +#define DC_OVERLAY_SCALE_FACTOR_X 0x1A40
> > +#define DC_OVERLAY_SCALE_FACTOR_Y 0x1A80
> > +#define DC_OVERLAY_H_FILTER_COEF_INDEX 0x1AC0
> > +#define DC_OVERLAY_H_FILTER_COEF_DATA 0x1B00
> > +#define DC_OVERLAY_V_FILTER_COEF_INDEX 0x1B40
> > +#define DC_OVERLAY_V_FILTER_COEF_DATA 0x1B80
> > +#define DC_OVERLAY_INIT_OFFSET 0x1BC0
> > +#define DC_OVERLAY_COLOR_KEY 0x1740
> > +#define DC_OVERLAY_COLOR_KEY_HIGH 0x1780
> > +#define DC_OVERLAY_CLEAR_VALUE 0x1940
> > +#define DC_OVERLAY_COLOR_TABLE_INDEX 0x1980
> > +#define DC_OVERLAY_COLOR_TABLE_DATA 0x19C0
> > +#define DC_OVERLAY_SRC_GLOBAL_COLOR 0x16C0
> > +# define OVERLAY_ALPHA_LEN(x) ((x) << 24)
> > +
> > +#define DC_OVERLAY_DST_GLOBAL_COLOR 0x1700
> > +#define DC_OVERLAY_ROI_ORIGIN 0x1D00
> > +#define DC_OVERLAY_ROI_SIZE 0x1D40
> > +#define DC_OVERLAY_WATER_MARK 0x1DC0
> > +#define DC_OVERLAY_DEGAMMA_INDEX 0x2200
> > +#define DC_OVERLAY_DEGAMMA_DATA 0x2240
> > +#define DC_OVERLAY_DEGAMMA_EX_DATA 0x2280
> > +#define DC_OVERLAY_YUVTORGB_COEF0 0x1EC0
> > +#define DC_OVERLAY_YUVTORGB_COEF1 0x1F00
> > +#define DC_OVERLAY_YUVTORGB_COEF2 0x1F40
> > +#define DC_OVERLAY_YUVTORGB_COEF3 0x1F80
> > +#define DC_OVERLAY_YUVTORGB_COEF4 0x1FC0
> > +#define DC_OVERLAY_YUVTORGB_COEFD0 0x2000
> > +#define DC_OVERLAY_YUVTORGB_COEFD1 0x2040
> > +#define DC_OVERLAY_YUVTORGB_COEFD2 0x2080
> > +#define DC_OVERLAY_Y_CLAMP_BOUND 0x22C0
> > +#define DC_OVERLAY_UV_CLAMP_BOUND 0x2300
> > +#define DC_OVERLAY_RGBTORGB_COEF0 0x20C0
> > +#define DC_OVERLAY_RGBTORGB_COEF1 0x2100
> > +#define DC_OVERLAY_RGBTORGB_COEF2 0x2140
> > +#define DC_OVERLAY_RGBTORGB_COEF3 0x2180
> > +#define DC_OVERLAY_RGBTORGB_COEF4 0x21C0
> > +
> > +#define DC_CURSOR_CONFIG 0x1468
> > +# define CURSOR_HOT_X(x) ((x) << 16)
> > +# define CURSOR_HOT_X_MASK GENMASK(23, 16)
> > +# define CURSOR_HOT_y(x) ((x) << 8)
> > +# define CURSOR_HOT_y_MASK GENMASK(15, 8)
> > +# define CURSOR_SIZE(x) ((x) << 5)
> > +# define CURSOR_SIZE_MASK GENMASK(7, 5)
> > +# define CURSOR_VALID(x) ((x) << 3)
> > +# define CURSOR_VALID_MASK GENMASK(3, 3)
> > +# define CURSOR_TRIG_FETCH(x) ((x) << 2)
> > +# define CURSOR_TRIG_FETCH_MASK GENMASK(2, 2)
> > +# define CURSOR_FORMAT(x) ((x) << 0)
> > +# define CURSOR_FORMAT_MASK GENMASK(1, 0)
> > +# define CURSOR_FORMAT_DISABLE 0
> > +# define CURSOR_FORMAT_MARK 1
> > +# define CURSOR_FORMAT_A8R8G8B8 2
> > +
> > +#define DC_CURSOR_ADDRESS 0x146C
> > +#define DC_CURSOR_LOCATION 0x1470
> > +# define X_LCOTION(x) (x)
> > +# define Y_LCOTION(x) ((x) << 16)
> > +
> > +#define DC_CURSOR_BACKGROUND 0x1474
> > +#define DC_CURSOR_FOREGROUND 0x1478
> > +#define DC_CURSOR_CLK_GATING 0x1484
> > +#define DC_CURSOR_CONFIG_EX 0x24E8
> > +#define DC_CURSOR_OFFSET 0x1080
> > +
> > +#define DC_DISPLAY_DITHER_CONFIG 0x1410
> > +#define DC_DISPLAY_PANEL_CONFIG 0x1418
> > +# define PANEL_RGB2YUV_EN BIT(16)
> > +# define PANEL_GAMMA_EN BIT(13)
> > +# define PANEL_OUTPUT_EN BIT(12)
> > +
> > +#define DC_DISPLAY_PANEL_CONFIG_EX 0x2518
> > +# define PANEL_SHADOW_EN BIT(0)
> > +
> > +#define DC_DISPLAY_DITHER_TABLE_LOW 0x1420
> > +#define DC_DISPLAY_DITHER_TABLE_HIGH 0x1428
> > +#define DC_DISPLAY_H 0x1430
> > +# define H_ACTIVE_LEN(x) (x)
> > +# define H_TOTAL_LEN(x) ((x) << 16)
> > +
> > +#define DC_DISPLAY_H_SYNC 0x1438
> > +# define H_SYNC_START_LEN(x) (x)
> > +# define H_SYNC_END_LEN(x) ((x) << 15)
> > +# define H_PLUS_LEN(x) ((x) << 30)
> > +# define H_POLARITY_LEN(x) ((x) << 31)
> > +
> > +#define DC_DISPLAY_V 0x1440
> > +# define V_ACTIVE_LEN(x) (x)
> > +# define V_TOTAL_LEN(x) ((x) << 16)
> > +
> > +#define DC_DISPLAY_V_SYNC 0x1448
> > +# define V_SYNC_START_LEN(x) (x)
> > +# define V_SYNC_END_LEN(x) ((x) << 15)
> > +# define V_PLUS_LEN(x) ((x) << 30)
> > +# define V_POLARITY_LEN(x) ((x) << 31)
> > +
> > +#define DC_DISPLAY_CURRENT_LOCATION 0x1450
> > +#define DC_DISPLAY_GAMMA_INDEX 0x1458
> > +#define DC_DISPLAY_GAMMA_DATA 0x1460
> > +#define DC_DISPLAY_INT 0x147C
> > +#define DC_DISPLAY_INT_ENABLE 0x1480
> > +#define DC_DISPLAY_DBI_CONFIG 0x1488
> > +#define DC_DISPLAY_GENERAL_CONFIG 0x14B0
> > +#define DC_DISPLAY_DPI_CONFIG 0x14B8
> > +#define DC_DISPLAY_PANEL_START 0x1CCC
> > +# define PANEL0_EN BIT(0)
> > +# define PANEL1_EN BIT(1)
> > +# define TWO_PANEL_EN BIT(2)
> > +# define SYNC_EN BIT(3)
> > +
> > +#define DC_DISPLAY_DEBUG_COUNTER_SELECT 0x14D0
> > +#define DC_DISPLAY_DEBUG_COUNTER_VALUE 0x14D8
> > +#define DC_DISPLAY_DP_CONFIG 0x1CD0
> > +# define DP_SELECT BIT(3)
> > +
> > +#define DC_DISPLAY_GAMMA_EX_INDEX 0x1CF0
> > +#define DC_DISPLAY_GAMMA_EX_DATA 0x1CF8
> > +#define DC_DISPLAY_GAMMA_EX_ONE_DATA 0x1D80
> > +#define DC_DISPLAY_RGBTOYUV_COEF0 0x1E48
> > +#define DC_DISPLAY_RGBTOYUV_COEF1 0x1E50
> > +#define DC_DISPLAY_RGBTOYUV_COEF2 0x1E58
> > +#define DC_DISPLAY_RGBTOYUV_COEF3 0x1E60
> > +#define DC_DISPLAY_RGBTOYUV_COEF4 0x1E68
> > +#define DC_DISPLAY_RGBTOYUV_COEFD0 0x1E70
> > +#define DC_DISPLAY_RGBTOYUV_COEFD1 0x1E78
> > +#define DC_DISPLAY_RGBTOYUV_COEFD2 0x1E80
> > +
> > +#define DC_CLK_GATTING 0x1A28
> > +#define DC_QOS_CONFIG 0x1A38
> > +
> > +#define DC_TRANSPARENCY_OPAQUE 0x00
> > +#define DC_TRANSPARENCY_KEY 0x02
> > +#define DC_DISPLAY_DITHERTABLE_LOW 0x7B48F3C0
> > +#define DC_DISPLAY_DITHERTABLE_HIGH 0x596AD1E2
> > +
> > +#define DC_TILE_MODE4X4 0x15
> > +
> > +#define GAMMA_SIZE 256
> > +#define GAMMA_EX_SIZE 300
> > +#define DEGAMMA_SIZE 260
> > +
> > +#define RGB_TO_RGB_TABLE_SIZE 9
> > +#define YUV_TO_RGB_TABLE_SIZE 16
> > +#define RGB_TO_YUV_TABLE_SIZE 12
> > +
> > +#define DC_LAYER_NUM 6
> > +#define DC_DISPLAY_NUM 2
> > +#define DC_CURSOR_NUM 2
> > +
> > +enum dc_hw_plane_id {
> > + PRIMARY_PLANE_0,
> > + OVERLAY_PLANE_0,
> > + OVERLAY_PLANE_1,
> > + PRIMARY_PLANE_1,
> > + OVERLAY_PLANE_2,
> > + OVERLAY_PLANE_3,
> > + CURSOR_PLANE_0,
> > + CURSOR_PLANE_1,
> > + PLANE_NUM
> > +};
> > +
> > +enum dc_hw_color_format {
> > + FORMAT_X4R4G4B4,
> > + FORMAT_A4R4G4B4,
> > + FORMAT_X1R5G5B5,
> > + FORMAT_A1R5G5B5,
> > + FORMAT_R5G6B5,
> > + FORMAT_X8R8G8B8,
> > + FORMAT_A8R8G8B8,
> > + FORMAT_YUY2,
> > + FORMAT_UYVY,
> > + FORMAT_INDEX8,
> > + FORMAT_MONOCHROME,
> > + FORMAT_YV12 = 0xf,
> > + FORMAT_A8,
> > + FORMAT_NV12,
> > + FORMAT_NV16,
> > + FORMAT_RG16,
> > + FORMAT_R8,
> > + FORMAT_NV12_10BIT,
> > + FORMAT_A2R10G10B10,
> > + FORMAT_NV16_10BIT,
> > + FORMAT_INDEX1,
> > + FORMAT_INDEX2,
> > + FORMAT_INDEX4,
> > + FORMAT_P010,
> > + FORMAT_YUV444,
> > + FORMAT_YUV444_10BIT,
> > +};
> > +
> > +enum dc_hw_yuv_color_space {
> > + COLOR_SPACE_601 = 0,
> > + COLOR_SPACE_709 = 1,
> > + COLOR_SPACE_2020 = 3,
> > +};
> > +
> > +enum dc_hw_rotation {
> > + ROT_0 = 0,
> > + ROT_90 = 4,
> > + ROT_180 = 5,
> > + ROT_270 = 6,
> > + FLIP_X = 1,
> > + FLIP_Y = 2,
> > + FLIP_XY = 3,
> > +};
> > +
> > +enum dc_hw_swizzle {
> > + SWIZZLE_ARGB = 0,
> > + SWIZZLE_RGBA,
> > + SWIZZLE_ABGR,
> > + SWIZZLE_BGRA,
> > +};
> > +
> > +enum dc_hw_out {
> > + OUT_DPI,
> > + OUT_DP,
> > +};
> > +
> > +enum dc_hw_cursor_size {
> > + CURSOR_SIZE_32X32 = 0,
> > + CURSOR_SIZE_64X64,
> > +};
> > +
> > +struct dc_hw_plane_reg {
> > + u32 y_address;
> > + u32 u_address;
> > + u32 v_address;
> > + u32 y_stride;
> > + u32 u_stride;
> > + u32 v_stride;
> > + u32 size;
> > + u32 top_left;
> > + u32 bottom_right;
> > + u32 scale_factor_x;
> > + u32 scale_factor_y;
> > + u32 h_filter_coef_index;
> > + u32 h_filter_coef_data;
> > + u32 v_filter_coef_index;
> > + u32 v_filter_coef_data;
> > + u32 init_offset;
> > + u32 color_key;
> > + u32 color_key_high;
> > + u32 clear_value;
> > + u32 color_table_index;
> > + u32 color_table_data;
> > + u32 scale_config;
> > + u32 water_mark;
> > + u32 degamma_index;
> > + u32 degamma_data;
> > + u32 degamma_ex_data;
> > + u32 src_global_color;
> > + u32 dst_global_color;
> > + u32 blend_config;
> > + u32 roi_origin;
> > + u32 roi_size;
> > + u32 yuv_to_rgb_coef0;
> > + u32 yuv_to_rgb_coef1;
> > + u32 yuv_to_rgb_coef2;
> > + u32 yuv_to_rgb_coef3;
> > + u32 yuv_to_rgb_coef4;
> > + u32 yuv_to_rgb_coefd0;
> > + u32 yuv_to_rgb_coefd1;
> > + u32 yuv_to_rgb_coefd2;
> > + u32 y_clamp_bound;
> > + u32 uv_clamp_bound;
> > + u32 rgb_to_rgb_coef0;
> > + u32 rgb_to_rgb_coef1;
> > + u32 rgb_to_rgb_coef2;
> > + u32 rgb_to_rgb_coef3;
> > + u32 rgb_to_rgb_coef4;
> > +};
> > +
> > +struct dc_hw_gamma {
> > + u16 gamma[GAMMA_EX_SIZE][3];
> > +};
> > +
> > +struct dc_hw_read {
>
> Not used, please drop.
Will delete it
>
> > + u32 reg;
> > + u32 value;
> > +};
> > +
> > +struct dc_hw {
> > + enum dc_hw_out out[DC_DISPLAY_NUM];
> > + void *hi_base;
> > + void *reg_base;
> > + struct dc_hw_plane_reg reg[DC_LAYER_NUM];
> > +
> > + struct dc_hw_gamma gamma[DC_DISPLAY_NUM];
> > + struct vs_dc_info *info;
> > +};
> > +
> > +struct vs_dc_plane {
> > + enum dc_hw_plane_id id;
> > + u32 offset;
> > +};
> > +
> > +struct vs_dc {
> > + struct vs_crtc *crtc[DC_DISPLAY_NUM];
>
> Not defined here. Please drop and add when it is actually defined.
>
> > + struct dc_hw hw;
> > +
> > + struct vs_dc_plane planes[PLANE_NUM];
> > +};
> > +
> > +int dc_hw_init(struct vs_dc *dc);
> > +void dc_hw_disable_plane(struct vs_dc *dc, u8 id);
> > +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr,
> > + u32 crtc_w, u32 crtc_x, u32 crtc_y,
> > + s32 hotspot_x, int32_t hotspot_y);
> > +void dc_hw_disable_cursor(struct dc_hw *hw, u8 id);
> > +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> > + u16 r, u16 g, u16 b);
> > +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
> > +void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode
> *mode,
> > + u8 encoder_type, u32 output_fmt);
> > +void dc_hw_disable(struct dc_hw *hw, int id);
> > +void dc_hw_enable_interrupt(struct dc_hw *hw);
> > +void dc_hw_disable_interrupt(struct dc_hw *hw);
> > +u32 dc_hw_get_interrupt(struct dc_hw *hw);
> > +void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable);
> > +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
> > +void dc_hw_commit(struct dc_hw *hw);
> > +void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format,
> > + enum drm_color_encoding encoding, u8 id, bool
> is_yuv);
> > +void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format,
> dma_addr_t *dma_addr,
> > + struct drm_framebuffer *drm_fb, struct drm_rect *src);
> > +void plane_hw_update_format(struct vs_dc *dc, u32 format, enum
> drm_color_encoding encoding,
> > + unsigned int rotation, bool visible, unsigned int zpos,
> > + u8 id, u8 display_id);
> > +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct
> drm_rect *dst,
> > + u8 id, u8 display_id, unsigned int rotation);
> > +void plane_hw_update_blend(struct vs_dc *dc, u16 alpha, u16
> pixel_blend_mode,
> > + u8 id, u8 display_id);
>
> Could you please settle on a single prefix for all your function names?
> Ideally it should be close to the driver name. It's hard to understand
> that the function comes from the verisilicon driver if its name starts
> from dc_ or especially with plane_.
Yes starting with plane_ is not a good idea ,i will add vs_
_ , thanks
>
> I'd strongly suggest to stop defining anything outside of the selected
I don't quite understand what "the selected" means,
I hope you can fill in some specific details about it
Thanks
> vs_ namespace.
>
> > +
> > +#endif /* __VS_DC_HW_H__ */
> > diff --git a/drivers/gpu/drm/verisilicon/vs_type.h
> b/drivers/gpu/drm/verisilicon/vs_type.h
> > new file mode 100644
> > index 000000000000..30ccc2eda48b
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_type.h
> > @@ -0,0 +1,84 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_TYPE_H__
> > +#define __VS_TYPE_H__
> > +
> > +#include <drm/drm_plane.h>
>
> These types are largely unused within this patch. Please drop all the
> unused parts and add them later, when required.
Yes some types could be added in later patches
Thank you for your correction.
>
> > +
> > +struct vs_plane_primary_info {
> > + u8 id;
> > + unsigned int num_formats;
> > + const u32 *formats;
> > + u8 num_modifiers;
> > + const u64 *modifiers;
> > + unsigned int min_width;
> > + unsigned int min_height;
> > + unsigned int max_width;
> > + unsigned int max_height;
> > + unsigned int rotation;
> > + unsigned int color_encoding;
> > +
> > + int min_scale; /* 16.16 fixed point */
> > + int max_scale; /* 16.16 fixed point */
> > +
> > + u8 zpos;
> > +
> > +};
> > +
> > +struct vs_plane_overlay_info {
> > + u8 id;
> > + unsigned int num_formats;
> > + const u32 *formats;
> > + u8 num_modifiers;
> > + const u64 *modifiers;
> > + unsigned int min_width;
> > + unsigned int min_height;
> > + unsigned int max_width;
> > + unsigned int max_height;
> > + unsigned int rotation;
> > + unsigned int color_encoding;
> > +
> > + int min_scale; /* 16.16 fixed point */
> > + int max_scale; /* 16.16 fixed point */
> > +
> > + u8 zpos;
> > +
> > +};
> > +
> > +struct vs_plane_cursor_info {
> > + u8 id;
> > + unsigned int num_formats;
> > + const u32 *formats;
> > + unsigned int min_width;
> > + unsigned int min_height;
> > + unsigned int max_width;
> > + unsigned int max_height;
> > + u8 zpos;
> > +
> > +};
> > +
> > +struct vs_dc_info {
> > + const char *name;
> > +
> > + u8 panel_num;
> > +
> > + /* planes */
> > + u8 layer_num;
> > + u8 primary_num;
> > + u8 overlay_num;
> > + u8 cursor_num;
> > + const struct vs_plane_primary_info *primary;
> > + const struct vs_plane_overlay_info *overlay;
> > + const struct vs_plane_cursor_info *cursor;
> > +
> > + /* 0 means no gamma LUT */
> > + u16 gamma_size;
> > + u8 gamma_bits;
> > +
> > + u16 pitch_alignment;
> > +};
> > +
> > +#endif /* __VS_TYPE_H__ */
> > --
> > 2.27.0
> >
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 08/10] drm/vs: add vs drm master driver
2024-05-21 21:14 ` Dmitry Baryshkov
@ 2024-06-23 7:16 ` Keith Zhao
2024-06-23 21:07 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-23 7:16 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Dmitry:
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年5月22日 5:14
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 08/10] drm/vs: add vs drm master driver
>
> On Tue, May 21, 2024 at 06:58:15PM +0800, keith wrote:
> > Add vs DRM master driver for JH7110 SoC ADD DMA GEM driver
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > ---
> > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > drivers/gpu/drm/verisilicon/vs_drv.c | 718
> > +++++++++++++++++++++++++++
> > 2 files changed, 720 insertions(+), 1 deletion(-) create mode 100644
> > drivers/gpu/drm/verisilicon/vs_drv.c
> >
> > diff --git a/drivers/gpu/drm/verisilicon/Makefile
> > b/drivers/gpu/drm/verisilicon/Makefile
> > index 26a43ca0fd36..88a07a308e31 100644
> > --- a/drivers/gpu/drm/verisilicon/Makefile
> > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > @@ -3,6 +3,7 @@
> > vs_drm-objs := vs_dc_hw.o \
> > vs_modeset.o \
> > vs_plane.o \
> > - vs_crtc.o
> > + vs_crtc.o \
> > + vs_drv.o
> >
> > obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git
> > a/drivers/gpu/drm/verisilicon/vs_drv.c
> > b/drivers/gpu/drm/verisilicon/vs_drv.c
> > new file mode 100644
> > index 000000000000..c22fd2199fe2
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> > @@ -0,0 +1,718 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +#include <linux/clk.h>
> > +#include <linux/component.h>
> > +#include <linux/of_clk.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/of_device.h>
> > +
> > +#include <drm/drm_aperture.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_crtc.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <drm/drm_fb_helper.h>
> > +#include <drm/drm_fbdev_generic.h>
> > +#include <drm/drm_file.h>
> > +#include <drm/drm_gem_dma_helper.h>
> > +#include <drm/drm_module.h>
> > +#include <drm/drm_of.h>
> > +#include <drm/drm_probe_helper.h>
> > +#include <drm/drm_vblank.h>
> > +#include <drm/drm_blend.h>
> > +
> > +#include "vs_drv.h"
> > +#include "vs_crtc.h"
> > +#include "vs_plane.h"
> > +#include "vs_modeset.h"
> > +
> > +#define DRV_NAME "verisilicon"
> > +#define DRV_DESC "Verisilicon DRM driver"
> > +#define DRV_DATE "20230516"
> > +#define DRV_MAJOR 1
> > +#define DRV_MINOR 0
> > +
> > +#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
> > +
> > +static const u32 primary_overlay_format[] = {
> > + DRM_FORMAT_RGB565,
> > + DRM_FORMAT_BGR565,
> > + DRM_FORMAT_XRGB8888,
> > + DRM_FORMAT_XBGR8888,
> > + DRM_FORMAT_RGBX8888,
> > + DRM_FORMAT_BGRX8888,
> > + DRM_FORMAT_ARGB8888,
> > + DRM_FORMAT_ABGR8888,
> > + DRM_FORMAT_RGBA8888,
> > + DRM_FORMAT_BGRA8888,
> > + DRM_FORMAT_XRGB4444,
> > + DRM_FORMAT_XBGR4444,
> > + DRM_FORMAT_RGBX4444,
> > + DRM_FORMAT_BGRX4444,
> > + DRM_FORMAT_ARGB4444,
> > + DRM_FORMAT_ABGR4444,
> > + DRM_FORMAT_RGBA4444,
> > + DRM_FORMAT_BGRA4444,
> > + DRM_FORMAT_XRGB1555,
> > + DRM_FORMAT_XBGR1555,
> > + DRM_FORMAT_RGBX5551,
> > + DRM_FORMAT_BGRX5551,
> > + DRM_FORMAT_ARGB1555,
> > + DRM_FORMAT_ABGR1555,
> > + DRM_FORMAT_RGBA5551,
> > + DRM_FORMAT_BGRA5551,
> > + DRM_FORMAT_ARGB2101010,
> > + DRM_FORMAT_ABGR2101010,
> > + DRM_FORMAT_RGBA1010102,
> > + DRM_FORMAT_BGRA1010102,
> > + DRM_FORMAT_YUYV,
> > + DRM_FORMAT_YVYU,
> > + DRM_FORMAT_UYVY,
> > + DRM_FORMAT_VYUY,
> > + DRM_FORMAT_YVU420,
> > + DRM_FORMAT_YUV420,
> > + DRM_FORMAT_NV12,
> > + DRM_FORMAT_NV21,
> > + DRM_FORMAT_NV16,
> > + DRM_FORMAT_NV61,
> > + DRM_FORMAT_P010,
> > +};
> > +
> > +static const u32 cursor_formats[] = {
> > + DRM_FORMAT_ARGB8888
> > +};
> > +
> > +static const u64 format_modifier[] = {
> > + DRM_FORMAT_MOD_LINEAR,
> > + DRM_FORMAT_MOD_INVALID
> > +};
> > +
> > +static const u64 secondary_format_modifiers[] = {
> > + DRM_FORMAT_MOD_LINEAR,
> > + DRM_FORMAT_MOD_INVALID
> > +};
> > +
> > +static const struct vs_plane_primary_info dc_hw_planes_primary[2] = {
> > + {
> > + .id = PRIMARY_PLANE_0,
> > + .num_formats = ARRAY_SIZE(primary_overlay_format),
> > + .formats = primary_overlay_format,
> > + .num_modifiers = ARRAY_SIZE(format_modifier),
> > + .modifiers = format_modifier,
> > + .min_width = 0,
> > + .min_height = 0,
> > + .max_width = 4096,
> > + .max_height = 4096,
> > + .min_scale = FRAC_16_16(1, 3),
> > + .max_scale = FRAC_16_16(10, 1),
> > + .rotation = DRM_MODE_ROTATE_0 |
> > + DRM_MODE_ROTATE_90 |
> > + DRM_MODE_ROTATE_180 |
> > + DRM_MODE_ROTATE_270 |
> > + DRM_MODE_REFLECT_X |
> > + DRM_MODE_REFLECT_Y,
> > + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> BIT(DRM_COLOR_YCBCR_BT2020),
> > + .zpos = 0,
>
> How are these zpos related to the zpos from drm_plane_state?
Zpos was added to drm_plane_state by calling drm_plane_create_zpos_property funs,
vs_plane_primary_create
------> drm_plane_create_zpos_property(......vs_plane_primary_info-> zpos )
>
> > + },
> > + {
> > + .id = PRIMARY_PLANE_1,
> > + .num_formats = ARRAY_SIZE(primary_overlay_format),
> > + .formats = primary_overlay_format,
> > + .num_modifiers = ARRAY_SIZE(format_modifier),
> > + .modifiers = format_modifier,
> > + .min_width = 0,
> > + .min_height = 0,
> > + .max_width = 4096,
> > + .max_height = 4096,
> > + .min_scale = FRAC_16_16(1, 3),
> > + .max_scale = FRAC_16_16(10, 1),
> > + .rotation = DRM_MODE_ROTATE_0 |
> > + DRM_MODE_ROTATE_90 |
> > + DRM_MODE_ROTATE_180 |
> > + DRM_MODE_ROTATE_270 |
> > + DRM_MODE_REFLECT_X |
> > + DRM_MODE_REFLECT_Y,
> > + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> BIT(DRM_COLOR_YCBCR_BT2020),
> > + .zpos = 3,
> > + },
> > +};
> > +
> > +static const struct vs_plane_overlay_info dc_hw_planes_overlay[4] = {
> > + {
> > + .id = OVERLAY_PLANE_0,
> > + .num_formats = ARRAY_SIZE(primary_overlay_format),
> > + .formats = primary_overlay_format,
> > + .num_modifiers = ARRAY_SIZE(format_modifier),
> > + .modifiers = format_modifier,
> > + .min_width = 0,
> > + .min_height = 0,
> > + .max_width = 4096,
> > + .max_height = 4096,
> > + .min_scale = FRAC_16_16(1, 3),
> > + .max_scale = FRAC_16_16(10, 1),
> > + .rotation = DRM_MODE_ROTATE_0 |
> > + DRM_MODE_ROTATE_90 |
> > + DRM_MODE_ROTATE_180 |
> > + DRM_MODE_ROTATE_270 |
> > + DRM_MODE_REFLECT_X |
> > + DRM_MODE_REFLECT_Y,
> > + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> BIT(DRM_COLOR_YCBCR_BT2020),
> > + .zpos = 1,
> > + },
> > + {
> > + .id = OVERLAY_PLANE_1,
> > + .num_formats = ARRAY_SIZE(primary_overlay_format),
> > + .formats = primary_overlay_format,
> > + .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> > + .modifiers = secondary_format_modifiers,
> > + .min_width = 0,
> > + .min_height = 0,
> > + .max_width = 4096,
> > + .max_height = 4096,
> > + .min_scale = DRM_PLANE_NO_SCALING,
> > + .max_scale = DRM_PLANE_NO_SCALING,
> > + .rotation = 0,
> > + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> BIT(DRM_COLOR_YCBCR_BT2020),
> > + .zpos = 2,
> > + },
> > + {
> > + .id = OVERLAY_PLANE_2,
> > + .num_formats = ARRAY_SIZE(primary_overlay_format),
> > + .formats = primary_overlay_format,
> > + .num_modifiers = ARRAY_SIZE(format_modifier),
> > + .modifiers = format_modifier,
> > + .min_width = 0,
> > + .min_height = 0,
> > + .max_width = 4096,
> > + .max_height = 4096,
> > + .min_scale = FRAC_16_16(1, 3),
> > + .max_scale = FRAC_16_16(10, 1),
> > + .rotation = DRM_MODE_ROTATE_0 |
> > + DRM_MODE_ROTATE_90 |
> > + DRM_MODE_ROTATE_180 |
> > + DRM_MODE_ROTATE_270 |
> > + DRM_MODE_REFLECT_X |
> > + DRM_MODE_REFLECT_Y,
> > + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> BIT(DRM_COLOR_YCBCR_BT2020),
> > + .zpos = 4,
> > + },
> > + {
> > + .id = OVERLAY_PLANE_3,
> > + .num_formats = ARRAY_SIZE(primary_overlay_format),
> > + .formats = primary_overlay_format,
> > + .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> > + .modifiers = secondary_format_modifiers,
> > + .min_width = 0,
> > + .min_height = 0,
> > + .max_width = 4096,
> > + .max_height = 4096,
> > + .min_scale = DRM_PLANE_NO_SCALING,
> > + .max_scale = DRM_PLANE_NO_SCALING,
> > + .rotation = 0,
> > + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> BIT(DRM_COLOR_YCBCR_BT2020),
> > + .zpos = 5,
> > + },
> > +};
> > +
> > +static const struct vs_plane_cursor_info dc_hw_planes_cursor[2] = {
> > + {
> > + .id = CURSOR_PLANE_0,
> > + .num_formats = ARRAY_SIZE(cursor_formats),
> > + .formats = cursor_formats,
> > + .min_width = 32,
> > + .min_height = 32,
> > + .max_width = 64,
> > + .max_height = 64,
> > + .zpos = 255,
> > + },
> > + {
> > + .id = CURSOR_PLANE_1,
> > + .num_formats = ARRAY_SIZE(cursor_formats),
> > + .formats = cursor_formats,
> > + .min_width = 32,
> > + .min_height = 32,
> > + .max_width = 64,
> > + .max_height = 64,
> > + .zpos = 255,
> > + },
> > +};
> > +
> > +static const struct vs_dc_info dc8200_info = {
> > + .name = "DC8200",
> > + .panel_num = 2,
> > + .primary_num = 2,
> > + .overlay_num = 4,
> > + .cursor_num = 2,
>
> ARRAY_SIZE would have been better.
>
> > + .primary = dc_hw_planes_primary,
> > + .overlay = dc_hw_planes_overlay,
> > + .cursor = dc_hw_planes_cursor,
> > + .layer_num = 6,
> > + .gamma_size = GAMMA_EX_SIZE,
> > + .gamma_bits = 12,
> > + .pitch_alignment = 128,
> > +};
> > +
> > +static int vs_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
> > + struct drm_mode_create_dumb *args) {
> > + struct vs_drm_device *priv = to_vs_drm_private(dev);
> > + unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
> > +
> > + args->pitch = ALIGN(pitch, priv->pitch_alignment);
> > + return drm_gem_dma_dumb_create_internal(file, dev, args); }
> > +
> > +DEFINE_DRM_GEM_FOPS(vs_drm_fops);
> > +
> > +static struct drm_driver vs_drm_driver = {
> > + .driver_features = DRIVER_MODESET | DRIVER_ATOMIC |
> DRIVER_GEM,
> > +
> > +
> DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vs_gem_dumb_cr
> eate),
> > +
> > + .fops = &vs_drm_fops,
> > + .name = DRV_NAME,
> > + .desc = DRV_DESC,
> > + .date = DRV_DATE,
> > + .major = DRV_MAJOR,
> > + .minor = DRV_MINOR,
> > +};
> > +
> > +static irqreturn_t vs_dc_isr(int irq, void *data) {
> > + struct vs_drm_device *priv = data;
> > + struct vs_dc *dc = &priv->dc;
> > + struct vs_dc_info *dc_info = dc->hw.info;
> > + u32 i;
> > +
> > + dc_hw_get_interrupt(&dc->hw);
> > +
> > + for (i = 0; i < dc_info->panel_num; i++)
> > + drm_crtc_handle_vblank(&dc->crtc[i]->base);
>
> Is it true that all CRTCs have vblank at the same time?
Thanks for pointing out the error
In fact, it needs to be determined based on the state of the interrupt register
I continue to refine its logical flow
>
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static int vs_drm_device_init_res(struct vs_drm_device *priv) {
> > + struct device *dev = priv->base.dev;
> > + struct platform_device *pdev = to_platform_device(dev);
> > + int ret;
> > + struct vs_dc *dc;
> > +
> > + dc = &priv->dc;
> > + dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
> > + if (IS_ERR(dc->hw.hi_base))
> > + return PTR_ERR(dc->hw.hi_base);
> > +
> > + dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
> > + if (IS_ERR(dc->hw.reg_base))
> > + return PTR_ERR(dc->hw.reg_base);
> > +
> > + dc->hw.info = (struct vs_dc_info *)of_device_get_match_data(dev);
> > +
> > + ret = devm_clk_bulk_get_all(dev, &priv->clks);
> > + if (ret < 0) {
> > + dev_err(dev, "can't get vout clock, ret=%d\n", ret);
> > + return ret;
> > + }
> > + priv->clk_count = ret;
> > +
> > + priv->rsts = devm_reset_control_array_get_shared(dev);
> > + if (IS_ERR(priv->rsts))
> > + return PTR_ERR(priv->rsts);
> > +
> > + priv->irq = platform_get_irq(pdev, 0);
> > +
> > + /* do not autoenable, will be enabled later */
> > + ret = devm_request_irq(dev, priv->irq, vs_dc_isr, IRQF_NO_AUTOEN,
> dev_name(dev), priv);
> > + if (ret < 0) {
> > + dev_err(dev, "Failed to install irq:%u.\n", priv->irq);
> > + return ret;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static u32 get_addr_offset(u32 id)
> > +{
> > + u32 offset = 0;
> > +
> > + switch (id) {
> > + case PRIMARY_PLANE_1:
> > + case OVERLAY_PLANE_1:
> > + offset = 0x04;
> > + break;
> > + case OVERLAY_PLANE_2:
> > + offset = 0x08;
> > + break;
> > + case OVERLAY_PLANE_3:
> > + offset = 0x0C;
> > + break;
> > + default:
> > + break;
> > + }
> > +
> > + return offset;
> > +}
> > +
> > +static int vs_drm_device_crtc_plane_create(struct vs_drm_device
> > +*priv) {
> > + struct vs_dc *dc;
> > + struct drm_device *drm_dev;
> > + int i, ret;
> > + struct device_node *port;
> > + struct vs_crtc *crtc;
> > + struct vs_dc_info *dc_info;
> > + struct vs_plane *plane;
> > + struct vs_plane_primary_info *primary_info;
> > + struct vs_plane_overlay_info *overlay_info;
> > + struct vs_plane_cursor_info *cursor_info;
> > +
> > + struct device *dev = priv->base.dev;
> > + u32 max_width = 0, max_height = 0;
> > + u32 min_width = 0xffff, min_heigth = 0xffff;
> > + u32 possible_crtc = 0;
> > +
> > + dc = &priv->dc;
> > + dc_info = dc->hw.info;
> > + drm_dev = &priv->base;
> > +
> > + for (i = 0; i < dc_info->panel_num; i++) {
> > + crtc = vs_crtc_create(drm_dev, dc_info);
> > + if (!crtc) {
> > + drm_err(drm_dev, "Failed to create CRTC.\n");
> > + ret = -ENOMEM;
> > + return ret;
> > + }
> > + crtc->dev = drm_dev->dev;
> > +
> > + port = of_graph_get_port_by_id(crtc->dev->of_node, i);
> > + if (!port) {
> > + drm_err(drm_dev, "no port node found for crtc_port%d\n", i);
> > + return -ENOENT;
> > + }
> > +
> > + crtc->base.port = port;
> > + dc->crtc[i] = crtc;
> > +
> > + of_node_put(port);
> > + }
> > +
> > + if (!dc->crtc[0]->base.port || !dc->crtc[1]->base.port) {
> > + drm_err(drm_dev, "no port no crtc mask, fail to create plane\n");
> > + return -ENOENT;
> > + }
> > +
> > + for (i = 0; i < dc_info->primary_num; i++) {
> > + primary_info = (struct vs_plane_primary_info
> > +*)&dc_info->primary[i];
> > +
> > + if (primary_info->id == PRIMARY_PLANE_0)
> > + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base);
> > + else
> > + possible_crtc = drm_crtc_mask(&dc->crtc[1]->base);
> > +
> > + plane = vs_plane_primary_create(drm_dev, primary_info,
> > + dc_info->layer_num, possible_crtc);
> > + if (IS_ERR(plane)) {
> > + dev_err(dev, "failed to construct plane\n");
> > + return PTR_ERR(plane);
> > + }
> > +
> > + plane->id = primary_info->id;
> > + dc->planes[plane->id].id = primary_info->id;
> > + dc->planes[plane->id].offset = get_addr_offset(primary_info->id);
> > +
> > + if (primary_info->id == PRIMARY_PLANE_0)
> > + dc->crtc[0]->base.primary = &plane->base;
> > + else
> > + dc->crtc[1]->base.primary = &plane->base;
> > +
> > + min_width = min_t(u32, min_width, primary_info->min_width);
> > + min_heigth = min_t(u32, min_heigth, primary_info->min_height);
> > + /*
> > + * Note: these values are used for multiple independent things:
> > + * hw display mode filtering, plane buffer sizes ...
> > + * Use the combined maximum values here to cover all use cases,
> > + * and do more specific checking in the respective code paths.
> > + */
> > + max_width = max_t(u32, max_width, primary_info->max_width);
> > + max_height = max_t(u32, max_height, primary_info->max_height);
> > + }
> > +
> > + for (i = 0; i < dc_info->overlay_num; i++) {
> > + overlay_info = (struct vs_plane_overlay_info
> > +*)&dc_info->overlay[i];
> > +
> > + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base) |
> > + drm_crtc_mask(&dc->crtc[1]->base);
> > +
> > + plane = vs_plane_overlay_create(drm_dev, overlay_info,
> > + dc_info->layer_num, possible_crtc);
> > + if (IS_ERR(plane)) {
> > + dev_err(dev, "failed to construct plane\n");
> > + return PTR_ERR(plane);
> > + }
> > +
> > + plane->id = overlay_info->id;
> > + dc->planes[plane->id].id = overlay_info->id;
> > + dc->planes[plane->id].offset = get_addr_offset(overlay_info->id);
> > + }
> > +
> > + for (i = 0; i < dc_info->cursor_num; i++) {
> > + cursor_info = (struct vs_plane_cursor_info *)&dc_info->cursor[i];
> > +
> > + if (cursor_info->id == CURSOR_PLANE_0)
> > + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base);
> > + else
> > + possible_crtc = drm_crtc_mask(&dc->crtc[1]->base);
> > +
> > + plane = vs_plane_cursor_create(drm_dev, cursor_info, possible_crtc);
> > + if (IS_ERR(plane)) {
> > + dev_err(dev, "failed to construct plane\n");
> > + return PTR_ERR(plane);
> > + }
> > +
> > + plane->id = cursor_info->id;
> > + dc->planes[plane->id].id = cursor_info->id;
> > + dc->planes[plane->id].offset = get_addr_offset(cursor_info->id);
> > +
> > + if (cursor_info->id == CURSOR_PLANE_0)
> > + dc->crtc[0]->base.cursor = &plane->base;
> > + else
> > + dc->crtc[1]->base.cursor = &plane->base;
> > + drm_dev->mode_config.cursor_width =
> > + max_t(u32, drm_dev->mode_config.cursor_width,
> > + cursor_info->max_width);
> > + drm_dev->mode_config.cursor_height =
> > + max_t(u32, drm_dev->mode_config.cursor_height,
> > + cursor_info->max_height);
> > + }
> > +
> > + drm_dev->mode_config.min_width = min_width;
> > + drm_dev->mode_config.min_height = min_heigth;
> > + drm_dev->mode_config.max_width = max_width;
> > + drm_dev->mode_config.max_height = max_height;
>
> I thought that I saw mode_config.min/max being initialized.
Yes the mode_config.min/max has been initialized,
This place is doing an update according to detail info.
>
> > +
> > + if (dc_info->pitch_alignment > priv->pitch_alignment)
> > + priv->pitch_alignment = dc_info->pitch_alignment;
> > +
> > + return 0;
> > +}
> > +
> > +static int vs_load(struct vs_drm_device *priv) {
> > + int ret;
> > +
> > + ret = clk_bulk_prepare_enable(priv->clk_count, priv->clks);
> > + if (ret)
> > + return ret;
> > +
> > + reset_control_deassert(priv->rsts);
> > +
> > + ret = dc_hw_init(&priv->dc);
> > + if (ret) {
> > + DRM_ERROR("failed to init DC HW\n");
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int vs_drm_bind(struct device *dev) {
> > + struct vs_drm_device *priv;
> > + int ret;
> > + struct drm_device *drm_dev;
> > +
> > + priv = devm_drm_dev_alloc(dev, &vs_drm_driver, struct vs_drm_device,
> base);
> > + if (IS_ERR(priv))
> > + return PTR_ERR(priv);
> > +
> > + priv->pitch_alignment = 64;
> > + drm_dev = &priv->base;
> > + dev_set_drvdata(dev, drm_dev);
> > +
> > + ret = dma_set_coherent_mask(drm_dev->dev, DMA_BIT_MASK(40));
> > + if (ret)
> > + return ret;
> > +
> > + ret = vs_drm_device_init_res(priv);
> > + if (ret)
> > + return ret;
> > +
> > + vs_mode_config_init(drm_dev);
> > +
> > + /* Remove existing drivers that may own the framebuffer memory. */
> > + ret = drm_aperture_remove_framebuffers(&vs_drm_driver);
> > + if (ret)
> > + return ret;
> > +
> > + ret = vs_drm_device_crtc_plane_create(priv);
> > + if (ret) {
> > + DRM_ERROR("Failed to create ctrc and plane\n");
> > + return ret;
> > + }
> > +
> > + ret = vs_load(priv);
> > + if (ret)
> > + return ret;
> > +
> > + /* Now try and bind all our sub-components */
> > + ret = component_bind_all(dev, drm_dev);
> > + if (ret) {
> > + ret = -EPROBE_DEFER;
> > + goto unload;
> > + }
> > + ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
> > + if (ret)
> > + goto err_unbind_all;
> > +
> > + drm_mode_config_reset(drm_dev);
> > +
> > + ret = drmm_kms_helper_poll_init(drm_dev);
> > + if (ret)
> > + goto err_unbind_all;
> > +
> > + ret = drm_dev_register(drm_dev, 0);
> > + if (ret)
> > + goto err_unbind_all;
> > +
> > + drm_fbdev_generic_setup(drm_dev, 32);
> > +
> > + return 0;
> > +
> > +err_unbind_all:
> > + component_unbind_all(drm_dev->dev, drm_dev);
> > +unload:
> > + reset_control_assert(priv->rsts);
> > + clk_bulk_disable_unprepare(priv->clk_count, priv->clks);
> > + return ret;
> > +
> > +}
> > +
> > +static void vs_drm_unbind(struct device *dev) {
> > + struct drm_device *drm_dev = dev_get_drvdata(dev);
> > + struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
> > +
> > + reset_control_assert(priv->rsts);
> > + clk_bulk_disable_unprepare(priv->clk_count, priv->clks);
> > +
> > + drm_dev_unregister(drm_dev);
> > + drm_atomic_helper_shutdown(drm_dev);
> > + component_unbind_all(drm_dev->dev, drm_dev); }
> > +
> > +static const struct component_master_ops vs_drm_ops = {
> > + .bind = vs_drm_bind,
> > + .unbind = vs_drm_unbind,
> > +};
> > +
> > +static struct platform_driver *drm_sub_drivers[] = {
> > +
> > +};
> > +
> > +static struct component_match *vs_add_external_components(struct
> > +device *dev) {
> > + struct component_match *match = NULL;
> > + int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(drm_sub_drivers); ++i) {
> > + struct platform_driver *drv = drm_sub_drivers[i];
> > + struct device *p = NULL, *d;
> > +
> > + while ((d = platform_find_device_by_driver(p, &drv->driver))) {
> > + put_device(p);
> > +
> > + drm_of_component_match_add(dev, &match,
> component_compare_of,
> > + d->of_node);
> > + p = d;
> > + }
> > + put_device(p);
>
> What about just going through the graph connections instead and adding them?
The purpose of using components is to create encoder and connector to the drm subsystem by calling component_bind_all
graph connection needs to be based on whether there is a bridge at present.
If the bridge has been added, it can be obtained through drm_of_get_bridge
Create a connector based on the obtained bridge and then attach the connector to the encoder.
Then do drm_dev_register.
I don't know if my understanding is consistent with yours. Please help confirm it.
Thanks
> > + return match ? match : ERR_PTR(-ENODEV); }
> > +
> > +static int vs_drm_platform_probe(struct platform_device *pdev) {
> > + struct device *dev = &pdev->dev;
> > + struct component_match *match;
> > +
> > + /* all the planes and CRTC would be created in this platform device
> > + * , so external components are encoder + connector or self-defined
>
> Comma should go to the previous line.
Got it ,I will modify it according to the comments
>
> > + * encoder.
> > + */
> > + match = vs_add_external_components(dev);
> > + if (IS_ERR(match))
> > + return PTR_ERR(match);
> > +
> > + return component_master_add_with_match(dev, &vs_drm_ops, match); }
> > +
> > +static int vs_drm_platform_remove(struct platform_device *pdev) {
> > + component_master_del(&pdev->dev, &vs_drm_ops);
> > + return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM_SLEEP
> > +static int vs_drm_suspend(struct device *dev) {
> > + return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
> > +}
> > +
> > +static int vs_drm_resume(struct device *dev) {
> > + drm_mode_config_helper_resume(dev_get_drvdata(dev));
> > +
> > + return 0;
> > +}
> > +#endif
> > +
> > +static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend,
> > +vs_drm_resume);
> > +
> > +static const struct of_device_id vs_drm_dt_ids[] = {
> > + { .compatible = "starfive,jh7110-dc8200", .data = &dc8200_info,},
> > + { },
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
> > +
> > +static struct platform_driver vs_drm_platform_driver = {
> > + .probe = vs_drm_platform_probe,
> > + .remove = vs_drm_platform_remove,
> > +
> > + .driver = {
> > + .name = DRV_NAME,
> > + .of_match_table = vs_drm_dt_ids,
> > + .pm = &vs_drm_pm_ops,
> > + },
> > +};
> > +
> > +static int __init vs_drm_init(void)
> > +{
> > + int ret;
> > +
> > + ret = platform_register_drivers(drm_sub_drivers,
> ARRAY_SIZE(drm_sub_drivers));
> > + if (ret)
> > + return ret;
> > +
> > + ret = drm_platform_driver_register(&vs_drm_platform_driver);
> > + if (ret)
> > + platform_unregister_drivers(drm_sub_drivers,
> > +ARRAY_SIZE(drm_sub_drivers));
> > +
> > + return ret;
> > +}
> > +
> > +static void __exit vs_drm_fini(void)
> > +{
> > + platform_driver_unregister(&vs_drm_platform_driver);
> > + platform_unregister_drivers(drm_sub_drivers,
> > +ARRAY_SIZE(drm_sub_drivers)); }
> > +
> > +late_initcall_sync(vs_drm_init);
>
> Why _sync?
late_initcall_sync will make it success ,when do devm_drm_of_get_bridge.
Also it can use the " EPROBE_DEFER " to avoid it,
>
> > +module_exit(vs_drm_fini);
> > +
> > +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
> MODULE_LICENSE("GPL");
> > --
> > 2.27.0
> >
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 05/10] drm/vs: add vs mode config init
2024-05-21 20:52 ` Dmitry Baryshkov
@ 2024-06-23 7:17 ` Keith Zhao
2024-06-23 20:52 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-23 7:17 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Dmitry:
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年5月22日 4:53
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 05/10] drm/vs: add vs mode config init
>
> On Tue, May 21, 2024 at 06:58:12PM +0800, keith wrote:
> > add vs mode config base api
>
> Commit message? Please describe e.g. why are you using
> drm_atomic_helper_commit_tail_rpm() instead of
> drm_atomic_helper_commit_tail().
>
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
>
> Name
This can be modified.
>
> > ---
> > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > drivers/gpu/drm/verisilicon/vs_modeset.c | 36
> > ++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_modeset.h |
> > 10 +++++++
> > 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644
> > drivers/gpu/drm/verisilicon/vs_modeset.c
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.h
> >
> > diff --git a/drivers/gpu/drm/verisilicon/Makefile
> > b/drivers/gpu/drm/verisilicon/Makefile
> > index 7da54b259940..536091f37378 100644
> > --- a/drivers/gpu/drm/verisilicon/Makefile
> > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > @@ -1,5 +1,6 @@
> > # SPDX-License-Identifier: GPL-2.0
> >
> > -vs_drm-objs := vs_dc_hw.o
> > +vs_drm-objs := vs_dc_hw.o \
> > + vs_modeset.o
> >
> > obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git
> > a/drivers/gpu/drm/verisilicon/vs_modeset.c
> > b/drivers/gpu/drm/verisilicon/vs_modeset.c
> > new file mode 100644
> > index 000000000000..c71fe0d32504
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_modeset.c
> > @@ -0,0 +1,36 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +#include <drm/drm_damage_helper.h>
>
> I don't see anything concerning damage helpers being used here.
>
Yes , it should use drm_atomic_helper.h instead of drm_damage_helper.h
> > +#include <drm/drm_fb_helper.h>
> > +#include <drm/drm_gem_framebuffer_helper.h>
> > +
> > +#include "vs_modeset.h"
> > +
> > +static const struct drm_mode_config_funcs vs_mode_config_funcs = {
> > + .fb_create = drm_gem_fb_create,
> > + .atomic_check = drm_atomic_helper_check,
> > + .atomic_commit = drm_atomic_helper_commit,
> > +};
> > +
> > +static struct drm_mode_config_helper_funcs vs_mode_config_helpers = {
> > + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
> > +};
> > +
> > +void vs_mode_config_init(struct drm_device *dev) {
> > + int ret;
> > +
> > + ret = drmm_mode_config_init(dev);
> > + if (ret)
> > + return;
> > +
> > + dev->mode_config.min_width = 0;
> > + dev->mode_config.min_height = 0;
> > + dev->mode_config.max_width = 4096;
> > + dev->mode_config.max_height = 4096;
> > +
> > + dev->mode_config.funcs = &vs_mode_config_funcs;
> > + dev->mode_config.helper_private = &vs_mode_config_helpers; }
> > diff --git a/drivers/gpu/drm/verisilicon/vs_modeset.h
> > b/drivers/gpu/drm/verisilicon/vs_modeset.h
> > new file mode 100644
> > index 000000000000..bd04f81d2ad2
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_modeset.h
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_MODESET_H__
> > +#define __VS_MODESET_H__
> > +
> > +void vs_mode_config_init(struct drm_device *dev); #endif /*
> > +__VS_FB_H__ */
> > --
> > 2.27.0
> >
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 07/10] drm/vs: add ctrc fun
2024-05-21 21:08 ` Dmitry Baryshkov
@ 2024-06-23 7:17 ` Keith Zhao
2024-06-23 20:56 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-23 7:17 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Dmitry:
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年5月22日 5:08
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 07/10] drm/vs: add ctrc fun
>
> On Tue, May 21, 2024 at 06:58:14PM +0800, keith wrote:
> > add crtc funs and helper funs
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > ---
> > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > drivers/gpu/drm/verisilicon/vs_crtc.c | 241
> > ++++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_crtc.h |
> > 17 ++
> > 3 files changed, 260 insertions(+), 1 deletion(-) create mode 100644
> > drivers/gpu/drm/verisilicon/vs_crtc.c
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
> >
> > diff --git a/drivers/gpu/drm/verisilicon/Makefile
> > b/drivers/gpu/drm/verisilicon/Makefile
> > index 1c593b943261..26a43ca0fd36 100644
> > --- a/drivers/gpu/drm/verisilicon/Makefile
> > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > @@ -2,6 +2,7 @@
> >
> > vs_drm-objs := vs_dc_hw.o \
> > vs_modeset.o \
> > - vs_plane.o
> > + vs_plane.o \
> > + vs_crtc.o
> >
> > obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git
> > a/drivers/gpu/drm/verisilicon/vs_crtc.c
> > b/drivers/gpu/drm/verisilicon/vs_crtc.c
> > new file mode 100644
> > index 000000000000..ea7640a63c28
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
> > @@ -0,0 +1,241 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + *
> > + */
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_crtc.h>
> > +#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_vblank.h>
> > +
> > +#include "vs_crtc.h"
> > +
> > +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
> > + struct drm_crtc_state *state)
> > +{
> > + __drm_atomic_helper_crtc_destroy_state(state);
> > + kfree(to_vs_crtc_state(state));
> > +}
> > +
> > +static void vs_crtc_reset(struct drm_crtc *crtc) {
> > + struct vs_crtc_state *state;
> > +
> > + if (crtc->state)
> > + vs_crtc_atomic_destroy_state(crtc, crtc->state);
> > +
> > + state = kzalloc(sizeof(*state), GFP_KERNEL);
> > + if (!state)
> > + return;
> > +
> > + __drm_atomic_helper_crtc_reset(crtc, &state->base); }
> > +
> > +static struct drm_crtc_state *
> > +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc) {
> > + struct vs_crtc_state *old_state;
> > + struct vs_crtc_state *state;
> > +
> > + if (!crtc->state)
> > + return NULL;
> > +
> > + old_state = to_vs_crtc_state(crtc->state);
> > +
> > + state = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);
> > + if (!state)
> > + return NULL;
> > +
> > + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
> > +
> > + return &state->base;
> > +}
> > +
> > +static int vs_crtc_enable_vblank(struct drm_crtc *crtc) {
> > + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> > + struct vs_dc *dc = &priv->dc;
> > +
> > + dc_hw_enable_interrupt(&dc->hw);
> > +
> > + return 0;
> > +}
> > +
> > +static void vs_crtc_disable_vblank(struct drm_crtc *crtc) {
> > + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> > + struct vs_dc *dc = &priv->dc;
> > +
> > + dc_hw_disable_interrupt(&dc->hw);
> > +}
> > +
> > +static const struct drm_crtc_funcs vs_crtc_funcs = {
> > + .set_config = drm_atomic_helper_set_config,
> > + .page_flip = drm_atomic_helper_page_flip,
> > + .reset = vs_crtc_reset,
> > + .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
> > + .atomic_destroy_state = vs_crtc_atomic_destroy_state,
> > + .enable_vblank = vs_crtc_enable_vblank,
> > + .disable_vblank = vs_crtc_disable_vblank,
> > +};
> > +
> > +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
> > + struct drm_atomic_state *state) {
> > + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> > + struct vs_dc *dc = &priv->dc;
> > +
> > + struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
> > + struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> > + int id;
> > +
> > + id = to_vs_display_id(dc, crtc);
> > + if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
> > + dc_hw_set_out(&dc->hw, OUT_DPI, id);
> > + clk_set_rate(priv->clks[7].clk, mode->clock * 1000);
> > + clk_set_parent(priv->clks[5].clk, priv->clks[7].clk);
> > + } else {
> > + dc_hw_set_out(&dc->hw, OUT_DP, id);
> > + clk_set_parent(priv->clks[4].clk, priv->clks[6].clk);
> > + }
> > +
> > + dc_hw_enable(&dc->hw, id, mode, crtc_state->encoder_type,
> > +crtc_state->output_fmt);
> > +
> > + enable_irq(priv->irq);
> > +
> > + drm_crtc_vblank_on(crtc);
> > +}
> > +
> > +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
> > + struct drm_atomic_state *state) {
> > + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> > + struct vs_dc *dc = &priv->dc;
> > + int id;
> > +
> > + drm_crtc_vblank_off(crtc);
> > +
> > + disable_irq(priv->irq);
> > +
> > + id = to_vs_display_id(dc, crtc);
> > + dc_hw_disable(&dc->hw, id);
> > +
> > + if (crtc->state->event && !crtc->state->active) {
> > + spin_lock_irq(&crtc->dev->event_lock);
> > + drm_crtc_send_vblank_event(crtc, crtc->state->event);
> > + crtc->state->event = NULL;
> > + spin_unlock_irq(&crtc->dev->event_lock);
> > + }
> > +}
> > +
> > +static void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> > + struct drm_color_lut *lut, unsigned int size) {
> > + u16 i, r, g, b;
> > + u8 bits, id;
> > +
> > + if (size != dc->hw.info->gamma_size) {
> > + drm_err(crtc->dev, "gamma size does not match!\n");
> > + return;
> > + }
> > +
> > + id = to_vs_display_id(dc, crtc);
> > +
> > + bits = dc->hw.info->gamma_bits;
> > + for (i = 0; i < size; i++) {
> > + r = drm_color_lut_extract(lut[i].red, bits);
> > + g = drm_color_lut_extract(lut[i].green, bits);
> > + b = drm_color_lut_extract(lut[i].blue, bits);
> > + dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
> > +
> > + if (i >= dc->hw.info->gamma_size)
> > + return;
> > +
> > + dc->hw.gamma[id].gamma[i][0] = r;
> > + dc->hw.gamma[id].gamma[i][1] = g;
> > + dc->hw.gamma[id].gamma[i][2] = b;
> > + }
> > +}
> > +
> > +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
> > + struct drm_atomic_state *state)
> > +{
> > + struct drm_crtc_state *new_state =
> drm_atomic_get_new_crtc_state(state,
> > + crtc);
> > +
> > + struct drm_property_blob *blob = new_state->gamma_lut;
> > + struct drm_color_lut *lut;
> > + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> > + struct vs_dc *dc = &priv->dc;
> > + u8 id;
> > +
> > + id = to_vs_display_id(dc, crtc);
> > + if (new_state->color_mgmt_changed) {
> > + if (blob && blob->length) {
> > + lut = blob->data;
> > + vs_dc_set_gamma(dc, crtc, lut,
> > + blob->length / sizeof(*lut));
> > + dc_hw_enable_gamma(&dc->hw, id, true);
> > + } else {
> > + dc_hw_enable_gamma(&dc->hw, id, false);
> > + }
> > + }
> > +}
> > +
> > +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
> > + struct drm_atomic_state *state)
> > +{
> > + struct drm_pending_vblank_event *event = crtc->state->event;
> > + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev);
> > + struct vs_dc *dc = &priv->dc;
> > +
> > + dc_hw_enable_shadow_register(dc, false);
> > +
> > + if (event) {
> > + WARN_ON(drm_crtc_vblank_get(crtc) != 0);
> > +
> > + spin_lock_irq(&crtc->dev->event_lock);
> > + drm_crtc_arm_vblank_event(crtc, event);
> > + crtc->state->event = NULL;
> > + spin_unlock_irq(&crtc->dev->event_lock);
> > + }
> > +
> > + dc_hw_enable_shadow_register(dc, true); }
> > +
> > +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
> > + .atomic_check = drm_crtc_helper_atomic_check,
> > + .atomic_enable = vs_crtc_atomic_enable,
> > + .atomic_disable = vs_crtc_atomic_disable,
> > + .atomic_begin = vs_crtc_atomic_begin,
> > + .atomic_flush = vs_crtc_atomic_flush,
> > +};
> > +
> > +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> > + struct vs_dc_info *info)
> > +{
> > + struct vs_crtc *crtc;
> > + int ret;
> > +
> > + if (!info)
> > + return NULL;
> > +
> > + crtc = drmm_crtc_alloc_with_planes(drm_dev, struct vs_crtc, base, NULL,
> > + NULL, &vs_crtc_funcs,
> > + info->name ? info->name : NULL);
> > +
> > + drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
> > +
> > + if (info->gamma_size) {
> > + ret = drm_mode_crtc_set_gamma_size(&crtc->base,
> > + info->gamma_size);
> > + if (ret)
> > + return NULL;
> > +
> > + drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
> > + info->gamma_size);
> > + }
> > +
> > + return crtc;
> > +}
> > diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h
> > b/drivers/gpu/drm/verisilicon/vs_crtc.h
> > new file mode 100644
> > index 000000000000..b1e588bb780d
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
> > @@ -0,0 +1,17 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_CRTC_H__
> > +#define __VS_CRTC_H__
> > +
> > +#include <drm/drm_crtc.h>
> > +#include <drm/drm_crtc_helper.h>
>
> Do you really need to include them here?
>
The location of include can be optimized
Delete #include <drm/drm_crtc.h>
Move drm_crtc_helper.h to vs_crtc.c
> > +
> > +#include "vs_drv.h"
> > +
> > +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> > + struct vs_dc_info *info);
> > +
> > +#endif /* __VS_CRTC_H__ */
> > --
> > 2.27.0
> >
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 06/10] drm/vs: add vs plane api
2024-05-21 21:06 ` Dmitry Baryshkov
@ 2024-06-23 7:17 ` Keith Zhao
2024-06-23 20:54 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-23 7:17 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Dmitry:
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年5月22日 5:06
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 06/10] drm/vs: add vs plane api
>
> On Tue, May 21, 2024 at 06:58:13PM +0800, keith wrote:
> > add plane funs and helper funs
> > add vs drm common struct and funs
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > ---
> > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++
> > drivers/gpu/drm/verisilicon/vs_plane.c | 487
> > +++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_plane.h |
> > 26 ++
> > 4 files changed, 608 insertions(+), 1 deletion(-) create mode 100644
> > drivers/gpu/drm/verisilicon/vs_drv.h
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
> >
> > diff --git a/drivers/gpu/drm/verisilicon/Makefile
> > b/drivers/gpu/drm/verisilicon/Makefile
> > index 536091f37378..1c593b943261 100644
> > --- a/drivers/gpu/drm/verisilicon/Makefile
> > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > @@ -1,6 +1,7 @@
> > # SPDX-License-Identifier: GPL-2.0
> >
> > vs_drm-objs := vs_dc_hw.o \
> > - vs_modeset.o
> > + vs_modeset.o \
> > + vs_plane.o
> >
> > obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git
> > a/drivers/gpu/drm/verisilicon/vs_drv.h
> > b/drivers/gpu/drm/verisilicon/vs_drv.h
> > new file mode 100644
> > index 000000000000..d9f6efa7c8f9
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> > @@ -0,0 +1,93 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_DRV_H__
> > +#define __VS_DRV_H__
> > +
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/clk.h>
> > +#include <linux/reset.h>
> > +
> > +#include <drm/drm_drv.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_gem.h>
> > +#include <drm/drm_managed.h>
> > +
> > +#include "vs_dc_hw.h"
> > +
> > +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
>
> Is that all the docs you want to add?
It should delete the redundant parts which is unused,
To make this patch clearer to review
>
> > +struct vs_drm_device {
> > + struct drm_device base;
> > + unsigned int pitch_alignment;
> > + /* clocks */
> > + unsigned int clk_count;
> > + struct clk_bulk_data *clks;
> > + struct reset_control *rsts;
> > + struct vs_dc dc;
> > + int irq;
>
> As usual, please drop unused fields and add them when required.
In principle, I try to split the patch independently according to this.
In fact, there is still a lot of room for optimization
The subsequent patches will maintain independence and remove redundant parts for decoupling
>
> > +};
> > +
> > +static inline struct vs_drm_device *
> > +to_vs_drm_private(const struct drm_device *dev) {
> > + return container_of(dev, struct vs_drm_device, base); }
> > +
> > +struct vs_crtc_state {
> > + struct drm_crtc_state base;
> > +
> > + u32 output_fmt;
> > + u8 encoder_type;
> > + u8 bpp;
> > +};
>
> Not used here, drop.
>
> > +
> > +struct vs_crtc {
> > + struct drm_crtc base;
> > + struct device *dev;
> > +};
>
>
> > +
> > +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc
> > +*crtc) {
> > + u8 panel_num = dc->hw.info->panel_num;
> > + u32 index = drm_crtc_index(crtc);
> > + int i;
> > +
> > + for (i = 0; i < panel_num; i++) {
> > + if (index == dc->crtc[i]->base.index)
> > + return i;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static inline struct vs_crtc_state *
> > +to_vs_crtc_state(struct drm_crtc_state *state) {
> > + return container_of(state, struct vs_crtc_state, base); }
> > +
> > +struct vs_plane_state {
> > + struct drm_plane_state base;
> > + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES]; };
> > +
> > +struct vs_plane {
> > + struct drm_plane base;
> > + u8 id;
> > +};
> > +
> > +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane) {
> > + return container_of(plane, struct vs_plane, base); }
> > +
> > +static inline struct vs_plane_state * to_vs_plane_state(struct
> > +drm_plane_state *state) {
> > + return container_of(state, struct vs_plane_state, base); }
> > +
> > +#endif /* __VS_DRV_H__ */
> > diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c
> > b/drivers/gpu/drm/verisilicon/vs_plane.c
> > new file mode 100644
> > index 000000000000..653f0ce72ed6
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_plane.c
> > @@ -0,0 +1,487 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_blend.h>
> > +#include <drm/drm_gem_dma_helper.h>
> > +#include <drm/drm_fb_dma_helper.h>
> > +#include <drm/drm_framebuffer.h>
> > +#include <drm/drm_plane.h>
> > +#include <drm/drm_plane_helper.h>
> > +
> > +#include "vs_plane.h"
> > +
> > +static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
> > + struct drm_plane_state *state) {
> > + struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
> > +
> > + __drm_atomic_helper_plane_destroy_state(state);
> > + kfree(vs_plane_state);
> > +}
> > +
> > +static void vs_plane_reset(struct drm_plane *plane) {
> > + struct vs_plane_state *state;
> > + struct vs_plane *vs_plane = to_vs_plane(plane);
> > +
> > + if (plane->state)
> > + vs_plane_atomic_destroy_state(plane, plane->state);
> > +
> > + state = kzalloc(sizeof(*state), GFP_KERNEL);
> > + if (!state)
> > + return;
> > +
> > + state->base.zpos = vs_plane->id;
> > + __drm_atomic_helper_plane_reset(plane, &state->base); }
> > +
> > +static struct drm_plane_state *
> > +vs_plane_atomic_duplicate_state(struct drm_plane *plane) {
> > + struct vs_plane_state *state;
> > +
> > + if (WARN_ON(!plane->state))
> > + return NULL;
> > +
> > + state = kzalloc(sizeof(*state), GFP_KERNEL);
> > + if (!state)
> > + return NULL;
> > +
> > + __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
> > +
> > + return &state->base;
> > +}
> > +
> > +static bool vs_format_mod_supported(struct drm_plane *plane,
> > + u32 format,
> > + u64 modifier)
> > +{
> > + int i;
> > +
> > + /* We always have to allow these modifiers:
> > + * 1. Core DRM checks for LINEAR support if userspace does not provide
> modifiers.
> > + * 2. Not passing any modifiers is the same as explicitly passing INVALID.
> > + */
> > + if (modifier == DRM_FORMAT_MOD_LINEAR)
> > + return true;
> > +
> > + /* Check that the modifier is on the list of the plane's supported modifiers.
> */
> > + for (i = 0; i < plane->modifier_count; i++) {
> > + if (modifier == plane->modifiers[i])
> > + break;
> > + }
> > +
> > + if (i == plane->modifier_count)
> > + return false;
> > +
> > + return true;
> > +}
> > +
> > +const struct drm_plane_funcs vs_plane_funcs = {
> > + .update_plane = drm_atomic_helper_update_plane,
> > + .disable_plane = drm_atomic_helper_disable_plane,
> > + .reset = vs_plane_reset,
> > + .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
> > + .atomic_destroy_state = vs_plane_atomic_destroy_state,
> > + .format_mod_supported = vs_format_mod_supported,
> > +};
> > +
> > +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
> > +{
> > + const struct drm_format_info *info;
> > +
> > + if (!fb)
> > + return 0;
> > +
> > + info = drm_format_info(fb->format->format);
> > + if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
> > + return 0;
> > +
> > + return info->num_planes;
> > +}
> > +
> > +static bool vs_dc_mod_supported(const u64 *info_modifiers, u64
> > +modifier) {
> > + const u64 *mods;
> > +
> > + if (!info_modifiers)
> > + return false;
> > +
> > + for (mods = info_modifiers; *mods != DRM_FORMAT_MOD_INVALID;
> mods++) {
> > + if (*mods == modifier)
> > + return true;
> > + }
> > +
> > + return false;
> > +}
> > +
> > +static int vs_primary_plane_atomic_check(struct drm_plane *plane,
> > +struct drm_atomic_state *state) {
> > + struct drm_plane_state *new_state =
> drm_atomic_get_new_plane_state(state, plane);
> > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> > + struct vs_dc *dc = &priv->dc;
> > + struct drm_framebuffer *fb = new_state->fb;
> > + const struct vs_plane_primary_info *primary_info;
> > + struct drm_crtc_state *crtc_state;
> > + int i;
> > +
> > + if (!new_state->crtc || !new_state->fb)
> > + return 0;
> > + for (i = 0; i < dc->hw.info->primary_num; i++) {
> > + primary_info = (struct vs_plane_primary_info
> *)&dc->hw.info->primary[i];
> > + if (primary_info->id == to_vs_plane(plane)->id)
> > + break;
> > + }
> > +
> > + primary_info = &dc->hw.info->primary[i];
> > +
> > + if (fb->width < primary_info->min_width ||
> > + fb->width > primary_info->max_width ||
> > + fb->height < primary_info->min_height ||
> > + fb->height > primary_info->max_height)
> > + drm_err_once(plane->dev, "buffer size may not support on
> plane%d.\n",
> > + to_vs_plane(plane)->id);
> > +
> > + if (!vs_dc_mod_supported(primary_info->modifiers, fb->modifier)) {
> > + drm_err(plane->dev, "unsupported modifier on plane%d.\n",
> to_vs_plane(plane)->id);
> > + return -EINVAL;
> > + }
> > +
> > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state,
> new_state->crtc);
> > + return drm_atomic_helper_check_plane_state(new_state, crtc_state,
> > + primary_info->min_scale,
> > + primary_info->max_scale,
> > + true, true);
> > +}
> > +
> > +static int vs_overlay_plane_atomic_check(struct drm_plane *plane,
> > +struct drm_atomic_state *state) {
> > + struct drm_plane_state *new_state =
> drm_atomic_get_new_plane_state(state, plane);
> > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> > + struct vs_dc *dc = &priv->dc;
> > + struct drm_framebuffer *fb = new_state->fb;
> > + const struct vs_plane_overlay_info *overlay_info;
> > + struct drm_crtc_state *crtc_state;
> > + int i;
> > +
> > + if (!new_state->crtc || !new_state->fb)
> > + return 0;
> > +
> > + for (i = 0; i < dc->hw.info->overlay_num; i++) {
> > + overlay_info = (struct vs_plane_overlay_info
> *)&dc->hw.info->overlay[i];
> > + if (overlay_info->id == to_vs_plane(plane)->id)
> > + break;
> > + }
> > +
> > + overlay_info = &dc->hw.info->overlay[i];
> > +
> > + if (fb->width < overlay_info->min_width ||
> > + fb->width > overlay_info->max_width ||
> > + fb->height < overlay_info->min_height ||
> > + fb->height > overlay_info->max_height)
> > + drm_err_once(plane->dev, "buffer size may not support on
> plane%d.\n",
> > + to_vs_plane(plane)->id);
> > +
> > + if (!vs_dc_mod_supported(overlay_info->modifiers, fb->modifier)) {
> > + drm_err(plane->dev, "unsupported modifier on plane%d.\n",
> to_vs_plane(plane)->id);
> > + return -EINVAL;
> > +}
> > +
> > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state,
> new_state->crtc);
> > + return drm_atomic_helper_check_plane_state(new_state, crtc_state,
> > + overlay_info->min_scale,
> > + overlay_info->max_scale,
> > + true, true);
> > +}
> > +
> > +static int vs_cursor_plane_atomic_check(struct drm_plane *plane,
> > +struct drm_atomic_state *state) {
> > + struct drm_plane_state *new_state =
> drm_atomic_get_new_plane_state(state, plane);
> > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> > + struct vs_dc *dc = &priv->dc;
> > + struct drm_framebuffer *fb = new_state->fb;
> > + const struct vs_plane_cursor_info *cursor_info;
> > + struct drm_crtc_state *crtc_state;
> > + int i;
> > +
> > + if (!new_state->crtc || !new_state->fb)
> > + return 0;
> > +
> > + for (i = 0; i < dc->hw.info->cursor_num; i++) {
> > + cursor_info = (struct vs_plane_cursor_info *)&dc->hw.info->cursor[i];
> > + if (cursor_info->id == to_vs_plane(plane)->id)
> > + break;
> > + }
> > +
> > + cursor_info = &dc->hw.info->cursor[i];
> > +
> > + if (fb->width < cursor_info->min_width ||
> > + fb->width > cursor_info->max_width ||
> > + fb->height < cursor_info->min_height ||
> > + fb->height > cursor_info->max_height)
> > + drm_err_once(plane->dev, "buffer size may not support on
> plane%d.\n",
> > + to_vs_plane(plane)->id);
> > +
> > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state,
> new_state->crtc);
> > + return drm_atomic_helper_check_plane_state(new_state, crtc_state,
> > + DRM_PLANE_NO_SCALING,
> > + DRM_PLANE_NO_SCALING,
> > + true, true);
>
> Looking at these three functions:
> - Define a common struct for plane info;
ok
> - Define a single function handling common case;
Ok
> - Extend it as necessary for primary / overlay cases (or just skip the
> corresponding check for cursor plane type).
This greatly reduces the duplication of code lines
>
> > +}
> > +
> > +static void vs_plane_atomic_update(struct drm_plane *plane, struct
> > +drm_atomic_state *state) {
> > + struct drm_plane_state *new_state =
> drm_atomic_get_new_plane_state(state, plane);
> > + struct drm_plane_state *old_state =
> > +drm_atomic_get_old_plane_state(state, plane);
> > +
> > + unsigned char i, num_planes, display_id, id;
> > + u32 format;
> > + bool is_yuv;
> > + struct vs_plane *vs_plane = to_vs_plane(plane);
> > + struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
> > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> > + struct vs_dc *dc = &priv->dc;
> > +
> > + if (!new_state->fb || !new_state->crtc)
> > + return;
> > +
> > + drm_fb_dma_sync_non_coherent(plane->dev, old_state, new_state);
> > +
> > + num_planes = vs_get_plane_number(new_state->fb);
> > +
> > + for (i = 0; i < num_planes; i++) {
> > + dma_addr_t dma_addr;
> > +
> > + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state,
> i);
> > + plane_state->dma_addr[i] = dma_addr;
> > + }
> > +
> > + display_id = to_vs_display_id(dc, new_state->crtc);
> > + format = new_state->fb->format->format;
> > + is_yuv = new_state->fb->format->is_yuv;
> > + id = vs_plane->id;
> > +
> > + plane_hw_update_format_colorspace(dc, format,
> new_state->color_encoding, id, is_yuv);
> > + if (new_state->visible)
> > + plane_hw_update_address(dc, id, format, plane_state->dma_addr,
> > + new_state->fb, &new_state->src);
> > + plane_hw_update_format(dc, format, new_state->color_encoding,
> new_state->rotation,
> > + new_state->visible, new_state->zpos, id, display_id);
> > + plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id,
> > + display_id, new_state->rotation);
> > + plane_hw_update_blend(dc, new_state->alpha,
> new_state->pixel_blend_mode,
> > + id, display_id);
> > +}
> > +
> > +static void vs_cursor_plane_atomic_update(struct drm_plane *plane,
> > +struct drm_atomic_state *state) {
> > + struct drm_plane_state *new_state =
> drm_atomic_get_new_plane_state(state,
> > + plane);
> > + struct drm_plane_state *old_state =
> drm_atomic_get_old_plane_state(state,
> > + plane);
> > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> > + struct vs_dc *dc = &priv->dc;
> > + unsigned char display_id;
> > + u32 crtc_w, crtc_x, crtc_y;
> > + s32 hotspot_x, hotspot_y;
> > + dma_addr_t dma_addr;
> > +
> > + display_id = to_vs_display_id(dc, new_state->crtc);
> > +
> > + if (!new_state->fb || !new_state->crtc)
> > + return;
> > +
> > + drm_fb_dma_sync_non_coherent(new_state->fb->dev, old_state,
> new_state);
> > + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, 0);
> > + crtc_w = new_state->crtc_w;
> > +
> > + if (new_state->crtc_x > 0) {
> > + crtc_x = new_state->crtc_x;
> > + hotspot_x = 0;
> > + } else {
> > + hotspot_x = -new_state->crtc_x;
> > + crtc_x = 0;
> > + }
> > + if (new_state->crtc_y > 0) {
> > + crtc_y = new_state->crtc_y;
> > + hotspot_y = 0;
> > + } else {
> > + hotspot_y = -new_state->crtc_y;
> > + crtc_y = 0;
> > + }
> > + dc_hw_update_cursor(&dc->hw, display_id, dma_addr, crtc_w, crtc_x,
> > + crtc_y, hotspot_x, hotspot_y); }
> > +
> > +static void vs_plane_atomic_disable(struct drm_plane *plane, struct
> > +drm_atomic_state *state) {
> > + struct vs_plane *vs_plane = to_vs_plane(plane);
> > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> > + struct vs_dc *dc = &priv->dc;
> > +
> > + dc_hw_disable_plane(dc, vs_plane->id); }
> > +
> > +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane,
> > +struct drm_atomic_state *state) {
> > + struct drm_plane_state *old_state =
> drm_atomic_get_old_plane_state(state, plane);
> > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev);
> > + struct vs_dc *dc = &priv->dc;
> > + unsigned char display_id;
> > +
> > + display_id = to_vs_display_id(dc, old_state->crtc);
> > + dc_hw_disable_cursor(&dc->hw, display_id); }
> > +
> > +const struct drm_plane_helper_funcs primary_plane_helpers = {
> > + .atomic_check = vs_primary_plane_atomic_check,
> > + .atomic_update = vs_plane_atomic_update,
> > + .atomic_disable = vs_plane_atomic_disable, };
> > +
> > +const struct drm_plane_helper_funcs overlay_plane_helpers = {
> > + .atomic_check = vs_overlay_plane_atomic_check,
> > + .atomic_update = vs_plane_atomic_update,
> > + .atomic_disable = vs_plane_atomic_disable, };
> > +
> > +const struct drm_plane_helper_funcs cursor_plane_helpers = {
> > + .atomic_check = vs_cursor_plane_atomic_check,
> > + .atomic_update = vs_cursor_plane_atomic_update,
> > + .atomic_disable = vs_cursor_plane_atomic_disable, };
> > +
> > +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev,
> > + struct vs_plane_primary_info *info,
> > + unsigned int layer_num,
> > + unsigned int possible_crtcs)
> > +{
> > + struct vs_plane *plane;
> > + int ret;
> > +
> > + if (!info)
> > + return NULL;
> > +
> > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
> > + possible_crtcs,
> > + &vs_plane_funcs,
> > + info->formats, info->num_formats,
> > + info->modifiers, DRM_PLANE_TYPE_PRIMARY,
> > + NULL);
> > + if (IS_ERR(plane))
> > + return ERR_CAST(plane);
> > +
> > + drm_plane_helper_add(&plane->base, &primary_plane_helpers);
> > +
> > + drm_plane_create_alpha_property(&plane->base);
> > + drm_plane_create_blend_mode_property(&plane->base,
> > + BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> > + BIT(DRM_MODE_BLEND_PREMULTI) |
> > + BIT(DRM_MODE_BLEND_COVERAGE));
> > +
> > + if (info->color_encoding) {
> > + ret = drm_plane_create_color_properties(&plane->base,
> info->color_encoding,
> > + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
> > + DRM_COLOR_YCBCR_BT709,
> > + DRM_COLOR_YCBCR_LIMITED_RANGE);
> > + if (ret)
> > + return NULL;
> > + }
> > +
> > + if (info->rotation) {
> > + ret = drm_plane_create_rotation_property(&plane->base,
> > + DRM_MODE_ROTATE_0,
> > + info->rotation);
> > + if (ret)
> > + return NULL;
> > + }
> > +
> > + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
> layer_num - 1);
> > + if (ret)
> > + return NULL;
> > +
> > + return plane;
> > +}
> > +
> > +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev,
> > + struct vs_plane_overlay_info *info,
> > + unsigned int layer_num,
> > + unsigned int possible_crtcs)
>
> This looks almost like a previous function. Consider merging them.
Ok ,got it
>
> > +{
> > + struct vs_plane *plane;
> > + int ret;
> > +
> > + if (!info)
> > + return NULL;
> > +
> > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
> > + possible_crtcs,
> > + &vs_plane_funcs,
> > + info->formats, info->num_formats,
> > + info->modifiers, DRM_PLANE_TYPE_OVERLAY,
> > + NULL);
> > + if (IS_ERR(plane))
> > + return ERR_CAST(plane);
> > +
> > + drm_plane_helper_add(&plane->base, &overlay_plane_helpers);
> > +
> > + drm_plane_create_alpha_property(&plane->base);
> > + drm_plane_create_blend_mode_property(&plane->base,
> > + BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> > + BIT(DRM_MODE_BLEND_PREMULTI) |
> > + BIT(DRM_MODE_BLEND_COVERAGE));
> > +
> > + if (info->color_encoding) {
> > + ret = drm_plane_create_color_properties(&plane->base,
> info->color_encoding,
> > + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
> > + DRM_COLOR_YCBCR_BT709,
> > + DRM_COLOR_YCBCR_LIMITED_RANGE);
> > + if (ret)
> > + return NULL;
> > + }
> > +
> > + if (info->rotation) {
> > + ret = drm_plane_create_rotation_property(&plane->base,
> > + DRM_MODE_ROTATE_0,
> > + info->rotation);
> > + if (ret)
> > + return NULL;
> > + }
> > +
> > + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
> layer_num - 1);
> > + if (ret)
> > + return NULL;
> > +
> > + return plane;
> > +}
> > +
> > +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev,
> > + struct vs_plane_cursor_info *info,
> > + unsigned int possible_crtcs)
> > +{
> > + struct vs_plane *plane;
> > + int ret;
> > +
> > + if (!info)
> > + return NULL;
> > +
> > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
> > + possible_crtcs,
> > + &vs_plane_funcs,
> > + info->formats, info->num_formats,
> > + NULL, DRM_PLANE_TYPE_CURSOR,
> > + NULL);
> > + if (IS_ERR(plane))
> > + return ERR_CAST(plane);
> > +
> > + drm_plane_helper_add(&plane->base, &cursor_plane_helpers);
> > +
> > + ret = drm_plane_create_zpos_immutable_property(&plane->base,
> info->zpos);
> > + if (ret)
> > + return NULL;
> > +
> > + return plane;
> > +}
> > diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h
> > b/drivers/gpu/drm/verisilicon/vs_plane.h
> > new file mode 100644
> > index 000000000000..0416146226a8
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_plane.h
> > @@ -0,0 +1,26 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_PLANE_H__
> > +#define __VS_PLANE_H__
> > +
> > +#include <drm/drm_plane_helper.h>
> > +
> > +#include "vs_drv.h"
> > +
> > +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev,
> > + struct vs_plane_primary_info *info,
> > + unsigned int layer_num,
> > + unsigned int possible_crtcs);
> > +
> > +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev,
> > + struct vs_plane_overlay_info *info,
> > + unsigned int layer_num,
> > + unsigned int possible_crtcs);
> > +
> > +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev,
> > + struct vs_plane_cursor_info *info,
> > + unsigned int possible_crtcs);
> > +#endif /* __VS_PLANE_H__ */
> > --
> > 2.27.0
> >
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 10/10] drm/vs: add simple dsi encoder
2024-05-21 15:25 ` Dmitry Baryshkov
@ 2024-06-23 7:17 ` Keith Zhao
2024-06-23 21:11 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-23 7:17 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Dmitry:
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年5月21日 23:25
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder
>
> On Tue, May 21, 2024 at 06:58:17PM +0800, keith wrote:
> > add encoder to match cdns dsi driver
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
>
> Please fix your git configuration to include your full name into the S-o-B and
> Author fields.
Ok ,will fix it
>
> > ---
> > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > drivers/gpu/drm/verisilicon/vs_drv.c | 1 +
> > drivers/gpu/drm/verisilicon/vs_drv.h | 1 +
> > drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190
> > ++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_simple_enc.h |
> > 25 +++
> > 5 files changed, 219 insertions(+), 1 deletion(-) create mode 100644
> > drivers/gpu/drm/verisilicon/vs_simple_enc.c
> > create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
> >
> > diff --git a/drivers/gpu/drm/verisilicon/Makefile
> > b/drivers/gpu/drm/verisilicon/Makefile
> > index 2d02b4a3a567..c35ba9bd6f81 100644
> > --- a/drivers/gpu/drm/verisilicon/Makefile
> > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > @@ -4,7 +4,8 @@ vs_drm-objs := vs_dc_hw.o \
> > vs_modeset.o \
> > vs_plane.o \
> > vs_crtc.o \
> > - vs_drv.o
> > + vs_drv.o \
> > + vs_simple_enc.o
> >
> > vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o
> > obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git
> > a/drivers/gpu/drm/verisilicon/vs_drv.c
> > b/drivers/gpu/drm/verisilicon/vs_drv.c
> > index 6f04102b05b3..2748d48f2c7e 100644
> > --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> > +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> > @@ -612,6 +612,7 @@ static struct platform_driver *drm_sub_drivers[] =
> > { #ifdef CONFIG_DRM_INNO_STARFIVE_HDMI
> > &starfive_hdmi_driver,
> > #endif
> > + &simple_encoder_driver,
> > };
> >
> > static struct component_match *vs_add_external_components(struct
> > device *dev) diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h
> > b/drivers/gpu/drm/verisilicon/vs_drv.h
> > index c3c08ed5f8ac..f3f0f170777d 100644
> > --- a/drivers/gpu/drm/verisilicon/vs_drv.h
> > +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> > @@ -17,6 +17,7 @@
> > #include <drm/drm_managed.h>
> >
> > #include "vs_dc_hw.h"
> > +#include "vs_simple_enc.h"
> >
> > /*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
> > struct vs_drm_device { diff --git
> > a/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> > b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> > new file mode 100644
> > index 000000000000..d0b1755d77d2
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> > @@ -0,0 +1,190 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
>
> Now it is 2024, so the copyright should probably cover the range.
Ok ,will fix it
>
> > + */
> > +#include <linux/component.h>
> > +#include <linux/of_device.h>
> > +#include <linux/module.h>
> > +#include <linux/regmap.h>
> > +#include <linux/media-bus-format.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/of.h>
> > +
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_bridge.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <drm/drm_of.h>
> > +
> > +#include "vs_crtc.h"
> > +#include "vs_simple_enc.h"
> > +
> > +static const struct simple_encoder_priv dsi_priv = {
> > + .encoder_type = DRM_MODE_ENCODER_DSI
>
> So, is it 'simple' aka something generic or DSI? In the latter case, please rename
> it accordingly.
Ok will done
>
> > +};
> > +
> > +static inline struct vs_simple_encoder *to_simple_encoder(struct
> > +drm_encoder *enc) {
> > + return container_of(enc, struct vs_simple_encoder, encoder); }
> > +
> > +static int encoder_parse_dt(struct device *dev) {
> > + struct vs_simple_encoder *simple = dev_get_drvdata(dev);
> > + unsigned int args[2];
> > +
> > + simple->dss_regmap =
> syscon_regmap_lookup_by_phandle_args(dev->of_node,
> > + "starfive,syscon",
> > + 2, args);
> > +
> > + if (IS_ERR(simple->dss_regmap)) {
> > + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
> > + "getting the regmap failed\n");
> > + }
> > +
> > + simple->offset = args[0];
> > + simple->mask = args[1];
>
> Is the value that you've read platform dependent or use case dependent?
> What is the actual value being written? Why are you using syscon for it?
The syscon is used to select crtcs binded with encoder,
If this encoder binds to crtc0 , set the syscon reg bit0 = 1
If this encoder binds to crtc1 , set the syscon reg bit1 = 1 (0x2)
Maybe I can do this by the possible_crtc instead of using args from dts
>
> > +
> > + return 0;
> > +}
> > +
> > +static void vs_encoder_atomic_enable(struct drm_encoder *encoder,
> > +struct drm_atomic_state *state) {
> > + struct vs_simple_encoder *simple = to_simple_encoder(encoder);
> > +
> > + regmap_update_bits(simple->dss_regmap, simple->offset, simple->mask,
> > +simple->mask);
>
>
> A purist in me would ask to have separate mask and value to write.
Understand , will avoid this action
>
> > +}
>
> Is it necessary to clear those bits when stopping the stream?
No need to do this , if clear those bits , the encoder will point to a unknown crtc
>
>
> [skipped the rest]
>
> > +
> > +
> > +struct platform_driver simple_encoder_driver = {
> > + .probe = vs_encoder_probe,
> > + .remove = vs_encoder_remove,
> > + .driver = {
> > + .name = "vs-simple-encoder",
> > + .of_match_table = of_match_ptr(simple_encoder_dt_match),
> > + },
> > +};
> > +
> > +MODULE_DESCRIPTION("Simple Encoder Driver");
>
> VeriSilicon DSI Encoder
Ok will done
>
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.h
> > b/drivers/gpu/drm/verisilicon/vs_simple_enc.h
> > new file mode 100644
> > index 000000000000..73e356bfeb2c
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.h
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2022 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_SIMPLE_ENC_H_
> > +#define __VS_SIMPLE_ENC_H_
> > +
> > +#include <drm/drm_encoder.h>
> > +
> > +struct simple_encoder_priv {
> > + unsigned char encoder_type;
> > +};
> > +
> > +struct vs_simple_encoder {
> > + struct drm_encoder encoder;
> > + struct device *dev;
> > + const struct simple_encoder_priv *priv;
> > + struct regmap *dss_regmap;
> > + unsigned int offset;
> > + unsigned int mask;
> > +};
>
> Is there a need for aheader for the encoder? Can you move the definitions to
> the source file?
Ok will done
>
> > +
> > +extern struct platform_driver simple_encoder_driver; #endif /*
> > +__VS_SIMPLE_ENC_H_ */
> > --
> > 2.27.0
> >
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver
2024-05-22 7:24 ` Maxime Ripard
@ 2024-06-23 7:17 ` Keith Zhao
2024-06-24 9:25 ` Maxime Ripard
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-23 7:17 UTC (permalink / raw)
To: Maxime Ripard
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, tzimmermann@suse.de,
airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com,
heiko@sntech.de, andy.yan@rock-chips.com, Xingyu Wu,
p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Maxime:
> -----Original Message-----
> From: Maxime Ripard <mripard@kernel.org>
> Sent: 2024年5月22日 15:25
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> tzimmermann@suse.de; airlied@gmail.com; daniel@ffwll.ch; robh@kernel.org;
> krzk+dt@kernel.org; conor+dt@kernel.org; hjc@rock-chips.com;
> heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi
> bridge driver
>
> Hi,
>
> On Tue, May 21, 2024 at 06:58:10PM GMT, keith wrote:
> > Add the ROCKCHIP inno hdmi driver that uses the Inno DesignWare HDMI
> > TX bridge and remove the old separate one.
> >
> > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > ---
> > drivers/gpu/drm/rockchip/Kconfig | 1 +
> > drivers/gpu/drm/rockchip/Makefile | 2 +-
> > drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++
> > .../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 -
> > drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 -----------------
> > 5 files changed, 519 insertions(+), 1119 deletions(-) create mode
> > 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h}
> > (85%) delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
> >
> > diff --git a/drivers/gpu/drm/rockchip/Kconfig
> > b/drivers/gpu/drm/rockchip/Kconfig
> > index 1bf3e2829cd0..cc6cfd5a30d6 100644
> > --- a/drivers/gpu/drm/rockchip/Kconfig
> > +++ b/drivers/gpu/drm/rockchip/Kconfig
> > @@ -74,6 +74,7 @@ config ROCKCHIP_DW_MIPI_DSI
> >
> > config ROCKCHIP_INNO_HDMI
> > bool "Rockchip specific extensions for Innosilicon HDMI"
> > + select DRM_INNO_HDMI
> > help
> > This selects support for Rockchip SoC specific extensions
> > for the Innosilicon HDMI driver. If you want to enable diff --git
> > a/drivers/gpu/drm/rockchip/Makefile
> > b/drivers/gpu/drm/rockchip/Makefile
> > index 3ff7b21c0414..4b2d0cba8db3 100644
> > --- a/drivers/gpu/drm/rockchip/Makefile
> > +++ b/drivers/gpu/drm/rockchip/Makefile
> > @@ -12,7 +12,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) +=
> > analogix_dp-rockchip.o
> > rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
> > rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
> > rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) +=
> dw-mipi-dsi-rockchip.o
> > -rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
> > +rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi-rockchip.o
> > rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
> > rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
> > rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o diff
> > --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > new file mode 100644
> > index 000000000000..69d0e913e13b
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > @@ -0,0 +1,517 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> > + * Zheng Yang <zhengyang@rock-chips.com>
> > + * Yakir Yang <ykk@rock-chips.com>
> > + */
> > +
> > +#include <linux/irq.h>
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/hdmi.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/platform_device.h>
> > +
> > +#include <drm/bridge/inno_hdmi.h>
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_edid.h>
> > +#include <drm/drm_of.h>
> > +#include <drm/drm_probe_helper.h>
> > +#include <drm/drm_simple_kms_helper.h>
> > +
> > +#include "rockchip_drm_drv.h"
> > +
> > +#include "inno_hdmi-rockchip.h"
> > +
> > +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
> > +
> > +struct rk_inno_hdmi {
> > + struct rockchip_encoder encoder;
> > + struct inno_hdmi inno_hdmi;
> > + struct clk *pclk;
> > + struct clk *refclk;
> > +};
> > +
> > +static struct inno_hdmi *rk_encoder_to_inno_hdmi(struct drm_encoder
> > +*encoder) {
> > + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
> > + struct rk_inno_hdmi *rk_hdmi = container_of(rkencoder, struct
> > +rk_inno_hdmi, encoder);
> > +
> > + return &rk_hdmi->inno_hdmi;
> > +}
> > +
> > +enum {
> > + CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
> > + CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
> > + CSC_RGB_0_255_TO_RGB_16_235_8BIT,
> > +};
> > +
> > +static const char coeff_csc[][24] = {
> > + /*
> > + * RGB2YUV:601 SD mode:
> > + * Cb = -0.291G - 0.148R + 0.439B + 128
> > + * Y = 0.504G + 0.257R + 0.098B + 16
> > + * Cr = -0.368G + 0.439R - 0.071B + 128
> > + */
> > + {
> > + 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
> > + 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
> > + 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
> > + },
> > + /*
> > + * RGB2YUV:709 HD mode:
> > + * Cb = - 0.338G - 0.101R + 0.439B + 128
> > + * Y = 0.614G + 0.183R + 0.062B + 16
> > + * Cr = - 0.399G + 0.439R - 0.040B + 128
> > + */
> > + {
> > + 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
> > + 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
> > + 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
> > + },
> > + /*
> > + * RGB[0:255]2RGB[16:235]:
> > + * R' = R x (235-16)/255 + 16;
> > + * G' = G x (235-16)/255 + 16;
> > + * B' = B x (235-16)/255 + 16;
> > + */
> > + {
> > + 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
> > + 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
> > + 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
> > + },
> > +};
> > +
> > +static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
> > + { 74250000, 0x3f, 0xbb },
> > + { 165000000, 0x6f, 0xbb },
> > + { ~0UL, 0x00, 0x00 }
> > +};
> > +
> > +static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = {
> > + { 74250000, 0x3f, 0xaa },
> > + { 165000000, 0x5f, 0xaa },
> > + { ~0UL, 0x00, 0x00 }
> > +};
> > +
> > +static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi,
> > + unsigned long pixelclk)
> > +{
> > + const struct inno_hdmi_phy_config *phy_configs =
> hdmi->plat_data->phy_configs;
> > + int i;
> > +
> > + for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) {
> > + if (pixelclk <= phy_configs[i].pixelclock)
> > + return i;
> > + }
> > +
> > + DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n",
> > + pixelclk);
> > +
> > + return -EINVAL;
> > +}
> > +
> > +static void inno_hdmi_standby(struct inno_hdmi *hdmi) {
> > + inno_hdmi_sys_power(hdmi, false);
> > +
> > + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
> > + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
> > + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
> > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); };
> > +
> > +static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
> > + unsigned long mpixelclock)
> > +{
> > + struct inno_hdmi_phy_config *phy_config;
> > + int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock);
> > +
> > + if (ret < 0) {
> > + phy_config = hdmi->plat_data->default_phy_config;
> > + DRM_DEV_ERROR(hdmi->dev,
> > + "Using default phy configuration for TMDS rate %lu",
> > + mpixelclock);
> > + } else {
> > + phy_config = &hdmi->plat_data->phy_configs[ret];
> > + }
> > +
> > + inno_hdmi_sys_power(hdmi, false);
> > +
> > + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS,
> phy_config->pre_emphasis);
> > + hdmi_writeb(hdmi, HDMI_PHY_DRIVER,
> phy_config->voltage_level_control);
> > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
> > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
> > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
> > + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
> > + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
> > + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
> > +
> > + inno_hdmi_sys_power(hdmi, true);
> > +};
> > +
> > +static void inno_hdmi_reset(struct inno_hdmi *hdmi) {
> > + u32 val;
> > + u32 msk;
> > +
> > + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL,
> v_NOT_RST_DIGITAL);
> > + udelay(100);
> > +
> > + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG,
> v_NOT_RST_ANALOG);
> > + udelay(100);
> > +
> > + msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
> > + val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON |
> v_INT_POL_HIGH;
> > + hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
> > +
> > + inno_hdmi_standby(hdmi);
> > +}
> > +
> > +static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) {
> > + struct drm_connector *connector = &hdmi->connector;
> > + struct drm_connector_state *conn_state = connector->state;
> > + struct inno_hdmi_connector_state *inno_conn_state =
> > + to_inno_hdmi_conn_state(conn_state);
> > + int c0_c2_change = 0;
> > + int csc_enable = 0;
> > + int csc_mode = 0;
> > + int auto_csc = 0;
> > + int value;
> > + int i;
> > +
> > + /* Input video mode is SDR RGB24bit, data enable signal from external */
> > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
> > + v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
> > +
> > + /* Input color hardcode to RGB, and output color hardcode to RGB888 */
> > + value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
> > + v_VIDEO_OUTPUT_COLOR(0) |
> > + v_VIDEO_INPUT_CSP(0);
> > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
> > +
> > + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
> > + if (inno_conn_state->rgb_limited_range) {
> > + csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT;
> > + auto_csc = AUTO_CSC_DISABLE;
> > + c0_c2_change = C0_C2_CHANGE_DISABLE;
> > + csc_enable = v_CSC_ENABLE;
> > +
> > + } else {
> > + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
> > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
> > +
> > + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
> > + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
> > + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
> > + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
> > + return 0;
> > + }
> > + } else {
> > + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601)
> {
> > + if (inno_conn_state->enc_out_format ==
> HDMI_COLORSPACE_YUV444) {
> > + csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
> > + auto_csc = AUTO_CSC_DISABLE;
> > + c0_c2_change = C0_C2_CHANGE_DISABLE;
> > + csc_enable = v_CSC_ENABLE;
> > + }
> > + } else {
> > + if (inno_conn_state->enc_out_format ==
> HDMI_COLORSPACE_YUV444) {
> > + csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
> > + auto_csc = AUTO_CSC_DISABLE;
> > + c0_c2_change = C0_C2_CHANGE_DISABLE;
> > + csc_enable = v_CSC_ENABLE;
> > + }
> > + }
> > + }
> > +
> > + for (i = 0; i < 24; i++)
> > + hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
> > + coeff_csc[csc_mode][i]);
> > +
> > + value = v_SOF_DISABLE | csc_enable |
> v_COLOR_DEPTH_NOT_INDICATED(1);
> > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
> > + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
> > + m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
> > + v_VIDEO_C0_C2_SWAP(c0_c2_change));
> > +
> > + return 0;
> > +}
> > +
> > +static int inno_hdmi_setup(struct inno_hdmi *hdmi,
> > + struct drm_display_mode *mode)
> > +{
> > + struct drm_display_info *display = &hdmi->connector.display_info;
> > + unsigned long mpixelclock = mode->clock * 1000;
> > +
> > + /* Mute video and audio output */
> > + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
> > + v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
> > +
> > + /* Set HDMI Mode */
> > + hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
> > + v_HDMI_DVI(display->is_hdmi));
> > +
> > + inno_hdmi_config_video_timing(hdmi, mode);
> > +
> > + inno_hdmi_config_video_csc(hdmi);
> > +
> > + if (display->is_hdmi)
> > + inno_hdmi_config_video_avi(hdmi, mode);
> > +
> > + /*
> > + * When IP controller have configured to an accurate video
> > + * timing, then the TMDS clock source would be switched to
> > + * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
> > + * clock rate, and reconfigure the DDC clock.
> > + */
> > + inno_hdmi_i2c_init(hdmi, mpixelclock);
> > +
> > + /* Unmute video and audio output */
> > + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
> > + v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
> > +
> > + inno_hdmi_power_up(hdmi, mpixelclock);
> > +
> > + return 0;
> > +}
> >
>
> It's kind of a general comment, but I don't think that's the right abstraction. You
> should create a inno_hdmi bridge that allows to supplement some of the atomic
> hooks, but not reimplement them entirely each time.
>
> You can have a look at how dw-hdmi does it for example. Also, why do you still
> need the encoder and connectors?
>
Hi Maxime:
This series of patches does not consider referencing bridge ,
just split the public interface based on the current structure (encoder + connector),
and then make it into a public API.
The next step is to implement the driver code of the public part based on the bridge architecture.
By the way, does the current situation require the introduction of the next_bridge concept?
dw-hdmi attach:
static int dw_hdmi_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct dw_hdmi *hdmi = bridge->driver_private;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
return drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
bridge, flags);
return dw_hdmi_connector_create(hdmi);
}
For inno hdmi , I want to define it like this , will it be ok?
static int inno_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
......
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
DRM_ERROR("Fix bridge driver to make connector optional!");
return -EINVAL;
}
return 0;
}
......
And then , create the connector outside of bridge:
ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0);
if (ret)
return ret;
hdmi->connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(hdmi->connector)) {
dev_err(dev, "Unable to create bridge connector\n");
ret = PTR_ERR(hdmi->connector);
return ret;
}
Best regards
> Maxime
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi
2024-05-21 10:58 ` [PATCH v4 02/10] drm/bridge: add common api for inno hdmi keith
2024-05-21 9:30 ` Krzysztof Kozlowski
2024-05-21 15:36 ` Alex Bee
@ 2024-06-23 18:42 ` Markus Elfring
2 siblings, 0 replies; 53+ messages in thread
From: Markus Elfring @ 2024-06-23 18:42 UTC (permalink / raw)
To: Keith Zhao, dri-devel, devicetree, linux-arm-kernel,
Andrzej Hajda, Andy Yan, Conor Dooley, Daniel Vetter,
David Airlie, Heiko Stübner, Jack Zhu, Jernej Skrabec,
Jonas Karlman, Krzysztof Kozlowski, Laurent Pinchart,
Maarten Lankhorst, Maxime Ripard, Neil Armstrong, Philipp Zabel,
Robert Foss, Rob Herring, Sandy Huang, Shengyang Chen,
Thomas Zimmermann, Xingyu Wu
Cc: LKML
…
> Signed-off-by: keith <keith.zhao@starfivetech.com>
Should the personal name be more unique
(according to the Developer's Certificate of Origin)?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.10-rc4#n438
…
> +++ b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c
> @@ -0,0 +1,587 @@
…
> +static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap,
> + struct i2c_msg *msgs, int num)
> +{
…
> + mutex_lock(&i2c->lock);
> +
> + /* Clear the EDID interrupt flag and unmute the interrupt */
…
> + hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
> +
> + mutex_unlock(&i2c->lock);
> +
> + return ret;
> +}
…
Would you become interested to apply a statement like “guard(mutex)(&i2c->lock);”?
https://elixir.bootlin.com/linux/v6.10-rc4/source/include/linux/mutex.h#L196
Regards,
Markus
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-06-23 7:16 ` Keith Zhao
@ 2024-06-23 20:51 ` Dmitry Baryshkov
2024-06-25 8:32 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-06-23 20:51 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Hi Keith,
On Sun, Jun 23, 2024 at 07:16:47AM GMT, Keith Zhao wrote:
> > On Tue, May 21, 2024 at 06:58:11PM +0800, keith wrote:
> > > +}
> > > +
> > > +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
> > > +{
> > > + u32 value = dc_read(hw, reg);
> > > +
> > > + value &= ~clear;
> > > + value |= set;
> > > + dc_write(hw, reg, value);
> >
> > regmap_update_bits?
>
> regmap_update_bits follows 4 steps:
>
> 1、ret = _regmap_read(map, reg, &orig);
> .........
>
> 2、tmp = orig & ~mask;
> 3、tmp |= val & mask;
> ......
> 4、ret = _regmap_write(map, reg, tmp);
> If the value out of mask range
> It will just clear the mask bir
>
> dc_set_clear will do clear and set without limit.
>
> Maybe the name should be dc_clear_set
This is not really better. regmap_update_bits() has clear semantics of
updating a value in the field that is defined by a mask. You function is
just clearing some bits and setting other bits. It's not obvious whether
it is a mask and value, several concurrent flags or something else.
Even if you are not going to switch to regmaps (you don't have to),
please use mask & value instead.
> }
> > > +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
> >
> > Is there any reason why load_rgb_to_yuv differs from two other
> > functions?
> >
> load_rgb_to_yuv matches crtcs
>
> load_yuv_to_rgb matches planes
> load_rgb_to_rgb matches planes
Then these functins should have that reflected in their names (and also
documented, why). If the CSC programming interface is similar, please
split the implementation to have common code and different data to be
used for programming.
> the coefficient(table) is diff between load_rgb_to_yuv and load_yuv_to_rgb
> > > +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct
> > drm_rect *dst,
> > > + u8 id, u8 display_id, unsigned int rotation);
> > > +void plane_hw_update_blend(struct vs_dc *dc, u16 alpha, u16
> > pixel_blend_mode,
> > > + u8 id, u8 display_id);
> >
> > Could you please settle on a single prefix for all your function names?
> > Ideally it should be close to the driver name. It's hard to understand
> > that the function comes from the verisilicon driver if its name starts
> > from dc_ or especially with plane_.
> Yes starting with plane_ is not a good idea ,i will add vs_
> _ , thanks
> >
> > I'd strongly suggest to stop defining anything outside of the selected
> I don't quite understand what "the selected" means,
> I hope you can fill in some specific details about it
> Thanks
"the selected vs_ namespace". So prefix all function names and all
structures with vs_
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 05/10] drm/vs: add vs mode config init
2024-06-23 7:17 ` Keith Zhao
@ 2024-06-23 20:52 ` Dmitry Baryshkov
0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-06-23 20:52 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
On Sun, Jun 23, 2024 at 07:17:01AM GMT, Keith Zhao wrote:
> Hi Dmitry:
>
> > -----Original Message-----
> > From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Please drop such headers from your replies. A simple "On 1st of January
John Doe wrote" is more than enough.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 06/10] drm/vs: add vs plane api
2024-06-23 7:17 ` Keith Zhao
@ 2024-06-23 20:54 ` Dmitry Baryshkov
0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-06-23 20:54 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
On Sun, Jun 23, 2024 at 07:17:07AM GMT, Keith Zhao wrote:
> >
> > On Tue, May 21, 2024 at 06:58:13PM +0800, keith wrote:
> > > add plane funs and helper funs
> > > add vs drm common struct and funs
> > >
> > > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > > ---
> > > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > > drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++
> > > drivers/gpu/drm/verisilicon/vs_plane.c | 487
> > > +++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_plane.h |
> > > 26 ++
> > > 4 files changed, 608 insertions(+), 1 deletion(-) create mode 100644
> > > drivers/gpu/drm/verisilicon/vs_drv.h
> > > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
> > > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
> > > +
> > > +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
> >
> > Is that all the docs you want to add?
> It should delete the redundant parts which is unused,
> To make this patch clearer to review
I'm sorry, I can't understand your comment.
> >
> > > +struct vs_drm_device {
> > > + struct drm_device base;
> > > + unsigned int pitch_alignment;
> > > + /* clocks */
> > > + unsigned int clk_count;
> > > + struct clk_bulk_data *clks;
> > > + struct reset_control *rsts;
> > > + struct vs_dc dc;
> > > + int irq;
> >
> > As usual, please drop unused fields and add them when required.
>
> In principle, I try to split the patch independently according to this.
> In fact, there is still a lot of room for optimization
> The subsequent patches will maintain independence and remove redundant parts for decoupling
Yes, please.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 07/10] drm/vs: add ctrc fun
2024-06-23 7:17 ` Keith Zhao
@ 2024-06-23 20:56 ` Dmitry Baryshkov
0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-06-23 20:56 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
On Sun, Jun 23, 2024 at 07:17:04AM GMT, Keith Zhao wrote:
> > On Tue, May 21, 2024 at 06:58:14PM +0800, keith wrote:
> > > add crtc funs and helper funs
> > >
> > > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > > ---
> > > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > > drivers/gpu/drm/verisilicon/vs_crtc.c | 241
> > > ++++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_crtc.h |
> > > 17 ++
> > > 3 files changed, 260 insertions(+), 1 deletion(-) create mode 100644
> > > drivers/gpu/drm/verisilicon/vs_crtc.c
> > > create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
> > >
> > > diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h
> > > b/drivers/gpu/drm/verisilicon/vs_crtc.h
> > > new file mode 100644
> > > index 000000000000..b1e588bb780d
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
> > > @@ -0,0 +1,17 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +/*
> > > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > > + */
> > > +
> > > +#ifndef __VS_CRTC_H__
> > > +#define __VS_CRTC_H__
> > > +
> > > +#include <drm/drm_crtc.h>
> > > +#include <drm/drm_crtc_helper.h>
> >
> > Do you really need to include them here?
> >
> The location of include can be optimized
> Delete #include <drm/drm_crtc.h>
> Move drm_crtc_helper.h to vs_crtc.c
Yes, please.
>
> > > +
> > > +#include "vs_drv.h"
> > > +
> > > +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> > > + struct vs_dc_info *info);
This prototype needs #include <drm_device.h>, not drm_crtc*.
Or even better drop the include completely and just formward-declare the
structure:
struct drm_device;
struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev, struct
vs_dc_info *info);
> > > +
> > > +#endif /* __VS_CRTC_H__ */
> > > --
> > > 2.27.0
> > >
> >
> > --
> > With best wishes
> > Dmitry
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 08/10] drm/vs: add vs drm master driver
2024-06-23 7:16 ` Keith Zhao
@ 2024-06-23 21:07 ` Dmitry Baryshkov
2024-06-25 8:34 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-06-23 21:07 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
On Sun, Jun 23, 2024 at 07:16:57AM GMT, Keith Zhao wrote:
> > On Tue, May 21, 2024 at 06:58:15PM +0800, keith wrote:
> > > Add vs DRM master driver for JH7110 SoC ADD DMA GEM driver
> > >
> > > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > > ---
> > > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > > drivers/gpu/drm/verisilicon/vs_drv.c | 718
> > > +++++++++++++++++++++++++++
> > > 2 files changed, 720 insertions(+), 1 deletion(-) create mode 100644
> > > drivers/gpu/drm/verisilicon/vs_drv.c
> > >
> > BIT(DRM_COLOR_YCBCR_BT2020),
> > > + .zpos = 0,
> >
> > How are these zpos related to the zpos from drm_plane_state?
> Zpos was added to drm_plane_state by calling drm_plane_create_zpos_property funs,
>
> vs_plane_primary_create
> ------> drm_plane_create_zpos_property(......vs_plane_primary_info-> zpos )
Yes. But why do you need zpos here? Especially if it's set to 0.
> >
> > > +
> > > + drm_dev->mode_config.min_width = min_width;
> > > + drm_dev->mode_config.min_height = min_heigth;
> > > + drm_dev->mode_config.max_width = max_width;
> > > + drm_dev->mode_config.max_height = max_height;
> >
> > I thought that I saw mode_config.min/max being initialized.
> Yes the mode_config.min/max has been initialized,
> This place is doing an update according to detail info.
Then please drop previous initialisation. While looking at the code it's
impossible to understand which one is correct.
> > > +
> > > +static struct component_match *vs_add_external_components(struct
> > > +device *dev) {
> > > + struct component_match *match = NULL;
> > > + int i;
> > > +
> > > + for (i = 0; i < ARRAY_SIZE(drm_sub_drivers); ++i) {
> > > + struct platform_driver *drv = drm_sub_drivers[i];
> > > + struct device *p = NULL, *d;
> > > +
> > > + while ((d = platform_find_device_by_driver(p, &drv->driver))) {
> > > + put_device(p);
> > > +
> > > + drm_of_component_match_add(dev, &match,
> > component_compare_of,
> > > + d->of_node);
> > > + p = d;
> > > + }
> > > + put_device(p);
> >
> > What about just going through the graph connections instead and adding them?
>
> The purpose of using components is to create encoder and connector to the drm subsystem by calling component_bind_all
>
> graph connection needs to be based on whether there is a bridge at present.
> If the bridge has been added, it can be obtained through drm_of_get_bridge
> Create a connector based on the obtained bridge and then attach the connector to the encoder.
> Then do drm_dev_register.
>
> I don't know if my understanding is consistent with yours. Please help confirm it.
> Thanks
Your code is looping over the subdrivers, locating devices and then
adding them as components. Can you instead use device nodes which are
connected to your master via the OF graph? If I understand examples in
your DT bindings correctly, this approach should work.
> > > +static void __exit vs_drm_fini(void)
> > > +{
> > > + platform_driver_unregister(&vs_drm_platform_driver);
> > > + platform_unregister_drivers(drm_sub_drivers,
> > > +ARRAY_SIZE(drm_sub_drivers)); }
> > > +
> > > +late_initcall_sync(vs_drm_init);
> >
> > Why _sync?
>
> late_initcall_sync will make it success ,when do devm_drm_of_get_bridge.
> Also it can use the " EPROBE_DEFER " to avoid it,
Why do you need this? It's perfectly fine to have DRM devices probe
assynchronously.
> >
> > > +module_exit(vs_drm_fini);
> > > +
> > > +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
> > MODULE_LICENSE("GPL");
> > > --
> > > 2.27.0
> > >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder
2024-06-23 7:17 ` Keith Zhao
@ 2024-06-23 21:11 ` Dmitry Baryshkov
2024-06-25 8:33 ` Keith Zhao
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-06-23 21:11 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
On Sun, Jun 23, 2024 at 07:17:09AM GMT, Keith Zhao wrote:
> Hi Dmitry:
>
> > On Tue, May 21, 2024 at 06:58:17PM +0800, keith wrote:
> > > + "starfive,syscon",
> > > + 2, args);
> > > +
> > > + if (IS_ERR(simple->dss_regmap)) {
> > > + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
> > > + "getting the regmap failed\n");
> > > + }
> > > +
> > > + simple->offset = args[0];
> > > + simple->mask = args[1];
> >
> > Is the value that you've read platform dependent or use case dependent?
> > What is the actual value being written? Why are you using syscon for it?
>
> The syscon is used to select crtcs binded with encoder,
> If this encoder binds to crtc0 , set the syscon reg bit0 = 1
> If this encoder binds to crtc1 , set the syscon reg bit1 = 1 (0x2)
> Maybe I can do this by the possible_crtc instead of using args from dts
If this is a constant between your platforms, it should not be a part of
DT.
>
>
> >
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void vs_encoder_atomic_enable(struct drm_encoder *encoder,
> > > +struct drm_atomic_state *state) {
> > > + struct vs_simple_encoder *simple = to_simple_encoder(encoder);
> > > +
> > > + regmap_update_bits(simple->dss_regmap, simple->offset, simple->mask,
> > > +simple->mask);
> >
> >
> > A purist in me would ask to have separate mask and value to write.
> Understand , will avoid this action
> >
> > > +}
> >
> > Is it necessary to clear those bits when stopping the stream?
> No need to do this , if clear those bits , the encoder will point to a unknown crtc
what are the consequences? Is it desirable or not?
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver
2024-06-23 7:17 ` Keith Zhao
@ 2024-06-24 9:25 ` Maxime Ripard
0 siblings, 0 replies; 53+ messages in thread
From: Maxime Ripard @ 2024-06-24 9:25 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, tzimmermann@suse.de,
airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com,
heiko@sntech.de, andy.yan@rock-chips.com, Xingyu Wu,
p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
[-- Attachment #1: Type: text/plain, Size: 16187 bytes --]
On Sun, Jun 23, 2024 at 07:17:14AM GMT, Keith Zhao wrote:
> Hi Maxime:
>
>
> > -----Original Message-----
> > From: Maxime Ripard <mripard@kernel.org>
> > Sent: 2024年5月22日 15:25
> > To: Keith Zhao <keith.zhao@starfivetech.com>
> > Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> > Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> > jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> > tzimmermann@suse.de; airlied@gmail.com; daniel@ffwll.ch; robh@kernel.org;
> > krzk+dt@kernel.org; conor+dt@kernel.org; hjc@rock-chips.com;
> > heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> > <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> > <jack.zhu@starfivetech.com>; Shengyang Chen
> > <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> > devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> > linux-arm-kernel@lists.infradead.org
> > Subject: Re: [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi
> > bridge driver
> >
> > Hi,
> >
> > On Tue, May 21, 2024 at 06:58:10PM GMT, keith wrote:
> > > Add the ROCKCHIP inno hdmi driver that uses the Inno DesignWare HDMI
> > > TX bridge and remove the old separate one.
> > >
> > > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > > ---
> > > drivers/gpu/drm/rockchip/Kconfig | 1 +
> > > drivers/gpu/drm/rockchip/Makefile | 2 +-
> > > drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++
> > > .../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 -
> > > drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 -----------------
> > > 5 files changed, 519 insertions(+), 1119 deletions(-) create mode
> > > 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > > rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h}
> > > (85%) delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
> > >
> > > diff --git a/drivers/gpu/drm/rockchip/Kconfig
> > > b/drivers/gpu/drm/rockchip/Kconfig
> > > index 1bf3e2829cd0..cc6cfd5a30d6 100644
> > > --- a/drivers/gpu/drm/rockchip/Kconfig
> > > +++ b/drivers/gpu/drm/rockchip/Kconfig
> > > @@ -74,6 +74,7 @@ config ROCKCHIP_DW_MIPI_DSI
> > >
> > > config ROCKCHIP_INNO_HDMI
> > > bool "Rockchip specific extensions for Innosilicon HDMI"
> > > + select DRM_INNO_HDMI
> > > help
> > > This selects support for Rockchip SoC specific extensions
> > > for the Innosilicon HDMI driver. If you want to enable diff --git
> > > a/drivers/gpu/drm/rockchip/Makefile
> > > b/drivers/gpu/drm/rockchip/Makefile
> > > index 3ff7b21c0414..4b2d0cba8db3 100644
> > > --- a/drivers/gpu/drm/rockchip/Makefile
> > > +++ b/drivers/gpu/drm/rockchip/Makefile
> > > @@ -12,7 +12,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) +=
> > > analogix_dp-rockchip.o
> > > rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
> > > rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
> > > rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) +=
> > dw-mipi-dsi-rockchip.o
> > > -rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
> > > +rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi-rockchip.o
> > > rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
> > > rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
> > > rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o diff
> > > --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > > b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > > new file mode 100644
> > > index 000000000000..69d0e913e13b
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> > > @@ -0,0 +1,517 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> > > + * Zheng Yang <zhengyang@rock-chips.com>
> > > + * Yakir Yang <ykk@rock-chips.com>
> > > + */
> > > +
> > > +#include <linux/irq.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/err.h>
> > > +#include <linux/hdmi.h>
> > > +#include <linux/mod_devicetable.h>
> > > +#include <linux/module.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/platform_device.h>
> > > +
> > > +#include <drm/bridge/inno_hdmi.h>
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_edid.h>
> > > +#include <drm/drm_of.h>
> > > +#include <drm/drm_probe_helper.h>
> > > +#include <drm/drm_simple_kms_helper.h>
> > > +
> > > +#include "rockchip_drm_drv.h"
> > > +
> > > +#include "inno_hdmi-rockchip.h"
> > > +
> > > +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
> > > +
> > > +struct rk_inno_hdmi {
> > > + struct rockchip_encoder encoder;
> > > + struct inno_hdmi inno_hdmi;
> > > + struct clk *pclk;
> > > + struct clk *refclk;
> > > +};
> > > +
> > > +static struct inno_hdmi *rk_encoder_to_inno_hdmi(struct drm_encoder
> > > +*encoder) {
> > > + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
> > > + struct rk_inno_hdmi *rk_hdmi = container_of(rkencoder, struct
> > > +rk_inno_hdmi, encoder);
> > > +
> > > + return &rk_hdmi->inno_hdmi;
> > > +}
> > > +
> > > +enum {
> > > + CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
> > > + CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
> > > + CSC_RGB_0_255_TO_RGB_16_235_8BIT,
> > > +};
> > > +
> > > +static const char coeff_csc[][24] = {
> > > + /*
> > > + * RGB2YUV:601 SD mode:
> > > + * Cb = -0.291G - 0.148R + 0.439B + 128
> > > + * Y = 0.504G + 0.257R + 0.098B + 16
> > > + * Cr = -0.368G + 0.439R - 0.071B + 128
> > > + */
> > > + {
> > > + 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
> > > + 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
> > > + 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
> > > + },
> > > + /*
> > > + * RGB2YUV:709 HD mode:
> > > + * Cb = - 0.338G - 0.101R + 0.439B + 128
> > > + * Y = 0.614G + 0.183R + 0.062B + 16
> > > + * Cr = - 0.399G + 0.439R - 0.040B + 128
> > > + */
> > > + {
> > > + 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
> > > + 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
> > > + 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
> > > + },
> > > + /*
> > > + * RGB[0:255]2RGB[16:235]:
> > > + * R' = R x (235-16)/255 + 16;
> > > + * G' = G x (235-16)/255 + 16;
> > > + * B' = B x (235-16)/255 + 16;
> > > + */
> > > + {
> > > + 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
> > > + 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
> > > + 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
> > > + },
> > > +};
> > > +
> > > +static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
> > > + { 74250000, 0x3f, 0xbb },
> > > + { 165000000, 0x6f, 0xbb },
> > > + { ~0UL, 0x00, 0x00 }
> > > +};
> > > +
> > > +static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = {
> > > + { 74250000, 0x3f, 0xaa },
> > > + { 165000000, 0x5f, 0xaa },
> > > + { ~0UL, 0x00, 0x00 }
> > > +};
> > > +
> > > +static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi,
> > > + unsigned long pixelclk)
> > > +{
> > > + const struct inno_hdmi_phy_config *phy_configs =
> > hdmi->plat_data->phy_configs;
> > > + int i;
> > > +
> > > + for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) {
> > > + if (pixelclk <= phy_configs[i].pixelclock)
> > > + return i;
> > > + }
> > > +
> > > + DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n",
> > > + pixelclk);
> > > +
> > > + return -EINVAL;
> > > +}
> > > +
> > > +static void inno_hdmi_standby(struct inno_hdmi *hdmi) {
> > > + inno_hdmi_sys_power(hdmi, false);
> > > +
> > > + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
> > > + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
> > > + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
> > > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); };
> > > +
> > > +static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
> > > + unsigned long mpixelclock)
> > > +{
> > > + struct inno_hdmi_phy_config *phy_config;
> > > + int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock);
> > > +
> > > + if (ret < 0) {
> > > + phy_config = hdmi->plat_data->default_phy_config;
> > > + DRM_DEV_ERROR(hdmi->dev,
> > > + "Using default phy configuration for TMDS rate %lu",
> > > + mpixelclock);
> > > + } else {
> > > + phy_config = &hdmi->plat_data->phy_configs[ret];
> > > + }
> > > +
> > > + inno_hdmi_sys_power(hdmi, false);
> > > +
> > > + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS,
> > phy_config->pre_emphasis);
> > > + hdmi_writeb(hdmi, HDMI_PHY_DRIVER,
> > phy_config->voltage_level_control);
> > > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
> > > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
> > > + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
> > > + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
> > > + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
> > > + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
> > > +
> > > + inno_hdmi_sys_power(hdmi, true);
> > > +};
> > > +
> > > +static void inno_hdmi_reset(struct inno_hdmi *hdmi) {
> > > + u32 val;
> > > + u32 msk;
> > > +
> > > + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL,
> > v_NOT_RST_DIGITAL);
> > > + udelay(100);
> > > +
> > > + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG,
> > v_NOT_RST_ANALOG);
> > > + udelay(100);
> > > +
> > > + msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
> > > + val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON |
> > v_INT_POL_HIGH;
> > > + hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
> > > +
> > > + inno_hdmi_standby(hdmi);
> > > +}
> > > +
> > > +static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) {
> > > + struct drm_connector *connector = &hdmi->connector;
> > > + struct drm_connector_state *conn_state = connector->state;
> > > + struct inno_hdmi_connector_state *inno_conn_state =
> > > + to_inno_hdmi_conn_state(conn_state);
> > > + int c0_c2_change = 0;
> > > + int csc_enable = 0;
> > > + int csc_mode = 0;
> > > + int auto_csc = 0;
> > > + int value;
> > > + int i;
> > > +
> > > + /* Input video mode is SDR RGB24bit, data enable signal from external */
> > > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
> > > + v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
> > > +
> > > + /* Input color hardcode to RGB, and output color hardcode to RGB888 */
> > > + value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
> > > + v_VIDEO_OUTPUT_COLOR(0) |
> > > + v_VIDEO_INPUT_CSP(0);
> > > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
> > > +
> > > + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
> > > + if (inno_conn_state->rgb_limited_range) {
> > > + csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT;
> > > + auto_csc = AUTO_CSC_DISABLE;
> > > + c0_c2_change = C0_C2_CHANGE_DISABLE;
> > > + csc_enable = v_CSC_ENABLE;
> > > +
> > > + } else {
> > > + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
> > > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
> > > +
> > > + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
> > > + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
> > > + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
> > > + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
> > > + return 0;
> > > + }
> > > + } else {
> > > + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601)
> > {
> > > + if (inno_conn_state->enc_out_format ==
> > HDMI_COLORSPACE_YUV444) {
> > > + csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
> > > + auto_csc = AUTO_CSC_DISABLE;
> > > + c0_c2_change = C0_C2_CHANGE_DISABLE;
> > > + csc_enable = v_CSC_ENABLE;
> > > + }
> > > + } else {
> > > + if (inno_conn_state->enc_out_format ==
> > HDMI_COLORSPACE_YUV444) {
> > > + csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
> > > + auto_csc = AUTO_CSC_DISABLE;
> > > + c0_c2_change = C0_C2_CHANGE_DISABLE;
> > > + csc_enable = v_CSC_ENABLE;
> > > + }
> > > + }
> > > + }
> > > +
> > > + for (i = 0; i < 24; i++)
> > > + hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
> > > + coeff_csc[csc_mode][i]);
> > > +
> > > + value = v_SOF_DISABLE | csc_enable |
> > v_COLOR_DEPTH_NOT_INDICATED(1);
> > > + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
> > > + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
> > > + m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
> > > + v_VIDEO_C0_C2_SWAP(c0_c2_change));
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int inno_hdmi_setup(struct inno_hdmi *hdmi,
> > > + struct drm_display_mode *mode)
> > > +{
> > > + struct drm_display_info *display = &hdmi->connector.display_info;
> > > + unsigned long mpixelclock = mode->clock * 1000;
> > > +
> > > + /* Mute video and audio output */
> > > + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
> > > + v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
> > > +
> > > + /* Set HDMI Mode */
> > > + hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
> > > + v_HDMI_DVI(display->is_hdmi));
> > > +
> > > + inno_hdmi_config_video_timing(hdmi, mode);
> > > +
> > > + inno_hdmi_config_video_csc(hdmi);
> > > +
> > > + if (display->is_hdmi)
> > > + inno_hdmi_config_video_avi(hdmi, mode);
> > > +
> > > + /*
> > > + * When IP controller have configured to an accurate video
> > > + * timing, then the TMDS clock source would be switched to
> > > + * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
> > > + * clock rate, and reconfigure the DDC clock.
> > > + */
> > > + inno_hdmi_i2c_init(hdmi, mpixelclock);
> > > +
> > > + /* Unmute video and audio output */
> > > + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
> > > + v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
> > > +
> > > + inno_hdmi_power_up(hdmi, mpixelclock);
> > > +
> > > + return 0;
> > > +}
> > >
> >
> > It's kind of a general comment, but I don't think that's the right abstraction. You
> > should create a inno_hdmi bridge that allows to supplement some of the atomic
> > hooks, but not reimplement them entirely each time.
> >
> > You can have a look at how dw-hdmi does it for example. Also, why do you still
> > need the encoder and connectors?
> >
> Hi Maxime:
> This series of patches does not consider referencing bridge ,
> just split the public interface based on the current structure (encoder + connector),
> and then make it into a public API.
> The next step is to implement the driver code of the public part based on the bridge architecture.
I'm not sure what you have in mind, but I stand by what I was saying
previously. SoC-specific drivers shouldn't have code to handle the
common part of the bridge, it should be the other way around: the common
part should add hooks to handle the SoC-specific parts.
> By the way, does the current situation require the introduction of the next_bridge concept?
> dw-hdmi attach:
> static int dw_hdmi_bridge_attach(struct drm_bridge *bridge,
> enum drm_bridge_attach_flags flags)
> {
> struct dw_hdmi *hdmi = bridge->driver_private;
>
> if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
> return drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> bridge, flags);
>
> return dw_hdmi_connector_create(hdmi);
> }
>
> For inno hdmi , I want to define it like this , will it be ok?
> static int inno_bridge_attach(struct drm_bridge *bridge,
> enum drm_bridge_attach_flags flags)
> {
> ......
>
> if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
> DRM_ERROR("Fix bridge driver to make connector optional!");
> return -EINVAL;
> }
>
> return 0;
> }
> ......
> And then , create the connector outside of bridge:
> ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0);
> if (ret)
> return ret;
>
> hdmi->connector = drm_bridge_connector_init(drm, encoder);
> if (IS_ERR(hdmi->connector)) {
> dev_err(dev, "Unable to create bridge connector\n");
> ret = PTR_ERR(hdmi->connector);
> return ret;
> }
Yes, it looks reasonable as long as you don't break old drivers.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
2024-06-23 20:51 ` Dmitry Baryshkov
@ 2024-06-25 8:32 ` Keith Zhao
0 siblings, 0 replies; 53+ messages in thread
From: Keith Zhao @ 2024-06-25 8:32 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年6月24日 4:51
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs.
>
> Hi Keith,
>
> On Sun, Jun 23, 2024 at 07:16:47AM GMT, Keith Zhao wrote:
> > > On Tue, May 21, 2024 at 06:58:11PM +0800, keith wrote:
> > > > +}
> > > > +
> > > > +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32
> > > > +set, u32 clear) {
> > > > + u32 value = dc_read(hw, reg);
> > > > +
> > > > + value &= ~clear;
> > > > + value |= set;
> > > > + dc_write(hw, reg, value);
> > >
> > > regmap_update_bits?
> >
> > regmap_update_bits follows 4 steps:
> >
> > 1、ret = _regmap_read(map, reg, &orig); .........
> >
> > 2、tmp = orig & ~mask;
> > 3、tmp |= val & mask;
> > ......
> > 4、ret = _regmap_write(map, reg, tmp);
> > If the value out of mask range
> > It will just clear the mask bir
> >
> > dc_set_clear will do clear and set without limit.
> >
> > Maybe the name should be dc_clear_set
>
> This is not really better. regmap_update_bits() has clear semantics of updating a
> value in the field that is defined by a mask. You function is just clearing some bits
> and setting other bits. It's not obvious whether it is a mask and value, several
> concurrent flags or something else.
>
> Even if you are not going to switch to regmaps (you don't have to), please use
> mask & value instead.
>
Ok got it
> > }
> > > > +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16
> > > > +*table)
> > >
> > > Is there any reason why load_rgb_to_yuv differs from two other
> > > functions?
> > >
> > load_rgb_to_yuv matches crtcs
> >
> > load_yuv_to_rgb matches planes
> > load_rgb_to_rgb matches planes
>
> Then these functins should have that reflected in their names (and also
> documented, why). If the CSC programming interface is similar, please split the
> implementation to have common code and different data to be used for
> programming.
>
Ok got it
> > the coefficient(table) is diff between load_rgb_to_yuv and
> > load_yuv_to_rgb
>
> > > > +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect
> > > > +*src, struct
> > > drm_rect *dst,
> > > > + u8 id, u8 display_id, unsigned int rotation); void
> > > > +plane_hw_update_blend(struct vs_dc *dc, u16 alpha, u16
> > > pixel_blend_mode,
> > > > + u8 id, u8 display_id);
> > >
> > > Could you please settle on a single prefix for all your function names?
> > > Ideally it should be close to the driver name. It's hard to
> > > understand that the function comes from the verisilicon driver if
> > > its name starts from dc_ or especially with plane_.
> > Yes starting with plane_ is not a good idea ,i will add vs_ _ ,
> > thanks
> > >
> > > I'd strongly suggest to stop defining anything outside of the
> > > selected
> > I don't quite understand what "the selected" means, I hope you can
> > fill in some specific details about it Thanks
>
> "the selected vs_ namespace". So prefix all function names and all structures
> with vs_
Ok, got it.
>
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 10/10] drm/vs: add simple dsi encoder
2024-06-23 21:11 ` Dmitry Baryshkov
@ 2024-06-25 8:33 ` Keith Zhao
2024-06-25 10:59 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Keith Zhao @ 2024-06-25 8:33 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年6月24日 5:11
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder
>
> On Sun, Jun 23, 2024 at 07:17:09AM GMT, Keith Zhao wrote:
> > Hi Dmitry:
> >
> > > On Tue, May 21, 2024 at 06:58:17PM +0800, keith wrote:
>
> > > > + "starfive,syscon",
> > > > + 2, args);
> > > > +
> > > > + if (IS_ERR(simple->dss_regmap)) {
> > > > + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
> > > > + "getting the regmap failed\n");
> > > > + }
> > > > +
> > > > + simple->offset = args[0];
> > > > + simple->mask = args[1];
> > >
> > > Is the value that you've read platform dependent or use case dependent?
> > > What is the actual value being written? Why are you using syscon for it?
> >
> > The syscon is used to select crtcs binded with encoder, If this
> > encoder binds to crtc0 , set the syscon reg bit0 = 1 If this encoder
> > binds to crtc1 , set the syscon reg bit1 = 1 (0x2) Maybe I can do this
> > by the possible_crtc instead of using args from dts
>
> If this is a constant between your platforms, it should not be a part of DT.
>
> >
> >
> > >
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static void vs_encoder_atomic_enable(struct drm_encoder *encoder,
> > > > +struct drm_atomic_state *state) {
> > > > + struct vs_simple_encoder *simple = to_simple_encoder(encoder);
> > > > +
> > > > + regmap_update_bits(simple->dss_regmap, simple->offset,
> > > > +simple->mask,
> > > > +simple->mask);
> > >
> > >
> > > A purist in me would ask to have separate mask and value to write.
> > Understand , will avoid this action
> > >
> > > > +}
> > >
> > > Is it necessary to clear those bits when stopping the stream?
> > No need to do this , if clear those bits , the encoder will point to a
> > unknown crtc
>
> what are the consequences? Is it desirable or not?
There are two crtcs.
Each display terminal encoder can combine any crtc, depending on the value of possible crtc.
When the bit is 0, it means that the encoder matches crtc0.
When the bit is 1, it means that the encoder matches crtc1.
The possible crtc of this encoder is 2 , the reg bit is 1.
When the video stream is stopped, if the bit is cleared, the result is that the encoder hardware points to crtc0,
and the encoder points to crtc1 based on the drm framework(because the possible crtc no change).
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* RE: [PATCH v4 08/10] drm/vs: add vs drm master driver
2024-06-23 21:07 ` Dmitry Baryshkov
@ 2024-06-25 8:34 ` Keith Zhao
0 siblings, 0 replies; 53+ messages in thread
From: Keith Zhao @ 2024-06-25 8:34 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
> -----Original Message-----
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Sent: 2024年6月24日 5:08
> To: Keith Zhao <keith.zhao@starfivetech.com>
> Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> <jack.zhu@starfivetech.com>; Shengyang Chen
> <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v4 08/10] drm/vs: add vs drm master driver
>
> On Sun, Jun 23, 2024 at 07:16:57AM GMT, Keith Zhao wrote:
> > > On Tue, May 21, 2024 at 06:58:15PM +0800, keith wrote:
> > > > Add vs DRM master driver for JH7110 SoC ADD DMA GEM driver
> > > >
> > > > Signed-off-by: keith <keith.zhao@starfivetech.com>
> > > > ---
> > > > drivers/gpu/drm/verisilicon/Makefile | 3 +-
> > > > drivers/gpu/drm/verisilicon/vs_drv.c | 718
> > > > +++++++++++++++++++++++++++
> > > > 2 files changed, 720 insertions(+), 1 deletion(-) create mode
> > > > 100644 drivers/gpu/drm/verisilicon/vs_drv.c
> > > >
>
> > > BIT(DRM_COLOR_YCBCR_BT2020),
> > > > + .zpos = 0,
> > >
> > > How are these zpos related to the zpos from drm_plane_state?
> > Zpos was added to drm_plane_state by calling
> > drm_plane_create_zpos_property funs,
> >
> > vs_plane_primary_create
> > ------> drm_plane_create_zpos_property(......vs_plane_primary_info->
> > ------> zpos )
>
> Yes. But why do you need zpos here? Especially if it's set to 0.
if any plane has the zpos attribute (whether variable or immutable),
then all planes should have the zpos attribute to ensure consistent stacking order and behavior.
Here is the initial value of zpos property
Usually min can be set to 0 and I set the zpos of primary plane to 0......
>
> > >
> > > > +
> > > > + drm_dev->mode_config.min_width = min_width;
> > > > + drm_dev->mode_config.min_height = min_heigth;
> > > > + drm_dev->mode_config.max_width = max_width;
> > > > + drm_dev->mode_config.max_height = max_height;
> > >
> > > I thought that I saw mode_config.min/max being initialized.
> > Yes the mode_config.min/max has been initialized,
> > This place is doing an update according to detail info.
>
> Then please drop previous initialisation. While looking at the code it's
> impossible to understand which one is correct.
Ok got it.
>
>
> > > > +
> > > > +static struct component_match *vs_add_external_components(struct
> > > > +device *dev) {
> > > > + struct component_match *match = NULL;
> > > > + int i;
> > > > +
> > > > + for (i = 0; i < ARRAY_SIZE(drm_sub_drivers); ++i) {
> > > > + struct platform_driver *drv = drm_sub_drivers[i];
> > > > + struct device *p = NULL, *d;
> > > > +
> > > > + while ((d = platform_find_device_by_driver(p, &drv->driver))) {
> > > > + put_device(p);
> > > > +
> > > > + drm_of_component_match_add(dev, &match,
> > > component_compare_of,
> > > > + d->of_node);
> > > > + p = d;
> > > > + }
> > > > + put_device(p);
> > >
> > > What about just going through the graph connections instead and adding
> them?
> >
> > The purpose of using components is to create encoder and connector to the
> drm subsystem by calling component_bind_all
> >
> > graph connection needs to be based on whether there is a bridge at present.
> > If the bridge has been added, it can be obtained through drm_of_get_bridge
> > Create a connector based on the obtained bridge and then attach the
> connector to the encoder.
> > Then do drm_dev_register.
> >
> > I don't know if my understanding is consistent with yours. Please help confirm
> it.
> > Thanks
>
> Your code is looping over the subdrivers, locating devices and then
> adding them as components. Can you instead use device nodes which are
> connected to your master via the OF graph? If I understand examples in
> your DT bindings correctly, this approach should work.
Yes, The OF graph method appears to be more efficient and does not require traversal.
After find the device node ,
Let it start:
drm_of_component_match_add(dev, &match, component_compare_of, device->of_node);
>
> > > > +static void __exit vs_drm_fini(void)
> > > > +{
> > > > + platform_driver_unregister(&vs_drm_platform_driver);
> > > > + platform_unregister_drivers(drm_sub_drivers,
> > > > +ARRAY_SIZE(drm_sub_drivers)); }
> > > > +
> > > > +late_initcall_sync(vs_drm_init);
> > >
> > > Why _sync?
> >
> > late_initcall_sync will make it success ,when do devm_drm_of_get_bridge.
> > Also it can use the " EPROBE_DEFER " to avoid it,
>
> Why do you need this? It's perfectly fine to have DRM devices probe
> assynchronously.
Will replace it by module_init
>
> > >
> > > > +module_exit(vs_drm_fini);
> > > > +
> > > > +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
> > > MODULE_LICENSE("GPL");
> > > > --
> > > > 2.27.0
> > > >
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder
2024-06-25 8:33 ` Keith Zhao
@ 2024-06-25 10:59 ` Dmitry Baryshkov
0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2024-06-25 10:59 UTC (permalink / raw)
To: Keith Zhao
Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
rfoss@kernel.org, Laurent.pinchart@ideasonboard.com,
jonas@kwiboo.se, jernej.skrabec@gmail.com,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com,
Xingyu Wu, p.zabel@pengutronix.de, Jack Zhu, Shengyang Chen,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
On Tue, Jun 25, 2024 at 08:33:48AM GMT, Keith Zhao wrote:
>
>
> > -----Original Message-----
> > From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > Sent: 2024年6月24日 5:11
> > To: Keith Zhao <keith.zhao@starfivetech.com>
> > Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org;
> > Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> > jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com;
> > mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com;
> > daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> > hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu
> > <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu
> > <jack.zhu@starfivetech.com>; Shengyang Chen
> > <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org;
> > devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> > linux-arm-kernel@lists.infradead.org
> > Subject: Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder
> >
> > On Sun, Jun 23, 2024 at 07:17:09AM GMT, Keith Zhao wrote:
> > > Hi Dmitry:
> > >
> > > > On Tue, May 21, 2024 at 06:58:17PM +0800, keith wrote:
> >
> > > > > + "starfive,syscon",
> > > > > + 2, args);
> > > > > +
> > > > > + if (IS_ERR(simple->dss_regmap)) {
> > > > > + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
> > > > > + "getting the regmap failed\n");
> > > > > + }
> > > > > +
> > > > > + simple->offset = args[0];
> > > > > + simple->mask = args[1];
> > > >
> > > > Is the value that you've read platform dependent or use case dependent?
> > > > What is the actual value being written? Why are you using syscon for it?
> > >
> > > The syscon is used to select crtcs binded with encoder, If this
> > > encoder binds to crtc0 , set the syscon reg bit0 = 1 If this encoder
> > > binds to crtc1 , set the syscon reg bit1 = 1 (0x2) Maybe I can do this
> > > by the possible_crtc instead of using args from dts
> >
> > If this is a constant between your platforms, it should not be a part of DT.
> >
> > >
> > >
> > > >
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static void vs_encoder_atomic_enable(struct drm_encoder *encoder,
> > > > > +struct drm_atomic_state *state) {
> > > > > + struct vs_simple_encoder *simple = to_simple_encoder(encoder);
> > > > > +
> > > > > + regmap_update_bits(simple->dss_regmap, simple->offset,
> > > > > +simple->mask,
> > > > > +simple->mask);
> > > >
> > > >
> > > > A purist in me would ask to have separate mask and value to write.
> > > Understand , will avoid this action
> > > >
> > > > > +}
> > > >
> > > > Is it necessary to clear those bits when stopping the stream?
> > > No need to do this , if clear those bits , the encoder will point to a
> > > unknown crtc
> >
> > what are the consequences? Is it desirable or not?
> There are two crtcs.
> Each display terminal encoder can combine any crtc, depending on the value of possible crtc.
> When the bit is 0, it means that the encoder matches crtc0.
> When the bit is 1, it means that the encoder matches crtc1.
> The possible crtc of this encoder is 2 , the reg bit is 1.
> When the video stream is stopped, if the bit is cleared, the result is that the encoder hardware points to crtc0,
> and the encoder points to crtc1 based on the drm framework(because the possible crtc no change).
I'm not sure if I understood you correctly. If it doesn't disable or
disconnect the encoder, I'd skip that in the .disable path.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
end of thread, other threads:[~2024-06-25 15:12 UTC | newest]
Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-21 10:58 [PATCH v4 00/10] drm/verisilicon : support DC8200 and inno hdmi keith
2024-05-21 7:18 ` Krzysztof Kozlowski
2024-05-21 8:03 ` Heiko Stübner
2024-05-21 14:55 ` Alex Bee
2024-05-21 10:58 ` [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline keith
2024-05-21 7:30 ` Krzysztof Kozlowski
2024-05-21 9:50 ` Keith Zhao
2024-05-21 10:58 ` [PATCH v4 02/10] drm/bridge: add common api for inno hdmi keith
2024-05-21 9:30 ` Krzysztof Kozlowski
2024-05-21 15:36 ` Alex Bee
2024-05-21 15:42 ` Laurent Pinchart
2024-05-22 5:58 ` Keith Zhao
2024-05-22 7:32 ` Laurent Pinchart
2024-06-23 18:42 ` Markus Elfring
2024-05-21 10:58 ` [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver keith
2024-05-22 7:24 ` Maxime Ripard
2024-06-23 7:17 ` Keith Zhao
2024-06-24 9:25 ` Maxime Ripard
2024-05-21 10:58 ` [PATCH v4 04/10] drm/vs: Add hardware funcs for vs keith
2024-05-21 20:50 ` kernel test robot
2024-05-21 20:50 ` Dmitry Baryshkov
2024-06-23 7:16 ` Keith Zhao
2024-06-23 20:51 ` Dmitry Baryshkov
2024-06-25 8:32 ` Keith Zhao
2024-05-21 21:01 ` kernel test robot
2024-05-22 1:34 ` kernel test robot
2024-05-21 10:58 ` [PATCH v4 05/10] drm/vs: add vs mode config init keith
2024-05-21 20:52 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
2024-06-23 20:52 ` Dmitry Baryshkov
2024-05-21 10:58 ` [PATCH v4 06/10] drm/vs: add vs plane api keith
2024-05-21 20:39 ` kernel test robot
2024-05-21 21:06 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
2024-06-23 20:54 ` Dmitry Baryshkov
2024-05-21 10:58 ` [PATCH v4 07/10] drm/vs: add ctrc fun keith
2024-05-21 21:08 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
2024-06-23 20:56 ` Dmitry Baryshkov
2024-05-21 10:58 ` [PATCH v4 08/10] drm/vs: add vs drm master driver keith
2024-05-21 21:14 ` Dmitry Baryshkov
2024-06-23 7:16 ` Keith Zhao
2024-06-23 21:07 ` Dmitry Baryshkov
2024-06-25 8:34 ` Keith Zhao
2024-05-21 10:58 ` [PATCH v4 09/10] drm/vs: Innosilicon HDMI support keith
2024-05-21 9:31 ` Krzysztof Kozlowski
2024-05-21 10:58 ` [PATCH v4 10/10] drm/vs: add simple dsi encoder keith
2024-05-21 15:25 ` Dmitry Baryshkov
2024-06-23 7:17 ` Keith Zhao
2024-06-23 21:11 ` Dmitry Baryshkov
2024-06-25 8:33 ` Keith Zhao
2024-06-25 10:59 ` Dmitry Baryshkov
2024-05-22 7:29 ` Maxime Ripard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).