Hello, this is the third iteration of CMM support series.
A reference to the v1 cover letter, with some background on the CMM is available here: https://lkml.org/lkml/2019/6/6/583
The series is now based on the v5.3-rc4-based renesas-devel-2019-08-21 branch of Geert's tree, which already contains the CMM clock enablement patches that were part of v2 and which I have now dropped.
Notable changes in the iteratoin are: - Added per-SoC compatible strings as requested by Geert: updated bindings and DTS patches accordingly and dropped R-b tags from there. - Rework of CMM driver: - Use the DRM provided functions to extract and scale to HW precision the LUT table entries as suggested by Uli. - Re-worked the suspend/resume logic as suggested by Laurent: - remove resume/suspend handlers from CMM driver - handle re-enablement of CMM at DU resume time - Use pm-runtime to handle clock enable/disable of CMM. - Integration with DU: - enforce suspend/resume ordering by creating a device_link between DU (consumer) and CMM (supplier): DU suspends before and resume after CMM - Force re-enablement of CMM by forcing the color_mgmt_changed flag of a CRTC state which had the CMM in use at DU resume time.
Compared to v2 system suspend/resume has been more thoughtfully tested by running an application program which uses the CMM, suspending and resuming the system and making sure the DU and the CMM are still operational.
Tested on M3-[W|N] with HDMI output.
The test application used to verify the LUT operations is available at: https://jmondi.org/cgit/kmsxx/ where a color-inversion 1D-LUT table is applied.
The testing provides good results when running in 'flip' mode, where colors seem actually inverted. I'm less certain about the 'non-flip' static image mode as it seems red/green/yellow colors get all reduced to a shade of black. Other opinions and testing with more realistic use-cases are of course very welcome.
Thanks j
Jacopo Mondi (14): dt-bindings: display: renesas,cmm: Add R-Car CMM documentation dt-bindings: display, renesas,du: Document cmms property arm64: dts: renesas: r8a7796: Add CMM units arm64: dts: renesas: r8a7795: Add CMM units arm64: dts: renesas: r8a77965: Add CMM units arm64: dts: renesas: r8a77990: Add CMM units arm64: dts: renesas: r8a77995: Add CMM units drm: rcar-du: Add support for CMM drm: rcar-du: Claim CMM support for Gen3 SoCs drm: rcar-du: kms: Collect CMM instances drm: rcar-du: crtc: Enable and disable CMMs drm: rcar-du: crtc: Register GAMMA_LUT properties drm: rcar-du: kms: Update CMM in atomic commit tail drm: rcar-du: Force CMM enablement when resuming
.../bindings/display/renesas,cmm.txt | 33 +++ .../bindings/display/renesas,du.txt | 5 + arch/arm64/boot/dts/renesas/r8a7795.dtsi | 36 ++- arch/arm64/boot/dts/renesas/r8a7796.dtsi | 25 ++ arch/arm64/boot/dts/renesas/r8a77965.dtsi | 25 ++ arch/arm64/boot/dts/renesas/r8a77990.dtsi | 20 +- arch/arm64/boot/dts/renesas/r8a77995.dtsi | 20 +- drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 ++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++ drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 17 ++ drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_drv.c | 33 ++- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 4 + drivers/gpu/drm/rcar-du/rcar_du_group.c | 8 + drivers/gpu/drm/rcar-du/rcar_du_group.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_kms.c | 98 +++++++ drivers/gpu/drm/rcar-du/rcar_du_regs.h | 5 + 19 files changed, 634 insertions(+), 7 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/renesas,cmm.txt create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
-- 2.22.0
Add device tree bindings documentation for the Renesas R-Car Display Unit Color Management Module.
CMM is the image enhancement module available on each R-Car DU video channel on R-Car Gen2 and Gen3 SoCs (V3H and V3M excluded).
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- .../bindings/display/renesas,cmm.txt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/renesas,cmm.txt
diff --git a/Documentation/devicetree/bindings/display/renesas,cmm.txt b/Documentation/devicetree/bindings/display/renesas,cmm.txt new file mode 100644 index 000000000000..bc599b69c278 --- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.txt @@ -0,0 +1,33 @@ +* Renesas R-Car Color Management Module (CMM) + +Renesas R-Car image enhancement module connected to R-Car DU video channels. + +Required properties: + - compatible: shall be one or more of the following: + - "renesas,cmm-r8a7795": for R8A7795 (R-Car H3) compatible CMM. + - "renesas,cmm-r8a7796": for R8A7796 (R-Car M3-W) compatible CMM. + - "renesas,cmm-r8a77965": for R8A77965 (R-Car M3-N) compatible CMM. + - "renesas,cmm-r8a77990": for R8A77990 (R-Car E3) compatible CMM. + - "renesas,cmm-r8a77995": for R8A77995 (R-Car D3) compatible CMM. + - "renesas,rcar-gen3-cmm": for a generic R-Car Gen3 compatible CMM. + - "renesas,rcar-gen2-cmm": for a generic R-Car Gen2 compatible CMM. + + When the generic compatible string is specified, the SoC-specific + version corresponding to the platform should be listed first. + + - reg: the address base and length of the memory area where CMM control + registers are mapped to. + + - clocks: phandle and clock-specifier pair to the CMM functional clock + supplier. + +Example: +-------- + + cmm0: cmm@fea40000 { + compatible = "renesas,cmm-r8a7796"; + reg = <0 0xfea40000 0 0x1000>; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + clocks = <&cpg CPG_MOD 711>; + resets = <&cpg 711>; + }; -- 2.22.0
Hi Jacopo,
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add device tree bindings documentation for the Renesas R-Car Display Unit Color Management Module.
CMM is the image enhancement module available on each R-Car DU video channel on R-Car Gen2 and Gen3 SoCs (V3H and V3M excluded).
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.txt @@ -0,0 +1,33 @@ +* Renesas R-Car Color Management Module (CMM)
+Renesas R-Car image enhancement module connected to R-Car DU video channels.
+Required properties:
- compatible: shall be one or more of the following:
- "renesas,cmm-r8a7795": for R8A7795 (R-Car H3) compatible CMM.
- "renesas,cmm-r8a7796": for R8A7796 (R-Car M3-W) compatible CMM.
- "renesas,cmm-r8a77965": for R8A77965 (R-Car M3-N) compatible CMM.
- "renesas,cmm-r8a77990": for R8A77990 (R-Car E3) compatible CMM.
- "renesas,cmm-r8a77995": for R8A77995 (R-Car D3) compatible CMM.
Please use "renesas,<socype->-cmm" instead of "renesas,cmm-<soctype>".
- "renesas,rcar-gen3-cmm": for a generic R-Car Gen3 compatible CMM.
- "renesas,rcar-gen2-cmm": for a generic R-Car Gen2 compatible CMM.
- When the generic compatible string is specified, the SoC-specific
- version corresponding to the platform should be listed first.
- reg: the address base and length of the memory area where CMM control
- registers are mapped to.
- clocks: phandle and clock-specifier pair to the CMM functional clock
- supplier.
Thinking about yaml validation:
power-domains? resets?
+Example: +--------
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea40000 0 0x1000>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
clocks = <&cpg CPG_MOD 711>;
resets = <&cpg 711>;
};
Gr{oetje,eeting}s,
Geert
Hi Geert,
On Mon, Aug 26, 2019 at 09:34:41AM +0200, Geert Uytterhoeven wrote:
Hi Jacopo,
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add device tree bindings documentation for the Renesas R-Car Display Unit Color Management Module.
CMM is the image enhancement module available on each R-Car DU video channel on R-Car Gen2 and Gen3 SoCs (V3H and V3M excluded).
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.txt @@ -0,0 +1,33 @@ +* Renesas R-Car Color Management Module (CMM)
+Renesas R-Car image enhancement module connected to R-Car DU video channels.
+Required properties:
- compatible: shall be one or more of the following:
- "renesas,cmm-r8a7795": for R8A7795 (R-Car H3) compatible CMM.
- "renesas,cmm-r8a7796": for R8A7796 (R-Car M3-W) compatible CMM.
- "renesas,cmm-r8a77965": for R8A77965 (R-Car M3-N) compatible CMM.
- "renesas,cmm-r8a77990": for R8A77990 (R-Car E3) compatible CMM.
- "renesas,cmm-r8a77995": for R8A77995 (R-Car D3) compatible CMM.
Please use "renesas,<socype->-cmm" instead of "renesas,cmm-<soctype>".
I actually copied it from the r-car gpio bindings, and I liked cmm-<soctype> better. If you prefer I can change it though.
- "renesas,rcar-gen3-cmm": for a generic R-Car Gen3 compatible CMM.
- "renesas,rcar-gen2-cmm": for a generic R-Car Gen2 compatible CMM.
- When the generic compatible string is specified, the SoC-specific
- version corresponding to the platform should be listed first.
- reg: the address base and length of the memory area where CMM control
- registers are mapped to.
- clocks: phandle and clock-specifier pair to the CMM functional clock
- supplier.
Thinking about yaml validation:
power-domains? resets?
They should indeed be documented.
Thanks j
+Example: +--------
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea40000 0 0x1000>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
clocks = <&cpg CPG_MOD 711>;
resets = <&cpg 711>;
};
Gr{oetje,eeting}s,
Geert
-- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Jacopo,
On Mon, Aug 26, 2019 at 9:58 AM Jacopo Mondi jacopo@jmondi.org wrote:
On Mon, Aug 26, 2019 at 09:34:41AM +0200, Geert Uytterhoeven wrote:
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add device tree bindings documentation for the Renesas R-Car Display Unit Color Management Module.
CMM is the image enhancement module available on each R-Car DU video channel on R-Car Gen2 and Gen3 SoCs (V3H and V3M excluded).
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.txt @@ -0,0 +1,33 @@ +* Renesas R-Car Color Management Module (CMM)
+Renesas R-Car image enhancement module connected to R-Car DU video channels.
+Required properties:
- compatible: shall be one or more of the following:
- "renesas,cmm-r8a7795": for R8A7795 (R-Car H3) compatible CMM.
- "renesas,cmm-r8a7796": for R8A7796 (R-Car M3-W) compatible CMM.
- "renesas,cmm-r8a77965": for R8A77965 (R-Car M3-N) compatible CMM.
- "renesas,cmm-r8a77990": for R8A77990 (R-Car E3) compatible CMM.
- "renesas,cmm-r8a77995": for R8A77995 (R-Car D3) compatible CMM.
Please use "renesas,<socype->-cmm" instead of "renesas,cmm-<soctype>".
I actually copied it from the r-car gpio bindings, and I liked cmm-<soctype> better. If you prefer I can change it though.
We switched from "renesas,cmm-<soctype>" to "renesas,<socype->-cmm" a few years ago, upon request from the DT people:
vendor -> family/SoC -> IP core
Unfortunately we cannot change the old style in existing bindings, without great effort and backwards compatibility ramifications.
Gr{oetje,eeting}s,
Geert
Hi Jacopo,
On Mon, Aug 26, 2019 at 09:59:43AM +0200, Jacopo Mondi wrote:
On Mon, Aug 26, 2019 at 09:34:41AM +0200, Geert Uytterhoeven wrote:
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add device tree bindings documentation for the Renesas R-Car Display Unit Color Management Module.
CMM is the image enhancement module available on each R-Car DU video channel on R-Car Gen2 and Gen3 SoCs (V3H and V3M excluded).
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.txt @@ -0,0 +1,33 @@ +* Renesas R-Car Color Management Module (CMM)
+Renesas R-Car image enhancement module connected to R-Car DU video channels.
+Required properties:
- compatible: shall be one or more of the following:
- "renesas,cmm-r8a7795": for R8A7795 (R-Car H3) compatible CMM.
- "renesas,cmm-r8a7796": for R8A7796 (R-Car M3-W) compatible CMM.
- "renesas,cmm-r8a77965": for R8A77965 (R-Car M3-N) compatible CMM.
- "renesas,cmm-r8a77990": for R8A77990 (R-Car E3) compatible CMM.
- "renesas,cmm-r8a77995": for R8A77995 (R-Car D3) compatible CMM.
Please use "renesas,<socype->-cmm" instead of "renesas,cmm-<soctype>".
I actually copied it from the r-car gpio bindings, and I liked cmm-<soctype> better. If you prefer I can change it though.
- "renesas,rcar-gen3-cmm": for a generic R-Car Gen3 compatible CMM.
- "renesas,rcar-gen2-cmm": for a generic R-Car Gen2 compatible CMM.
- When the generic compatible string is specified, the SoC-specific
- version corresponding to the platform should be listed first.
- reg: the address base and length of the memory area where CMM control
- registers are mapped to.
- clocks: phandle and clock-specifier pair to the CMM functional clock
- supplier.
Thinking about yaml validation:
power-domains? resets?
They should indeed be documented.
How about converting this binding to yaml alreay ? It should be fairly simple.
+Example: +--------
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea40000 0 0x1000>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
clocks = <&cpg CPG_MOD 711>;
resets = <&cpg 711>;
};
Hi Laurent,
On Mon, Aug 26, 2019 at 01:15:50PM +0300, Laurent Pinchart wrote:
Hi Jacopo,
On Mon, Aug 26, 2019 at 09:59:43AM +0200, Jacopo Mondi wrote:
On Mon, Aug 26, 2019 at 09:34:41AM +0200, Geert Uytterhoeven wrote:
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add device tree bindings documentation for the Renesas R-Car Display Unit Color Management Module.
CMM is the image enhancement module available on each R-Car DU video channel on R-Car Gen2 and Gen3 SoCs (V3H and V3M excluded).
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.txt @@ -0,0 +1,33 @@ +* Renesas R-Car Color Management Module (CMM)
+Renesas R-Car image enhancement module connected to R-Car DU video channels.
+Required properties:
- compatible: shall be one or more of the following:
- "renesas,cmm-r8a7795": for R8A7795 (R-Car H3) compatible CMM.
- "renesas,cmm-r8a7796": for R8A7796 (R-Car M3-W) compatible CMM.
- "renesas,cmm-r8a77965": for R8A77965 (R-Car M3-N) compatible CMM.
- "renesas,cmm-r8a77990": for R8A77990 (R-Car E3) compatible CMM.
- "renesas,cmm-r8a77995": for R8A77995 (R-Car D3) compatible CMM.
Please use "renesas,<socype->-cmm" instead of "renesas,cmm-<soctype>".
I actually copied it from the r-car gpio bindings, and I liked cmm-<soctype> better. If you prefer I can change it though.
- "renesas,rcar-gen3-cmm": for a generic R-Car Gen3 compatible CMM.
- "renesas,rcar-gen2-cmm": for a generic R-Car Gen2 compatible CMM.
- When the generic compatible string is specified, the SoC-specific
- version corresponding to the platform should be listed first.
- reg: the address base and length of the memory area where CMM control
- registers are mapped to.
- clocks: phandle and clock-specifier pair to the CMM functional clock
- supplier.
Thinking about yaml validation:
power-domains? resets?
They should indeed be documented.
How about converting this binding to yaml alreay ? It should be fairly simple.
I'm trying to, and I'm having my portion of fun time at it.
The definition of the schema itself seems good, but I wonder, is this the first renesas schema we have? Because it seems to me the schema validator is having an hard time to digest the examplea 'clocks' and 'power-domains' properties, which have 1 phandle and 2 specifiers and 1 phandle and 1 specifier respectively for Rensas SoCs.
In other words, if in the example I have:
examples: - | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg 711> <---- 1 phandle + 1 specifier resets = <&cpg 711>; power-domains = <&sysc>; <---- 1 phandle };
The schema validation is good.
While if I use an actual example - | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg CPG_MOD 711> <---- 1 phandle + 2 specifier resets = <&cpg 711>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; <---- 1 phandle }; + 1 specfier
The schema validation fails... Error: Documentation/devicetree/bindings/display/renesas,cmm.example.dts:20.29-30 syntax error FATAL ERROR: Unable to parse input tree
Are clocks properties with > 2 entries and power-domains properties with
1 entries supported?
Because from what I read here: https://github.com/robherring/yaml-bindings/blob/master/schemas/clock/clock.... "The length of a clock specifier is defined by the value of a #clock-cells property in the clock provider node."
And that's expected, but is the examples actually validated against the clock provider pointed by the phandle? Because in that case, if we had a yaml schema for the cpg-mssr provider, it would indeed specify clock-cells=2.
Do we need a schema for cpg-mssr first, or am I doing something else wrong?
Thanks j
+Example: +--------
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea40000 0 0x1000>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
clocks = <&cpg CPG_MOD 711>;
resets = <&cpg 711>;
};
-- Regards,
Laurent Pinchart
Hi Jacopo,
On Fri, Aug 30, 2019 at 08:01:09PM +0200, Jacopo Mondi wrote:
On Mon, Aug 26, 2019 at 01:15:50PM +0300, Laurent Pinchart wrote:
On Mon, Aug 26, 2019 at 09:59:43AM +0200, Jacopo Mondi wrote:
On Mon, Aug 26, 2019 at 09:34:41AM +0200, Geert Uytterhoeven wrote:
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add device tree bindings documentation for the Renesas R-Car Display Unit Color Management Module.
CMM is the image enhancement module available on each R-Car DU video channel on R-Car Gen2 and Gen3 SoCs (V3H and V3M excluded).
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.txt @@ -0,0 +1,33 @@ +* Renesas R-Car Color Management Module (CMM)
+Renesas R-Car image enhancement module connected to R-Car DU video channels.
+Required properties:
- compatible: shall be one or more of the following:
- "renesas,cmm-r8a7795": for R8A7795 (R-Car H3) compatible CMM.
- "renesas,cmm-r8a7796": for R8A7796 (R-Car M3-W) compatible CMM.
- "renesas,cmm-r8a77965": for R8A77965 (R-Car M3-N) compatible CMM.
- "renesas,cmm-r8a77990": for R8A77990 (R-Car E3) compatible CMM.
- "renesas,cmm-r8a77995": for R8A77995 (R-Car D3) compatible CMM.
Please use "renesas,<socype->-cmm" instead of "renesas,cmm-<soctype>".
I actually copied it from the r-car gpio bindings, and I liked cmm-<soctype> better. If you prefer I can change it though.
- "renesas,rcar-gen3-cmm": for a generic R-Car Gen3 compatible CMM.
- "renesas,rcar-gen2-cmm": for a generic R-Car Gen2 compatible CMM.
- When the generic compatible string is specified, the SoC-specific
- version corresponding to the platform should be listed first.
- reg: the address base and length of the memory area where CMM control
- registers are mapped to.
- clocks: phandle and clock-specifier pair to the CMM functional clock
- supplier.
Thinking about yaml validation:
power-domains? resets?
They should indeed be documented.
How about converting this binding to yaml alreay ? It should be fairly simple.
I'm trying to, and I'm having my portion of fun time at it.
The definition of the schema itself seems good, but I wonder, is this the first renesas schema we have? Because it seems to me the schema validator is having an hard time to digest the examplea 'clocks' and 'power-domains' properties, which have 1 phandle and 2 specifiers and 1 phandle and 1 specifier respectively for Rensas SoCs.
In other words, if in the example I have:
examples:
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg 711> <---- 1 phandle + 1 specifier resets = <&cpg 711>; power-domains = <&sysc>; <---- 1 phandle };
The schema validation is good.
While if I use an actual example
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg CPG_MOD 711> <---- 1 phandle + 2 specifier resets = <&cpg 711>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; <---- 1 phandle }; + 1 specfier
The schema validation fails... Error: Documentation/devicetree/bindings/display/renesas,cmm.example.dts:20.29-30 syntax error FATAL ERROR: Unable to parse input tree
Are clocks properties with > 2 entries and power-domains properties with
1 entries supported?
Because from what I read here: https://github.com/robherring/yaml-bindings/blob/master/schemas/clock/clock.... "The length of a clock specifier is defined by the value of a #clock-cells property in the clock provider node."
And that's expected, but is the examples actually validated against the clock provider pointed by the phandle? Because in that case, if we had a yaml schema for the cpg-mssr provider, it would indeed specify clock-cells=2.
Do we need a schema for cpg-mssr first, or am I doing something else wrong?
I think you just need to #include the headers that define CPG_MOD and R8A7796_PD_ALWAYS_ON.
+Example: +--------
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea40000 0 0x1000>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
clocks = <&cpg CPG_MOD 711>;
resets = <&cpg 711>;
};
Hi Laurent,
On Thu, Sep 5, 2019 at 1:50 PM Laurent Pinchart laurent.pinchart@ideasonboard.com wrote:
On Fri, Aug 30, 2019 at 08:01:09PM +0200, Jacopo Mondi wrote:
On Mon, Aug 26, 2019 at 01:15:50PM +0300, Laurent Pinchart wrote:
How about converting this binding to yaml alreay ? It should be fairly simple.
I'm trying to, and I'm having my portion of fun time at it.
The definition of the schema itself seems good, but I wonder, is this the first renesas schema we have? Because it seems to me the schema validator is having an hard time to digest the examplea 'clocks' and 'power-domains' properties, which have 1 phandle and 2 specifiers and 1 phandle and 1 specifier respectively for Rensas SoCs.
In other words, if in the example I have:
examples:
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg 711> <---- 1 phandle + 1 specifier resets = <&cpg 711>; power-domains = <&sysc>; <---- 1 phandle };
The schema validation is good.
While if I use an actual example
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg CPG_MOD 711> <---- 1 phandle + 2 specifier resets = <&cpg 711>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; <---- 1 phandle }; + 1 specfier
The schema validation fails... Error: Documentation/devicetree/bindings/display/renesas,cmm.example.dts:20.29-30 syntax error FATAL ERROR: Unable to parse input tree
Are clocks properties with > 2 entries and power-domains properties with
1 entries supported?
Because from what I read here: https://github.com/robherring/yaml-bindings/blob/master/schemas/clock/clock.... "The length of a clock specifier is defined by the value of a #clock-cells property in the clock provider node."
And that's expected, but is the examples actually validated against the clock provider pointed by the phandle? Because in that case, if we had a yaml schema for the cpg-mssr provider, it would indeed specify clock-cells=2.
Do we need a schema for cpg-mssr first, or am I doing something else wrong?
I think you just need to #include the headers that define CPG_MOD and R8A7796_PD_ALWAYS_ON.
If that helps, you might want to replace the symbols in the examples by their actual values (1 resp. 32).
And perhaps keep the symbols as comments?
clocks = <&cpg 1 /* CPG_MOD */ 711>; power-domains = <&sysc 32 /* R8A7796_PD_ALWAYS_ON */>;
Gr{oetje,eeting}s,
Geert
Hi Geert,
On Thu, Sep 05, 2019 at 02:05:34PM +0200, Geert Uytterhoeven wrote:
On Thu, Sep 5, 2019 at 1:50 PM Laurent Pinchart wrote:
On Fri, Aug 30, 2019 at 08:01:09PM +0200, Jacopo Mondi wrote:
On Mon, Aug 26, 2019 at 01:15:50PM +0300, Laurent Pinchart wrote:
How about converting this binding to yaml alreay ? It should be fairly simple.
I'm trying to, and I'm having my portion of fun time at it.
The definition of the schema itself seems good, but I wonder, is this the first renesas schema we have? Because it seems to me the schema validator is having an hard time to digest the examplea 'clocks' and 'power-domains' properties, which have 1 phandle and 2 specifiers and 1 phandle and 1 specifier respectively for Rensas SoCs.
In other words, if in the example I have:
examples:
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg 711> <---- 1 phandle + 1 specifier resets = <&cpg 711>; power-domains = <&sysc>; <---- 1 phandle };
The schema validation is good.
While if I use an actual example
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg CPG_MOD 711> <---- 1 phandle + 2 specifier resets = <&cpg 711>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; <---- 1 phandle }; + 1 specfier
The schema validation fails... Error: Documentation/devicetree/bindings/display/renesas,cmm.example.dts:20.29-30 syntax error FATAL ERROR: Unable to parse input tree
Are clocks properties with > 2 entries and power-domains properties with
1 entries supported?
Because from what I read here: https://github.com/robherring/yaml-bindings/blob/master/schemas/clock/clock.... "The length of a clock specifier is defined by the value of a #clock-cells property in the clock provider node."
And that's expected, but is the examples actually validated against the clock provider pointed by the phandle? Because in that case, if we had a yaml schema for the cpg-mssr provider, it would indeed specify clock-cells=2.
Do we need a schema for cpg-mssr first, or am I doing something else wrong?
I think you just need to #include the headers that define CPG_MOD and R8A7796_PD_ALWAYS_ON.
If that helps, you might want to replace the symbols in the examples by their actual values (1 resp. 32).
And perhaps keep the symbols as comments?
clocks = <&cpg 1 /* CPG_MOD */ 711>; power-domains = <&sysc 32 /* R8A7796_PD_ALWAYS_ON */>;
I think adding the required #include at the beginning of the example is a better solution.
Hi Laurent, Geert,
On Thu, Sep 05, 2019 at 03:20:59PM +0300, Laurent Pinchart wrote:
Hi Geert,
On Thu, Sep 05, 2019 at 02:05:34PM +0200, Geert Uytterhoeven wrote:
On Thu, Sep 5, 2019 at 1:50 PM Laurent Pinchart wrote:
On Fri, Aug 30, 2019 at 08:01:09PM +0200, Jacopo Mondi wrote:
On Mon, Aug 26, 2019 at 01:15:50PM +0300, Laurent Pinchart wrote:
How about converting this binding to yaml alreay ? It should be fairly simple.
I'm trying to, and I'm having my portion of fun time at it.
The definition of the schema itself seems good, but I wonder, is this the first renesas schema we have? Because it seems to me the schema validator is having an hard time to digest the examplea 'clocks' and 'power-domains' properties, which have 1 phandle and 2 specifiers and 1 phandle and 1 specifier respectively for Rensas SoCs.
In other words, if in the example I have:
examples:
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg 711> <---- 1 phandle + 1 specifier resets = <&cpg 711>; power-domains = <&sysc>; <---- 1 phandle };
The schema validation is good.
While if I use an actual example
- | cmm0: cmm@fea40000 { compatible = "renesas,r8a7796-cmm"; reg = <0 0xfea40000 0 0x1000>; clocks = <&cpg CPG_MOD 711> <---- 1 phandle + 2 specifier resets = <&cpg 711>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; <---- 1 phandle }; + 1 specfier
The schema validation fails... Error: Documentation/devicetree/bindings/display/renesas,cmm.example.dts:20.29-30 syntax error FATAL ERROR: Unable to parse input tree
Are clocks properties with > 2 entries and power-domains properties with
1 entries supported?
Because from what I read here: https://github.com/robherring/yaml-bindings/blob/master/schemas/clock/clock.... "The length of a clock specifier is defined by the value of a #clock-cells property in the clock provider node."
And that's expected, but is the examples actually validated against the clock provider pointed by the phandle? Because in that case, if we had a yaml schema for the cpg-mssr provider, it would indeed specify clock-cells=2.
Do we need a schema for cpg-mssr first, or am I doing something else wrong?
I think you just need to #include the headers that define CPG_MOD and R8A7796_PD_ALWAYS_ON.
If that helps, you might want to replace the symbols in the examples by their actual values (1 resp. 32).
And perhaps keep the symbols as comments?
clocks = <&cpg 1 /* CPG_MOD */ 711>; power-domains = <&sysc 32 /* R8A7796_PD_ALWAYS_ON */>;
I think adding the required #include at the beginning of the example is a better solution.
I didn't realize that, but it actually makes sense, as the example is extracted and actually compiled from the yaml schema.. brilliant!
With a simple:
--- a/Documentation/devicetree/bindings/display/renesas,cmm.yaml +++ b/Documentation/devicetree/bindings/display/renesas,cmm.yaml @@ -51,6 +51,9 @@ additionalProperties: false
examples: - | + #include <dt-bindings/clock/r8a7796-cpg-mssr.h> + #include <dt-bindings/power/r8a7796-sysc.h>
The example now compiles.
Thanks, I will submit the bindings in yaml format in next iteration.
-- Regards,
Laurent Pinchart
Document the newly added 'cmms' property which accepts a list of phandle and channel index pairs that point to the CMM units available for each Display Unit output video channel.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com --- Documentation/devicetree/bindings/display/renesas,du.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index c97dfacad281..c2265e2a1af2 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -45,6 +45,10 @@ Required Properties: instance that serves the DU channel, and the channel index identifies the LIF instance in that VSP.
+ - cmms: A list of phandles to the CMM instances present in the SoC, one + for each available DU channel. The property shall not be specified for + SoCs that do not provide any CMM (such as V3M and V3H). + Required nodes:
The connections to the DU output video ports are modeled using the OF graph @@ -91,6 +95,7 @@ Example: R8A7795 (R-Car H3) ES2.0 DU <&cpg CPG_MOD 721>; clock-names = "du.0", "du.1", "du.2", "du.3"; vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; + cmms = <&cmm0 &cmm1 &cmm2 &cmm3>;
ports { #address-cells = <1>; -- 2.22.0
On Sun, Aug 25, 2019 at 03:51:42PM +0200, Jacopo Mondi wrote:
Document the newly added 'cmms' property which accepts a list of phandle and channel index pairs that point to the CMM units available for each Display Unit output video channel.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
Documentation/devicetree/bindings/display/renesas,du.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index c97dfacad281..c2265e2a1af2 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -45,6 +45,10 @@ Required Properties: instance that serves the DU channel, and the channel index identifies the LIF instance in that VSP.
- cmms: A list of phandles to the CMM instances present in the SoC, one
- for each available DU channel. The property shall not be specified for
- SoCs that do not provide any CMM (such as V3M and V3H).
renesas,cmms
Perhaps define what CMM is.
Required nodes:
The connections to the DU output video ports are modeled using the OF graph @@ -91,6 +95,7 @@ Example: R8A7795 (R-Car H3) ES2.0 DU <&cpg CPG_MOD 721>; clock-names = "du.0", "du.1", "du.2", "du.3"; vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
cmms = <&cmm0 &cmm1 &cmm2 &cmm3>;
ports { #address-cells = <1>;
-- 2.22.0
On Tue, Aug 27, 2019 at 10:29 PM Rob Herring robh@kernel.org wrote:
On Sun, Aug 25, 2019 at 03:51:42PM +0200, Jacopo Mondi wrote:
Document the newly added 'cmms' property which accepts a list of phandle and channel index pairs that point to the CMM units available for each Display Unit output video channel.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
Documentation/devicetree/bindings/display/renesas,du.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index c97dfacad281..c2265e2a1af2 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -45,6 +45,10 @@ Required Properties: instance that serves the DU channel, and the channel index identifies the LIF instance in that VSP.
- cmms: A list of phandles to the CMM instances present in the SoC, one
- for each available DU channel. The property shall not be specified for
- SoCs that do not provide any CMM (such as V3M and V3H).
renesas,cmms
So I guess we really wanted to have the prefix for the vsps property, too?
Gr{oetje,eeting}s,
Geert
On Wed, Aug 28, 2019 at 09:32:23AM +0200, Geert Uytterhoeven wrote:
On Tue, Aug 27, 2019 at 10:29 PM Rob Herring robh@kernel.org wrote:
On Sun, Aug 25, 2019 at 03:51:42PM +0200, Jacopo Mondi wrote:
Document the newly added 'cmms' property which accepts a list of phandle and channel index pairs that point to the CMM units available for each Display Unit output video channel.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
Documentation/devicetree/bindings/display/renesas,du.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index c97dfacad281..c2265e2a1af2 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -45,6 +45,10 @@ Required Properties: instance that serves the DU channel, and the channel index identifies the LIF instance in that VSP.
- cmms: A list of phandles to the CMM instances present in the SoC, one
- for each available DU channel. The property shall not be specified for
- SoCs that do not provide any CMM (such as V3M and V3H).
renesas,cmms
So I guess we really wanted to have the prefix for the vsps property, too?
Yes, we should have :-( My bad.
Add CMM units to Renesas R-Car M3-W device tree and reference them from the Display Unit they are connected to.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- arch/arm64/boot/dts/renesas/r8a7796.dtsi | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index 3dc9d73f589a..8d78e1f98a23 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -2613,6 +2613,30 @@ renesas,fcp = <&fcpvi0>; };
+ cmm0: cmm@fea40000 { + compatible = "renesas,cmm-r8a7796"; + reg = <0 0xfea40000 0 0x1000>; + clocks = <&cpg CPG_MOD 711>; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 711>; + }; + + cmm1: cmm@fea50000 { + compatible = "renesas,cmm-r8a7796"; + reg = <0 0xfea50000 0 0x1000>; + clocks = <&cpg CPG_MOD 710>; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 710>; + }; + + cmm2: cmm@fea60000 { + compatible = "renesas,cmm-r8a7796"; + reg = <0 0xfea60000 0 0x1000>; + clocks = <&cpg CPG_MOD 709>; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 709>; + }; + csi20: csi2@fea80000 { compatible = "renesas,r8a7796-csi2"; reg = <0 0xfea80000 0 0x10000>; @@ -2766,6 +2790,7 @@ status = "disabled";
vsps = <&vspd0 &vspd1 &vspd2>; + cmms = <&cmm0 &cmm1 &cmm2>;
ports { #address-cells = <1>;
Hi Jacopo,
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add CMM units to Renesas R-Car M3-W device tree and reference them from the Display Unit they are connected to.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
arch/arm64/boot/dts/renesas/r8a7796.dtsi | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index 3dc9d73f589a..8d78e1f98a23 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -2613,6 +2613,30 @@ renesas,fcp = <&fcpvi0>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
Shouldn't you add "renesas,rcar-gen3-cmm" as a fallback? (for all CMM nodes in all DT patches)
Gr{oetje,eeting}s,
Geert
Hi Geert.
On Mon, Aug 26, 2019 at 09:28:56AM +0200, Geert Uytterhoeven wrote:
Hi Jacopo,
On Sun, Aug 25, 2019 at 3:50 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add CMM units to Renesas R-Car M3-W device tree and reference them from the Display Unit they are connected to.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
arch/arm64/boot/dts/renesas/r8a7796.dtsi | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index 3dc9d73f589a..8d78e1f98a23 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -2613,6 +2613,30 @@ renesas,fcp = <&fcpvi0>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
Shouldn't you add "renesas,rcar-gen3-cmm" as a fallback?
Should I? Since you have suggested to drop all per-SoC compatibles from the driver I guess so...
Thanks j
(for all CMM nodes in all DT patches)
Gr{oetje,eeting}s,
Geert
-- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Jacopo,
Thank you for the patch.
Should you squash this with the patches that add CMM units to the other SoCs ?
On Sun, Aug 25, 2019 at 03:51:43PM +0200, Jacopo Mondi wrote:
Add CMM units to Renesas R-Car M3-W device tree and reference them from the Display Unit they are connected to.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Apart from the issue pointed out by Geert,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
arch/arm64/boot/dts/renesas/r8a7796.dtsi | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index 3dc9d73f589a..8d78e1f98a23 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -2613,6 +2613,30 @@ renesas,fcp = <&fcpvi0>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea40000 0 0x1000>;
clocks = <&cpg CPG_MOD 711>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
resets = <&cpg 711>;
};
cmm1: cmm@fea50000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea50000 0 0x1000>;
clocks = <&cpg CPG_MOD 710>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
resets = <&cpg 710>;
};
cmm2: cmm@fea60000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea60000 0 0x1000>;
clocks = <&cpg CPG_MOD 709>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
resets = <&cpg 709>;
};
- csi20: csi2@fea80000 { compatible = "renesas,r8a7796-csi2"; reg = <0 0xfea80000 0 0x10000>;
@@ -2766,6 +2790,7 @@ status = "disabled";
vsps = <&vspd0 &vspd1 &vspd2>;
cmms = <&cmm0 &cmm1 &cmm2>; ports { #address-cells = <1>;
Hi Laurent,
On Tue, Aug 27, 2019 at 01:43:37AM +0300, Laurent Pinchart wrote:
Hi Jacopo,
Thank you for the patch.
Should you squash this with the patches that add CMM units to the other SoCs ?
I don't know, I guess it depends on Geert's preferences. Geert?
On Sun, Aug 25, 2019 at 03:51:43PM +0200, Jacopo Mondi wrote:
Add CMM units to Renesas R-Car M3-W device tree and reference them from the Display Unit they are connected to.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Apart from the issue pointed out by Geert,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
arch/arm64/boot/dts/renesas/r8a7796.dtsi | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index 3dc9d73f589a..8d78e1f98a23 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -2613,6 +2613,30 @@ renesas,fcp = <&fcpvi0>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea40000 0 0x1000>;
clocks = <&cpg CPG_MOD 711>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
resets = <&cpg 711>;
};
cmm1: cmm@fea50000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea50000 0 0x1000>;
clocks = <&cpg CPG_MOD 710>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
resets = <&cpg 710>;
};
cmm2: cmm@fea60000 {
compatible = "renesas,cmm-r8a7796";
reg = <0 0xfea60000 0 0x1000>;
clocks = <&cpg CPG_MOD 709>;
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
resets = <&cpg 709>;
};
- csi20: csi2@fea80000 { compatible = "renesas,r8a7796-csi2"; reg = <0 0xfea80000 0 0x10000>;
@@ -2766,6 +2790,7 @@ status = "disabled";
vsps = <&vspd0 &vspd1 &vspd2>;
cmms = <&cmm0 &cmm1 &cmm2>; ports { #address-cells = <1>;
-- Regards,
Laurent Pinchart
Hi Jacopo,
On Tue, Aug 27, 2019 at 11:53 AM Jacopo Mondi jacopo@jmondi.org wrote:
On Tue, Aug 27, 2019 at 01:43:37AM +0300, Laurent Pinchart wrote:
Should you squash this with the patches that add CMM units to the other SoCs ?
I don't know, I guess it depends on Geert's preferences. Geert?
If you add it to all supported SoCs at the same time, a single patch makes sense.
Acceptance will mostly depends on who's at the end of the arm-soc pipeline: Olof would prefer a single patch ;-)
Gr{oetje,eeting}s,
Geert
Add CMM units to Renesas R-Car H3 device tree and reference them from the Display Unit they are connected to.
While at it, re-sort the du device node properties to match the ordering found in other SoCs.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- arch/arm64/boot/dts/renesas/r8a7795.dtsi | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi index 95deff66eeb6..21b4069f07e7 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi @@ -2909,6 +2909,38 @@ iommus = <&ipmmu_vi1 10>; };
+ cmm0: cmm@fea40000 { + compatible = "renesas,cmm-r8a7795"; + reg = <0 0xfea40000 0 0x1000>; + clocks = <&cpg CPG_MOD 711>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 711>; + }; + + cmm1: cmm@fea50000 { + compatible = "renesas,cmm-r8a7795"; + reg = <0 0xfea50000 0 0x1000>; + clocks = <&cpg CPG_MOD 710>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 710>; + }; + + cmm2: cmm@fea60000 { + compatible = "renesas,cmm-r8a7795"; + reg = <0 0xfea60000 0 0x1000>; + clocks = <&cpg CPG_MOD 709>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 709>; + }; + + cmm3: cmm@fea70000 { + compatible = "renesas,cmm-r8a7795"; + reg = <0 0xfea70000 0 0x1000>; + clocks = <&cpg CPG_MOD 708>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 708>; + }; + csi20: csi2@fea80000 { compatible = "renesas,r8a7795-csi2"; reg = <0 0xfea80000 0 0x10000>; @@ -3112,9 +3144,11 @@ <&cpg CPG_MOD 722>, <&cpg CPG_MOD 721>; clock-names = "du.0", "du.1", "du.2", "du.3"; - vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; status = "disabled";
+ vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; + cmms = <&cmm0 &cmm1 &cmm2 &cmm3>; + ports { #address-cells = <1>; #size-cells = <0>;
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:44PM +0200, Jacopo Mondi wrote:
Add CMM units to Renesas R-Car H3 device tree and reference them from the Display Unit they are connected to.
While at it, re-sort the du device node properties to match the ordering found in other SoCs.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Apart from the issue with compatible string as pointed out for patch 03/14,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
arch/arm64/boot/dts/renesas/r8a7795.dtsi | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi index 95deff66eeb6..21b4069f07e7 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi @@ -2909,6 +2909,38 @@ iommus = <&ipmmu_vi1 10>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a7795";
reg = <0 0xfea40000 0 0x1000>;
clocks = <&cpg CPG_MOD 711>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 711>;
};
cmm1: cmm@fea50000 {
compatible = "renesas,cmm-r8a7795";
reg = <0 0xfea50000 0 0x1000>;
clocks = <&cpg CPG_MOD 710>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 710>;
};
cmm2: cmm@fea60000 {
compatible = "renesas,cmm-r8a7795";
reg = <0 0xfea60000 0 0x1000>;
clocks = <&cpg CPG_MOD 709>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 709>;
};
cmm3: cmm@fea70000 {
compatible = "renesas,cmm-r8a7795";
reg = <0 0xfea70000 0 0x1000>;
clocks = <&cpg CPG_MOD 708>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 708>;
};
- csi20: csi2@fea80000 { compatible = "renesas,r8a7795-csi2"; reg = <0 0xfea80000 0 0x10000>;
@@ -3112,9 +3144,11 @@ <&cpg CPG_MOD 722>, <&cpg CPG_MOD 721>; clock-names = "du.0", "du.1", "du.2", "du.3";
vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; status = "disabled";
vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
cmms = <&cmm0 &cmm1 &cmm2 &cmm3>;
ports { #address-cells = <1>; #size-cells = <0>;
Add CMM units to Renesas R-Car M3-N device tree and reference them from the Display Unit they are connected to.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- arch/arm64/boot/dts/renesas/r8a77965.dtsi | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi index 4ae163220f60..8cf0d049203d 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi @@ -2320,6 +2320,30 @@ resets = <&cpg 611>; };
+ cmm0: cmm@fea40000 { + compatible = "renesas,cmm-r8a77965"; + reg = <0 0xfea40000 0 0x1000>; + clocks = <&cpg CPG_MOD 711>; + power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; + resets = <&cpg 711>; + }; + + cmm1: cmm@fea50000 { + compatible = "renesas,cmm-r8a77965"; + reg = <0 0xfea50000 0 0x1000>; + clocks = <&cpg CPG_MOD 710>; + power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; + resets = <&cpg 710>; + }; + + cmm3: cmm@fea70000 { + compatible = "renesas,cmm-r8a77965"; + reg = <0 0xfea70000 0 0x1000>; + clocks = <&cpg CPG_MOD 708>; + power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; + resets = <&cpg 708>; + }; + csi20: csi2@fea80000 { compatible = "renesas,r8a77965-csi2"; reg = <0 0xfea80000 0 0x10000>; @@ -2470,6 +2494,7 @@ status = "disabled";
vsps = <&vspd0 0>, <&vspd1 0>, <&vspd0 1>; + cmms = <&cmm0 &cmm1 &cmm3>;
ports { #address-cells = <1>;
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:45PM +0200, Jacopo Mondi wrote:
Add CMM units to Renesas R-Car M3-N device tree and reference them from the Display Unit they are connected to.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Apart from the issue with compatible string as pointed out for patch 03/14,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
arch/arm64/boot/dts/renesas/r8a77965.dtsi | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi index 4ae163220f60..8cf0d049203d 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi @@ -2320,6 +2320,30 @@ resets = <&cpg 611>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a77965";
reg = <0 0xfea40000 0 0x1000>;
clocks = <&cpg CPG_MOD 711>;
power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
resets = <&cpg 711>;
};
cmm1: cmm@fea50000 {
compatible = "renesas,cmm-r8a77965";
reg = <0 0xfea50000 0 0x1000>;
clocks = <&cpg CPG_MOD 710>;
power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
resets = <&cpg 710>;
};
cmm3: cmm@fea70000 {
compatible = "renesas,cmm-r8a77965";
reg = <0 0xfea70000 0 0x1000>;
clocks = <&cpg CPG_MOD 708>;
power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
resets = <&cpg 708>;
};
- csi20: csi2@fea80000 { compatible = "renesas,r8a77965-csi2"; reg = <0 0xfea80000 0 0x10000>;
@@ -2470,6 +2494,7 @@ status = "disabled";
vsps = <&vspd0 0>, <&vspd1 0>, <&vspd0 1>;
cmms = <&cmm0 &cmm1 &cmm3>; ports { #address-cells = <1>;
Add CMM units to Renesas R-Car E3 device tree and reference them from the Display Unit they are connected to.
While at it, re-sort the du device node properties to match the ordering found in other SoCs.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- arch/arm64/boot/dts/renesas/r8a77990.dtsi | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi index 455954c3d98e..89ebe6f565af 100644 --- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi @@ -1727,6 +1727,22 @@ iommus = <&ipmmu_vi0 9>; };
+ cmm0: cmm@fea40000 { + compatible = "renesas,cmm-r8a77990"; + reg = <0 0xfea40000 0 0x1000>; + clocks = <&cpg CPG_MOD 711>; + power-domains = <&sysc R8A77990_PD_ALWAYS_ON>; + resets = <&cpg 711>; + }; + + cmm1: cmm@fea50000 { + compatible = "renesas,cmm-r8a77990"; + reg = <0 0xfea50000 0 0x1000>; + clocks = <&cpg CPG_MOD 710>; + power-domains = <&sysc R8A77990_PD_ALWAYS_ON>; + resets = <&cpg 710>; + }; + csi40: csi2@feaa0000 { compatible = "renesas,r8a77990-csi2"; reg = <0 0xfeaa0000 0 0x10000>; @@ -1768,9 +1784,11 @@ clock-names = "du.0", "du.1"; resets = <&cpg 724>; reset-names = "du.0"; - vsps = <&vspd0 0>, <&vspd1 0>; status = "disabled";
+ vsps = <&vspd0 0>, <&vspd1 0>; + cmms = <&cmm0 &cmm1>; + ports { #address-cells = <1>; #size-cells = <0>;
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:46PM +0200, Jacopo Mondi wrote:
Add CMM units to Renesas R-Car E3 device tree and reference them from the Display Unit they are connected to.
While at it, re-sort the du device node properties to match the ordering found in other SoCs.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Apart from the issue with compatible string as pointed out for patch 03/14,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
arch/arm64/boot/dts/renesas/r8a77990.dtsi | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi index 455954c3d98e..89ebe6f565af 100644 --- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi @@ -1727,6 +1727,22 @@ iommus = <&ipmmu_vi0 9>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a77990";
reg = <0 0xfea40000 0 0x1000>;
clocks = <&cpg CPG_MOD 711>;
power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
resets = <&cpg 711>;
};
cmm1: cmm@fea50000 {
compatible = "renesas,cmm-r8a77990";
reg = <0 0xfea50000 0 0x1000>;
clocks = <&cpg CPG_MOD 710>;
power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
resets = <&cpg 710>;
};
- csi40: csi2@feaa0000 { compatible = "renesas,r8a77990-csi2"; reg = <0 0xfeaa0000 0 0x10000>;
@@ -1768,9 +1784,11 @@ clock-names = "du.0", "du.1"; resets = <&cpg 724>; reset-names = "du.0";
vsps = <&vspd0 0>, <&vspd1 0>; status = "disabled";
vsps = <&vspd0 0>, <&vspd1 0>;
cmms = <&cmm0 &cmm1>;
ports { #address-cells = <1>; #size-cells = <0>;
Add CMM units to Renesas R-Car D3 device tree and reference them from the Display Unit they are connected to.
While at it, re-sort the du device node properties to match the ordering found in other SoCs.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- arch/arm64/boot/dts/renesas/r8a77995.dtsi | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a77995.dtsi b/arch/arm64/boot/dts/renesas/r8a77995.dtsi index 183fef86cf7c..b91a20fbbbc6 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77995.dtsi @@ -993,6 +993,22 @@ iommus = <&ipmmu_vi0 9>; };
+ cmm0: cmm@fea40000 { + compatible = "renesas,cmm-r8a77995"; + reg = <0 0xfea40000 0 0x1000>; + clocks = <&cpg CPG_MOD 711>; + power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; + resets = <&cpg 711>; + }; + + cmm1: cmm@fea50000 { + compatible = "renesas,cmm-r8a77995"; + reg = <0 0xfea50000 0 0x1000>; + clocks = <&cpg CPG_MOD 710>; + power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; + resets = <&cpg 710>; + }; + du: display@feb00000 { compatible = "renesas,du-r8a77995"; reg = <0 0xfeb00000 0 0x40000>; @@ -1003,9 +1019,11 @@ clock-names = "du.0", "du.1"; resets = <&cpg 724>; reset-names = "du.0"; - vsps = <&vspd0 0>, <&vspd1 0>; status = "disabled";
+ vsps = <&vspd0 0>, <&vspd1 0>; + cmms = <&cmm0 &cmm1>; + ports { #address-cells = <1>; #size-cells = <0>;
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:47PM +0200, Jacopo Mondi wrote:
Add CMM units to Renesas R-Car D3 device tree and reference them from the Display Unit they are connected to.
While at it, re-sort the du device node properties to match the ordering found in other SoCs.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Apart from the issue with compatible string as pointed out for patch 03/14,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
arch/arm64/boot/dts/renesas/r8a77995.dtsi | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a77995.dtsi b/arch/arm64/boot/dts/renesas/r8a77995.dtsi index 183fef86cf7c..b91a20fbbbc6 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77995.dtsi @@ -993,6 +993,22 @@ iommus = <&ipmmu_vi0 9>; };
cmm0: cmm@fea40000 {
compatible = "renesas,cmm-r8a77995";
reg = <0 0xfea40000 0 0x1000>;
clocks = <&cpg CPG_MOD 711>;
power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
resets = <&cpg 711>;
};
cmm1: cmm@fea50000 {
compatible = "renesas,cmm-r8a77995";
reg = <0 0xfea50000 0 0x1000>;
clocks = <&cpg CPG_MOD 710>;
power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
resets = <&cpg 710>;
};
- du: display@feb00000 { compatible = "renesas,du-r8a77995"; reg = <0 0xfeb00000 0 0x40000>;
@@ -1003,9 +1019,11 @@ clock-names = "du.0", "du.1"; resets = <&cpg 724>; reset-names = "du.0";
vsps = <&vspd0 0>, <&vspd1 0>; status = "disabled";
vsps = <&vspd0 0>, <&vspd1 0>;
cmms = <&cmm0 &cmm1>;
ports { #address-cells = <1>; #size-cells = <0>;
Add a driver for the R-Car Display Unit Color Correction Module.
In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++++ 4 files changed, 308 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 1529849e217e..539d232790d1 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -13,6 +13,13 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm.
+config DRM_RCAR_CMM + bool "R-Car DU Color Management Module (CMM) Support" + depends on DRM && OF + depends on DRM_RCAR_DU + help + Enable support for R-Car Color Management Module (CMM). + config DRM_RCAR_DW_HDMI tristate "R-Car DU Gen3 HDMI Encoder Support" depends on DRM && OF diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 6c2ed9c46467..4d1187ccc3e5 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -15,6 +15,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c new file mode 100644 index 000000000000..55361f5701e8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * rcar_cmm.c -- R-Car Display Unit Color Management Module + * + * Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include <drm/drm_color_mgmt.h> + +#include "rcar_cmm.h" + +#define CM2_LUT_CTRL 0x0000 +#define CM2_LUT_CTRL_LUT_EN BIT(0) +#define CM2_LUT_TBL_BASE 0x0600 +#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4) + +struct rcar_cmm { + void __iomem *base; + bool enabled; + + /* + * @lut: 1D-LUT status + * @lut.enabled: 1D-LUT enabled flag + * @lut.size: Number of entries in the LUT table + * @lut.table: Table of 1D-LUT entries scaled to HW support + * precision (8-bits per color component) + */ + struct { + bool enabled; + unsigned int size; + u32 table[CMM_GAMMA_LUT_SIZE]; + } lut; +}; + +static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) +{ + return ioread32(rcmm->base + reg); +} + +static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) +{ + iowrite32(data, rcmm->base + reg); +} + +/* + * rcar_cmm_lut_extract() - Scale down to hw precision the DRM LUT table + * entries and store them. + * @rcmm: Pointer to the CMM device + * @size: Number of entries in the table + * @drm_lut: DRM LUT table + */ +static void rcar_cmm_lut_extract(struct rcar_cmm *rcmm, size_t size, + const struct drm_color_lut *drm_lut) +{ + unsigned int i; + + for (i = 0; i < size; ++i) { + const struct drm_color_lut *lut = &drm_lut[i]; + + rcmm->lut.table[i] = drm_color_lut_extract(lut->red, 8) << 16 + | drm_color_lut_extract(lut->green, 8) << 8 + | drm_color_lut_extract(lut->blue, 8); + } + + rcmm->lut.size = size; +} + +/* + * rcar_cmm_lut_load() - Write to hw the LUT table entries from the local table. + * + * @rcmm: Pointer to the CMM device + */ +static void rcar_cmm_lut_load(struct rcar_cmm *rcmm) +{ + unsigned int i; + + for (i = 0; i < rcmm->lut.size; ++i) { + u32 entry = rcmm->lut.table[i]; + + rcar_cmm_write(rcmm, CM2_LUT_TBL(i), entry); + } +} + +/** + * rcar_cmm_setup() - configure the CMM unit + * + * @pdev: The platform device associated with the CMM instance + * @config: The CRTC-provided configuration. + * + * Configure the CMM unit with the CRTC-provided configuration. + * Currently enabling, disabling and programming of the 1-D LUT unit is + * supported. + */ +int rcar_cmm_setup(struct platform_device *pdev, + const struct rcar_cmm_config *config) +{ + struct rcar_cmm *rcmm = platform_get_drvdata(pdev); + + if (config->lut.size > CMM_GAMMA_LUT_SIZE) + return -EINVAL; + + /* + * As rcar_cmm_setup() is called by atomic commit tail helper, it might + * be called when the CMM is disabled. As we can't program the hardware + * in that case, store the configuration internally and apply it when + * the CMM will be enabled by the CRTC through rcar_cmm_enable(). + */ + if (!rcmm->enabled) { + if (!config->lut.enable) + return 0; + + rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table); + rcmm->lut.enabled = true; + + return 0; + } + + /* Stop LUT operations if requested. */ + if (!config->lut.enable) { + if (rcmm->lut.enabled) { + rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0); + rcmm->lut.enabled = false; + rcmm->lut.size = 0; + } + + return 0; + } + + /* + * Enable LUT and program the new gamma table values. + * + * FIXME: In order to have stable operations it is required to first + * enable the 1D-LUT and then program its table entries. This seems to + * contradict what the chip manual reports, and will have to be + * reconsidered when implementing support for double buffering. + */ + if (!rcmm->lut.enabled) { + rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN); + rcmm->lut.enabled = true; + } + + rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table); + rcar_cmm_lut_load(rcmm); + + return 0; +} +EXPORT_SYMBOL_GPL(rcar_cmm_setup); + +/** + * rcar_cmm_enable() - enable the CMM unit + * + * @pdev: The platform device associated with the CMM instance + * + * Enable the CMM unit by enabling the parent clock and enabling the CMM + * components, such as 1-D LUT, if requested. + */ +int rcar_cmm_enable(struct platform_device *pdev) +{ + struct rcar_cmm *rcmm = platform_get_drvdata(pdev); + int ret; + + if (!rcmm) + return -EPROBE_DEFER; + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) + return ret; + + /* Apply the LUT table values saved at rcar_cmm_setup() time. */ + if (rcmm->lut.enabled) { + rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN); + rcar_cmm_lut_load(rcmm); + } + + rcmm->enabled = true; + + return 0; +} +EXPORT_SYMBOL_GPL(rcar_cmm_enable); + +/** + * rcar_cmm_disable() - disable the CMM unit + * + * @pdev: The platform device associated with the CMM instance + * + * Disable the CMM unit by stopping the parent clock. + */ +void rcar_cmm_disable(struct platform_device *pdev) +{ + struct rcar_cmm *rcmm = platform_get_drvdata(pdev); + + rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0); + + pm_runtime_put(&pdev->dev); + + rcmm->lut.enabled = false; + rcmm->lut.size = 0; + + rcmm->enabled = false; +} +EXPORT_SYMBOL_GPL(rcar_cmm_disable); + +static int rcar_cmm_probe(struct platform_device *pdev) +{ + struct rcar_cmm *rcmm; + struct resource *res; + + rcmm = devm_kzalloc(&pdev->dev, sizeof(*rcmm), GFP_KERNEL); + if (!rcmm) + return -ENOMEM; + + platform_set_drvdata(pdev, rcmm); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rcmm->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rcmm->base)) + return PTR_ERR(rcmm->base); + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int rcar_cmm_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id rcar_cmm_of_table[] = { + { .compatible = "renesas,cmm-r8a7795", }, + { .compatible = "renesas,cmm-r8a7796", }, + { .compatible = "renesas,cmm-r8a77965", }, + { .compatible = "renesas,cmm-r8a77990", }, + { .compatible = "renesas,cmm-r8a77995", }, + { .compatible = "renesas,rcar-gen3-cmm", }, + { .compatible = "renesas,rcar-gen2-cmm", }, + { }, +}; +MODULE_DEVICE_TABLE(of, rcar_cmm_of_table); + +static struct platform_driver rcar_cmm_platform_driver = { + .probe = rcar_cmm_probe, + .remove = rcar_cmm_remove, + .driver = { + .name = "rcar-cmm", + .of_match_table = rcar_cmm_of_table, + }, +}; + +module_platform_driver(rcar_cmm_platform_driver); + +MODULE_AUTHOR("Jacopo Mondi jacopo+renesas@jmondi.org"); +MODULE_DESCRIPTION("Renesas R-Car CMM Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/rcar-du/rcar_cmm.h new file mode 100644 index 000000000000..b0bb7349ebaa --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * rcar_cmm.h -- R-Car Display Unit Color Management Module + * + * Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org + */ + +#ifndef __RCAR_CMM_H__ +#define __RCAR_CMM_H__ + +#define CMM_GAMMA_LUT_SIZE 256 + +struct drm_color_lut; +struct platform_device; + +/** + * struct rcar_cmm_config - CMM configuration + * + * @lut: 1D-LUT configuration + * @lut.enable: 1D-LUT enable flag + * @lut.table: 1D-LUT table entries + * @lut.size: Number of 1D-LUT (max 256) + */ +struct rcar_cmm_config { + struct { + bool enable; + struct drm_color_lut *table; + unsigned int size; + } lut; +}; + +int rcar_cmm_enable(struct platform_device *pdev); +void rcar_cmm_disable(struct platform_device *pdev); + +int rcar_cmm_setup(struct platform_device *pdev, + const struct rcar_cmm_config *config); + +#endif /* __RCAR_CMM_H__ */ -- 2.22.0
Hi Jacopo,
On Sun, Aug 25, 2019 at 3:51 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add a driver for the R-Car Display Unit Color Correction Module. In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c
+static const struct of_device_id rcar_cmm_of_table[] = {
{ .compatible = "renesas,cmm-r8a7795", },
{ .compatible = "renesas,cmm-r8a7796", },
{ .compatible = "renesas,cmm-r8a77965", },
{ .compatible = "renesas,cmm-r8a77990", },
{ .compatible = "renesas,cmm-r8a77995", },
{ .compatible = "renesas,rcar-gen3-cmm", },
As they're all handled the same, you can drop the SoC-specific values from the driver's match table.
{ .compatible = "renesas,rcar-gen2-cmm", },
Just wondering: has this been tested on R-Car Gen2?
Gr{oetje,eeting}s,
Geert
Hi Geert,
On Mon, Aug 26, 2019 at 09:31:02AM +0200, Geert Uytterhoeven wrote:
Hi Jacopo,
On Sun, Aug 25, 2019 at 3:51 PM Jacopo Mondi jacopo+renesas@jmondi.org wrote:
Add a driver for the R-Car Display Unit Color Correction Module. In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
Thanks for your patch!
--- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c
+static const struct of_device_id rcar_cmm_of_table[] = {
{ .compatible = "renesas,cmm-r8a7795", },
{ .compatible = "renesas,cmm-r8a7796", },
{ .compatible = "renesas,cmm-r8a77965", },
{ .compatible = "renesas,cmm-r8a77990", },
{ .compatible = "renesas,cmm-r8a77995", },
{ .compatible = "renesas,rcar-gen3-cmm", },
As they're all handled the same, you can drop the SoC-specific values from the driver's match table.
{ .compatible = "renesas,rcar-gen2-cmm", },
Just wondering: has this been tested on R-Car Gen2?
Not from me :( It might not be the smartest move to add a compatible for an un-tested chip generation. I dragged the gen2 compatible in along the series as it was there in the downstream driver and I assumed BSP has been tested there, but since I've not been able to run any test on Gen2 board I should probably drop it? Any volunteer with a Gen2 board that want to run a test?
Thanks j
Gr{oetje,eeting}s,
Geert
-- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:48PM +0200, Jacopo Mondi wrote:
Add a driver for the R-Car Display Unit Color Correction Module.
In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++++ 4 files changed, 308 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 1529849e217e..539d232790d1 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -13,6 +13,13 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm.
+config DRM_RCAR_CMM
- bool "R-Car DU Color Management Module (CMM) Support"
- depends on DRM && OF
- depends on DRM_RCAR_DU
- help
Enable support for R-Car Color Management Module (CMM).
config DRM_RCAR_DW_HDMI tristate "R-Car DU Gen3 HDMI Encoder Support" depends on DRM && OF diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 6c2ed9c46467..4d1187ccc3e5 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -15,6 +15,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c new file mode 100644 index 000000000000..55361f5701e8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- rcar_cmm.c -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h>
+#include <drm/drm_color_mgmt.h>
+#include "rcar_cmm.h"
+#define CM2_LUT_CTRL 0x0000 +#define CM2_LUT_CTRL_LUT_EN BIT(0) +#define CM2_LUT_TBL_BASE 0x0600 +#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4)
+struct rcar_cmm {
- void __iomem *base;
- bool enabled;
- /*
* @lut: 1D-LUT status
* @lut.enabled: 1D-LUT enabled flag
* @lut.size: Number of entries in the LUT table
Please see my review of patch 13/14, I wonder if we could drop this field.
* @lut.table: Table of 1D-LUT entries scaled to HW support
* precision (8-bits per color component)
*/
- struct {
bool enabled;
unsigned int size;
u32 table[CMM_GAMMA_LUT_SIZE];
- } lut;
+};
+static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) +{
- return ioread32(rcmm->base + reg);
+}
+static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) +{
- iowrite32(data, rcmm->base + reg);
+}
+/*
- rcar_cmm_lut_extract() - Scale down to hw precision the DRM LUT table
s/hw/hardware/ (and below too)
entries and store them.
- @rcmm: Pointer to the CMM device
- @size: Number of entries in the table
- @drm_lut: DRM LUT table
- */
+static void rcar_cmm_lut_extract(struct rcar_cmm *rcmm, size_t size,
const struct drm_color_lut *drm_lut)
+{
- unsigned int i;
- for (i = 0; i < size; ++i) {
const struct drm_color_lut *lut = &drm_lut[i];
rcmm->lut.table[i] = drm_color_lut_extract(lut->red, 8) << 16
| drm_color_lut_extract(lut->green, 8) << 8
| drm_color_lut_extract(lut->blue, 8);
- }
- rcmm->lut.size = size;
+}
+/*
- rcar_cmm_lut_load() - Write to hw the LUT table entries from the local table.
No need for a blank line
- @rcmm: Pointer to the CMM device
- */
+static void rcar_cmm_lut_load(struct rcar_cmm *rcmm)
I would name this rcar_cmm_lut_write().
+{
- unsigned int i;
- for (i = 0; i < rcmm->lut.size; ++i) {
u32 entry = rcmm->lut.table[i];
rcar_cmm_write(rcmm, CM2_LUT_TBL(i), entry);
You don't need the local entry variable.
- }
+}
+/**
- rcar_cmm_setup() - configure the CMM unit
s/configure/Configure/ and s/$/./, or the other way around for the other functions (I don't mine which one, but let's stay consistent).
No need for a blank line (same for the functions below).
- @pdev: The platform device associated with the CMM instance
- @config: The CRTC-provided configuration.
- Configure the CMM unit with the CRTC-provided configuration.
- Currently enabling, disabling and programming of the 1-D LUT unit is
- supported.
- */
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config)
+{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- if (config->lut.size > CMM_GAMMA_LUT_SIZE)
return -EINVAL;
- /*
* As rcar_cmm_setup() is called by atomic commit tail helper, it might
* be called when the CMM is disabled. As we can't program the hardware
* in that case, store the configuration internally and apply it when
* the CMM will be enabled by the CRTC through rcar_cmm_enable().
*/
- if (!rcmm->enabled) {
if (!config->lut.enable)
return 0;
rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
rcmm->lut.enabled = true;
return 0;
- }
- /* Stop LUT operations if requested. */
- if (!config->lut.enable) {
if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
rcmm->lut.enabled = false;
rcmm->lut.size = 0;
}
return 0;
- }
- /*
* Enable LUT and program the new gamma table values.
*
* FIXME: In order to have stable operations it is required to first
* enable the 1D-LUT and then program its table entries. This seems to
* contradict what the chip manual reports, and will have to be
* reconsidered when implementing support for double buffering.
*/
- if (!rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcmm->lut.enabled = true;
- }
- rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
- rcar_cmm_lut_load(rcmm);
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_setup);
+/**
- rcar_cmm_enable() - enable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Enable the CMM unit by enabling the parent clock and enabling the CMM
- components, such as 1-D LUT, if requested.
- */
+int rcar_cmm_enable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- int ret;
- if (!rcmm)
return -EPROBE_DEFER;
This function is called in rcar_du_crtc_atomic_enable(), so that's not the right error code. It seems we need another function for the CMM API to defer probing :-/ I would call it rcar_cmm_init(). This check would then be removed.
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
return ret;
- /* Apply the LUT table values saved at rcar_cmm_setup() time. */
- if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcar_cmm_lut_load(rcmm);
You will not like this, but I just realised that we're now reprogramming the LUT contents every time the CMM is enabled. Do you think that's something we should optimise ? And yes, that would require introducing back an update flag in rcmm->lut :-S Sorry for not realising this when I proposed dropping it.
- }
- rcmm->enabled = true;
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_enable);
+/**
- rcar_cmm_disable() - disable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Disable the CMM unit by stopping the parent clock.
- */
+void rcar_cmm_disable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
- pm_runtime_put(&pdev->dev);
- rcmm->lut.enabled = false;
- rcmm->lut.size = 0;
- rcmm->enabled = false;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_disable);
+static int rcar_cmm_probe(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm;
- struct resource *res;
- rcmm = devm_kzalloc(&pdev->dev, sizeof(*rcmm), GFP_KERNEL);
- if (!rcmm)
return -ENOMEM;
- platform_set_drvdata(pdev, rcmm);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rcmm->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rcmm->base))
return PTR_ERR(rcmm->base);
You really don't like combining those two calls, do you ? :-)
- pm_runtime_enable(&pdev->dev);
- return 0;
+}
+static int rcar_cmm_remove(struct platform_device *pdev) +{
- pm_runtime_disable(&pdev->dev);
- return 0;
+}
+static const struct of_device_id rcar_cmm_of_table[] = {
- { .compatible = "renesas,cmm-r8a7795", },
- { .compatible = "renesas,cmm-r8a7796", },
- { .compatible = "renesas,cmm-r8a77965", },
- { .compatible = "renesas,cmm-r8a77990", },
- { .compatible = "renesas,cmm-r8a77995", },
As Geert pointed out, I would drop those entries.
- { .compatible = "renesas,rcar-gen3-cmm", },
- { .compatible = "renesas,rcar-gen2-cmm", },
- { },
+}; +MODULE_DEVICE_TABLE(of, rcar_cmm_of_table);
+static struct platform_driver rcar_cmm_platform_driver = {
- .probe = rcar_cmm_probe,
- .remove = rcar_cmm_remove,
- .driver = {
.name = "rcar-cmm",
.of_match_table = rcar_cmm_of_table,
- },
+};
+module_platform_driver(rcar_cmm_platform_driver);
+MODULE_AUTHOR("Jacopo Mondi jacopo+renesas@jmondi.org"); +MODULE_DESCRIPTION("Renesas R-Car CMM Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/rcar-du/rcar_cmm.h new file mode 100644 index 000000000000..b0bb7349ebaa --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- rcar_cmm.h -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#ifndef __RCAR_CMM_H__ +#define __RCAR_CMM_H__
+#define CMM_GAMMA_LUT_SIZE 256
+struct drm_color_lut; +struct platform_device;
+/**
- struct rcar_cmm_config - CMM configuration
- @lut: 1D-LUT configuration
- @lut.enable: 1D-LUT enable flag
- @lut.table: 1D-LUT table entries
- @lut.size: Number of 1D-LUT (max 256)
s/1D-LUT/1D-LUT entries/
- */
+struct rcar_cmm_config {
- struct {
bool enable;
struct drm_color_lut *table;
unsigned int size;
- } lut;
+};
+int rcar_cmm_enable(struct platform_device *pdev); +void rcar_cmm_disable(struct platform_device *pdev);
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config);
+#endif /* __RCAR_CMM_H__ */
Hi Laurent,
On Tue, Aug 27, 2019 at 03:24:22AM +0300, Laurent Pinchart wrote:
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:48PM +0200, Jacopo Mondi wrote:
Add a driver for the R-Car Display Unit Color Correction Module.
In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++++ 4 files changed, 308 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 1529849e217e..539d232790d1 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -13,6 +13,13 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm.
+config DRM_RCAR_CMM
- bool "R-Car DU Color Management Module (CMM) Support"
- depends on DRM && OF
- depends on DRM_RCAR_DU
- help
Enable support for R-Car Color Management Module (CMM).
config DRM_RCAR_DW_HDMI tristate "R-Car DU Gen3 HDMI Encoder Support" depends on DRM && OF diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 6c2ed9c46467..4d1187ccc3e5 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -15,6 +15,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c new file mode 100644 index 000000000000..55361f5701e8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- rcar_cmm.c -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h>
+#include <drm/drm_color_mgmt.h>
+#include "rcar_cmm.h"
+#define CM2_LUT_CTRL 0x0000 +#define CM2_LUT_CTRL_LUT_EN BIT(0) +#define CM2_LUT_TBL_BASE 0x0600 +#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4)
+struct rcar_cmm {
- void __iomem *base;
- bool enabled;
- /*
* @lut: 1D-LUT status
* @lut.enabled: 1D-LUT enabled flag
* @lut.size: Number of entries in the LUT table
Please see my review of patch 13/14, I wonder if we could drop this field.
* @lut.table: Table of 1D-LUT entries scaled to HW support
* precision (8-bits per color component)
*/
- struct {
bool enabled;
unsigned int size;
u32 table[CMM_GAMMA_LUT_SIZE];
- } lut;
+};
+static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) +{
- return ioread32(rcmm->base + reg);
+}
+static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) +{
- iowrite32(data, rcmm->base + reg);
+}
+/*
- rcar_cmm_lut_extract() - Scale down to hw precision the DRM LUT table
s/hw/hardware/ (and below too)
entries and store them.
- @rcmm: Pointer to the CMM device
- @size: Number of entries in the table
- @drm_lut: DRM LUT table
- */
+static void rcar_cmm_lut_extract(struct rcar_cmm *rcmm, size_t size,
const struct drm_color_lut *drm_lut)
+{
- unsigned int i;
- for (i = 0; i < size; ++i) {
const struct drm_color_lut *lut = &drm_lut[i];
rcmm->lut.table[i] = drm_color_lut_extract(lut->red, 8) << 16
| drm_color_lut_extract(lut->green, 8) << 8
| drm_color_lut_extract(lut->blue, 8);
- }
- rcmm->lut.size = size;
+}
+/*
- rcar_cmm_lut_load() - Write to hw the LUT table entries from the local table.
No need for a blank line
- @rcmm: Pointer to the CMM device
- */
+static void rcar_cmm_lut_load(struct rcar_cmm *rcmm)
I would name this rcar_cmm_lut_write().
I won't, as I would like to convey the LUT tables is loaded from the local cache after it has been scaled down to the hardware supported precision.
+{
- unsigned int i;
- for (i = 0; i < rcmm->lut.size; ++i) {
u32 entry = rcmm->lut.table[i];
rcar_cmm_write(rcmm, CM2_LUT_TBL(i), entry);
You don't need the local entry variable.
True, but the code is nicer to read and the compiler should be smart enough to optimize it away
- }
+}
+/**
- rcar_cmm_setup() - configure the CMM unit
s/configure/Configure/ and s/$/./, or the other way around for the other functions (I don't mine which one, but let's stay consistent).
Oh right, sorry for the confusion
No need for a blank line (same for the functions below).
- @pdev: The platform device associated with the CMM instance
- @config: The CRTC-provided configuration.
- Configure the CMM unit with the CRTC-provided configuration.
- Currently enabling, disabling and programming of the 1-D LUT unit is
- supported.
- */
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config)
+{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- if (config->lut.size > CMM_GAMMA_LUT_SIZE)
return -EINVAL;
- /*
* As rcar_cmm_setup() is called by atomic commit tail helper, it might
* be called when the CMM is disabled. As we can't program the hardware
* in that case, store the configuration internally and apply it when
* the CMM will be enabled by the CRTC through rcar_cmm_enable().
*/
- if (!rcmm->enabled) {
if (!config->lut.enable)
return 0;
rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
rcmm->lut.enabled = true;
return 0;
- }
- /* Stop LUT operations if requested. */
- if (!config->lut.enable) {
if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
rcmm->lut.enabled = false;
rcmm->lut.size = 0;
}
return 0;
- }
- /*
* Enable LUT and program the new gamma table values.
*
* FIXME: In order to have stable operations it is required to first
* enable the 1D-LUT and then program its table entries. This seems to
* contradict what the chip manual reports, and will have to be
* reconsidered when implementing support for double buffering.
*/
- if (!rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcmm->lut.enabled = true;
- }
- rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
- rcar_cmm_lut_load(rcmm);
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_setup);
+/**
- rcar_cmm_enable() - enable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Enable the CMM unit by enabling the parent clock and enabling the CMM
- components, such as 1-D LUT, if requested.
- */
+int rcar_cmm_enable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- int ret;
- if (!rcmm)
return -EPROBE_DEFER;
This function is called in rcar_du_crtc_atomic_enable(), so that's not the right error code. It seems we need another function for the CMM API to defer probing :-/ I would call it rcar_cmm_init(). This check would then be removed.
I agree about the return code, but not the name, as this function actually enables the CMM. PROBE_DEFER does not make any sense here, I wonder where it come from, as the probing of CMM and DU has long happened once we get here (at least, I assume so, if we receive a gamma_table, userspace has already been running, and both DU and CMM should have probed. Otherwise, we can exploit the newly created device link, and make sure DU probes after the CMM).
I would just change the return value here, and possibly use the device link to ensure the correct probing sequence.
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
return ret;
- /* Apply the LUT table values saved at rcar_cmm_setup() time. */
- if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcar_cmm_lut_load(rcmm);
You will not like this, but I just realised that we're now reprogramming the LUT contents every time the CMM is enabled. Do you think that's something we should optimise ? And yes, that would require introducing
Why so? If we receive an enable after a disable which stops the CMM clock and we have no guarantees the table entries have been kept, or what we receive from userspace has changed or not. Why is this an issue in your opinion?
back an update flag in rcmm->lut :-S Sorry for not realising this when I proposed dropping it.
- }
- rcmm->enabled = true;
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_enable);
+/**
- rcar_cmm_disable() - disable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Disable the CMM unit by stopping the parent clock.
- */
+void rcar_cmm_disable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
- pm_runtime_put(&pdev->dev);
- rcmm->lut.enabled = false;
- rcmm->lut.size = 0;
- rcmm->enabled = false;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_disable);
+static int rcar_cmm_probe(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm;
- struct resource *res;
- rcmm = devm_kzalloc(&pdev->dev, sizeof(*rcmm), GFP_KERNEL);
- if (!rcmm)
return -ENOMEM;
- platform_set_drvdata(pdev, rcmm);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rcmm->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rcmm->base))
return PTR_ERR(rcmm->base);
You really don't like combining those two calls, do you ? :-)
devm_of_iomap() ?
- pm_runtime_enable(&pdev->dev);
- return 0;
+}
+static int rcar_cmm_remove(struct platform_device *pdev) +{
- pm_runtime_disable(&pdev->dev);
- return 0;
+}
+static const struct of_device_id rcar_cmm_of_table[] = {
- { .compatible = "renesas,cmm-r8a7795", },
- { .compatible = "renesas,cmm-r8a7796", },
- { .compatible = "renesas,cmm-r8a77965", },
- { .compatible = "renesas,cmm-r8a77990", },
- { .compatible = "renesas,cmm-r8a77995", },
As Geert pointed out, I would drop those entries.
yes
- { .compatible = "renesas,rcar-gen3-cmm", },
- { .compatible = "renesas,rcar-gen2-cmm", },
- { },
+}; +MODULE_DEVICE_TABLE(of, rcar_cmm_of_table);
+static struct platform_driver rcar_cmm_platform_driver = {
- .probe = rcar_cmm_probe,
- .remove = rcar_cmm_remove,
- .driver = {
.name = "rcar-cmm",
.of_match_table = rcar_cmm_of_table,
- },
+};
+module_platform_driver(rcar_cmm_platform_driver);
+MODULE_AUTHOR("Jacopo Mondi jacopo+renesas@jmondi.org"); +MODULE_DESCRIPTION("Renesas R-Car CMM Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/rcar-du/rcar_cmm.h new file mode 100644 index 000000000000..b0bb7349ebaa --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- rcar_cmm.h -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#ifndef __RCAR_CMM_H__ +#define __RCAR_CMM_H__
+#define CMM_GAMMA_LUT_SIZE 256
+struct drm_color_lut; +struct platform_device;
+/**
- struct rcar_cmm_config - CMM configuration
- @lut: 1D-LUT configuration
- @lut.enable: 1D-LUT enable flag
- @lut.table: 1D-LUT table entries
- @lut.size: Number of 1D-LUT (max 256)
s/1D-LUT/1D-LUT entries/
ack, I'll change this.
Thanks j
- */
+struct rcar_cmm_config {
- struct {
bool enable;
struct drm_color_lut *table;
unsigned int size;
- } lut;
+};
+int rcar_cmm_enable(struct platform_device *pdev); +void rcar_cmm_disable(struct platform_device *pdev);
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config);
+#endif /* __RCAR_CMM_H__ */
-- Regards,
Laurent Pinchart
On Tue, Aug 27, 2019 at 04:56:19PM +0200, Jacopo Mondi wrote:
Hi Laurent,
On Tue, Aug 27, 2019 at 03:24:22AM +0300, Laurent Pinchart wrote:
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:48PM +0200, Jacopo Mondi wrote:
Add a driver for the R-Car Display Unit Color Correction Module.
In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++++ 4 files changed, 308 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 1529849e217e..539d232790d1 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -13,6 +13,13 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm.
+config DRM_RCAR_CMM
- bool "R-Car DU Color Management Module (CMM) Support"
- depends on DRM && OF
- depends on DRM_RCAR_DU
- help
Enable support for R-Car Color Management Module (CMM).
config DRM_RCAR_DW_HDMI tristate "R-Car DU Gen3 HDMI Encoder Support" depends on DRM && OF diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 6c2ed9c46467..4d1187ccc3e5 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -15,6 +15,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c new file mode 100644 index 000000000000..55361f5701e8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- rcar_cmm.c -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h>
+#include <drm/drm_color_mgmt.h>
+#include "rcar_cmm.h"
+#define CM2_LUT_CTRL 0x0000 +#define CM2_LUT_CTRL_LUT_EN BIT(0) +#define CM2_LUT_TBL_BASE 0x0600 +#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4)
+struct rcar_cmm {
- void __iomem *base;
- bool enabled;
- /*
* @lut: 1D-LUT status
* @lut.enabled: 1D-LUT enabled flag
* @lut.size: Number of entries in the LUT table
Please see my review of patch 13/14, I wonder if we could drop this field.
* @lut.table: Table of 1D-LUT entries scaled to HW support
* precision (8-bits per color component)
*/
- struct {
bool enabled;
unsigned int size;
u32 table[CMM_GAMMA_LUT_SIZE];
- } lut;
+};
+static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) +{
- return ioread32(rcmm->base + reg);
+}
+static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) +{
- iowrite32(data, rcmm->base + reg);
+}
+/*
- rcar_cmm_lut_extract() - Scale down to hw precision the DRM LUT table
s/hw/hardware/ (and below too)
entries and store them.
- @rcmm: Pointer to the CMM device
- @size: Number of entries in the table
- @drm_lut: DRM LUT table
- */
+static void rcar_cmm_lut_extract(struct rcar_cmm *rcmm, size_t size,
const struct drm_color_lut *drm_lut)
+{
- unsigned int i;
- for (i = 0; i < size; ++i) {
const struct drm_color_lut *lut = &drm_lut[i];
rcmm->lut.table[i] = drm_color_lut_extract(lut->red, 8) << 16
| drm_color_lut_extract(lut->green, 8) << 8
| drm_color_lut_extract(lut->blue, 8);
- }
- rcmm->lut.size = size;
+}
+/*
- rcar_cmm_lut_load() - Write to hw the LUT table entries from the local table.
No need for a blank line
- @rcmm: Pointer to the CMM device
- */
+static void rcar_cmm_lut_load(struct rcar_cmm *rcmm)
I would name this rcar_cmm_lut_write().
I won't, as I would like to convey the LUT tables is loaded from the
Sorry, I meant "I wouldn't"... "I won't" is really harsh, sorry about it :p
Hi Laurent,
On Tue, Aug 27, 2019 at 04:56:19PM +0200, Jacopo Mondi wrote:
On Tue, Aug 27, 2019 at 03:24:22AM +0300, Laurent Pinchart wrote:
On Sun, Aug 25, 2019 at 03:51:48PM +0200, Jacopo Mondi wrote:
Add a driver for the R-Car Display Unit Color Correction Module.
In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++++ 4 files changed, 308 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 1529849e217e..539d232790d1 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -13,6 +13,13 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm.
+config DRM_RCAR_CMM
- bool "R-Car DU Color Management Module (CMM) Support"
- depends on DRM && OF
- depends on DRM_RCAR_DU
- help
Enable support for R-Car Color Management Module (CMM).
config DRM_RCAR_DW_HDMI tristate "R-Car DU Gen3 HDMI Encoder Support" depends on DRM && OF diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 6c2ed9c46467..4d1187ccc3e5 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -15,6 +15,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c new file mode 100644 index 000000000000..55361f5701e8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- rcar_cmm.c -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h>
+#include <drm/drm_color_mgmt.h>
+#include "rcar_cmm.h"
+#define CM2_LUT_CTRL 0x0000 +#define CM2_LUT_CTRL_LUT_EN BIT(0) +#define CM2_LUT_TBL_BASE 0x0600 +#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4)
+struct rcar_cmm {
- void __iomem *base;
- bool enabled;
- /*
* @lut: 1D-LUT status
* @lut.enabled: 1D-LUT enabled flag
* @lut.size: Number of entries in the LUT table
Please see my review of patch 13/14, I wonder if we could drop this field.
* @lut.table: Table of 1D-LUT entries scaled to HW support
* precision (8-bits per color component)
*/
- struct {
bool enabled;
unsigned int size;
u32 table[CMM_GAMMA_LUT_SIZE];
- } lut;
+};
+static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) +{
- return ioread32(rcmm->base + reg);
+}
+static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) +{
- iowrite32(data, rcmm->base + reg);
+}
+/*
- rcar_cmm_lut_extract() - Scale down to hw precision the DRM LUT table
s/hw/hardware/ (and below too)
entries and store them.
- @rcmm: Pointer to the CMM device
- @size: Number of entries in the table
- @drm_lut: DRM LUT table
- */
+static void rcar_cmm_lut_extract(struct rcar_cmm *rcmm, size_t size,
const struct drm_color_lut *drm_lut)
+{
- unsigned int i;
- for (i = 0; i < size; ++i) {
const struct drm_color_lut *lut = &drm_lut[i];
rcmm->lut.table[i] = drm_color_lut_extract(lut->red, 8) << 16
| drm_color_lut_extract(lut->green, 8) << 8
| drm_color_lut_extract(lut->blue, 8);
- }
- rcmm->lut.size = size;
+}
+/*
- rcar_cmm_lut_load() - Write to hw the LUT table entries from the local table.
No need for a blank line
- @rcmm: Pointer to the CMM device
- */
+static void rcar_cmm_lut_load(struct rcar_cmm *rcmm)
I would name this rcar_cmm_lut_write().
I won't, as I would like to convey the LUT tables is loaded from the local cache after it has been scaled down to the hardware supported precision.
"load" hints a read though, and here you write the LUT to the hardware. Without reading the comments I would have thought this function would read the LUT back from the hardware.
+{
- unsigned int i;
- for (i = 0; i < rcmm->lut.size; ++i) {
u32 entry = rcmm->lut.table[i];
rcar_cmm_write(rcmm, CM2_LUT_TBL(i), entry);
You don't need the local entry variable.
True, but the code is nicer to read and the compiler should be smart enough to optimize it away
I'm not sure about nicer to read, I find the opposite personally, but it's your code :-)
- }
+}
+/**
- rcar_cmm_setup() - configure the CMM unit
s/configure/Configure/ and s/$/./, or the other way around for the other functions (I don't mine which one, but let's stay consistent).
Oh right, sorry for the confusion
It's just my OCD kicking in :-)
No need for a blank line (same for the functions below).
- @pdev: The platform device associated with the CMM instance
- @config: The CRTC-provided configuration.
- Configure the CMM unit with the CRTC-provided configuration.
- Currently enabling, disabling and programming of the 1-D LUT unit is
- supported.
- */
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config)
+{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- if (config->lut.size > CMM_GAMMA_LUT_SIZE)
return -EINVAL;
- /*
* As rcar_cmm_setup() is called by atomic commit tail helper, it might
* be called when the CMM is disabled. As we can't program the hardware
* in that case, store the configuration internally and apply it when
* the CMM will be enabled by the CRTC through rcar_cmm_enable().
*/
- if (!rcmm->enabled) {
if (!config->lut.enable)
return 0;
rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
rcmm->lut.enabled = true;
return 0;
- }
- /* Stop LUT operations if requested. */
- if (!config->lut.enable) {
if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
rcmm->lut.enabled = false;
rcmm->lut.size = 0;
}
return 0;
- }
- /*
* Enable LUT and program the new gamma table values.
*
* FIXME: In order to have stable operations it is required to first
* enable the 1D-LUT and then program its table entries. This seems to
* contradict what the chip manual reports, and will have to be
* reconsidered when implementing support for double buffering.
*/
- if (!rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcmm->lut.enabled = true;
- }
- rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
- rcar_cmm_lut_load(rcmm);
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_setup);
+/**
- rcar_cmm_enable() - enable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Enable the CMM unit by enabling the parent clock and enabling the CMM
- components, such as 1-D LUT, if requested.
- */
+int rcar_cmm_enable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- int ret;
- if (!rcmm)
return -EPROBE_DEFER;
This function is called in rcar_du_crtc_atomic_enable(), so that's not the right error code. It seems we need another function for the CMM API to defer probing :-/ I would call it rcar_cmm_init(). This check would then be removed.
I agree about the return code, but not the name, as this function actually enables the CMM.
I meant creating a new rcar_cmm_init() function that would just have the !rcmm check.
PROBE_DEFER does not make any sense here, I wonder where it come from, as the probing of CMM and DU has long happened once we get here (at least, I assume so, if we receive a gamma_table, userspace has already been running, and both DU and CMM should have probed. Otherwise, we can exploit the newly created device link, and make sure DU probes after the CMM).
I would just change the return value here, and possibly use the device link to ensure the correct probing sequence.
How does device link help here ?
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
return ret;
- /* Apply the LUT table values saved at rcar_cmm_setup() time. */
- if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcar_cmm_lut_load(rcmm);
You will not like this, but I just realised that we're now reprogramming the LUT contents every time the CMM is enabled. Do you think that's something we should optimise ? And yes, that would require introducing
Why so? If we receive an enable after a disable which stops the CMM clock and we have no guarantees the table entries have been kept, or what we receive from userspace has changed or not. Why is this an issue in your opinion?
I thought the hardware preserved the LUT ? Skipping the LUT write is an optimisation, so we could do without it in the initial version. I think it would become more important with the CLU though, as we'll have more data entries there. Maybe we should first check how much time the LUT and CLU writes take before deciding to optimise them.
back an update flag in rcmm->lut :-S Sorry for not realising this when I proposed dropping it.
- }
- rcmm->enabled = true;
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_enable);
+/**
- rcar_cmm_disable() - disable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Disable the CMM unit by stopping the parent clock.
- */
+void rcar_cmm_disable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
- pm_runtime_put(&pdev->dev);
- rcmm->lut.enabled = false;
- rcmm->lut.size = 0;
- rcmm->enabled = false;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_disable);
+static int rcar_cmm_probe(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm;
- struct resource *res;
- rcmm = devm_kzalloc(&pdev->dev, sizeof(*rcmm), GFP_KERNEL);
- if (!rcmm)
return -ENOMEM;
- platform_set_drvdata(pdev, rcmm);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rcmm->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rcmm->base))
return PTR_ERR(rcmm->base);
You really don't like combining those two calls, do you ? :-)
devm_of_iomap() ?
devm_platform_ioremap_resource()
- pm_runtime_enable(&pdev->dev);
- return 0;
+}
+static int rcar_cmm_remove(struct platform_device *pdev) +{
- pm_runtime_disable(&pdev->dev);
- return 0;
+}
+static const struct of_device_id rcar_cmm_of_table[] = {
- { .compatible = "renesas,cmm-r8a7795", },
- { .compatible = "renesas,cmm-r8a7796", },
- { .compatible = "renesas,cmm-r8a77965", },
- { .compatible = "renesas,cmm-r8a77990", },
- { .compatible = "renesas,cmm-r8a77995", },
As Geert pointed out, I would drop those entries.
yes
- { .compatible = "renesas,rcar-gen3-cmm", },
- { .compatible = "renesas,rcar-gen2-cmm", },
- { },
+}; +MODULE_DEVICE_TABLE(of, rcar_cmm_of_table);
+static struct platform_driver rcar_cmm_platform_driver = {
- .probe = rcar_cmm_probe,
- .remove = rcar_cmm_remove,
- .driver = {
.name = "rcar-cmm",
.of_match_table = rcar_cmm_of_table,
- },
+};
+module_platform_driver(rcar_cmm_platform_driver);
+MODULE_AUTHOR("Jacopo Mondi jacopo+renesas@jmondi.org"); +MODULE_DESCRIPTION("Renesas R-Car CMM Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/rcar-du/rcar_cmm.h new file mode 100644 index 000000000000..b0bb7349ebaa --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- rcar_cmm.h -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#ifndef __RCAR_CMM_H__ +#define __RCAR_CMM_H__
+#define CMM_GAMMA_LUT_SIZE 256
+struct drm_color_lut; +struct platform_device;
+/**
- struct rcar_cmm_config - CMM configuration
- @lut: 1D-LUT configuration
- @lut.enable: 1D-LUT enable flag
- @lut.table: 1D-LUT table entries
- @lut.size: Number of 1D-LUT (max 256)
s/1D-LUT/1D-LUT entries/
ack, I'll change this.
- */
+struct rcar_cmm_config {
- struct {
bool enable;
struct drm_color_lut *table;
unsigned int size;
- } lut;
+};
+int rcar_cmm_enable(struct platform_device *pdev); +void rcar_cmm_disable(struct platform_device *pdev);
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config);
+#endif /* __RCAR_CMM_H__ */
Hi Laurent,
On Tue, Aug 27, 2019 at 07:34:23PM +0300, Laurent Pinchart wrote:
Hi Laurent,
On Tue, Aug 27, 2019 at 04:56:19PM +0200, Jacopo Mondi wrote:
On Tue, Aug 27, 2019 at 03:24:22AM +0300, Laurent Pinchart wrote:
On Sun, Aug 25, 2019 at 03:51:48PM +0200, Jacopo Mondi wrote:
Add a driver for the R-Car Display Unit Color Correction Module.
In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++++ 4 files changed, 308 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 1529849e217e..539d232790d1 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -13,6 +13,13 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm.
+config DRM_RCAR_CMM
- bool "R-Car DU Color Management Module (CMM) Support"
- depends on DRM && OF
- depends on DRM_RCAR_DU
- help
Enable support for R-Car Color Management Module (CMM).
config DRM_RCAR_DW_HDMI tristate "R-Car DU Gen3 HDMI Encoder Support" depends on DRM && OF diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 6c2ed9c46467..4d1187ccc3e5 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -15,6 +15,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c new file mode 100644 index 000000000000..55361f5701e8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- rcar_cmm.c -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h>
+#include <drm/drm_color_mgmt.h>
+#include "rcar_cmm.h"
+#define CM2_LUT_CTRL 0x0000 +#define CM2_LUT_CTRL_LUT_EN BIT(0) +#define CM2_LUT_TBL_BASE 0x0600 +#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4)
+struct rcar_cmm {
- void __iomem *base;
- bool enabled;
- /*
* @lut: 1D-LUT status
* @lut.enabled: 1D-LUT enabled flag
* @lut.size: Number of entries in the LUT table
Please see my review of patch 13/14, I wonder if we could drop this field.
* @lut.table: Table of 1D-LUT entries scaled to HW support
* precision (8-bits per color component)
*/
- struct {
bool enabled;
unsigned int size;
u32 table[CMM_GAMMA_LUT_SIZE];
- } lut;
+};
+static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) +{
- return ioread32(rcmm->base + reg);
+}
+static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) +{
- iowrite32(data, rcmm->base + reg);
+}
+/*
- rcar_cmm_lut_extract() - Scale down to hw precision the DRM LUT table
s/hw/hardware/ (and below too)
entries and store them.
- @rcmm: Pointer to the CMM device
- @size: Number of entries in the table
- @drm_lut: DRM LUT table
- */
+static void rcar_cmm_lut_extract(struct rcar_cmm *rcmm, size_t size,
const struct drm_color_lut *drm_lut)
+{
- unsigned int i;
- for (i = 0; i < size; ++i) {
const struct drm_color_lut *lut = &drm_lut[i];
rcmm->lut.table[i] = drm_color_lut_extract(lut->red, 8) << 16
| drm_color_lut_extract(lut->green, 8) << 8
| drm_color_lut_extract(lut->blue, 8);
- }
- rcmm->lut.size = size;
+}
+/*
- rcar_cmm_lut_load() - Write to hw the LUT table entries from the local table.
No need for a blank line
- @rcmm: Pointer to the CMM device
- */
+static void rcar_cmm_lut_load(struct rcar_cmm *rcmm)
I would name this rcar_cmm_lut_write().
I won't, as I would like to convey the LUT tables is loaded from the local cache after it has been scaled down to the hardware supported precision.
"load" hints a read though, and here you write the LUT to the hardware. Without reading the comments I would have thought this function would read the LUT back from the hardware.
+{
- unsigned int i;
- for (i = 0; i < rcmm->lut.size; ++i) {
u32 entry = rcmm->lut.table[i];
rcar_cmm_write(rcmm, CM2_LUT_TBL(i), entry);
You don't need the local entry variable.
True, but the code is nicer to read and the compiler should be smart enough to optimize it away
I'm not sure about nicer to read, I find the opposite personally, but it's your code :-)
- }
+}
+/**
- rcar_cmm_setup() - configure the CMM unit
s/configure/Configure/ and s/$/./, or the other way around for the other functions (I don't mine which one, but let's stay consistent).
Oh right, sorry for the confusion
It's just my OCD kicking in :-)
No need for a blank line (same for the functions below).
- @pdev: The platform device associated with the CMM instance
- @config: The CRTC-provided configuration.
- Configure the CMM unit with the CRTC-provided configuration.
- Currently enabling, disabling and programming of the 1-D LUT unit is
- supported.
- */
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config)
+{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- if (config->lut.size > CMM_GAMMA_LUT_SIZE)
return -EINVAL;
- /*
* As rcar_cmm_setup() is called by atomic commit tail helper, it might
* be called when the CMM is disabled. As we can't program the hardware
* in that case, store the configuration internally and apply it when
* the CMM will be enabled by the CRTC through rcar_cmm_enable().
*/
- if (!rcmm->enabled) {
if (!config->lut.enable)
return 0;
rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
rcmm->lut.enabled = true;
return 0;
- }
- /* Stop LUT operations if requested. */
- if (!config->lut.enable) {
if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
rcmm->lut.enabled = false;
rcmm->lut.size = 0;
}
return 0;
- }
- /*
* Enable LUT and program the new gamma table values.
*
* FIXME: In order to have stable operations it is required to first
* enable the 1D-LUT and then program its table entries. This seems to
* contradict what the chip manual reports, and will have to be
* reconsidered when implementing support for double buffering.
*/
- if (!rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcmm->lut.enabled = true;
- }
- rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
- rcar_cmm_lut_load(rcmm);
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_setup);
+/**
- rcar_cmm_enable() - enable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Enable the CMM unit by enabling the parent clock and enabling the CMM
- components, such as 1-D LUT, if requested.
- */
+int rcar_cmm_enable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- int ret;
- if (!rcmm)
return -EPROBE_DEFER;
This function is called in rcar_du_crtc_atomic_enable(), so that's not the right error code. It seems we need another function for the CMM API to defer probing :-/ I would call it rcar_cmm_init(). This check would then be removed.
I agree about the return code, but not the name, as this function actually enables the CMM.
I meant creating a new rcar_cmm_init() function that would just have the !rcmm check.
PROBE_DEFER does not make any sense here, I wonder where it come from, as the probing of CMM and DU has long happened once we get here (at least, I assume so, if we receive a gamma_table, userspace has already been running, and both DU and CMM should have probed. Otherwise, we can exploit the newly created device link, and make sure DU probes after the CMM).
I would just change the return value here, and possibly use the device link to ensure the correct probing sequence.
How does device link help here ?
Currently it doesn't, as we are creating a stateless link.
But if we go for a managed device link (which is the default, by the way, you have to opt-out from it) we can guarantee the CMM has probed before the DU probes, so that we have a guarantee when we get here !rcmm cannot happen.
https://www.kernel.org/doc/html/v5.2-rc7/driver-api/device_link.html "The consumer devices are not probed before the supplier is bound to a driver, and they’re unbound before the supplier is unbound."
As we create the link, the CMM is the supplier of DU, so we could just drop the DL_FLAG_STATELESS flag in device_link_add() in 10/14.
Does this match your understanding ?
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
return ret;
- /* Apply the LUT table values saved at rcar_cmm_setup() time. */
- if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcar_cmm_lut_load(rcmm);
You will not like this, but I just realised that we're now reprogramming the LUT contents every time the CMM is enabled. Do you think that's something we should optimise ? And yes, that would require introducing
Why so? If we receive an enable after a disable which stops the CMM clock and we have no guarantees the table entries have been kept, or what we receive from userspace has changed or not. Why is this an issue in your opinion?
I thought the hardware preserved the LUT ? Skipping the LUT write is an optimisation, so we could do without it in the initial version. I think it would become more important with the CLU though, as we'll have more data entries there. Maybe we should first check how much time the LUT and CLU writes take before deciding to optimise them.
Yeah, let's post-pone optimizations...
back an update flag in rcmm->lut :-S Sorry for not realising this when I proposed dropping it.
- }
- rcmm->enabled = true;
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_enable);
+/**
- rcar_cmm_disable() - disable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Disable the CMM unit by stopping the parent clock.
- */
+void rcar_cmm_disable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
- pm_runtime_put(&pdev->dev);
- rcmm->lut.enabled = false;
- rcmm->lut.size = 0;
- rcmm->enabled = false;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_disable);
+static int rcar_cmm_probe(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm;
- struct resource *res;
- rcmm = devm_kzalloc(&pdev->dev, sizeof(*rcmm), GFP_KERNEL);
- if (!rcmm)
return -ENOMEM;
- platform_set_drvdata(pdev, rcmm);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rcmm->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rcmm->base))
return PTR_ERR(rcmm->base);
You really don't like combining those two calls, do you ? :-)
devm_of_iomap() ?
devm_platform_ioremap_resource()
Oh stupid, thanks!
Thanks j
- pm_runtime_enable(&pdev->dev);
- return 0;
+}
+static int rcar_cmm_remove(struct platform_device *pdev) +{
- pm_runtime_disable(&pdev->dev);
- return 0;
+}
+static const struct of_device_id rcar_cmm_of_table[] = {
- { .compatible = "renesas,cmm-r8a7795", },
- { .compatible = "renesas,cmm-r8a7796", },
- { .compatible = "renesas,cmm-r8a77965", },
- { .compatible = "renesas,cmm-r8a77990", },
- { .compatible = "renesas,cmm-r8a77995", },
As Geert pointed out, I would drop those entries.
yes
- { .compatible = "renesas,rcar-gen3-cmm", },
- { .compatible = "renesas,rcar-gen2-cmm", },
- { },
+}; +MODULE_DEVICE_TABLE(of, rcar_cmm_of_table);
+static struct platform_driver rcar_cmm_platform_driver = {
- .probe = rcar_cmm_probe,
- .remove = rcar_cmm_remove,
- .driver = {
.name = "rcar-cmm",
.of_match_table = rcar_cmm_of_table,
- },
+};
+module_platform_driver(rcar_cmm_platform_driver);
+MODULE_AUTHOR("Jacopo Mondi jacopo+renesas@jmondi.org"); +MODULE_DESCRIPTION("Renesas R-Car CMM Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/rcar-du/rcar_cmm.h new file mode 100644 index 000000000000..b0bb7349ebaa --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- rcar_cmm.h -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#ifndef __RCAR_CMM_H__ +#define __RCAR_CMM_H__
+#define CMM_GAMMA_LUT_SIZE 256
+struct drm_color_lut; +struct platform_device;
+/**
- struct rcar_cmm_config - CMM configuration
- @lut: 1D-LUT configuration
- @lut.enable: 1D-LUT enable flag
- @lut.table: 1D-LUT table entries
- @lut.size: Number of 1D-LUT (max 256)
s/1D-LUT/1D-LUT entries/
ack, I'll change this.
- */
+struct rcar_cmm_config {
- struct {
bool enable;
struct drm_color_lut *table;
unsigned int size;
- } lut;
+};
+int rcar_cmm_enable(struct platform_device *pdev); +void rcar_cmm_disable(struct platform_device *pdev);
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config);
+#endif /* __RCAR_CMM_H__ */
-- Regards,
Laurent Pinchart
Hi Jacopo,
On Thu, Sep 05, 2019 at 11:57:57AM +0200, Jacopo Mondi wrote:
On Tue, Aug 27, 2019 at 07:34:23PM +0300, Laurent Pinchart wrote:
On Tue, Aug 27, 2019 at 04:56:19PM +0200, Jacopo Mondi wrote:
On Tue, Aug 27, 2019 at 03:24:22AM +0300, Laurent Pinchart wrote:
On Sun, Aug 25, 2019 at 03:51:48PM +0200, Jacopo Mondi wrote:
Add a driver for the R-Car Display Unit Color Correction Module.
In most of Gen3 SoCs, each DU output channel is provided with a CMM unit to perform image enhancement and color correction.
Add support for CMM through a driver that supports configuration of the 1-dimensional LUT table. More advanced CMM feature will be implemented on top of this basic one.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_cmm.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_cmm.h | 38 +++++ 4 files changed, 308 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_cmm.h
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 1529849e217e..539d232790d1 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -13,6 +13,13 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm.
+config DRM_RCAR_CMM
- bool "R-Car DU Color Management Module (CMM) Support"
- depends on DRM && OF
- depends on DRM_RCAR_DU
- help
Enable support for R-Car Color Management Module (CMM).
config DRM_RCAR_DW_HDMI tristate "R-Car DU Gen3 HDMI Encoder Support" depends on DRM && OF diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 6c2ed9c46467..4d1187ccc3e5 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -15,6 +15,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.c b/drivers/gpu/drm/rcar-du/rcar_cmm.c new file mode 100644 index 000000000000..55361f5701e8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- rcar_cmm.c -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h>
+#include <drm/drm_color_mgmt.h>
+#include "rcar_cmm.h"
+#define CM2_LUT_CTRL 0x0000 +#define CM2_LUT_CTRL_LUT_EN BIT(0) +#define CM2_LUT_TBL_BASE 0x0600 +#define CM2_LUT_TBL(__i) (CM2_LUT_TBL_BASE + (__i) * 4)
+struct rcar_cmm {
- void __iomem *base;
- bool enabled;
- /*
* @lut: 1D-LUT status
* @lut.enabled: 1D-LUT enabled flag
* @lut.size: Number of entries in the LUT table
Please see my review of patch 13/14, I wonder if we could drop this field.
* @lut.table: Table of 1D-LUT entries scaled to HW support
* precision (8-bits per color component)
*/
- struct {
bool enabled;
unsigned int size;
u32 table[CMM_GAMMA_LUT_SIZE];
- } lut;
+};
+static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg) +{
- return ioread32(rcmm->base + reg);
+}
+static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data) +{
- iowrite32(data, rcmm->base + reg);
+}
+/*
- rcar_cmm_lut_extract() - Scale down to hw precision the DRM LUT table
s/hw/hardware/ (and below too)
entries and store them.
- @rcmm: Pointer to the CMM device
- @size: Number of entries in the table
- @drm_lut: DRM LUT table
- */
+static void rcar_cmm_lut_extract(struct rcar_cmm *rcmm, size_t size,
const struct drm_color_lut *drm_lut)
+{
- unsigned int i;
- for (i = 0; i < size; ++i) {
const struct drm_color_lut *lut = &drm_lut[i];
rcmm->lut.table[i] = drm_color_lut_extract(lut->red, 8) << 16
| drm_color_lut_extract(lut->green, 8) << 8
| drm_color_lut_extract(lut->blue, 8);
- }
- rcmm->lut.size = size;
+}
+/*
- rcar_cmm_lut_load() - Write to hw the LUT table entries from the local table.
No need for a blank line
- @rcmm: Pointer to the CMM device
- */
+static void rcar_cmm_lut_load(struct rcar_cmm *rcmm)
I would name this rcar_cmm_lut_write().
I won't, as I would like to convey the LUT tables is loaded from the local cache after it has been scaled down to the hardware supported precision.
"load" hints a read though, and here you write the LUT to the hardware. Without reading the comments I would have thought this function would read the LUT back from the hardware.
+{
- unsigned int i;
- for (i = 0; i < rcmm->lut.size; ++i) {
u32 entry = rcmm->lut.table[i];
rcar_cmm_write(rcmm, CM2_LUT_TBL(i), entry);
You don't need the local entry variable.
True, but the code is nicer to read and the compiler should be smart enough to optimize it away
I'm not sure about nicer to read, I find the opposite personally, but it's your code :-)
- }
+}
+/**
- rcar_cmm_setup() - configure the CMM unit
s/configure/Configure/ and s/$/./, or the other way around for the other functions (I don't mine which one, but let's stay consistent).
Oh right, sorry for the confusion
It's just my OCD kicking in :-)
No need for a blank line (same for the functions below).
- @pdev: The platform device associated with the CMM instance
- @config: The CRTC-provided configuration.
- Configure the CMM unit with the CRTC-provided configuration.
- Currently enabling, disabling and programming of the 1-D LUT unit is
- supported.
- */
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config)
+{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- if (config->lut.size > CMM_GAMMA_LUT_SIZE)
return -EINVAL;
- /*
* As rcar_cmm_setup() is called by atomic commit tail helper, it might
* be called when the CMM is disabled. As we can't program the hardware
* in that case, store the configuration internally and apply it when
* the CMM will be enabled by the CRTC through rcar_cmm_enable().
*/
- if (!rcmm->enabled) {
if (!config->lut.enable)
return 0;
rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
rcmm->lut.enabled = true;
return 0;
- }
- /* Stop LUT operations if requested. */
- if (!config->lut.enable) {
if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
rcmm->lut.enabled = false;
rcmm->lut.size = 0;
}
return 0;
- }
- /*
* Enable LUT and program the new gamma table values.
*
* FIXME: In order to have stable operations it is required to first
* enable the 1D-LUT and then program its table entries. This seems to
* contradict what the chip manual reports, and will have to be
* reconsidered when implementing support for double buffering.
*/
- if (!rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcmm->lut.enabled = true;
- }
- rcar_cmm_lut_extract(rcmm, config->lut.size, config->lut.table);
- rcar_cmm_lut_load(rcmm);
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_setup);
+/**
- rcar_cmm_enable() - enable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Enable the CMM unit by enabling the parent clock and enabling the CMM
- components, such as 1-D LUT, if requested.
- */
+int rcar_cmm_enable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- int ret;
- if (!rcmm)
return -EPROBE_DEFER;
This function is called in rcar_du_crtc_atomic_enable(), so that's not the right error code. It seems we need another function for the CMM API to defer probing :-/ I would call it rcar_cmm_init(). This check would then be removed.
I agree about the return code, but not the name, as this function actually enables the CMM.
I meant creating a new rcar_cmm_init() function that would just have the !rcmm check.
PROBE_DEFER does not make any sense here, I wonder where it come from, as the probing of CMM and DU has long happened once we get here (at least, I assume so, if we receive a gamma_table, userspace has already been running, and both DU and CMM should have probed. Otherwise, we can exploit the newly created device link, and make sure DU probes after the CMM).
I would just change the return value here, and possibly use the device link to ensure the correct probing sequence.
How does device link help here ?
Currently it doesn't, as we are creating a stateless link.
But if we go for a managed device link (which is the default, by the way, you have to opt-out from it) we can guarantee the CMM has probed before the DU probes, so that we have a guarantee when we get here !rcmm cannot happen.
https://www.kernel.org/doc/html/v5.2-rc7/driver-api/device_link.html "The consumer devices are not probed before the supplier is bound to a driver, and they’re unbound before the supplier is unbound."
As we create the link, the CMM is the supplier of DU, so we could just drop the DL_FLAG_STATELESS flag in device_link_add() in 10/14.
Does this match your understanding ?
Except there's a bit of a chicken and egg issue, as you call device_link_add() from rcar_du_cmm_init(), which thus require the DU driver to probe first :-) For this to work we would probably need an early initcall in the DU driver.
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
return ret;
- /* Apply the LUT table values saved at rcar_cmm_setup() time. */
- if (rcmm->lut.enabled) {
rcar_cmm_write(rcmm, CM2_LUT_CTRL, CM2_LUT_CTRL_LUT_EN);
rcar_cmm_lut_load(rcmm);
You will not like this, but I just realised that we're now reprogramming the LUT contents every time the CMM is enabled. Do you think that's something we should optimise ? And yes, that would require introducing
Why so? If we receive an enable after a disable which stops the CMM clock and we have no guarantees the table entries have been kept, or what we receive from userspace has changed or not. Why is this an issue in your opinion?
I thought the hardware preserved the LUT ? Skipping the LUT write is an optimisation, so we could do without it in the initial version. I think it would become more important with the CLU though, as we'll have more data entries there. Maybe we should first check how much time the LUT and CLU writes take before deciding to optimise them.
Yeah, let's post-pone optimizations...
back an update flag in rcmm->lut :-S Sorry for not realising this when I proposed dropping it.
- }
- rcmm->enabled = true;
- return 0;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_enable);
+/**
- rcar_cmm_disable() - disable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Disable the CMM unit by stopping the parent clock.
- */
+void rcar_cmm_disable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0);
- pm_runtime_put(&pdev->dev);
- rcmm->lut.enabled = false;
- rcmm->lut.size = 0;
- rcmm->enabled = false;
+} +EXPORT_SYMBOL_GPL(rcar_cmm_disable);
+static int rcar_cmm_probe(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm;
- struct resource *res;
- rcmm = devm_kzalloc(&pdev->dev, sizeof(*rcmm), GFP_KERNEL);
- if (!rcmm)
return -ENOMEM;
- platform_set_drvdata(pdev, rcmm);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rcmm->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rcmm->base))
return PTR_ERR(rcmm->base);
You really don't like combining those two calls, do you ? :-)
devm_of_iomap() ?
devm_platform_ioremap_resource()
Oh stupid, thanks!
- pm_runtime_enable(&pdev->dev);
- return 0;
+}
+static int rcar_cmm_remove(struct platform_device *pdev) +{
- pm_runtime_disable(&pdev->dev);
- return 0;
+}
+static const struct of_device_id rcar_cmm_of_table[] = {
- { .compatible = "renesas,cmm-r8a7795", },
- { .compatible = "renesas,cmm-r8a7796", },
- { .compatible = "renesas,cmm-r8a77965", },
- { .compatible = "renesas,cmm-r8a77990", },
- { .compatible = "renesas,cmm-r8a77995", },
As Geert pointed out, I would drop those entries.
yes
- { .compatible = "renesas,rcar-gen3-cmm", },
- { .compatible = "renesas,rcar-gen2-cmm", },
- { },
+}; +MODULE_DEVICE_TABLE(of, rcar_cmm_of_table);
+static struct platform_driver rcar_cmm_platform_driver = {
- .probe = rcar_cmm_probe,
- .remove = rcar_cmm_remove,
- .driver = {
.name = "rcar-cmm",
.of_match_table = rcar_cmm_of_table,
- },
+};
+module_platform_driver(rcar_cmm_platform_driver);
+MODULE_AUTHOR("Jacopo Mondi jacopo+renesas@jmondi.org"); +MODULE_DESCRIPTION("Renesas R-Car CMM Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rcar-du/rcar_cmm.h b/drivers/gpu/drm/rcar-du/rcar_cmm.h new file mode 100644 index 000000000000..b0bb7349ebaa --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_cmm.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- rcar_cmm.h -- R-Car Display Unit Color Management Module
- Copyright (C) 2019 Jacopo Mondi jacopo+renesas@jmondi.org
- */
+#ifndef __RCAR_CMM_H__ +#define __RCAR_CMM_H__
+#define CMM_GAMMA_LUT_SIZE 256
+struct drm_color_lut; +struct platform_device;
+/**
- struct rcar_cmm_config - CMM configuration
- @lut: 1D-LUT configuration
- @lut.enable: 1D-LUT enable flag
- @lut.table: 1D-LUT table entries
- @lut.size: Number of 1D-LUT (max 256)
s/1D-LUT/1D-LUT entries/
ack, I'll change this.
- */
+struct rcar_cmm_config {
- struct {
bool enable;
struct drm_color_lut *table;
unsigned int size;
- } lut;
+};
+int rcar_cmm_enable(struct platform_device *pdev); +void rcar_cmm_disable(struct platform_device *pdev);
+int rcar_cmm_setup(struct platform_device *pdev,
const struct rcar_cmm_config *config);
+#endif /* __RCAR_CMM_H__ */
Hi Laurent,
On Thu, Sep 05, 2019 at 02:17:12PM +0300, Laurent Pinchart wrote:
Hi Jacopo,
+/**
- rcar_cmm_enable() - enable the CMM unit
- @pdev: The platform device associated with the CMM instance
- Enable the CMM unit by enabling the parent clock and enabling the CMM
- components, such as 1-D LUT, if requested.
- */
+int rcar_cmm_enable(struct platform_device *pdev) +{
- struct rcar_cmm *rcmm = platform_get_drvdata(pdev);
- int ret;
- if (!rcmm)
return -EPROBE_DEFER;
This function is called in rcar_du_crtc_atomic_enable(), so that's not the right error code. It seems we need another function for the CMM API to defer probing :-/ I would call it rcar_cmm_init(). This check would then be removed.
I agree about the return code, but not the name, as this function actually enables the CMM.
I meant creating a new rcar_cmm_init() function that would just have the !rcmm check.
PROBE_DEFER does not make any sense here, I wonder where it come from, as the probing of CMM and DU has long happened once we get here (at least, I assume so, if we receive a gamma_table, userspace has already been running, and both DU and CMM should have probed. Otherwise, we can exploit the newly created device link, and make sure DU probes after the CMM).
I would just change the return value here, and possibly use the device link to ensure the correct probing sequence.
How does device link help here ?
Currently it doesn't, as we are creating a stateless link.
But if we go for a managed device link (which is the default, by the way, you have to opt-out from it) we can guarantee the CMM has probed before the DU probes, so that we have a guarantee when we get here !rcmm cannot happen.
https://www.kernel.org/doc/html/v5.2-rc7/driver-api/device_link.html "The consumer devices are not probed before the supplier is bound to a driver, and they’re unbound before the supplier is unbound."
As we create the link, the CMM is the supplier of DU, so we could just drop the DL_FLAG_STATELESS flag in device_link_add() in 10/14.
Does this match your understanding ?
Except there's a bit of a chicken and egg issue, as you call device_link_add() from rcar_du_cmm_init(), which thus require the DU driver to probe first :-) For this to work we would probably need an early initcall in the DU driver.
Yes indeed, the point where the link is created at the moment is too late... Is it worth an early initcall, or should we just assume that at the point where the LUT is operated userspace has already been running and both the CMM and the DU have probed already?
Hi Jacopo,
On Thu, Sep 05, 2019 at 03:14:53PM +0200, Jacopo Mondi wrote:
On Thu, Sep 05, 2019 at 02:17:12PM +0300, Laurent Pinchart wrote:
Hi Jacopo,
> +/** > + * rcar_cmm_enable() - enable the CMM unit > + * > + * @pdev: The platform device associated with the CMM instance > + * > + * Enable the CMM unit by enabling the parent clock and enabling the CMM > + * components, such as 1-D LUT, if requested. > + */ > +int rcar_cmm_enable(struct platform_device *pdev) > +{ > + struct rcar_cmm *rcmm = platform_get_drvdata(pdev); > + int ret; > + > + if (!rcmm) > + return -EPROBE_DEFER;
This function is called in rcar_du_crtc_atomic_enable(), so that's not the right error code. It seems we need another function for the CMM API to defer probing :-/ I would call it rcar_cmm_init(). This check would then be removed.
I agree about the return code, but not the name, as this function actually enables the CMM.
I meant creating a new rcar_cmm_init() function that would just have the !rcmm check.
PROBE_DEFER does not make any sense here, I wonder where it come from, as the probing of CMM and DU has long happened once we get here (at least, I assume so, if we receive a gamma_table, userspace has already been running, and both DU and CMM should have probed. Otherwise, we can exploit the newly created device link, and make sure DU probes after the CMM).
I would just change the return value here, and possibly use the device link to ensure the correct probing sequence.
How does device link help here ?
Currently it doesn't, as we are creating a stateless link.
But if we go for a managed device link (which is the default, by the way, you have to opt-out from it) we can guarantee the CMM has probed before the DU probes, so that we have a guarantee when we get here !rcmm cannot happen.
https://www.kernel.org/doc/html/v5.2-rc7/driver-api/device_link.html "The consumer devices are not probed before the supplier is bound to a driver, and they’re unbound before the supplier is unbound."
As we create the link, the CMM is the supplier of DU, so we could just drop the DL_FLAG_STATELESS flag in device_link_add() in 10/14.
Does this match your understanding ?
Except there's a bit of a chicken and egg issue, as you call device_link_add() from rcar_du_cmm_init(), which thus require the DU driver to probe first :-) For this to work we would probably need an early initcall in the DU driver.
Yes indeed, the point where the link is created at the moment is too late... Is it worth an early initcall, or should we just assume that at the point where the LUT is operated userspace has already been running and both the CMM and the DU have probed already?
We should at least guard against crashes, that's why I've proposed an init function in the CMM driver for the sole purpose of making sure the device has been probed, and deferring probe of the DU.
Add CMM to the list of supported features for Gen3 SoCs that provide it: - R8A7795 - R8A7796 - R8A77965 - R8A7799x
Leave R8A77970 out as V3M and V3H are the only Gen3 SoCs that do not support CMM.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 12 ++++++++---- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 6df37c2a9678..018480a8f35c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -276,7 +276,8 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = { .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, + | RCAR_DU_FEATURE_TVM_SYNC + | RCAR_DU_FEATURE_CMM, .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0), .routes = { /* @@ -309,7 +310,8 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = { .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, + | RCAR_DU_FEATURE_TVM_SYNC + | RCAR_DU_FEATURE_CMM, .channels_mask = BIT(2) | BIT(1) | BIT(0), .routes = { /* @@ -338,7 +340,8 @@ static const struct rcar_du_device_info rcar_du_r8a77965_info = { .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED - | RCAR_DU_FEATURE_TVM_SYNC, + | RCAR_DU_FEATURE_TVM_SYNC + | RCAR_DU_FEATURE_CMM, .channels_mask = BIT(3) | BIT(1) | BIT(0), .routes = { /* @@ -386,7 +389,8 @@ static const struct rcar_du_device_info rcar_du_r8a77970_info = { static const struct rcar_du_device_info rcar_du_r8a7799x_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_VSP1_SOURCE, + | RCAR_DU_FEATURE_VSP1_SOURCE + | RCAR_DU_FEATURE_CMM, .channels_mask = BIT(1) | BIT(0), .routes = { /* diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 1327cd0df90a..a00dccc447aa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -28,6 +28,7 @@ struct rcar_du_encoder; #define RCAR_DU_FEATURE_VSP1_SOURCE BIT(1) /* Has inputs from VSP1 */ #define RCAR_DU_FEATURE_INTERLACED BIT(2) /* HW supports interlaced */ #define RCAR_DU_FEATURE_TVM_SYNC BIT(3) /* Has TV switch/sync modes */ +#define RCAR_DU_FEATURE_CMM BIT(4) /* Has CMM */
#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */
Implement device tree parsing to collect the available CMM instances described by the 'cmms' property. Associate CMMs with CRTCs and store a mask of active CMMs in the DU group for later enablement.
Enforce the suspend/resume ordering of DU and CMM by creating a stateless device link between the two to make sure the CMM supplier device suspends after and resumes before the DU consumer.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 6 +++ drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_drv.h | 3 ++ drivers/gpu/drm/rcar-du/rcar_du_group.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_kms.c | 63 +++++++++++++++++++++++++ 5 files changed, 76 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 2da46e3dc4ae..23f1d6cc1719 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -1194,6 +1194,12 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, if (ret < 0) return ret;
+ /* CMM might be disabled for this CRTC. */ + if (rcdu->cmms[swindex]) { + rcrtc->cmm = rcdu->cmms[swindex]; + rgrp->cmms_mask |= BIT(hwindex % 2); + } + drm_crtc_helper_add(crtc, &crtc_helper_funcs);
/* Start with vertical blanking interrupt reporting disabled. */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 3b7fc668996f..5f2940c42225 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -39,6 +39,7 @@ struct rcar_du_vsp; * @vblank_wait: wait queue used to signal vertical blanking * @vblank_count: number of vertical blanking interrupts to wait for * @group: CRTC group this CRTC belongs to + * @cmm: CMM associated with this CRTC * @vsp: VSP feeding video to this CRTC * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC * @writeback: the writeback connector @@ -64,6 +65,7 @@ struct rcar_du_crtc { unsigned int vblank_count;
struct rcar_du_group *group; + struct platform_device *cmm; struct rcar_du_vsp *vsp; unsigned int vsp_pipe;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index a00dccc447aa..300ec60ba31b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/wait.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_group.h" #include "rcar_du_vsp.h" @@ -70,6 +71,7 @@ struct rcar_du_device_info {
#define RCAR_DU_MAX_CRTCS 4 #define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2) +#define RCAR_DU_MAX_CMMS 4 #define RCAR_DU_MAX_VSPS 4
struct rcar_du_device { @@ -86,6 +88,7 @@ struct rcar_du_device { struct rcar_du_encoder *encoders[RCAR_DU_OUTPUT_MAX];
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS]; + struct platform_device *cmms[RCAR_DU_MAX_CMMS]; struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS];
struct { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h index 87950c1f6a52..e9906609c635 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.h @@ -22,6 +22,7 @@ struct rcar_du_device; * @mmio_offset: registers offset in the device memory map * @index: group index * @channels_mask: bitmask of populated DU channels in this group + * @cmms_mask: bitmask of available CMMs in this group * @num_crtcs: number of CRTCs in this group (1 or 2) * @use_count: number of users of the group (rcar_du_group_(get|put)) * @used_crtcs: number of CRTCs currently in use @@ -37,6 +38,7 @@ struct rcar_du_group { unsigned int index;
unsigned int channels_mask; + unsigned int cmms_mask; unsigned int num_crtcs; unsigned int use_count; unsigned int used_crtcs; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 2dc9caee8767..61ca1d3c379a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -17,7 +17,9 @@ #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h>
+#include <linux/device.h> #include <linux/of_graph.h> +#include <linux/of_platform.h> #include <linux/wait.h>
#include "rcar_du_crtc.h" @@ -614,6 +616,62 @@ static int rcar_du_vsps_init(struct rcar_du_device *rcdu) return ret; }
+static int rcar_du_cmm_init(struct rcar_du_device *rcdu) +{ + const struct device_node *np = rcdu->dev->of_node; + unsigned int i; + int cells; + + cells = of_property_count_u32_elems(np, "cmms"); + if (cells == -EINVAL) + return 0; + + if (cells > RCAR_DU_MAX_CMMS || cells > rcdu->num_crtcs) { + dev_err(rcdu->dev, + "Invalid number of entries in 'cmms' property\n"); + return -EINVAL; + } + + for (i = 0; i < cells; ++i) { + struct platform_device *pdev; + struct device_link *link; + struct device_node *cmm; + + cmm = of_parse_phandle(np, "cmms", i); + if (IS_ERR(cmm)) { + dev_err(rcdu->dev, "Failed to parse 'cmms' property\n"); + return PTR_ERR(cmm); + } + + if (!of_device_is_available(cmm)) { + /* It's fine to have a phandle to a non-enabled CMM. */ + of_node_put(cmm); + continue; + } + + pdev = of_find_device_by_node(cmm); + if (IS_ERR(pdev)) { + dev_err(rcdu->dev, "No device found for CMM%u\n", i); + of_node_put(cmm); + return PTR_ERR(pdev); + } + + of_node_put(cmm); + + link = device_link_add(rcdu->dev, &pdev->dev, + DL_FLAG_STATELESS); + if (!link) { + dev_err(rcdu->dev, + "Failed to create device link to CMM%u\n", i); + return -EINVAL; + } + + rcdu->cmms[i] = pdev; + } + + return 0; +} + int rcar_du_modeset_init(struct rcar_du_device *rcdu) { static const unsigned int mmio_offsets[] = { @@ -704,6 +762,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) return ret; }
+ /* Initialize the Color Management Modules. */ + ret = rcar_du_cmm_init(rcdu); + if (ret) + return ret; + /* Create the CRTCs. */ for (swindex = 0, hwindex = 0; swindex < rcdu->num_crtcs; ++hwindex) { struct rcar_du_group *rgrp;
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:50PM +0200, Jacopo Mondi wrote:
Implement device tree parsing to collect the available CMM instances described by the 'cmms' property. Associate CMMs with CRTCs and store a mask of active CMMs in the DU group for later enablement.
Enforce the suspend/resume ordering of DU and CMM by creating a stateless device link between the two to make sure the CMM supplier device suspends after and resumes before the DU consumer.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 6 +++ drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_drv.h | 3 ++ drivers/gpu/drm/rcar-du/rcar_du_group.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_kms.c | 63 +++++++++++++++++++++++++ 5 files changed, 76 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 2da46e3dc4ae..23f1d6cc1719 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -1194,6 +1194,12 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, if (ret < 0) return ret;
/* CMM might be disabled for this CRTC. */
if (rcdu->cmms[swindex]) {
rcrtc->cmm = rcdu->cmms[swindex];
rgrp->cmms_mask |= BIT(hwindex % 2);
}
drm_crtc_helper_add(crtc, &crtc_helper_funcs);
/* Start with vertical blanking interrupt reporting disabled. */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 3b7fc668996f..5f2940c42225 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -39,6 +39,7 @@ struct rcar_du_vsp;
- @vblank_wait: wait queue used to signal vertical blanking
- @vblank_count: number of vertical blanking interrupts to wait for
- @group: CRTC group this CRTC belongs to
- @cmm: CMM associated with this CRTC
- @vsp: VSP feeding video to this CRTC
- @vsp_pipe: index of the VSP pipeline feeding video to this CRTC
- @writeback: the writeback connector
@@ -64,6 +65,7 @@ struct rcar_du_crtc { unsigned int vblank_count;
struct rcar_du_group *group;
- struct platform_device *cmm; struct rcar_du_vsp *vsp; unsigned int vsp_pipe;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index a00dccc447aa..300ec60ba31b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/wait.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_group.h" #include "rcar_du_vsp.h" @@ -70,6 +71,7 @@ struct rcar_du_device_info {
#define RCAR_DU_MAX_CRTCS 4 #define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2) +#define RCAR_DU_MAX_CMMS 4
Maybe alphabetically sorted ?
#define RCAR_DU_MAX_VSPS 4
struct rcar_du_device { @@ -86,6 +88,7 @@ struct rcar_du_device { struct rcar_du_encoder *encoders[RCAR_DU_OUTPUT_MAX];
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
- struct platform_device *cmms[RCAR_DU_MAX_CMMS];
As there's one CMM per CRTC, should we use RCAR_DU_MAX_CRTCS here ? It's not very useful to have two different macros that are required to have the same value :-)
struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS];
struct { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h index 87950c1f6a52..e9906609c635 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.h @@ -22,6 +22,7 @@ struct rcar_du_device;
- @mmio_offset: registers offset in the device memory map
- @index: group index
- @channels_mask: bitmask of populated DU channels in this group
- @cmms_mask: bitmask of available CMMs in this group
- @num_crtcs: number of CRTCs in this group (1 or 2)
- @use_count: number of users of the group (rcar_du_group_(get|put))
- @used_crtcs: number of CRTCs currently in use
@@ -37,6 +38,7 @@ struct rcar_du_group { unsigned int index;
unsigned int channels_mask;
- unsigned int cmms_mask; unsigned int num_crtcs; unsigned int use_count; unsigned int used_crtcs;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 2dc9caee8767..61ca1d3c379a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -17,7 +17,9 @@ #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h>
+#include <linux/device.h> #include <linux/of_graph.h> +#include <linux/of_platform.h> #include <linux/wait.h>
#include "rcar_du_crtc.h" @@ -614,6 +616,62 @@ static int rcar_du_vsps_init(struct rcar_du_device *rcdu) return ret; }
+static int rcar_du_cmm_init(struct rcar_du_device *rcdu) +{
- const struct device_node *np = rcdu->dev->of_node;
- unsigned int i;
- int cells;
- cells = of_property_count_u32_elems(np, "cmms");
- if (cells == -EINVAL)
return 0;
- if (cells > RCAR_DU_MAX_CMMS || cells > rcdu->num_crtcs) {
And if we remove RCAR_DU_MAX_CMMS as proposed above, I would just remove the first part of the condition, as rcdu->num_crtcs is guaranteed to be <= RCAR_DU_MAX_CRTCS.
With this addressed,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
dev_err(rcdu->dev,
"Invalid number of entries in 'cmms' property\n");
return -EINVAL;
- }
- for (i = 0; i < cells; ++i) {
struct platform_device *pdev;
struct device_link *link;
struct device_node *cmm;
cmm = of_parse_phandle(np, "cmms", i);
if (IS_ERR(cmm)) {
dev_err(rcdu->dev, "Failed to parse 'cmms' property\n");
return PTR_ERR(cmm);
}
if (!of_device_is_available(cmm)) {
/* It's fine to have a phandle to a non-enabled CMM. */
of_node_put(cmm);
continue;
}
pdev = of_find_device_by_node(cmm);
if (IS_ERR(pdev)) {
dev_err(rcdu->dev, "No device found for CMM%u\n", i);
of_node_put(cmm);
return PTR_ERR(pdev);
}
of_node_put(cmm);
link = device_link_add(rcdu->dev, &pdev->dev,
DL_FLAG_STATELESS);
if (!link) {
dev_err(rcdu->dev,
"Failed to create device link to CMM%u\n", i);
return -EINVAL;
}
rcdu->cmms[i] = pdev;
- }
- return 0;
+}
int rcar_du_modeset_init(struct rcar_du_device *rcdu) { static const unsigned int mmio_offsets[] = { @@ -704,6 +762,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) return ret; }
- /* Initialize the Color Management Modules. */
- ret = rcar_du_cmm_init(rcdu);
- if (ret)
return ret;
- /* Create the CRTCs. */ for (swindex = 0, hwindex = 0; swindex < rcdu->num_crtcs; ++hwindex) { struct rcar_du_group *rgrp;
Enable/disable the CMM associated with a CRTC at CRTC start and stop time and enable the CMM unit through the Display Extensional Functions register at group setup time.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 7 +++++++ drivers/gpu/drm/rcar-du/rcar_du_group.c | 8 ++++++++ drivers/gpu/drm/rcar-du/rcar_du_regs.h | 5 +++++ 3 files changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 23f1d6cc1719..3dac605c3a67 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -21,6 +21,7 @@ #include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_drv.h" #include "rcar_du_encoder.h" @@ -619,6 +620,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) rcar_du_vsp_disable(rcrtc);
+ if (rcrtc->cmm) + rcar_cmm_disable(rcrtc->cmm); + /* * Select switch sync mode. This stops display operation and configures * the HSYNC and VSYNC signals as inputs. @@ -686,6 +690,9 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, }
rcar_du_crtc_start(rcrtc); + + if (rcrtc->cmm) + rcar_cmm_enable(rcrtc->cmm); }
static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 9eee47969e77..25d0fc125d7a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -147,6 +147,14 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
rcar_du_group_setup_pins(rgrp);
+ if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) { + u32 defr7 = DEFR7_CODE + | (rgrp->cmms_mask & BIT(1) ? DEFR7_CMME1 : 0) + | (rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0); + + rcar_du_group_write(rgrp, DEFR7, defr7); + } + if (rcdu->info->gen >= 2) { rcar_du_group_setup_defr8(rgrp); rcar_du_group_setup_didsr(rgrp); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h index bc87f080b170..fb9964949368 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h @@ -197,6 +197,11 @@ #define DEFR6_MLOS1 (1 << 2) #define DEFR6_DEFAULT (DEFR6_CODE | DEFR6_TCNE1)
+#define DEFR7 0x000ec +#define DEFR7_CODE (0x7779 << 16) +#define DEFR7_CMME1 BIT(6) +#define DEFR7_CMME0 BIT(4) + /* ----------------------------------------------------------------------------- * R8A7790-only Control Registers */
Enable the GAMMA_LUT KMS property using the framework helpers to register the property and set the associated gamma table maximum size.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 3dac605c3a67..222ccc20d6d8 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -1082,6 +1082,7 @@ static const struct drm_crtc_funcs crtc_funcs_gen3 = { .set_crc_source = rcar_du_crtc_set_crc_source, .verify_crc_source = rcar_du_crtc_verify_crc_source, .get_crc_sources = rcar_du_crtc_get_crc_sources, + .gamma_set = drm_atomic_helper_legacy_gamma_set, };
/* ----------------------------------------------------------------------------- @@ -1205,6 +1206,9 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, if (rcdu->cmms[swindex]) { rcrtc->cmm = rcdu->cmms[swindex]; rgrp->cmms_mask |= BIT(hwindex % 2); + + drm_mode_crtc_set_gamma_size(crtc, CMM_GAMMA_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, CMM_GAMMA_LUT_SIZE); }
drm_crtc_helper_add(crtc, &crtc_helper_funcs);
Update CMM settings at in the atomic commit tail helper method.
The CMM is updated with new gamma values provided to the driver in the GAMMA_LUT blob property.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- drivers/gpu/drm/rcar-du/rcar_du_kms.c | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 61ca1d3c379a..047fdb982a11 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -22,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/wait.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_drv.h" #include "rcar_du_encoder.h" @@ -368,6 +369,37 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, * Atomic Check and Update */
+static void rcar_du_atomic_commit_update_cmm(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + struct rcar_cmm_config cmm_config = {}; + + if (!rcrtc->cmm || !crtc->state->color_mgmt_changed) + return; + + if (!crtc->state->gamma_lut) { + cmm_config.lut.enable = false; + rcar_cmm_setup(rcrtc->cmm, &cmm_config); + + return; + } + + cmm_config.lut.enable = true; + cmm_config.lut.table = (struct drm_color_lut *) + crtc->state->gamma_lut->data; + + /* Set LUT table size to 0 if entries should not be updated. */ + if (!old_state->gamma_lut || + old_state->gamma_lut->base.id != crtc->state->gamma_lut->base.id) + cmm_config.lut.size = crtc->state->gamma_lut->length + / sizeof(cmm_config.lut.table[0]); + else + cmm_config.lut.size = 0; + + rcar_cmm_setup(rcrtc->cmm, &cmm_config); +} + static int rcar_du_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -410,6 +442,9 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) rcdu->dpad1_source = rcrtc->index; }
+ for_each_old_crtc_in_state(old_state, crtc, crtc_state, i) + rcar_du_atomic_commit_update_cmm(crtc, crtc_state); + /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state,
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:53PM +0200, Jacopo Mondi wrote:
Update CMM settings at in the atomic commit tail helper method.
The CMM is updated with new gamma values provided to the driver in the GAMMA_LUT blob property.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_kms.c | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 61ca1d3c379a..047fdb982a11 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -22,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/wait.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_drv.h" #include "rcar_du_encoder.h" @@ -368,6 +369,37 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- Atomic Check and Update
*/
+static void rcar_du_atomic_commit_update_cmm(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
+{
- struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
- struct rcar_cmm_config cmm_config = {};
- if (!rcrtc->cmm || !crtc->state->color_mgmt_changed)
return;
- if (!crtc->state->gamma_lut) {
cmm_config.lut.enable = false;
rcar_cmm_setup(rcrtc->cmm, &cmm_config);
return;
- }
- cmm_config.lut.enable = true;
- cmm_config.lut.table = (struct drm_color_lut *)
crtc->state->gamma_lut->data;
- /* Set LUT table size to 0 if entries should not be updated. */
- if (!old_state->gamma_lut ||
old_state->gamma_lut->base.id != crtc->state->gamma_lut->base.id)
cmm_config.lut.size = crtc->state->gamma_lut->length
/ sizeof(cmm_config.lut.table[0]);
It has just occurred to me that the hardware only support LUTs of exactly 256 entries. Should we remove cmm_config.lut.size (simplifying the code in the CMM driver), and add a check to the CRTC .atomic_check() handler to reject invalid LUTs ? Sorry for not having caught this earlier.
- else
cmm_config.lut.size = 0;
- rcar_cmm_setup(rcrtc->cmm, &cmm_config);
+}
static int rcar_du_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -410,6 +442,9 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) rcdu->dpad1_source = rcrtc->index; }
- for_each_old_crtc_in_state(old_state, crtc, crtc_state, i)
rcar_du_atomic_commit_update_cmm(crtc, crtc_state);
- /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state,
On Tue, Aug 27, 2019 at 03:00:17AM +0300, Laurent Pinchart wrote:
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:53PM +0200, Jacopo Mondi wrote:
Update CMM settings at in the atomic commit tail helper method.
The CMM is updated with new gamma values provided to the driver in the GAMMA_LUT blob property.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_kms.c | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 61ca1d3c379a..047fdb982a11 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -22,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/wait.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_drv.h" #include "rcar_du_encoder.h" @@ -368,6 +369,37 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- Atomic Check and Update
*/
+static void rcar_du_atomic_commit_update_cmm(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
+{
- struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
- struct rcar_cmm_config cmm_config = {};
- if (!rcrtc->cmm || !crtc->state->color_mgmt_changed)
return;
- if (!crtc->state->gamma_lut) {
cmm_config.lut.enable = false;
rcar_cmm_setup(rcrtc->cmm, &cmm_config);
return;
- }
- cmm_config.lut.enable = true;
- cmm_config.lut.table = (struct drm_color_lut *)
crtc->state->gamma_lut->data;
- /* Set LUT table size to 0 if entries should not be updated. */
- if (!old_state->gamma_lut ||
old_state->gamma_lut->base.id != crtc->state->gamma_lut->base.id)
cmm_config.lut.size = crtc->state->gamma_lut->length
/ sizeof(cmm_config.lut.table[0]);
It has just occurred to me that the hardware only support LUTs of exactly 256 entries. Should we remove cmm_config.lut.size (simplifying the code in the CMM driver), and add a check to the CRTC .atomic_check() handler to reject invalid LUTs ? Sorry for not having caught this earlier.
Just an additional comment, if we drop the size field, then the cmm_config.lut.table pointer should be set to NULL when the LUT contents don't need to be updated.
- else
cmm_config.lut.size = 0;
- rcar_cmm_setup(rcrtc->cmm, &cmm_config);
+}
static int rcar_du_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -410,6 +442,9 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) rcdu->dpad1_source = rcrtc->index; }
- for_each_old_crtc_in_state(old_state, crtc, crtc_state, i)
rcar_du_atomic_commit_update_cmm(crtc, crtc_state);
- /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state,
-- Regards,
Laurent Pinchart
HI Laurent,
On Tue, Aug 27, 2019 at 03:19:27AM +0300, Laurent Pinchart wrote:
On Tue, Aug 27, 2019 at 03:00:17AM +0300, Laurent Pinchart wrote:
Hi Jacopo,
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:53PM +0200, Jacopo Mondi wrote:
Update CMM settings at in the atomic commit tail helper method.
The CMM is updated with new gamma values provided to the driver in the GAMMA_LUT blob property.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_kms.c | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 61ca1d3c379a..047fdb982a11 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -22,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/wait.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_drv.h" #include "rcar_du_encoder.h" @@ -368,6 +369,37 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- Atomic Check and Update
*/
+static void rcar_du_atomic_commit_update_cmm(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
+{
- struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
- struct rcar_cmm_config cmm_config = {};
- if (!rcrtc->cmm || !crtc->state->color_mgmt_changed)
return;
- if (!crtc->state->gamma_lut) {
cmm_config.lut.enable = false;
rcar_cmm_setup(rcrtc->cmm, &cmm_config);
return;
- }
- cmm_config.lut.enable = true;
- cmm_config.lut.table = (struct drm_color_lut *)
crtc->state->gamma_lut->data;
- /* Set LUT table size to 0 if entries should not be updated. */
- if (!old_state->gamma_lut ||
old_state->gamma_lut->base.id != crtc->state->gamma_lut->base.id)
cmm_config.lut.size = crtc->state->gamma_lut->length
/ sizeof(cmm_config.lut.table[0]);
It has just occurred to me that the hardware only support LUTs of
Where did you find this strict requirement ? I have tried programming less than 256 entries in the 1-D LUT table, and it seems to me things are working fine (from a visual inspection of the output image, I don't see much differences from when I program the full table, maybe that's an indication something is bad?)
Thanks j
exactly 256 entries. Should we remove cmm_config.lut.size (simplifying the code in the CMM driver), and add a check to the CRTC .atomic_check() handler to reject invalid LUTs ? Sorry for not having caught this earlier.
Just an additional comment, if we drop the size field, then the cmm_config.lut.table pointer should be set to NULL when the LUT contents don't need to be updated.
- else
cmm_config.lut.size = 0;
- rcar_cmm_setup(rcrtc->cmm, &cmm_config);
+}
static int rcar_du_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -410,6 +442,9 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) rcdu->dpad1_source = rcrtc->index; }
- for_each_old_crtc_in_state(old_state, crtc, crtc_state, i)
rcar_du_atomic_commit_update_cmm(crtc, crtc_state);
- /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state,
-- Regards,
Laurent Pinchart
-- Regards,
Laurent Pinchart
Hi Jacopo,
On Tue, Aug 27, 2019 at 04:44:21PM +0200, Jacopo Mondi wrote:
On Tue, Aug 27, 2019 at 03:19:27AM +0300, Laurent Pinchart wrote:
On Tue, Aug 27, 2019 at 03:00:17AM +0300, Laurent Pinchart wrote:
On Sun, Aug 25, 2019 at 03:51:53PM +0200, Jacopo Mondi wrote:
Update CMM settings at in the atomic commit tail helper method.
The CMM is updated with new gamma values provided to the driver in the GAMMA_LUT blob property.
Reviewed-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_kms.c | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 61ca1d3c379a..047fdb982a11 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -22,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/wait.h>
+#include "rcar_cmm.h" #include "rcar_du_crtc.h" #include "rcar_du_drv.h" #include "rcar_du_encoder.h" @@ -368,6 +369,37 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- Atomic Check and Update
*/
+static void rcar_du_atomic_commit_update_cmm(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
+{
- struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
- struct rcar_cmm_config cmm_config = {};
- if (!rcrtc->cmm || !crtc->state->color_mgmt_changed)
return;
- if (!crtc->state->gamma_lut) {
cmm_config.lut.enable = false;
rcar_cmm_setup(rcrtc->cmm, &cmm_config);
return;
- }
- cmm_config.lut.enable = true;
- cmm_config.lut.table = (struct drm_color_lut *)
crtc->state->gamma_lut->data;
- /* Set LUT table size to 0 if entries should not be updated. */
- if (!old_state->gamma_lut ||
old_state->gamma_lut->base.id != crtc->state->gamma_lut->base.id)
cmm_config.lut.size = crtc->state->gamma_lut->length
/ sizeof(cmm_config.lut.table[0]);
It has just occurred to me that the hardware only support LUTs of
Where did you find this strict requirement ? I have tried programming less than 256 entries in the 1-D LUT table, and it seems to me things are working fine (from a visual inspection of the output image, I don't see much differences from when I program the full table, maybe that's an indication something is bad?)
Or maybe a previous write of the full 256 entries has initialised the LUT correctly ?
There's no hardware register telling how many LUT entries the hardware should use, and the documentation makes it quite clear that the LUT contains 256 entries. It is indexed by the values of the 8-bit pixel components, so it has to be written fully.
exactly 256 entries. Should we remove cmm_config.lut.size (simplifying the code in the CMM driver), and add a check to the CRTC .atomic_check() handler to reject invalid LUTs ? Sorry for not having caught this earlier.
Just an additional comment, if we drop the size field, then the cmm_config.lut.table pointer should be set to NULL when the LUT contents don't need to be updated.
- else
cmm_config.lut.size = 0;
- rcar_cmm_setup(rcrtc->cmm, &cmm_config);
+}
static int rcar_du_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -410,6 +442,9 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) rcdu->dpad1_source = rcrtc->index; }
- for_each_old_crtc_in_state(old_state, crtc, crtc_state, i)
rcar_du_atomic_commit_update_cmm(crtc, crtc_state);
- /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state,
When resuming from system suspend, the DU driver is responsible for reprogramming and enabling the CMM unit if it was in use at the time the system entered the suspend state.
Force the color_mgmt_changed flag to true if any of the DRM color transformation properties was set in the CRTC state duplicated at suspend time, as the CMM gets reprogrammed only if said flag is active in the rcar_du_atomic_commit_update_cmm() method.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 018480a8f35c..6e38495fb78f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/wait.h>
+#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> @@ -482,6 +483,26 @@ static int rcar_du_pm_suspend(struct device *dev) static int rcar_du_pm_resume(struct device *dev) { struct rcar_du_device *rcdu = dev_get_drvdata(dev); + struct drm_atomic_state *state = rcdu->ddev->mode_config.suspend_state; + unsigned int i; + + for (i = 0; i < rcdu->num_crtcs; ++i) { + struct drm_crtc *crtc = &rcdu->crtcs[i].crtc; + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (!crtc_state) + continue; + + /* + * Force re-enablement of CMM after system resume if any + * of the DRM color transformation properties was set in + * the state saved at system suspend time. + */ + if (crtc_state->gamma_lut || crtc_state->degamma_lut || + crtc_state->ctm) + crtc_state->color_mgmt_changed = true; + }
return drm_mode_config_helper_resume(rcdu->ddev); }
Hi Jacopo,
(Question for Daniel below)
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:54PM +0200, Jacopo Mondi wrote:
When resuming from system suspend, the DU driver is responsible for reprogramming and enabling the CMM unit if it was in use at the time the system entered the suspend state.
Force the color_mgmt_changed flag to true if any of the DRM color transformation properties was set in the CRTC state duplicated at suspend time, as the CMM gets reprogrammed only if said flag is active in the rcar_du_atomic_commit_update_cmm() method.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_drv.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 018480a8f35c..6e38495fb78f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/wait.h>
+#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> @@ -482,6 +483,26 @@ static int rcar_du_pm_suspend(struct device *dev) static int rcar_du_pm_resume(struct device *dev) { struct rcar_du_device *rcdu = dev_get_drvdata(dev);
- struct drm_atomic_state *state = rcdu->ddev->mode_config.suspend_state;
- unsigned int i;
- for (i = 0; i < rcdu->num_crtcs; ++i) {
struct drm_crtc *crtc = &rcdu->crtcs[i].crtc;
struct drm_crtc_state *crtc_state;
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
if (!crtc_state)
continue;
Shouldn't you get the new state here ?
/*
* Force re-enablement of CMM after system resume if any
* of the DRM color transformation properties was set in
* the state saved at system suspend time.
*/
if (crtc_state->gamma_lut || crtc_state->degamma_lut ||
crtc_state->ctm)
We don't support degamma_lut or crm, so I would drop those.
With these small issues addressed,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
Shouldn't we however squash this with the previous patch to avoid bisection issues ?
crtc_state->color_mgmt_changed = true;
Daniel, is this something that would make sense in the KMS core (or helpers) ?
}
return drm_mode_config_helper_resume(rcdu->ddev);
}
Hi Laurent,
On Tue, Aug 27, 2019 at 03:05:17AM +0300, Laurent Pinchart wrote:
Hi Jacopo,
(Question for Daniel below)
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:54PM +0200, Jacopo Mondi wrote:
When resuming from system suspend, the DU driver is responsible for reprogramming and enabling the CMM unit if it was in use at the time the system entered the suspend state.
Force the color_mgmt_changed flag to true if any of the DRM color transformation properties was set in the CRTC state duplicated at suspend time, as the CMM gets reprogrammed only if said flag is active in the rcar_du_atomic_commit_update_cmm() method.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_drv.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 018480a8f35c..6e38495fb78f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/wait.h>
+#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> @@ -482,6 +483,26 @@ static int rcar_du_pm_suspend(struct device *dev) static int rcar_du_pm_resume(struct device *dev) { struct rcar_du_device *rcdu = dev_get_drvdata(dev);
- struct drm_atomic_state *state = rcdu->ddev->mode_config.suspend_state;
- unsigned int i;
- for (i = 0; i < rcdu->num_crtcs; ++i) {
struct drm_crtc *crtc = &rcdu->crtcs[i].crtc;
struct drm_crtc_state *crtc_state;
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
if (!crtc_state)
continue;
Shouldn't you get the new state here ?
I have followed the drm_atomic_helper_suspend() call stack, that calls drm_atomic_helper_duplicate_state() which then assign the crtct state with drm_atomic_get_crtc_state(), where I read:
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); ... state->crtcs[index].state = crtc_state; state->crtcs[index].old_state = crtc->state; state->crtcs[index].new_state = crtc_state;
So state or new_state for the purpose of getting back the crtc state are the same if I'm not mistaken.
/*
* Force re-enablement of CMM after system resume if any
* of the DRM color transformation properties was set in
* the state saved at system suspend time.
*/
if (crtc_state->gamma_lut || crtc_state->degamma_lut ||
crtc_state->ctm)
We don't support degamma_lut or crm, so I would drop those.
yeah, I added them as it was less code to change when we'll support them. But for now they could be removed.
With these small issues addressed,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
Shouldn't we however squash this with the previous patch to avoid bisection issues ?
Which one in your opinion? "drm: rcar-du: kms: Update CMM in atomic commit tail" ? It seems to me they do quite different things though..
Thanks j
crtc_state->color_mgmt_changed = true;
Daniel, is this something that would make sense in the KMS core (or helpers) ?
}
return drm_mode_config_helper_resume(rcdu->ddev);
}
-- Regards,
Laurent Pinchart
Hi Jacopo,
On Thu, Sep 05, 2019 at 12:58:09PM +0200, Jacopo Mondi wrote:
On Tue, Aug 27, 2019 at 03:05:17AM +0300, Laurent Pinchart wrote:
Hi Jacopo,
(Question for Daniel below)
Thank you for the patch.
On Sun, Aug 25, 2019 at 03:51:54PM +0200, Jacopo Mondi wrote:
When resuming from system suspend, the DU driver is responsible for reprogramming and enabling the CMM unit if it was in use at the time the system entered the suspend state.
Force the color_mgmt_changed flag to true if any of the DRM color transformation properties was set in the CRTC state duplicated at suspend time, as the CMM gets reprogrammed only if said flag is active in the rcar_du_atomic_commit_update_cmm() method.
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org
drivers/gpu/drm/rcar-du/rcar_du_drv.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 018480a8f35c..6e38495fb78f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/wait.h>
+#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> @@ -482,6 +483,26 @@ static int rcar_du_pm_suspend(struct device *dev) static int rcar_du_pm_resume(struct device *dev) { struct rcar_du_device *rcdu = dev_get_drvdata(dev);
- struct drm_atomic_state *state = rcdu->ddev->mode_config.suspend_state;
- unsigned int i;
- for (i = 0; i < rcdu->num_crtcs; ++i) {
struct drm_crtc *crtc = &rcdu->crtcs[i].crtc;
struct drm_crtc_state *crtc_state;
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
if (!crtc_state)
continue;
Shouldn't you get the new state here ?
I have followed the drm_atomic_helper_suspend() call stack, that calls drm_atomic_helper_duplicate_state() which then assign the crtct state with drm_atomic_get_crtc_state(), where I read:
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); ...
state->crtcs[index].state = crtc_state; state->crtcs[index].old_state = crtc->state; state->crtcs[index].new_state = crtc_state;
So state or new_state for the purpose of getting back the crtc state are the same if I'm not mistaken.
It seems to be the case, but the documentation of drm_atomic_get_existing_crtc_state() states
* This function is deprecated, @drm_atomic_get_old_crtc_state or * @drm_atomic_get_new_crtc_state should be used instead.
I would thus use drm_atomic_get_new_crtc_state().
/*
* Force re-enablement of CMM after system resume if any
* of the DRM color transformation properties was set in
* the state saved at system suspend time.
*/
if (crtc_state->gamma_lut || crtc_state->degamma_lut ||
crtc_state->ctm)
We don't support degamma_lut or crm, so I would drop those.
yeah, I added them as it was less code to change when we'll support them. But for now they could be removed.
With these small issues addressed,
Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
Shouldn't we however squash this with the previous patch to avoid bisection issues ?
Which one in your opinion? "drm: rcar-du: kms: Update CMM in atomic commit tail" ? It seems to me they do quite different things though..
Yes, but suspend/resume will be broken after 13/14 without 14/14. Not the end of the world, but not really nice if we need to bisect suspend/resume issues.
crtc_state->color_mgmt_changed = true;
Daniel, is this something that would make sense in the KMS core (or helpers) ?
}
return drm_mode_config_helper_resume(rcdu->ddev);
}
dri-devel@lists.freedesktop.org