Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH 1/4] dt-bindings: display/msm: sm8150-mdss: add DP node
From: Krzysztof Kozlowski @ 2024-03-27 10:11 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Vinod Koul, linux-arm-msm,
	dri-devel, freedreno, devicetree
In-Reply-To: <CAA8EJprg55BkRL5KUZ+6gNniq9TZjEem8MLqQdMZcXntvttEVg@mail.gmail.com>

On 27/03/2024 09:52, Dmitry Baryshkov wrote:
> On Wed, 27 Mar 2024 at 10:45, Krzysztof Kozlowski
> <krzysztof.kozlowski@linaro.org> wrote:
>>
>> On 26/03/2024 21:02, Dmitry Baryshkov wrote:
>>> diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
>>> index c0d6a4fdff97..40b077fb20aa 100644
>>> --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
>>> +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
>>> @@ -53,6 +53,16 @@ patternProperties:
>>>        compatible:
>>>          const: qcom,sm8150-dpu
>>>
>>> +  "^displayport-controller@[0-9a-f]+$":
>>> +    type: object
>>> +    additionalProperties: true
>>> +
>>> +    properties:
>>> +      compatible:
>>> +        items:
>>> +          - const: qcom,sm8150-dp
>>> +          - const: qcom,sm8350-dp
>>
>> This does not look right. sm8350 has its own mdss binding file.
> 
> So just a single entry here, even though SM8150 uses fallback compat string?

Ah, wait, I misread, I thought it is enum.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v2 2/3] dt-bindings: power: Add mediatek larb definition
From: Krzysztof Kozlowski @ 2024-03-27 10:10 UTC (permalink / raw)
  To: Yu-chang Lee (李禹璋),
	MandyJH Liu (劉人僖), conor+dt@kernel.org,
	robh@kernel.org, krzysztof.kozlowski+dt@linaro.org,
	matthias.bgg@gmail.com, ulf.hansson@linaro.org,
	angelogioacchino.delregno@collabora.com
  Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group,
	Xiufeng Li (李秀峰),
	linux-arm-kernel@lists.infradead.org, Fan Chen (陳凡)
In-Reply-To: <f25b4d913a584d753888e7a3c32502eae1f7fbf0.camel@mediatek.com>

On 27/03/2024 11:01, Yu-chang Lee (李禹璋) wrote:
> On Wed, 2024-03-27 at 09:39 +0100, Krzysztof Kozlowski wrote:
>>  	 
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>  On 27/03/2024 06:57, yu-chang.lee wrote:
>>> Add Smart Multimedia Interface Local Arbiter to mediatek
>>> power domain.
>>>
>>> Signed-off-by: yu-chang.lee <yu-chang.lee@mediatek.com>
>>> ---
>>>  .../devicetree/bindings/power/mediatek,power-controller.yaml  | 4
>> ++++
>>>  1 file changed, 4 insertions(+)
>>>
>>> diff --git
>> a/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>> b/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>>> index 8985e2df8a56..228c0dec5253 100644
>>> --- a/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>>> +++ b/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>>> @@ -125,6 +125,10 @@ $defs:
>>>          $ref: /schemas/types.yaml#/definitions/phandle
>>>          description: phandle to the device containing the SMI
>> register range.
>>>  
>>> +     mediatek,larb:
>>> +        $ref: /schemas/types.yaml#/definitions/phandle
>>> +        description: phandle to the device containing the LARB
>> register range.
>>
>> Why do you need it?
>>
>> Plus I also see mediatek,larbs and mediatek,larb-id... so now we have
>> third one similar.
>>
> MM driver used "mediatek,larbs" for it larb node.
> Power domain driver used "mediatek,larb".
> "mediatek,larb-id" is for larb in dts.
> 
> The naming is no related to each other.

Then it is just confusing.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v2 2/3] dt-bindings: power: Add mediatek larb definition
From: Yu-chang Lee (李禹璋) @ 2024-03-27 10:01 UTC (permalink / raw)
  To: krzysztof.kozlowski@linaro.org,
	MandyJH Liu (劉人僖), conor+dt@kernel.org,
	robh@kernel.org, krzysztof.kozlowski+dt@linaro.org,
	matthias.bgg@gmail.com, ulf.hansson@linaro.org,
	angelogioacchino.delregno@collabora.com
  Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group,
	Xiufeng Li (李秀峰),
	linux-arm-kernel@lists.infradead.org, Fan Chen (陳凡)
In-Reply-To: <6dd9959e-f741-47af-b10a-1894f72ae78f@linaro.org>

On Wed, 2024-03-27 at 09:39 +0100, Krzysztof Kozlowski wrote:
>  	 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>  On 27/03/2024 06:57, yu-chang.lee wrote:
> > Add Smart Multimedia Interface Local Arbiter to mediatek
> > power domain.
> > 
> > Signed-off-by: yu-chang.lee <yu-chang.lee@mediatek.com>
> > ---
> >  .../devicetree/bindings/power/mediatek,power-controller.yaml  | 4
> ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git
> a/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> b/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> > index 8985e2df8a56..228c0dec5253 100644
> > --- a/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> > +++ b/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> > @@ -125,6 +125,10 @@ $defs:
> >          $ref: /schemas/types.yaml#/definitions/phandle
> >          description: phandle to the device containing the SMI
> register range.
> >  
> > +     mediatek,larb:
> > +        $ref: /schemas/types.yaml#/definitions/phandle
> > +        description: phandle to the device containing the LARB
> register range.
> 
> Why do you need it?
> 
> Plus I also see mediatek,larbs and mediatek,larb-id... so now we have
> third one similar.
> 
MM driver used "mediatek,larbs" for it larb node.
Power domain driver used "mediatek,larb".
"mediatek,larb-id" is for larb in dts.

The naming is no related to each other.

Best Regards,
Yu-chang.

> Best regards,
> Krzysztof
> 

^ permalink raw reply

* Re: [PATCH v2 2/3] dt-bindings: power: Add mediatek larb definition
From: Krzysztof Kozlowski @ 2024-03-27  9:59 UTC (permalink / raw)
  To: Yu-chang Lee (李禹璋),
	MandyJH Liu (劉人僖), conor+dt@kernel.org,
	robh@kernel.org, krzysztof.kozlowski+dt@linaro.org,
	matthias.bgg@gmail.com, ulf.hansson@linaro.org,
	angelogioacchino.delregno@collabora.com
  Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group,
	Xiufeng Li (李秀峰),
	linux-arm-kernel@lists.infradead.org, Fan Chen (陳凡)
In-Reply-To: <f3eedfb3495bb9c28b5cbf466387c24822c5b6f6.camel@mediatek.com>

On 27/03/2024 10:34, Yu-chang Lee (李禹璋) wrote:
> On Wed, 2024-03-27 at 10:23 +0100, Krzysztof Kozlowski wrote:
>>  	 
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>  On 27/03/2024 09:39, Krzysztof Kozlowski wrote:
>>> On 27/03/2024 06:57, yu-chang.lee wrote:
>>>> Add Smart Multimedia Interface Local Arbiter to mediatek
>>>> power domain.
>>>>
>>>> Signed-off-by: yu-chang.lee <yu-chang.lee@mediatek.com>
>>>> ---
>>>>  .../devicetree/bindings/power/mediatek,power-controller.yaml  | 4
>> ++++
>>>>  1 file changed, 4 insertions(+)
>>>>
>>>> diff --git
>> a/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>> b/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>>>> index 8985e2df8a56..228c0dec5253 100644
>>>> --- a/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>>>> +++ b/Documentation/devicetree/bindings/power/mediatek,power-
>> controller.yaml
>>>> @@ -125,6 +125,10 @@ $defs:
>>>>          $ref: /schemas/types.yaml#/definitions/phandle
>>>>          description: phandle to the device containing the SMI
>> register range.
>>>>  
>>>> +     mediatek,larb:
>>>> +        $ref: /schemas/types.yaml#/definitions/phandle
>>>> +        description: phandle to the device containing the LARB
>> register range.
>>>
>>> Why do you need it?
>>>
>>> Plus I also see mediatek,larbs and mediatek,larb-id... so now we
>> have
>>> third one similar.
>>
>> ... and not even tested!
>>
>> Best regards,
>> Krzysztof
>>
> Hi,
> 
> I will double check the format of yaml for the next version, sorry for
> inconvenience. But I did test it on mt8188 chromebook, the reason why

How do you test a binding on chromebook?

> power domain need larb node is that when mtcmos power on, signal glitch
> may produce. Power domain driver must reset larb when this happen to 
> prevent dummy transaction on bus. That why I need larb node in dts.

No one talks here about larb node...

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH] media: dt-bindings: ovti,ov2680: Document clock/data-lanes
From: Sakari Ailus @ 2024-03-27  9:57 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: rmfrfs, robh, krzysztof.kozlowski+dt, conor+dt, linux-media,
	devicetree, Fabio Estevam
In-Reply-To: <20240326231033.2048193-1-festevam@gmail.com>

Hi Fabio,

On Tue, Mar 26, 2024 at 08:10:33PM -0300, Fabio Estevam wrote:
> From: Fabio Estevam <festevam@denx.de>
> 
> OV2680 has a single data lane MIPI interface.
> 
> Document the clock-lanes and data-lanes properties to avoid
> the following dt-schema warning:
> 
> imx7s-warp.dtb: camera@36: port:endpoint: Unevaluated properties are not allowed ('clock-lanes', 'data-lanes' were unexpected)
> 	from schema $id: http://devicetree.org/schemas/media/i2c/ovti,ov2680.yaml#
> 
> Signed-off-by: Fabio Estevam <festevam@denx.de>
> ---
>  .../bindings/media/i2c/ovti,ov2680.yaml       | 19 +++++++++++++++++--
>  1 file changed, 17 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml
> index cf456f8d9ddc..ae104da067e9 100644
> --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml
> +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml
> @@ -50,9 +50,22 @@ properties:
>        Definition of the regulator used as digital power supply.
>  
>    port:
> -    $ref: /schemas/graph.yaml#/properties/port
>      description:
>        A node containing an output port node.
> +    $ref: /schemas/graph.yaml#/$defs/port-base
> +    additionalProperties: false
> +
> +    properties:
> +      endpoint:
> +        $ref: /schemas/media/video-interfaces.yaml#
> +        unevaluatedProperties: false
> +
> +        properties:
> +          clock-lanes:
> +            const: 0
> +
> +          data-lanes:
> +            const: 1

If there's a single possible configuration only, is this needed? There's no
information here which the driver would need.

>  
>  required:
>    - compatible
> @@ -65,7 +78,7 @@ required:
>    - reset-gpios
>    - port
>  
> -additionalProperties: false
> +unevaluatedProperties: false
>  
>  examples:
>    - |
> @@ -89,6 +102,8 @@ examples:
>                  port {
>                          ov2680_to_mipi: endpoint {
>                                  remote-endpoint = <&mipi_from_sensor>;
> +                                clock-lanes = <0>;
> +                                data-lanes = <1>;
>                          };
>                  };
>          };

-- 
Regards,

Sakari Ailus

^ permalink raw reply

* Re: [PATCH v2 2/3] dt-bindings: power: Add mediatek larb definition
From: Yu-chang Lee (李禹璋) @ 2024-03-27  9:34 UTC (permalink / raw)
  To: krzysztof.kozlowski@linaro.org,
	MandyJH Liu (劉人僖), conor+dt@kernel.org,
	robh@kernel.org, krzysztof.kozlowski+dt@linaro.org,
	matthias.bgg@gmail.com, ulf.hansson@linaro.org,
	angelogioacchino.delregno@collabora.com
  Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group,
	Xiufeng Li (李秀峰),
	linux-arm-kernel@lists.infradead.org, Fan Chen (陳凡)
In-Reply-To: <c3ca3d90-898e-44b0-ad0f-dd78c09c5fcd@linaro.org>

On Wed, 2024-03-27 at 10:23 +0100, Krzysztof Kozlowski wrote:
>  	 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>  On 27/03/2024 09:39, Krzysztof Kozlowski wrote:
> > On 27/03/2024 06:57, yu-chang.lee wrote:
> >> Add Smart Multimedia Interface Local Arbiter to mediatek
> >> power domain.
> >>
> >> Signed-off-by: yu-chang.lee <yu-chang.lee@mediatek.com>
> >> ---
> >>  .../devicetree/bindings/power/mediatek,power-controller.yaml  | 4
> ++++
> >>  1 file changed, 4 insertions(+)
> >>
> >> diff --git
> a/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> b/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> >> index 8985e2df8a56..228c0dec5253 100644
> >> --- a/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> >> +++ b/Documentation/devicetree/bindings/power/mediatek,power-
> controller.yaml
> >> @@ -125,6 +125,10 @@ $defs:
> >>          $ref: /schemas/types.yaml#/definitions/phandle
> >>          description: phandle to the device containing the SMI
> register range.
> >>  
> >> +     mediatek,larb:
> >> +        $ref: /schemas/types.yaml#/definitions/phandle
> >> +        description: phandle to the device containing the LARB
> register range.
> > 
> > Why do you need it?
> > 
> > Plus I also see mediatek,larbs and mediatek,larb-id... so now we
> have
> > third one similar.
> 
> ... and not even tested!
> 
> Best regards,
> Krzysztof
> 
Hi,

I will double check the format of yaml for the next version, sorry for
inconvenience. But I did test it on mt8188 chromebook, the reason why
power domain need larb node is that when mtcmos power on, signal glitch
may produce. Power domain driver must reset larb when this happen to 
prevent dummy transaction on bus. That why I need larb node in dts.

Best Regards,
Yu-chang

^ permalink raw reply

* Re: [PATCH RESEND v6 0/5] spmi: pmic-arb: Add support for multiple buses
From: Krzysztof Kozlowski @ 2024-03-27  9:23 UTC (permalink / raw)
  To: Abel Vesa, Stephen Boyd, Matthias Brugger, Bjorn Andersson,
	Konrad Dybcio, Dmitry Baryshkov, Neil Armstrong,
	AngeloGioacchino Del Regno, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: Srini Kandagatla, Johan Hovold, linux-kernel, linux-arm-kernel,
	linux-arm-msm, linux-mediatek, devicetree
In-Reply-To: <20240326-spmi-multi-master-support-v6-0-1c87d8306c5b@linaro.org>

On 26/03/2024 17:28, Abel Vesa wrote:
> This RFC prepares for and adds support for 2 buses, which is supported
> in HW starting with version 7. Until now, none of the currently
> supported platforms in upstream have used the second bus. The X1E80100
> platform, on the other hand, needs the second bus for the USB2.0 to work
> as there are 3 SMB2360 PMICs which provide eUSB2 repeaters and they are
> all found on the second bus.
> 
> Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
> ---
> Changes in v6:
> - Changed the compatible to platform specific (X1E80100) along with the
>   schema. Fixed the spmi buses unit addresses and added the empty ranges

Why resending after few days? And why without reviews?

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v2 2/3] dt-bindings: power: Add mediatek larb definition
From: Krzysztof Kozlowski @ 2024-03-27  9:23 UTC (permalink / raw)
  To: yu-chang.lee, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Ulf Hansson, Matthias Brugger, AngeloGioacchino Del Regno,
	MandyJH Liu
  Cc: devicetree, linux-kernel, linux-pm, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, fan.chen,
	xiufeng.li
In-Reply-To: <6dd9959e-f741-47af-b10a-1894f72ae78f@linaro.org>

On 27/03/2024 09:39, Krzysztof Kozlowski wrote:
> On 27/03/2024 06:57, yu-chang.lee wrote:
>> Add Smart Multimedia Interface Local Arbiter to mediatek
>> power domain.
>>
>> Signed-off-by: yu-chang.lee <yu-chang.lee@mediatek.com>
>> ---
>>  .../devicetree/bindings/power/mediatek,power-controller.yaml  | 4 ++++
>>  1 file changed, 4 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>> index 8985e2df8a56..228c0dec5253 100644
>> --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>> +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>> @@ -125,6 +125,10 @@ $defs:
>>          $ref: /schemas/types.yaml#/definitions/phandle
>>          description: phandle to the device containing the SMI register range.
>>  
>> +     mediatek,larb:
>> +        $ref: /schemas/types.yaml#/definitions/phandle
>> +        description: phandle to the device containing the LARB register range.
> 
> Why do you need it?
> 
> Plus I also see mediatek,larbs and mediatek,larb-id... so now we have
> third one similar.

... and not even tested!

Best regards,
Krzysztof


^ permalink raw reply

* Re: [RFC PATCH 1/1] dt-bindings: display/msm: gpu: Split Adreno schemas into separate files
From: Krzysztof Kozlowski @ 2024-03-27  9:20 UTC (permalink / raw)
  To: Adam Skladowski
  Cc: phone-devel, ~postmarketos/upstreaming, Rob Clark, Abhinav Kumar,
	Dmitry Baryshkov, Sean Paul, Marijn Suijten, David Airlie,
	Daniel Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel
In-Reply-To: <20240326201140.10561-2-a39.skl@gmail.com>

On 26/03/2024 21:05, Adam Skladowski wrote:
> Split shared schema into per-gen and group adrenos by clocks used.
> 
> Signed-off-by: Adam Skladowski <a39.skl@gmail.com>
> ---
>  .../devicetree/bindings/display/msm/gpu.yaml  | 317 ++----------------
>  .../bindings/display/msm/qcom,adreno-306.yaml | 115 +++++++
>  .../bindings/display/msm/qcom,adreno-330.yaml | 111 ++++++
>  .../bindings/display/msm/qcom,adreno-405.yaml | 135 ++++++++
>  .../bindings/display/msm/qcom,adreno-506.yaml | 184 ++++++++++
>  .../bindings/display/msm/qcom,adreno-530.yaml | 161 +++++++++
>  .../bindings/display/msm/qcom,adreno-540.yaml | 154 +++++++++
>  .../bindings/display/msm/qcom,adreno-6xx.yaml | 160 +++++++++
>  .../display/msm/qcom,adreno-common.yaml       | 112 +++++++
>  9 files changed, 1157 insertions(+), 292 deletions(-)

One huge patch of 1150 insertions... please split it, e.g. first move
the common parts to common schema and include it in msm/gpu. Then move
device by device.

>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-306.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-330.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-405.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-506.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-530.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-540.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-6xx.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-common.yaml
> 


Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v2 2/3] dt-bindings: power: Add mediatek larb definition
From: Rob Herring @ 2024-03-27  9:01 UTC (permalink / raw)
  To: yu-chang.lee
  Cc: Matthias Brugger, MandyJH Liu, xiufeng.li, linux-kernel,
	devicetree, AngeloGioacchino Del Regno, linux-mediatek,
	Ulf Hansson, Project_Global_Chrome_Upstream_Group, fan.chen,
	linux-pm, Conor Dooley, linux-arm-kernel, Krzysztof Kozlowski
In-Reply-To: <20240327055732.28198-3-yu-chang.lee@mediatek.com>


On Wed, 27 Mar 2024 13:57:31 +0800, yu-chang.lee wrote:
> Add Smart Multimedia Interface Local Arbiter to mediatek
> power domain.
> 
> Signed-off-by: yu-chang.lee <yu-chang.lee@mediatek.com>
> ---
>  .../devicetree/bindings/power/mediatek,power-controller.yaml  | 4 ++++
>  1 file changed, 4 insertions(+)
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/power/mediatek,power-controller.yaml:128:6: [error] syntax error: expected <block end>, but found '<block mapping start>' (syntax)
./Documentation/devicetree/bindings/power/mediatek,power-controller.yaml:129:9: [warning] wrong indentation: expected 7 but found 8 (indentation)

dtschema/dtc warnings/errors:
make[2]: *** Deleting file 'Documentation/devicetree/bindings/power/mediatek,power-controller.example.dts'
Documentation/devicetree/bindings/power/mediatek,power-controller.yaml:128:6: did not find expected key
make[2]: *** [Documentation/devicetree/bindings/Makefile:26: Documentation/devicetree/bindings/power/mediatek,power-controller.example.dts] Error 1
make[2]: *** Waiting for unfinished jobs....
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml:
while parsing a block mapping
  in "<unicode string>", line 64, column 5
did not find expected key
  in "<unicode string>", line 128, column 6
./Documentation/devicetree/bindings/power/mediatek,power-controller.yaml:128:6: did not find expected key
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml: ignoring, error parsing file
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1430: dt_binding_check] Error 2
make: *** [Makefile:240: __sub-make] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20240327055732.28198-3-yu-chang.lee@mediatek.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* [PATCH v2] dt-bindings: display: bridge: it6505: Add #sound-dai-cells
From: Chen-Yu Tsai @ 2024-03-27  8:52 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Chen-Yu Tsai, David Airlie, Daniel Vetter, dri-devel, devicetree,
	linux-kernel

The ITE IT6505 display bridge can take one I2S input and transmit it
over the DisplayPort link.

Add #sound-dai-cells (= 0) to the binding for it.

Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v1 [1]:
- Reference /schemas/sound/dai-common.yaml
- Change "additionalProperties: false" to "unevaluatedProperties: false"

The driver side changes [2] are still being worked on.

[1] https://lore.kernel.org/dri-devel/20240126073511.2708574-1-wenst@chromium.org/
[2] https://lore.kernel.org/linux-arm-kernel/20230730180803.22570-4-jiaxin.yu@mediatek.com/
---
 .../devicetree/bindings/display/bridge/ite,it6505.yaml    | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
index c9a882ee6d98..c4469f463978 100644
--- a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
@@ -9,6 +9,9 @@ title: ITE it6505
 maintainers:
   - Allen Chen <allen.chen@ite.com.tw>
 
+allOf:
+  - $ref: /schemas/sound/dai-common.yaml#
+
 description: |
   The IT6505 is a high-performance DisplayPort 1.1a transmitter,
   fully compliant with DisplayPort 1.1a, HDCP 1.3 specifications.
@@ -52,6 +55,9 @@ properties:
     maxItems: 1
     description: extcon specifier for the Power Delivery
 
+  "#sound-dai-cells":
+    const: 0
+
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
 
@@ -105,7 +111,7 @@ required:
   - extcon
   - ports
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |

base-commit: 084c8e315db34b59d38d06e684b1a0dd07d30287
-- 
2.44.0.396.g6e790dbe36-goog


^ permalink raw reply related

* [PATCH v4 4/4] drivers: watchdog: ast2500 and ast2600 support bootstatus
From: Peter Yin @ 2024-03-27  8:53 UTC (permalink / raw)
  To: patrick, Wim Van Sebroeck, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
	linux-watchdog, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
In-Reply-To: <20240327085330.3281697-1-peteryin.openbmc@gmail.com>

Add WDIOF_EXTERN1 and WDIOF_CARDRESET bootstatus in ast2600

Regarding the AST2600 specification, the WDTn Timeout Status Register
(WDT10) has bit 1 reserved. Bit 1 of the status register indicates
on ast2500 if the boot was from the second boot source.
It does not indicate that the most recent reset was triggered by
the watchdog. The code should just be changed to set WDIOF_CARDRESET
if bit 0 of the status register is set.

Include SCU register to veriy WDIOF_EXTERN1 in ast2600 SCU74 or
ast2500 SCU3C when bit1 is set.

Signed-off-by: Peter Yin <peteryin.openbmc@gmail.com>
---
 drivers/watchdog/aspeed_wdt.c | 60 +++++++++++++++++++++++++----------
 1 file changed, 44 insertions(+), 16 deletions(-)

diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
index b4773a6aaf8c..29e9afdee619 100644
--- a/drivers/watchdog/aspeed_wdt.c
+++ b/drivers/watchdog/aspeed_wdt.c
@@ -11,10 +11,12 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/kstrtox.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/watchdog.h>
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -65,23 +67,32 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);
 #define WDT_RELOAD_VALUE	0x04
 #define WDT_RESTART		0x08
 #define WDT_CTRL		0x0C
-#define   WDT_CTRL_BOOT_SECONDARY	BIT(7)
-#define   WDT_CTRL_RESET_MODE_SOC	(0x00 << 5)
-#define   WDT_CTRL_RESET_MODE_FULL_CHIP	(0x01 << 5)
-#define   WDT_CTRL_RESET_MODE_ARM_CPU	(0x10 << 5)
-#define   WDT_CTRL_1MHZ_CLK		BIT(4)
-#define   WDT_CTRL_WDT_EXT		BIT(3)
-#define   WDT_CTRL_WDT_INTR		BIT(2)
-#define   WDT_CTRL_RESET_SYSTEM		BIT(1)
-#define   WDT_CTRL_ENABLE		BIT(0)
+#define WDT_CTRL_BOOT_SECONDARY	BIT(7)
+#define WDT_CTRL_RESET_MODE_SOC	(0x00 << 5)
+#define WDT_CTRL_RESET_MODE_FULL_CHIP	(0x01 << 5)
+#define WDT_CTRL_RESET_MODE_ARM_CPU	(0x10 << 5)
+#define WDT_CTRL_1MHZ_CLK		BIT(4)
+#define WDT_CTRL_WDT_EXT		BIT(3)
+#define WDT_CTRL_WDT_INTR		BIT(2)
+#define WDT_CTRL_RESET_SYSTEM		BIT(1)
+#define WDT_CTRL_ENABLE		BIT(0)
 #define WDT_TIMEOUT_STATUS	0x10
-#define   WDT_TIMEOUT_STATUS_IRQ		BIT(2)
-#define   WDT_TIMEOUT_STATUS_BOOT_SECONDARY	BIT(1)
+#define WDT_TIMEOUT_STATUS_IRQ		BIT(2)
+#define WDT_TIMEOUT_STATUS_BOOT_SECONDARY	BIT(1)
+#define WDT_TIMEOUT_STATUS_EVENT		BIT(0)
 #define WDT_CLEAR_TIMEOUT_STATUS	0x14
-#define   WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION	BIT(0)
+#define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION	BIT(0)
 #define WDT_RESET_MASK1		0x1c
 #define WDT_RESET_MASK2		0x20
 
+/*
+ * Ast2600 SCU74 bit1 is External reset flag
+ * Ast2500 SCU3C bit1 is External reset flag
+ */
+#define EXTERN_RESET_FLAG		BIT(1)
+#define AST2500_SYSTEM_RESET_EVENT	0x3C
+#define AST2600_SYSTEM_RESET_EVENT	0x74
+
 /*
  * WDT_RESET_WIDTH controls the characteristics of the external pulse (if
  * enabled), specifically:
@@ -330,6 +341,11 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
 	if (IS_ERR(wdt->base))
 		return PTR_ERR(wdt->base);
 
+	struct regmap *scu_base = syscon_regmap_lookup_by_phandle(dev->of_node,
+							     "aspeed,scu");
+	if (IS_ERR(scu_base))
+		return PTR_ERR(scu_base);
+
 	wdt->wdd.info = &aspeed_wdt_info;
 
 	if (wdt->cfg->irq_mask) {
@@ -459,14 +475,26 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
 	}
 
 	status = readl(wdt->base + WDT_TIMEOUT_STATUS);
-	if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) {
+	if (status & WDT_TIMEOUT_STATUS_EVENT)
 		wdt->wdd.bootstatus = WDIOF_CARDRESET;
 
-		if (of_device_is_compatible(np, "aspeed,ast2400-wdt") ||
-		    of_device_is_compatible(np, "aspeed,ast2500-wdt"))
-			wdt->wdd.groups = bswitch_groups;
+	if (of_device_is_compatible(np, "aspeed,ast2600-wdt")) {
+		ret = regmap_read(scu_base,
+				  AST2600_SYSTEM_RESET_EVENT,
+				  &status);
+	} else {
+		ret = regmap_read(scu_base,
+				  AST2500_SYSTEM_RESET_EVENT,
+				  &status);
+		wdt->wdd.groups = bswitch_groups;
 	}
 
+	/*
+	 * Reset cause by Extern Reset
+	 */
+	if (status & EXTERN_RESET_FLAG && !ret)
+		wdt->wdd.bootstatus |= WDIOF_EXTERN1;
+
 	dev_set_drvdata(dev, wdt);
 
 	return devm_watchdog_register_device(dev, &wdt->wdd);
-- 
2.25.1


^ permalink raw reply related

* [PATCH v4 3/4] dt-bindings: watchdog: aspeed-wdt: Add aspeed,scu
From: Peter Yin @ 2024-03-27  8:53 UTC (permalink / raw)
  To: patrick, Wim Van Sebroeck, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
	linux-watchdog, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
In-Reply-To: <20240327085330.3281697-1-peteryin.openbmc@gmail.com>

To use the SCU register to obtain reset flags for supporting
bootstatus.

Signed-off-by: Peter Yin <peteryin.openbmc@gmail.com>
---
 Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt b/Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt
index 3208adb3e52e..80a1f58b5a2e 100644
--- a/Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt
@@ -8,6 +8,8 @@ Required properties:
 
  - reg: physical base address of the controller and length of memory mapped
    region
+ - aspeed,scu: a reference to the System Control Unit node of the Aspeed
+   SOC.
 
 Optional properties:
 
@@ -62,6 +64,7 @@ Examples:
 		reg = <0x1e785000 0x1c>;
 		aspeed,reset-type = "system";
 		aspeed,external-signal;
+		aspeed,scu = <&syscon>;
 	};
 
 	#include <dt-bindings/watchdog/aspeed-wdt.h>
@@ -70,4 +73,5 @@ Examples:
 		reg = <0x1e785040 0x40>;
 		aspeed,reset-mask = <AST2600_WDT_RESET1_DEFAULT
 				     (AST2600_WDT_RESET2_DEFAULT & ~AST2600_WDT_RESET2_LPC)>;
+		aspeed,scu = <&syscon>;
 	};
-- 
2.25.1


^ permalink raw reply related

* [PATCH v4 2/4] ARM: dts: aspeed: Add the AST2600 WDT with SCU register
From: Peter Yin @ 2024-03-27  8:53 UTC (permalink / raw)
  To: patrick, Wim Van Sebroeck, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
	linux-watchdog, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
In-Reply-To: <20240327085330.3281697-1-peteryin.openbmc@gmail.com>

The AST2600 Watchdog Timer (WDT) references
the System Control Unit (SCU) register for its operation.

Signed-off-by: Peter Yin <peteryin.openbmc@gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index 5f640b7d6b6d..2f7788f2f153 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -558,23 +558,27 @@ uart5: serial@1e784000 {
 			wdt1: watchdog@1e785000 {
 				compatible = "aspeed,ast2600-wdt";
 				reg = <0x1e785000 0x40>;
+				aspeed,scu = <&syscon>;
 			};
 
 			wdt2: watchdog@1e785040 {
 				compatible = "aspeed,ast2600-wdt";
 				reg = <0x1e785040 0x40>;
+				aspeed,scu = <&syscon>;
 				status = "disabled";
 			};
 
 			wdt3: watchdog@1e785080 {
 				compatible = "aspeed,ast2600-wdt";
 				reg = <0x1e785080 0x40>;
+				aspeed,scu = <&syscon>;
 				status = "disabled";
 			};
 
 			wdt4: watchdog@1e7850c0 {
 				compatible = "aspeed,ast2600-wdt";
 				reg = <0x1e7850C0 0x40>;
+				aspeed,scu = <&syscon>;
 				status = "disabled";
 			};
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH v4 1/4] ARM: dts: aspeed: Add the AST2500 WDT with SCU register
From: Peter Yin @ 2024-03-27  8:53 UTC (permalink / raw)
  To: patrick, Wim Van Sebroeck, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
	linux-watchdog, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
In-Reply-To: <20240327085330.3281697-1-peteryin.openbmc@gmail.com>

The AST2500 WDT references the System Control Unit
register for its operation.

Signed-off-by: Peter Yin <peteryin.openbmc@gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-g5.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
index 04f98d1dbb97..5fd12c057c31 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
@@ -410,12 +410,14 @@ wdt1: watchdog@1e785000 {
 				compatible = "aspeed,ast2500-wdt";
 				reg = <0x1e785000 0x20>;
 				clocks = <&syscon ASPEED_CLK_APB>;
+				aspeed,scu = <&syscon>;
 			};
 
 			wdt2: watchdog@1e785020 {
 				compatible = "aspeed,ast2500-wdt";
 				reg = <0x1e785020 0x20>;
 				clocks = <&syscon ASPEED_CLK_APB>;
+				aspeed,scu = <&syscon>;
 			};
 
 			wdt3: watchdog@1e785040 {
@@ -423,6 +425,7 @@ wdt3: watchdog@1e785040 {
 				reg = <0x1e785040 0x20>;
 				clocks = <&syscon ASPEED_CLK_APB>;
 				status = "disabled";
+				aspeed,scu = <&syscon>;
 			};
 
 			pwm_tacho: pwm-tacho-controller@1e786000 {
-- 
2.25.1


^ permalink raw reply related

* [PATCH v4 0/4] drivers: watchdog: ast2500 and ast2600 support bootstatus
From: Peter Yin @ 2024-03-27  8:53 UTC (permalink / raw)
  To: patrick, Wim Van Sebroeck, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
	linux-watchdog, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel

Add WDIOF_EXTERN1 and WDIOF_CARDRESET bootstatus in ast2500/ast2600

Regarding the AST2600 specification, the WDTn Timeout Status Register
(WDT10) has bit 1 reserved. Bit 1 of the status register indicates
on ast2500 if the boot was from the second boot source.
It does not indicate that the most recent reset was triggered by
the watchdog. The code should just be changed to set WDIOF_CARDRESET
if bit 0 of the status register is set.

Include SCU register to veriy WDIOF_EXTERN1 in ast2600 SCU74 or
ast2500 SCU3C when bit1 is set.

v3 -> v4
  - Add error handling for syscon_regmap_lookup_by_phandle and
  regmap_read.

v2 -> v3
  - Fixed WDIOF_CARDRESET status bit check and added support
  for WDIOF_EXTERN1 on ast2500 and ast2600.

v1 -> v2
  - Add comment and support WDIOF_CARDRESET in ast2600

v1
  - Patch 0001 - Add WDIOF_EXTERN1 bootstatus
---

Peter Yin (4):
  ARM: dts: aspeed: Add the AST2500 WDT with SCU register
  ARM: dts: aspeed: Add the AST2600 WDT with SCU register
  dt-bindings: watchdog: aspeed-wdt: Add aspeed,scu
  drivers: watchdog: ast2500 and ast2600 support bootstatus

 .../bindings/watchdog/aspeed-wdt.txt          |  4 ++
 arch/arm/boot/dts/aspeed/aspeed-g5.dtsi       |  3 +
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi       |  4 ++
 drivers/watchdog/aspeed_wdt.c                 | 60 ++++++++++++++-----
 4 files changed, 55 insertions(+), 16 deletions(-)

-- 
2.25.1


^ permalink raw reply

* Re: [PATCH 1/4] dt-bindings: display/msm: sm8150-mdss: add DP node
From: Dmitry Baryshkov @ 2024-03-27  8:52 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Vinod Koul, linux-arm-msm,
	dri-devel, freedreno, devicetree
In-Reply-To: <e9ce004a-952a-4a94-abe9-2a8dd96b37fb@linaro.org>

On Wed, 27 Mar 2024 at 10:45, Krzysztof Kozlowski
<krzysztof.kozlowski@linaro.org> wrote:
>
> On 26/03/2024 21:02, Dmitry Baryshkov wrote:
> > diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
> > index c0d6a4fdff97..40b077fb20aa 100644
> > --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
> > +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
> > @@ -53,6 +53,16 @@ patternProperties:
> >        compatible:
> >          const: qcom,sm8150-dpu
> >
> > +  "^displayport-controller@[0-9a-f]+$":
> > +    type: object
> > +    additionalProperties: true
> > +
> > +    properties:
> > +      compatible:
> > +        items:
> > +          - const: qcom,sm8150-dp
> > +          - const: qcom,sm8350-dp
>
> This does not look right. sm8350 has its own mdss binding file.

So just a single entry here, even though SM8150 uses fallback compat string?

-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH v4 2/3] clk: qcom: add IPQ9574 interconnect clocks support
From: Dmitry Baryshkov @ 2024-03-27  8:49 UTC (permalink / raw)
  To: Varadarajan Narayanan
  Cc: andersson, konrad.dybcio, mturquette, sboyd, robh,
	krzysztof.kozlowski+dt, conor+dt, djakov, quic_anusha,
	linux-arm-msm, linux-clk, devicetree, linux-kernel, linux-pm
In-Reply-To: <20240327081850.2924870-3-quic_varada@quicinc.com>

On Wed, 27 Mar 2024 at 10:21, Varadarajan Narayanan
<quic_varada@quicinc.com> wrote:
>
> Unlike MSM platforms that manage NoC related clocks and scaling
> from RPM, IPQ SoCs dont involve RPM in managing NoC related
> clocks and there is no NoC scaling.
>
> However, there is a requirement to enable some NoC interface
> clocks for accessing the peripheral controllers present on
> these NoCs. Though exposing these as normal clocks would work,
> having a minimalistic interconnect driver to handle these clocks
> would make it consistent with other Qualcomm platforms resulting
> in common code paths. This is similar to msm8996-cbf's usage of
> icc-clk framework.
>
> Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
> ---
> v4: Use clk_hw instead of indices
>     Do icc register in qcom_cc_probe() call stream
>     Add icc clock info to qcom_cc_desc structure
> v3: Use indexed identifiers here to avoid confusion
>     Fix error messages and move to common.c
> v2: Move DTS to separate patch
>     Update commit log
>     Auto select CONFIG_INTERCONNECT & CONFIG_INTERCONNECT_CLK to fix build error
> ---
>  drivers/clk/qcom/Kconfig       |  2 ++
>  drivers/clk/qcom/common.c      | 34 ++++++++++++++++++++-
>  drivers/clk/qcom/common.h      |  4 ++-
>  drivers/clk/qcom/gcc-ipq9574.c | 54 ++++++++++++++++++++++++++++++++++

These changes must be separate.

>  4 files changed, 92 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index 8ab08e7b5b6c..af73a0b396eb 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -243,6 +243,8 @@ config IPQ_GCC_8074
>
>  config IPQ_GCC_9574
>         tristate "IPQ9574 Global Clock Controller"
> +       select INTERCONNECT
> +       select INTERCONNECT_CLK
>         help
>           Support for global clock controller on ipq9574 devices.
>           Say Y if you want to use peripheral devices such as UART, SPI,
> diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
> index 75f09e6e057e..523d30d0ccbc 100644
> --- a/drivers/clk/qcom/common.c
> +++ b/drivers/clk/qcom/common.c
> @@ -8,6 +8,8 @@
>  #include <linux/regmap.h>
>  #include <linux/platform_device.h>
>  #include <linux/clk-provider.h>
> +#include <linux/interconnect-clk.h>
> +#include <linux/interconnect-provider.h>
>  #include <linux/reset-controller.h>
>  #include <linux/of.h>
>
> @@ -234,6 +236,36 @@ static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec,
>         return cc->rclks[idx] ? &cc->rclks[idx]->hw : NULL;
>  }
>
> +static int qcom_cc_icc_register(struct device *dev,
> +                               const struct qcom_cc_desc *desc)
> +{
> +#if IS_ENABLED(CONFIG_INTERCONNECT_CLK)

General recommendation is to avoid #ifs inside function code. Please
move them outside and add an empty stub.

> +       struct icc_provider *provider;
> +       struct icc_clk_data *icd;
> +       int i;
> +
> +       if (!desc->icc_hws)
> +               return 0;
> +
> +       icd = devm_kcalloc(dev, desc->num_icc_hws, sizeof(*icd), GFP_KERNEL);
> +       if (!icd)
> +               return dev_err_probe(dev, -ENOMEM, "malloc for icc clock data failed\n");

No need to.

> +
> +       for (i = 0; i < desc->num_icc_hws; i++) {
> +               icd[i].clk = devm_clk_hw_get_clk(dev, desc->icc_hws[i], "");

Passing an empty string is not correct from the CCF point of view.

> +               if (IS_ERR_OR_NULL(icd[i].clk))
> +                       return dev_err_probe(dev, -ENOENT, "icc clock not found\n");

No, just IS_ERR and PTR_ERR. Don't throw away the resulting code.
In most of the case IS_ERR_OR_NULL is not correct. The function either
returns NULL or returns an error pointer. It can not be both.

> +               icd[i].name = clk_hw_get_name(desc->icc_hws[i]);
> +       }
> +
> +       provider = icc_clk_register(dev, desc->first_id, desc->num_icc_hws, icd);
> +       if (IS_ERR_OR_NULL(provider))

just use PTR_ERR_OR_ZERO

Also note that there is no qcom_cc_remove, so please add
devm_icc_clk_register() and use it here:

return PTR_ERR_OR_ZERO(devm_icc_clk_register(dev, ...));

> +               return dev_err_probe(dev, PTR_ERR(provider),
> +                                    "icc_clk_register failed\n");
> +#endif
> +       return 0;
> +}
> +
>  int qcom_cc_really_probe(struct platform_device *pdev,
>                          const struct qcom_cc_desc *desc, struct regmap *regmap)
>  {
> @@ -303,7 +335,7 @@ int qcom_cc_really_probe(struct platform_device *pdev,
>         if (ret)
>                 return ret;
>
> -       return 0;
> +       return qcom_cc_icc_register(dev, desc);
>  }
>  EXPORT_SYMBOL_GPL(qcom_cc_really_probe);
>
> diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
> index 9c8f7b798d9f..3c3a07f6dcb9 100644
> --- a/drivers/clk/qcom/common.h
> +++ b/drivers/clk/qcom/common.h
> @@ -29,6 +29,9 @@ struct qcom_cc_desc {
>         size_t num_gdscs;
>         struct clk_hw **clk_hws;
>         size_t num_clk_hws;
> +       struct clk_hw **icc_hws;
> +       size_t num_icc_hws;
> +       unsigned int first_id;
>  };
>
>  /**
> @@ -65,5 +68,4 @@ extern int qcom_cc_probe(struct platform_device *pdev,
>                          const struct qcom_cc_desc *desc);
>  extern int qcom_cc_probe_by_index(struct platform_device *pdev, int index,
>                                   const struct qcom_cc_desc *desc);
> -
>  #endif
> diff --git a/drivers/clk/qcom/gcc-ipq9574.c b/drivers/clk/qcom/gcc-ipq9574.c
> index 0a3f846695b8..187fd9dcdf49 100644
> --- a/drivers/clk/qcom/gcc-ipq9574.c
> +++ b/drivers/clk/qcom/gcc-ipq9574.c
> @@ -12,6 +12,7 @@
>
>  #include <dt-bindings/clock/qcom,ipq9574-gcc.h>
>  #include <dt-bindings/reset/qcom,ipq9574-gcc.h>
> +#include <dt-bindings/interconnect/qcom,ipq9574.h>
>
>  #include "clk-alpha-pll.h"
>  #include "clk-branch.h"
> @@ -4301,6 +4302,56 @@ static const struct qcom_reset_map gcc_ipq9574_resets[] = {
>         [GCC_WCSS_Q6_TBU_BCR] = { 0x12054, 0 },
>  };
>
> +#define IPQ_APPS_ID                    9574    /* some unique value */
> +
> +enum {
> +       ICC_ANOC_PCIE0,
> +       ICC_SNOC_PCIE0,
> +       ICC_ANOC_PCIE1,
> +       ICC_SNOC_PCIE1,
> +       ICC_ANOC_PCIE2,
> +       ICC_SNOC_PCIE2,
> +       ICC_ANOC_PCIE3,
> +       ICC_SNOC_PCIE3,
> +       ICC_SNOC_USB,
> +       ICC_ANOC_USB_AXI,
> +       ICC_NSSNOC_NSSCC,
> +       ICC_NSSNOC_SNOC_0,
> +       ICC_NSSNOC_SNOC_1,
> +       ICC_NSSNOC_PCNOC_1,
> +       ICC_NSSNOC_QOSGEN_REF,
> +       ICC_NSSNOC_TIMEOUT_REF,
> +       ICC_NSSNOC_XO_DCD,
> +       ICC_NSSNOC_ATB,
> +       ICC_MEM_NOC_NSSNOC,
> +       ICC_NSSNOC_MEMNOC,
> +       ICC_NSSNOC_MEM_NOC_1,
> +};
> +
> +static struct clk_hw *icc_ipq9574_hws[] = {
> +       [ICC_ANOC_PCIE0] = &gcc_anoc_pcie0_1lane_m_clk.clkr.hw,
> +       [ICC_SNOC_PCIE0] = &gcc_anoc_pcie1_1lane_m_clk.clkr.hw,
> +       [ICC_ANOC_PCIE1] = &gcc_anoc_pcie2_2lane_m_clk.clkr.hw,
> +       [ICC_SNOC_PCIE1] = &gcc_anoc_pcie3_2lane_m_clk.clkr.hw,
> +       [ICC_ANOC_PCIE2] = &gcc_snoc_pcie0_1lane_s_clk.clkr.hw,
> +       [ICC_SNOC_PCIE2] = &gcc_snoc_pcie1_1lane_s_clk.clkr.hw,
> +       [ICC_ANOC_PCIE3] = &gcc_snoc_pcie2_2lane_s_clk.clkr.hw,
> +       [ICC_SNOC_PCIE3] = &gcc_snoc_pcie3_2lane_s_clk.clkr.hw,
> +       [ICC_SNOC_USB] = &gcc_snoc_usb_clk.clkr.hw,
> +       [ICC_ANOC_USB_AXI] = &gcc_anoc_usb_axi_clk.clkr.hw,
> +       [ICC_NSSNOC_NSSCC] = &gcc_nssnoc_nsscc_clk.clkr.hw,
> +       [ICC_NSSNOC_SNOC_0] = &gcc_nssnoc_snoc_clk.clkr.hw,
> +       [ICC_NSSNOC_SNOC_1] = &gcc_nssnoc_snoc_1_clk.clkr.hw,
> +       [ICC_NSSNOC_PCNOC_1] = &gcc_nssnoc_pcnoc_1_clk.clkr.hw,
> +       [ICC_NSSNOC_QOSGEN_REF] = &gcc_nssnoc_qosgen_ref_clk.clkr.hw,
> +       [ICC_NSSNOC_TIMEOUT_REF] = &gcc_nssnoc_timeout_ref_clk.clkr.hw,
> +       [ICC_NSSNOC_XO_DCD] = &gcc_nssnoc_xo_dcd_clk.clkr.hw,
> +       [ICC_NSSNOC_ATB] = &gcc_nssnoc_atb_clk.clkr.hw,
> +       [ICC_MEM_NOC_NSSNOC] = &gcc_mem_noc_nssnoc_clk.clkr.hw,
> +       [ICC_NSSNOC_MEMNOC] = &gcc_nssnoc_memnoc_clk.clkr.hw,
> +       [ICC_NSSNOC_MEM_NOC_1] = &gcc_nssnoc_mem_noc_1_clk.clkr.hw,
> +};
> +
>  static const struct of_device_id gcc_ipq9574_match_table[] = {
>         { .compatible = "qcom,ipq9574-gcc" },
>         { }
> @@ -4323,6 +4374,9 @@ static const struct qcom_cc_desc gcc_ipq9574_desc = {
>         .num_resets = ARRAY_SIZE(gcc_ipq9574_resets),
>         .clk_hws = gcc_ipq9574_hws,
>         .num_clk_hws = ARRAY_SIZE(gcc_ipq9574_hws),
> +       .icc_hws = icc_ipq9574_hws,
> +       .num_icc_hws = ARRAY_SIZE(icc_ipq9574_hws),
> +       .first_id = IPQ_APPS_ID,
>  };
>
>  static int gcc_ipq9574_probe(struct platform_device *pdev)
> --
> 2.34.1
>
>


-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH 1/4] dt-bindings: display/msm: sm8150-mdss: add DP node
From: Krzysztof Kozlowski @ 2024-03-27  8:45 UTC (permalink / raw)
  To: Dmitry Baryshkov, Rob Clark, Abhinav Kumar, Sean Paul,
	Marijn Suijten, David Airlie, Daniel Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
	Vinod Koul
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree
In-Reply-To: <20240326-fd-fix-schema-v1-1-4475d6d6d633@linaro.org>

On 26/03/2024 21:02, Dmitry Baryshkov wrote:
> diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
> index c0d6a4fdff97..40b077fb20aa 100644
> --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml
> @@ -53,6 +53,16 @@ patternProperties:
>        compatible:
>          const: qcom,sm8150-dpu
>  
> +  "^displayport-controller@[0-9a-f]+$":
> +    type: object
> +    additionalProperties: true
> +
> +    properties:
> +      compatible:
> +        items:
> +          - const: qcom,sm8150-dp
> +          - const: qcom,sm8350-dp

This does not look right. sm8350 has its own mdss binding file.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v4 1/4] interconnect: qcom: icc-rpmh: Add QoS configuration support
From: Krzysztof Kozlowski @ 2024-03-27  8:44 UTC (permalink / raw)
  To: Konrad Dybcio, Odelu Kukatla, Bjorn Andersson, Georgi Djakov,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Kees Cook, cros-qcom-dts-watchers, Gustavo A . R . Silva,
	linux-arm-msm, linux-pm, devicetree, linux-kernel,
	linux-hardening, quic_rlaggysh, quic_mdtipton
In-Reply-To: <d59896bb-a559-4013-a615-37bb43278b2e@linaro.org>

On 26/03/2024 21:56, Konrad Dybcio wrote:
> On 25.03.2024 7:16 PM, Odelu Kukatla wrote:
>> It adds QoS support for QNOC device and includes support for
>> configuring priority, priority forward disable, urgency forwarding.
>> This helps in priortizing the traffic originating from different
>> interconnect masters at NoC(Network On Chip).
>>
>> Signed-off-by: Odelu Kukatla <quic_okukatla@quicinc.com>
>> ---
> 
> [...]
> 
>>  
>> +	if (desc->config) {
>> +		struct resource *res;
>> +		void __iomem *base;
>> +
>> +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +		if (!res)
>> +			goto skip_qos_config;
>> +
>> +		base = devm_ioremap_resource(dev, res);
> 
> You were asked to substitute this call like 3 times already..
> 
> devm_platform_get_and_ioremap_resource
> 
> or even better, devm_platform_ioremap_resource

Yeah, I wonder what else from my feedback got ignored :(


Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v2 2/3] dt-bindings: power: Add mediatek larb definition
From: Krzysztof Kozlowski @ 2024-03-27  8:39 UTC (permalink / raw)
  To: yu-chang.lee, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Ulf Hansson, Matthias Brugger, AngeloGioacchino Del Regno,
	MandyJH Liu
  Cc: devicetree, linux-kernel, linux-pm, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, fan.chen,
	xiufeng.li
In-Reply-To: <20240327055732.28198-3-yu-chang.lee@mediatek.com>

On 27/03/2024 06:57, yu-chang.lee wrote:
> Add Smart Multimedia Interface Local Arbiter to mediatek
> power domain.
> 
> Signed-off-by: yu-chang.lee <yu-chang.lee@mediatek.com>
> ---
>  .../devicetree/bindings/power/mediatek,power-controller.yaml  | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
> index 8985e2df8a56..228c0dec5253 100644
> --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
> +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
> @@ -125,6 +125,10 @@ $defs:
>          $ref: /schemas/types.yaml#/definitions/phandle
>          description: phandle to the device containing the SMI register range.
>  
> +     mediatek,larb:
> +        $ref: /schemas/types.yaml#/definitions/phandle
> +        description: phandle to the device containing the LARB register range.

Why do you need it?

Plus I also see mediatek,larbs and mediatek,larb-id... so now we have
third one similar.

Best regards,
Krzysztof


^ permalink raw reply

* RE: [PATCH v2 1/2] dt-bindings: dma: snps,dw-axi-dmac: Add JH8100 support
From: ChunHau Tan @ 2024-03-27  8:24 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Eugeniy Paltsev, Vinod Koul, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: Leyfoon Tan, JeeHeng Sia, dmaengine@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <6533503e-18e1-4957-96cc-db091e9c46c9@linaro.org>



> -----Original Message-----
> From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Sent: Wednesday, 27 March, 2024 3:50 PM
> To: ChunHau Tan <chunhau.tan@starfivetech.com>; Eugeniy Paltsev
> <Eugeniy.Paltsev@synopsys.com>; Vinod Koul <vkoul@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>;
> Conor Dooley <conor+dt@kernel.org>
> Cc: Leyfoon Tan <leyfoon.tan@starfivetech.com>; JeeHeng Sia
> <jeeheng.sia@starfivetech.com>; dmaengine@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v2 1/2] dt-bindings: dma: snps,dw-axi-dmac: Add JH8100
> support
> 
> On 27/03/2024 03:51, Tan Chun Hau wrote:
> > Add support for StarFive JH8100 SoC in Sysnopsys Designware AXI DMA
> > controller.
> >
> > Both JH8100 and JH7110 require reset operation in device probe.
> > However, JH8100 doesn't need to apply different configuration on
> > CH_CFG registers.
> 
> This is a friendly reminder during the review process.
> 
> It looks like you received a tag and forgot to add it.
> 
> If you do not know the process, here is a short explanation:
> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions,
> under or above your Signed-off-by tag. Tag is "received", when provided in a
> message replied to you on the mailing list. Tools like b4 can help here. However,
> there's no need to repost patches *only* to add the tags. The upstream
> maintainer will do that for tags received on the version they apply.
> 
> https://elixir.bootlin.com/linux/v6.5-rc3/source/Documentation/process/submitt
> ing-patches.rst#L577
> 
> If a tag was not added on purpose, please state why and what changed.

Hi Krzysztof, thank you very much for the feedback,
Sorry I overlooked it.
Do you prefer I resend V2 patch or send a V3 patch to include the Acked-by ?
Thank you.

> 
> Best regards,
> Krzysztof


^ permalink raw reply

* Re: [PATCH v4 2/3] clk: qcom: add IPQ9574 interconnect clocks support
From: Krzysztof Kozlowski @ 2024-03-27  8:34 UTC (permalink / raw)
  To: Varadarajan Narayanan, andersson, konrad.dybcio, mturquette,
	sboyd, robh, krzysztof.kozlowski+dt, conor+dt, djakov,
	quic_anusha, linux-arm-msm, linux-clk, devicetree, linux-kernel,
	linux-pm
In-Reply-To: <20240327081850.2924870-3-quic_varada@quicinc.com>

On 27/03/2024 09:18, Varadarajan Narayanan wrote:
> Unlike MSM platforms that manage NoC related clocks and scaling
> from RPM, IPQ SoCs dont involve RPM in managing NoC related
> clocks and there is no NoC scaling.
> 
> However, there is a requirement to enable some NoC interface
> clocks for accessing the peripheral controllers present on
> these NoCs. Though exposing these as normal clocks would work,
> having a minimalistic interconnect driver to handle these clocks
> would make it consistent with other Qualcomm platforms resulting
> in common code paths. This is similar to msm8996-cbf's usage of
> icc-clk framework.
> 
> Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
> ---
> v4: Use clk_hw instead of indices
>     Do icc register in qcom_cc_probe() call stream
>     Add icc clock info to qcom_cc_desc structure
> v3: Use indexed identifiers here to avoid confusion
>     Fix error messages and move to common.c
> v2: Move DTS to separate patch
>     Update commit log
>     Auto select CONFIG_INTERCONNECT & CONFIG_INTERCONNECT_CLK to fix build error
> ---
>  drivers/clk/qcom/Kconfig       |  2 ++
>  drivers/clk/qcom/common.c      | 34 ++++++++++++++++++++-
>  drivers/clk/qcom/common.h      |  4 ++-
>  drivers/clk/qcom/gcc-ipq9574.c | 54 ++++++++++++++++++++++++++++++++++
>  4 files changed, 92 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index 8ab08e7b5b6c..af73a0b396eb 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -243,6 +243,8 @@ config IPQ_GCC_8074
>  
>  config IPQ_GCC_9574
>  	tristate "IPQ9574 Global Clock Controller"
> +	select INTERCONNECT
> +	select INTERCONNECT_CLK
>  	help
>  	  Support for global clock controller on ipq9574 devices.
>  	  Say Y if you want to use peripheral devices such as UART, SPI,
> diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
> index 75f09e6e057e..523d30d0ccbc 100644
> --- a/drivers/clk/qcom/common.c
> +++ b/drivers/clk/qcom/common.c
> @@ -8,6 +8,8 @@
>  #include <linux/regmap.h>
>  #include <linux/platform_device.h>
>  #include <linux/clk-provider.h>
> +#include <linux/interconnect-clk.h>
> +#include <linux/interconnect-provider.h>
>  #include <linux/reset-controller.h>
>  #include <linux/of.h>
>  
> @@ -234,6 +236,36 @@ static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec,
>  	return cc->rclks[idx] ? &cc->rclks[idx]->hw : NULL;
>  }
>  
> +static int qcom_cc_icc_register(struct device *dev,
> +				const struct qcom_cc_desc *desc)
> +{
> +#if IS_ENABLED(CONFIG_INTERCONNECT_CLK)
> +	struct icc_provider *provider;
> +	struct icc_clk_data *icd;
> +	int i;
> +
> +	if (!desc->icc_hws)
> +		return 0;
> +
> +	icd = devm_kcalloc(dev, desc->num_icc_hws, sizeof(*icd), GFP_KERNEL);
> +	if (!icd)
> +		return dev_err_probe(dev, -ENOMEM, "malloc for icc clock data failed\n");

This is still not correct code.

No driver code prints errors on allocation failure.

Best regards,
Krzysztof


^ permalink raw reply

* [PATCH v12 5/5] riscv: dts: add clock generator for Sophgo SG2042 SoC
From: Chen Wang @ 2024-03-27  8:31 UTC (permalink / raw)
  To: aou, chao.wei, conor, krzysztof.kozlowski+dt, mturquette, palmer,
	paul.walmsley, richardcochran, robh+dt, sboyd, devicetree,
	linux-clk, linux-kernel, linux-riscv, haijiao.liu, xiaoguang.xing,
	guoren, jszhang, inochiama, samuel.holland
  Cc: Chen Wang
In-Reply-To: <cover.1711527932.git.unicorn_wang@outlook.com>

From: Chen Wang <unicorn_wang@outlook.com>

Add clock generator node to device tree for SG2042, and enable clock for
uart.

Signed-off-by: Chen Wang <unicorn_wang@outlook.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
---
 .../boot/dts/sophgo/sg2042-milkv-pioneer.dts  | 12 +++++
 arch/riscv/boot/dts/sophgo/sg2042.dtsi        | 49 ++++++++++++++++++-
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts
index 49b4b9c2c101..80cb017974d8 100644
--- a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts
+++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts
@@ -14,6 +14,18 @@ chosen {
 	};
 };
 
+&cgi_main {
+	clock-frequency = <25000000>;
+};
+
+&cgi_dpll0 {
+	clock-frequency = <25000000>;
+};
+
+&cgi_dpll1 {
+	clock-frequency = <25000000>;
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
index 81fda312f988..8aab027cf730 100644
--- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi
+++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
@@ -4,8 +4,10 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/clock/sophgo,sg2042-clkgen.h>
+#include <dt-bindings/clock/sophgo,sg2042-pll.h>
+#include <dt-bindings/clock/sophgo,sg2042-rpgate.h>
 #include <dt-bindings/interrupt-controller/irq.h>
-
 #include <dt-bindings/reset/sophgo,sg2042-reset.h>
 
 #include "sg2042-cpus.dtsi"
@@ -20,12 +22,54 @@ aliases {
 		serial0 = &uart0;
 	};
 
+	cgi_main: oscillator0 {
+		compatible = "fixed-clock";
+		clock-output-names = "cgi_main";
+		#clock-cells = <0>;
+	};
+
+	cgi_dpll0: oscillator1 {
+		compatible = "fixed-clock";
+		clock-output-names = "cgi_dpll0";
+		#clock-cells = <0>;
+	};
+
+	cgi_dpll1: oscillator2 {
+		compatible = "fixed-clock";
+		clock-output-names = "cgi_dpll1";
+		#clock-cells = <0>;
+	};
+
 	soc: soc {
 		compatible = "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <2>;
 		ranges;
 
+		pllclk: clock-controller@70300100c0 {
+			compatible = "sophgo,sg2042-pll";
+			reg = <0x70 0x300100c0 0x0 0x40>;
+			clocks = <&cgi_main>, <&cgi_dpll0>, <&cgi_dpll1>;
+			#clock-cells = <1>;
+		};
+
+		rpgate: clock-controller@7030010368 {
+			compatible = "sophgo,sg2042-rpgate";
+			reg = <0x70 0x30010368 0x0 0x98>;
+			clocks = <&clkgen GATE_CLK_RP_CPU_NORMAL>;
+			#clock-cells = <1>;
+		};
+
+		clkgen: clock-controller@7030012000 {
+			compatible = "sophgo,sg2042-clkgen";
+			reg = <0x70 0x30012000 0x0 0x1000>;
+			clocks = <&pllclk MPLL_CLK>,
+				 <&pllclk FPLL_CLK>,
+				 <&pllclk DPLL0_CLK>,
+				 <&pllclk DPLL1_CLK>;
+			#clock-cells = <1>;
+		};
+
 		clint_mswi: interrupt-controller@7094000000 {
 			compatible = "sophgo,sg2042-aclint-mswi", "thead,c900-aclint-mswi";
 			reg = <0x00000070 0x94000000 0x00000000 0x00004000>;
@@ -341,6 +385,9 @@ uart0: serial@7040000000 {
 			interrupt-parent = <&intc>;
 			interrupts = <112 IRQ_TYPE_LEVEL_HIGH>;
 			clock-frequency = <500000000>;
+			clocks = <&clkgen GATE_CLK_UART_500M>,
+				 <&clkgen GATE_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			resets = <&rstgen RST_UART0>;
-- 
2.25.1


^ permalink raw reply related

* [PATCH v12 4/5] clk: sophgo: Add SG2042 clock driver
From: Chen Wang @ 2024-03-27  8:30 UTC (permalink / raw)
  To: aou, chao.wei, conor, krzysztof.kozlowski+dt, mturquette, palmer,
	paul.walmsley, richardcochran, robh+dt, sboyd, devicetree,
	linux-clk, linux-kernel, linux-riscv, haijiao.liu, xiaoguang.xing,
	guoren, jszhang, inochiama, samuel.holland
  Cc: Chen Wang
In-Reply-To: <cover.1711527932.git.unicorn_wang@outlook.com>

From: Chen Wang <unicorn_wang@outlook.com>

Add a driver for the SOPHGO SG2042 clocks.

Signed-off-by: Chen Wang <unicorn_wang@outlook.com>
---
 drivers/clk/Kconfig                    |    1 +
 drivers/clk/Makefile                   |    1 +
 drivers/clk/sophgo/Kconfig             |    7 +
 drivers/clk/sophgo/Makefile            |    2 +
 drivers/clk/sophgo/clk-sophgo-sg2042.c | 1410 ++++++++++++++++++++++++
 drivers/clk/sophgo/clk-sophgo-sg2042.h |  216 ++++
 6 files changed, 1637 insertions(+)
 create mode 100644 drivers/clk/sophgo/Kconfig
 create mode 100644 drivers/clk/sophgo/Makefile
 create mode 100644 drivers/clk/sophgo/clk-sophgo-sg2042.c
 create mode 100644 drivers/clk/sophgo/clk-sophgo-sg2042.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 50af5fc7f570..bc28502ec3c9 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -489,6 +489,7 @@ source "drivers/clk/rockchip/Kconfig"
 source "drivers/clk/samsung/Kconfig"
 source "drivers/clk/sifive/Kconfig"
 source "drivers/clk/socfpga/Kconfig"
+source "drivers/clk/sophgo/Kconfig"
 source "drivers/clk/sprd/Kconfig"
 source "drivers/clk/starfive/Kconfig"
 source "drivers/clk/sunxi/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 14fa8d4ecc1f..4abe16c8ccdf 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip/
 obj-$(CONFIG_COMMON_CLK_SAMSUNG)	+= samsung/
 obj-$(CONFIG_CLK_SIFIVE)		+= sifive/
 obj-y					+= socfpga/
+obj-y					+= sophgo/
 obj-$(CONFIG_PLAT_SPEAR)		+= spear/
 obj-y					+= sprd/
 obj-$(CONFIG_ARCH_STI)			+= st/
diff --git a/drivers/clk/sophgo/Kconfig b/drivers/clk/sophgo/Kconfig
new file mode 100644
index 000000000000..2523818d64f9
--- /dev/null
+++ b/drivers/clk/sophgo/Kconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config CLK_SOPHGO_SG2042
+	bool "Sophgo SG2042 clock support"
+	depends on ARCH_SOPHGO || COMPILE_TEST
+	help
+	  Say yes here to support the clock controller on the Sophgo SG2042 SoC.
diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile
new file mode 100644
index 000000000000..13834cce260c
--- /dev/null
+++ b/drivers/clk/sophgo/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_CLK_SOPHGO_SG2042)	+= clk-sophgo-sg2042.o
diff --git a/drivers/clk/sophgo/clk-sophgo-sg2042.c b/drivers/clk/sophgo/clk-sophgo-sg2042.c
new file mode 100644
index 000000000000..a5648ff9f8d6
--- /dev/null
+++ b/drivers/clk/sophgo/clk-sophgo-sg2042.c
@@ -0,0 +1,1410 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sophgo SG2042 Clock Generator Driver
+ *
+ * Copyright (C) 2024 Sophgo Technology Inc. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/iopoll.h>
+#include <linux/platform_device.h>
+
+/*
+ * The clock of SG2042 is composed of three parts.
+ * The registers of these three parts of the clock are scattered in three
+ * different memory address spaces:
+ * - pll clocks
+ * - gate clocks for RP subsystem
+ * - div/mux, and gate clocks working for other subsystem than RP subsystem
+ */
+#include <dt-bindings/clock/sophgo,sg2042-pll.h>
+#include <dt-bindings/clock/sophgo,sg2042-rpgate.h>
+#include <dt-bindings/clock/sophgo,sg2042-clkgen.h>
+
+#include "clk-sophgo-sg2042.h"
+
+#define KHZ 1000UL
+#define MHZ (KHZ * KHZ)
+
+#define REFDIV_MIN 1
+#define REFDIV_MAX 63
+#define FBDIV_MIN 16
+#define FBDIV_MAX 320
+
+#define PLL_FREF_SG2042 (25 * MHZ)
+
+#define PLL_FOUTPOSTDIV_MIN (16 * MHZ)
+#define PLL_FOUTPOSTDIV_MAX (3200 * MHZ)
+
+#define PLL_FOUTVCO_MIN (800 * MHZ)
+#define PLL_FOUTVCO_MAX (3200 * MHZ)
+
+struct sg2042_pll_ctrl {
+	unsigned long freq;
+	unsigned int fbdiv;
+	unsigned int postdiv1;
+	unsigned int postdiv2;
+	unsigned int refdiv;
+};
+
+#define PLLCTRL_FBDIV_SHIFT	16
+#define PLLCTRL_FBDIV_MASK	(GENMASK(27, 16) >> PLLCTRL_FBDIV_SHIFT)
+#define PLLCTRL_POSTDIV2_SHIFT	12
+#define PLLCTRL_POSTDIV2_MASK	(GENMASK(14, 12) >> PLLCTRL_POSTDIV2_SHIFT)
+#define PLLCTRL_POSTDIV1_SHIFT	8
+#define PLLCTRL_POSTDIV1_MASK	(GENMASK(10, 8) >> PLLCTRL_POSTDIV1_SHIFT)
+#define PLLCTRL_REFDIV_SHIFT	0
+#define PLLCTRL_REFDIV_MASK	(GENMASK(5, 0) >> PLLCTRL_REFDIV_SHIFT)
+
+static inline u32 sg2042_pll_ctrl_encode(struct sg2042_pll_ctrl *ctrl)
+{
+	return ((ctrl->fbdiv & PLLCTRL_FBDIV_MASK) << PLLCTRL_FBDIV_SHIFT) |
+	       ((ctrl->postdiv2 & PLLCTRL_POSTDIV2_MASK) << PLLCTRL_POSTDIV2_SHIFT) |
+	       ((ctrl->postdiv1 & PLLCTRL_POSTDIV1_MASK) << PLLCTRL_POSTDIV1_SHIFT) |
+	       ((ctrl->refdiv & PLLCTRL_REFDIV_MASK) << PLLCTRL_REFDIV_SHIFT);
+}
+
+static inline void sg2042_pll_ctrl_decode(unsigned int reg_value,
+					  struct sg2042_pll_ctrl *ctrl)
+{
+	ctrl->fbdiv = (reg_value >> PLLCTRL_FBDIV_SHIFT) & PLLCTRL_FBDIV_MASK;
+	ctrl->refdiv = (reg_value >> PLLCTRL_REFDIV_SHIFT) & PLLCTRL_REFDIV_MASK;
+	ctrl->postdiv1 = (reg_value >> PLLCTRL_POSTDIV1_SHIFT) & PLLCTRL_POSTDIV1_MASK;
+	ctrl->postdiv2 = (reg_value >> PLLCTRL_POSTDIV2_SHIFT) & PLLCTRL_POSTDIV2_MASK;
+}
+
+static inline int sg2042_pll_enable(struct sg2042_pll_clock *pll, bool en)
+{
+	unsigned int value = 0;
+
+	if (en) {
+		/* wait pll lock */
+		if (readl_poll_timeout_atomic(pll->base + pll->offset_status,
+					      value,
+					      ((value >> pll->shift_status_lock) & 0x1),
+					      0,
+					      100000))
+			pr_warn("%s not locked\n", pll->hw.init->name);
+
+		/* wait pll updating */
+		if (readl_poll_timeout_atomic(pll->base + pll->offset_status,
+					      value,
+					      !((value >> pll->shift_status_updating) & 0x1),
+					      0,
+					      100000))
+			pr_warn("%s still updating\n", pll->hw.init->name);
+
+		/* enable pll */
+		value = readl(pll->base + pll->offset_enable);
+		writel(value | (1 << pll->shift_enable), pll->base + pll->offset_enable);
+	} else {
+		/* disable pll */
+		value = readl(pll->base + pll->offset_enable);
+		writel(value & (~(1 << pll->shift_enable)), pll->base + pll->offset_enable);
+	}
+
+	return 0;
+}
+
+/*
+ * @reg_value: current register value
+ * @parent_rate: parent frequency
+ *
+ * This function is used to calculate below "rate" in equation
+ * rate = (parent_rate/REFDIV) x FBDIV/POSTDIV1/POSTDIV2
+ *      = (parent_rate x FBDIV) / (REFDIV x POSTDIV1 x POSTDIV2)
+ */
+static unsigned long sg2042_pll_recalc_rate(unsigned int reg_value,
+					    unsigned long parent_rate)
+{
+	struct sg2042_pll_ctrl ctrl_table;
+	u64 rate, numerator, denominator;
+
+	sg2042_pll_ctrl_decode(reg_value, &ctrl_table);
+
+	numerator = parent_rate * ctrl_table.fbdiv;
+	denominator = ctrl_table.refdiv * ctrl_table.postdiv1 * ctrl_table.postdiv2;
+	do_div(numerator, denominator);
+	rate = numerator;
+
+	return rate;
+}
+
+/*
+ * Based on input rate/prate/fbdiv/refdiv, look up the postdiv1_2 table
+ * to get the closest postdiiv combination.
+ * postdiv1_2 contains all the possible combination lists of POSTDIV1 and POSTDIV2
+ * for example:
+ * postdiv1_2[0] = {2, 4, 8}, where div1 = 2, div2 = 4 , div1 * div2 = 8
+ *
+ * See TRM:
+ * FOUTPOSTDIV = FREF * FBDIV / REFDIV / (POSTDIV1 * POSTDIV2)
+ * So we get following formula to get POSTDIV1 and POSTDIV2:
+ * POSTDIV = (prate/REFDIV) x FBDIV/rate
+ * above POSTDIV = POSTDIV1*POSTDIV2
+ *
+ * @rate: FOUTPOSTDIV
+ * @prate: parent rate, i.e. FREF
+ * @fbdiv: FBDIV
+ * @refdiv: REFDIV
+ * @postdiv1: POSTDIV1, output
+ * @postdiv2: POSTDIV2, output
+ */
+static int sg2042_pll_get_postdiv_1_2(unsigned long rate,
+				      unsigned long prate,
+				      unsigned int fbdiv,
+				      unsigned int refdiv,
+				      unsigned int *postdiv1,
+				      unsigned int *postdiv2)
+{
+	int index;
+	u64 tmp0;
+
+	/* POSTDIV_RESULT_INDEX point to 3rd element in the array postdiv1_2 */
+	#define	POSTDIV_RESULT_INDEX	2
+
+	static int postdiv1_2[][3] = {
+		{2, 4,  8}, {3, 3,  9}, {2, 5, 10}, {2, 6, 12},
+		{2, 7, 14}, {3, 5, 15}, {4, 4, 16}, {3, 6, 18},
+		{4, 5, 20}, {3, 7, 21}, {4, 6, 24}, {5, 5, 25},
+		{4, 7, 28}, {5, 6, 30}, {5, 7, 35}, {6, 6, 36},
+		{6, 7, 42}, {7, 7, 49}
+	};
+
+	/* prate/REFDIV and result save to tmp0 */
+	tmp0 = prate;
+	do_div(tmp0, refdiv);
+
+	/* ((prate/REFDIV) x FBDIV) and result save to tmp0 */
+	tmp0 *= fbdiv;
+
+	/* ((prate/REFDIV) x FBDIV)/rate and result save to tmp0 */
+	do_div(tmp0, rate);
+
+	/* tmp0 is POSTDIV1*POSTDIV2, now we calculate div1 and div2 value */
+	if (tmp0 <= 7) {
+		/* (div1 * div2) <= 7, no need to use array search */
+		*postdiv1 = tmp0;
+		*postdiv2 = 1;
+		return 0;
+	}
+
+	/* (div1 * div2) > 7, use array search */
+	for (index = 0; index < ARRAY_SIZE(postdiv1_2); index++) {
+		if (tmp0 > postdiv1_2[index][POSTDIV_RESULT_INDEX]) {
+			continue;
+		} else {
+			/* found it */
+			*postdiv1 = postdiv1_2[index][1];
+			*postdiv2 = postdiv1_2[index][0];
+			return 0;
+		}
+	}
+	pr_warn("%s can not find in postdiv array!\n", __func__);
+	return -EINVAL;
+}
+
+/*
+ * Based on the given FOUTPISTDIV and the input FREF to calculate
+ * the REFDIV/FBDIV/PSTDIV1/POSTDIV2 combination for pllctrl register.
+ * @req_rate: expected output clock rate, i.e. FOUTPISTDIV
+ * @parent_rate: input parent clock rate, i.e. FREF
+ * @best: output to hold calculated combination of REFDIV/FBDIV/PSTDIV1/POSTDIV2
+ */
+static int sg2042_get_pll_ctl_setting(struct sg2042_pll_ctrl *best,
+				      unsigned long req_rate,
+				      unsigned long parent_rate)
+{
+	int ret;
+	unsigned int fbdiv, refdiv, postdiv1, postdiv2;
+	unsigned long foutpostdiv;
+	u64 tmp;
+	u64 foutvco;
+
+	if (parent_rate != PLL_FREF_SG2042) {
+		pr_err("INVALID FREF: %ld\n", parent_rate);
+		return -EINVAL;
+	}
+
+	if (req_rate < PLL_FOUTPOSTDIV_MIN || req_rate > PLL_FOUTPOSTDIV_MAX) {
+		pr_alert("INVALID FOUTPOSTDIV: %ld\n", req_rate);
+		return -EINVAL;
+	}
+
+	memset(best, 0, sizeof(struct sg2042_pll_ctrl));
+
+	for (refdiv = REFDIV_MIN; refdiv < REFDIV_MAX + 1; refdiv++) {
+		/* required by hardware: FREF/REFDIV must > 10 */
+		tmp = parent_rate;
+		do_div(tmp, refdiv);
+		if (tmp <= 10)
+			continue;
+
+		for (fbdiv = FBDIV_MIN; fbdiv < FBDIV_MAX + 1; fbdiv++) {
+			/*
+			 * FOUTVCO = FREF*FBDIV/REFDIV validation
+			 * required by hardware, FOUTVCO must [800MHz, 3200MHz]
+			 */
+			foutvco = parent_rate * fbdiv;
+			do_div(foutvco, refdiv);
+			if (foutvco < PLL_FOUTVCO_MIN || foutvco > PLL_FOUTVCO_MAX)
+				continue;
+
+			ret = sg2042_pll_get_postdiv_1_2(req_rate, parent_rate,
+							 fbdiv, refdiv,
+							 &postdiv1, &postdiv2);
+			if (ret)
+				continue;
+
+			/*
+			 * FOUTPOSTDIV = FREF*FBDIV/REFDIV/(POSTDIV1*POSTDIV2)
+			 *             = FOUTVCO/(POSTDIV1*POSTDIV2)
+			 */
+			tmp = foutvco;
+			do_div(tmp, (postdiv1 * postdiv2));
+			foutpostdiv = (unsigned long)tmp;
+			/* Iterative to approach the expected value */
+			if (abs_diff(foutpostdiv, req_rate) < abs_diff(best->freq, req_rate)) {
+				best->freq = foutpostdiv;
+				best->refdiv = refdiv;
+				best->fbdiv = fbdiv;
+				best->postdiv1 = postdiv1;
+				best->postdiv2 = postdiv2;
+				if (foutpostdiv == req_rate)
+					return 0;
+			}
+			continue;
+		}
+	}
+
+	if (best->freq == 0)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+/*
+ * @hw: ccf use to hook get sg2042_pll_clock
+ * @parent_rate: parent rate
+ *
+ * The is function will be called through clk_get_rate
+ * and return current rate after decoding reg value
+ */
+static unsigned long sg2042_clk_pll_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	unsigned int value;
+	unsigned long rate;
+	struct sg2042_pll_clock *pll = to_sg2042_pll_clk(hw);
+
+	value = readl(pll->base + pll->offset_ctrl);
+	rate = sg2042_pll_recalc_rate(value, parent_rate);
+
+	pr_debug("--> %s: pll_recalc_rate: val = %ld\n",
+		 clk_hw_get_name(hw), rate);
+	return rate;
+}
+
+static long sg2042_clk_pll_round_rate(struct clk_hw *hw,
+				      unsigned long req_rate,
+				      unsigned long *prate)
+{
+	unsigned int value;
+	struct sg2042_pll_ctrl pctrl_table;
+	long proper_rate;
+	int ret;
+
+	ret = sg2042_get_pll_ctl_setting(&pctrl_table, req_rate, *prate);
+	if (ret) {
+		proper_rate = 0;
+		goto out;
+	}
+
+	value = sg2042_pll_ctrl_encode(&pctrl_table);
+	proper_rate = (long)sg2042_pll_recalc_rate(value, *prate);
+
+out:
+	pr_debug("--> %s: pll_round_rate: val = %ld\n",
+		 clk_hw_get_name(hw), proper_rate);
+	return proper_rate;
+}
+
+static int sg2042_clk_pll_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req)
+{
+	req->rate = sg2042_clk_pll_round_rate(hw, min(req->rate, req->max_rate),
+					      &req->best_parent_rate);
+	pr_debug("--> %s: pll_determine_rate: val = %ld\n",
+		 clk_hw_get_name(hw), req->rate);
+	return 0;
+}
+
+static int sg2042_clk_pll_set_rate(struct clk_hw *hw,
+				   unsigned long rate,
+				   unsigned long parent_rate)
+{
+	unsigned long flags;
+	unsigned int value;
+	int ret = 0;
+	struct sg2042_pll_ctrl pctrl_table;
+	struct sg2042_pll_clock *pll = to_sg2042_pll_clk(hw);
+
+	spin_lock_irqsave(pll->lock, flags);
+	if (sg2042_pll_enable(pll, 0)) {
+		pr_warn("Can't disable pll(%s), status error\n", pll->hw.init->name);
+		goto out;
+	}
+	ret = sg2042_get_pll_ctl_setting(&pctrl_table, rate, parent_rate);
+	if (ret) {
+		pr_warn("%s: Can't find a proper pll setting\n", pll->hw.init->name);
+		goto out2;
+	}
+
+	value = sg2042_pll_ctrl_encode(&pctrl_table);
+
+	/* write the value to top register */
+	writel(value, pll->base + pll->offset_ctrl);
+
+out2:
+	sg2042_pll_enable(pll, 1);
+out:
+	spin_unlock_irqrestore(pll->lock, flags);
+
+	pr_debug("--> %s: pll_set_rate: val = 0x%x\n",
+		 clk_hw_get_name(hw), value);
+	return ret;
+}
+
+static const struct clk_ops sg2042_clk_pll_ops = {
+	.recalc_rate = sg2042_clk_pll_recalc_rate,
+	.round_rate = sg2042_clk_pll_round_rate,
+	.determine_rate = sg2042_clk_pll_determine_rate,
+	.set_rate = sg2042_clk_pll_set_rate,
+};
+
+static const struct clk_ops sg2042_clk_pll_ro_ops = {
+	.recalc_rate = sg2042_clk_pll_recalc_rate,
+	.round_rate = sg2042_clk_pll_round_rate,
+};
+
+static unsigned long sg2042_clk_divider_recalc_rate(struct clk_hw *hw,
+						    unsigned long parent_rate)
+{
+	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
+	unsigned int val;
+	unsigned long ret_rate;
+
+	if (!(readl(divider->reg) & BIT(3))) {
+		val = (int)(divider->initval);
+	} else {
+		val = readl(divider->reg) >> divider->shift;
+		val &= clk_div_mask(divider->width);
+	}
+
+	ret_rate = divider_recalc_rate(hw, parent_rate, val, NULL,
+				       divider->div_flags, divider->width);
+
+	pr_debug("--> %s: divider_recalc_rate: ret_rate = %ld\n",
+		 clk_hw_get_name(hw), ret_rate);
+	return ret_rate;
+}
+
+static long sg2042_clk_divider_round_rate(struct clk_hw *hw,
+					  unsigned long rate,
+					  unsigned long *prate)
+{
+	int bestdiv;
+	unsigned long ret_rate;
+	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
+
+	/* if read only, just return current value */
+	if (divider->div_flags & CLK_DIVIDER_READ_ONLY) {
+		if (!(readl(divider->reg) & BIT(3))) {
+			bestdiv = (int)(divider->initval);
+		} else {
+			bestdiv = readl(divider->reg) >> divider->shift;
+			bestdiv &= clk_div_mask(divider->width);
+		}
+		ret_rate = DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
+	} else {
+		ret_rate = divider_round_rate(hw, rate, prate, NULL,
+					      divider->width, divider->div_flags);
+	}
+
+	pr_debug("--> %s: divider_round_rate: val = %ld\n",
+		 clk_hw_get_name(hw), ret_rate);
+	return ret_rate;
+}
+
+static int sg2042_clk_divider_set_rate(struct clk_hw *hw,
+				       unsigned long rate,
+				       unsigned long parent_rate)
+{
+	unsigned int value;
+	unsigned int val, val2;
+	unsigned long flags = 0;
+	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
+
+	value = divider_get_val(rate, parent_rate, NULL,
+				divider->width, divider->div_flags);
+
+	if (divider->lock)
+		spin_lock_irqsave(divider->lock, flags);
+	else
+		__acquire(divider->lock);
+
+	/*
+	 * The sequence of clock frequency modification is:
+	 * Assert to reset divider.
+	 * Modify the value of Clock Divide Factor (and High Wide if needed).
+	 * De-assert to restore divided clock with new frequency.
+	 */
+	val = readl(divider->reg);
+
+	/* assert */
+	val &= ~0x1;
+	writel(val, divider->reg);
+
+	if (divider->div_flags & CLK_DIVIDER_HIWORD_MASK) {
+		val = clk_div_mask(divider->width) << (divider->shift + 16);
+	} else {
+		val = readl(divider->reg);
+		val &= ~(clk_div_mask(divider->width) << divider->shift);
+	}
+	val |= value << divider->shift;
+	val |= 1 << 3;
+	writel(val, divider->reg);
+	val2 = val;
+
+	/* de-assert */
+	val |= 1;
+	writel(val, divider->reg);
+
+	if (divider->lock)
+		spin_unlock_irqrestore(divider->lock, flags);
+	else
+		__release(divider->lock);
+
+	pr_debug("--> %s: divider_set_rate: register val = 0x%x\n",
+		 clk_hw_get_name(hw), val2);
+	return 0;
+}
+
+static const struct clk_ops sg2042_clk_divider_ops = {
+	.recalc_rate = sg2042_clk_divider_recalc_rate,
+	.round_rate = sg2042_clk_divider_round_rate,
+	.set_rate = sg2042_clk_divider_set_rate,
+};
+
+static const struct clk_ops sg2042_clk_divider_ro_ops = {
+	.recalc_rate = sg2042_clk_divider_recalc_rate,
+	.round_rate = sg2042_clk_divider_round_rate,
+};
+
+#define SG2042_PLL(_id, _name, _parent_name, _r_stat, _r_enable, _r_ctrl, _shift) \
+	{								\
+		.hw.init = CLK_HW_INIT(					\
+				_name,					\
+				_parent_name,				\
+				&sg2042_clk_pll_ops,			\
+				CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE),\
+		.id = _id,						\
+		.offset_ctrl = _r_ctrl,					\
+		.offset_status = _r_stat,				\
+		.offset_enable = _r_enable,				\
+		.shift_status_lock = 8 + (_shift),			\
+		.shift_status_updating = _shift,			\
+		.shift_enable = _shift,					\
+	}
+
+#define SG2042_PLL_RO(_id, _name, _parent_name, _r_stat, _r_enable, _r_ctrl, _shift) \
+	{								\
+		.hw.init = CLK_HW_INIT(					\
+				_name,					\
+				_parent_name,				\
+				&sg2042_clk_pll_ro_ops,			\
+				CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE),\
+		.id = _id,						\
+		.offset_ctrl = _r_ctrl,					\
+		.offset_status = _r_stat,				\
+		.offset_enable = _r_enable,				\
+		.shift_status_lock = 8 + (_shift),			\
+		.shift_status_updating = _shift,			\
+		.shift_enable = _shift,					\
+	}
+
+static struct sg2042_pll_clock sg2042_pll_clks[] = {
+	SG2042_PLL(MPLL_CLK, "mpll_clock", "cgi_main",
+		   R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_MPLL_CONTROL, 0),
+	SG2042_PLL_RO(FPLL_CLK, "fpll_clock", "cgi_main",
+		      R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_FPLL_CONTROL, 3),
+	SG2042_PLL_RO(DPLL0_CLK, "dpll0_clock", "cgi_dpll0",
+		      R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_DPLL0_CONTROL, 4),
+	SG2042_PLL_RO(DPLL1_CLK, "dpll1_clock", "cgi_dpll1",
+		      R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_DPLL1_CONTROL, 5),
+};
+
+#define SG2042_DIV(_id, _name, _parent_name,				\
+		  _r_ctrl, _shift, _width,				\
+		  _div_flag, _initval) {				\
+		.hw.init = CLK_HW_INIT(					\
+				_name,					\
+				_parent_name,				\
+				&sg2042_clk_divider_ops,		\
+				0),					\
+		.id = _id,						\
+		.offset_ctrl = _r_ctrl,					\
+		.shift = _shift,					\
+		.width = _width,					\
+		.div_flags = _div_flag,					\
+		.initval = _initval,					\
+	}
+
+#define SG2042_DIV_RO(_id, _name, _parent_name,				\
+		  _r_ctrl, _shift, _width,				\
+		  _div_flag, _initval) {				\
+		.hw.init = CLK_HW_INIT(					\
+				_name,					\
+				_parent_name,				\
+				&sg2042_clk_divider_ro_ops,		\
+				0),					\
+		.id = _id,						\
+		.offset_ctrl = _r_ctrl,					\
+		.shift = _shift,					\
+		.width = _width,					\
+		.div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY,	\
+		.initval = _initval,					\
+	}
+
+/*
+ * DIV items in the array are sorted according to the clock-tree diagram,
+ * from top to bottom, from upstream to downstream. Read TRM for details.
+ */
+#define DEF_DIVFLAG (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO)
+static struct sg2042_divider_clock sg2042_div_clks[] = {
+	SG2042_DIV_RO(DIV_CLK_DPLL0_DDR01_0,
+		      "clk_div_ddr01_0", "clk_gate_ddr01_div0",
+		      R_CLKDIVREG27, 16, 5, DEF_DIVFLAG, 1),
+	SG2042_DIV_RO(DIV_CLK_FPLL_DDR01_1,
+		      "clk_div_ddr01_1", "clk_gate_ddr01_div1",
+		      R_CLKDIVREG28, 16, 5, DEF_DIVFLAG, 1),
+
+	SG2042_DIV_RO(DIV_CLK_DPLL1_DDR23_0,
+		      "clk_div_ddr23_0", "clk_gate_ddr23_div0",
+		      R_CLKDIVREG29, 16, 5, DEF_DIVFLAG, 1),
+	SG2042_DIV_RO(DIV_CLK_FPLL_DDR23_1,
+		      "clk_div_ddr23_1", "clk_gate_ddr23_div1",
+		      R_CLKDIVREG30, 16, 5, DEF_DIVFLAG, 1),
+
+	SG2042_DIV(DIV_CLK_MPLL_RP_CPU_NORMAL_0,
+		   "clk_div_rp_cpu_normal_0", "clk_gate_rp_cpu_normal_div0",
+		   R_CLKDIVREG0, 16, 5, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_RP_CPU_NORMAL_1,
+		   "clk_div_rp_cpu_normal_1", "clk_gate_rp_cpu_normal_div1",
+		   R_CLKDIVREG1, 16, 5, DEF_DIVFLAG, 1),
+
+	SG2042_DIV(DIV_CLK_MPLL_AXI_DDR_0,
+		   "clk_div_axi_ddr_0", "clk_gate_axi_ddr_div0",
+		   R_CLKDIVREG25, 16, 5, DEF_DIVFLAG, 2),
+	SG2042_DIV(DIV_CLK_FPLL_AXI_DDR_1,
+		   "clk_div_axi_ddr_1", "clk_gate_axi_ddr_div1",
+		   R_CLKDIVREG26, 16, 5, DEF_DIVFLAG, 1),
+
+	SG2042_DIV(DIV_CLK_FPLL_TOP_RP_CMN_DIV2,
+		   "clk_div_top_rp_cmn_div2", "clk_mux_rp_cpu_normal",
+		   R_CLKDIVREG3, 16, 16, DEF_DIVFLAG, 2),
+
+	SG2042_DIV(DIV_CLK_FPLL_50M_A53, "clk_div_50m_a53", "fpll_clock",
+		   R_CLKDIVREG2, 16, 8, DEF_DIVFLAG, 20),
+	/* downstream of div_50m_a53 */
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER1, "clk_div_timer1", "clk_div_50m_a53",
+		   R_CLKDIVREG6, 16, 16, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER2, "clk_div_timer2", "clk_div_50m_a53",
+		   R_CLKDIVREG7, 16, 16, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER3, "clk_div_timer3", "clk_div_50m_a53",
+		   R_CLKDIVREG8, 16, 16, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER4, "clk_div_timer4", "clk_div_50m_a53",
+		   R_CLKDIVREG9, 16, 16, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER5, "clk_div_timer5", "clk_div_50m_a53",
+		   R_CLKDIVREG10, 16, 16, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER6, "clk_div_timer6", "clk_div_50m_a53",
+		   R_CLKDIVREG11, 16, 16, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER7, "clk_div_timer7", "clk_div_50m_a53",
+		   R_CLKDIVREG12, 16, 16, DEF_DIVFLAG, 1),
+	SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER8, "clk_div_timer8", "clk_div_50m_a53",
+		   R_CLKDIVREG13, 16, 16, DEF_DIVFLAG, 1),
+
+	/*
+	 * Set clk_div_uart_500m as RO, because the width of CLKDIVREG4 is too
+	 * narrow for us to produce 115200. Use UART internal divider directly.
+	 */
+	SG2042_DIV_RO(DIV_CLK_FPLL_UART_500M, "clk_div_uart_500m", "fpll_clock",
+		      R_CLKDIVREG4, 16, 7, DEF_DIVFLAG, 2),
+	SG2042_DIV(DIV_CLK_FPLL_AHB_LPC, "clk_div_ahb_lpc", "fpll_clock",
+		   R_CLKDIVREG5, 16, 16, DEF_DIVFLAG, 5),
+	SG2042_DIV(DIV_CLK_FPLL_EFUSE, "clk_div_efuse", "fpll_clock",
+		   R_CLKDIVREG14, 16, 7, DEF_DIVFLAG, 40),
+	SG2042_DIV(DIV_CLK_FPLL_TX_ETH0, "clk_div_tx_eth0", "fpll_clock",
+		   R_CLKDIVREG16, 16, 11, DEF_DIVFLAG, 8),
+	SG2042_DIV(DIV_CLK_FPLL_PTP_REF_I_ETH0,
+		   "clk_div_ptp_ref_i_eth0", "fpll_clock",
+		   R_CLKDIVREG17, 16, 8, DEF_DIVFLAG, 20),
+	SG2042_DIV(DIV_CLK_FPLL_REF_ETH0, "clk_div_ref_eth0", "fpll_clock",
+		   R_CLKDIVREG18, 16, 8, DEF_DIVFLAG, 40),
+	SG2042_DIV(DIV_CLK_FPLL_EMMC, "clk_div_emmc", "fpll_clock",
+		   R_CLKDIVREG19, 16, 5, DEF_DIVFLAG, 10),
+	SG2042_DIV(DIV_CLK_FPLL_SD, "clk_div_sd", "fpll_clock",
+		   R_CLKDIVREG21, 16, 5, DEF_DIVFLAG, 10),
+
+	SG2042_DIV(DIV_CLK_FPLL_TOP_AXI0, "clk_div_top_axi0", "fpll_clock",
+		   R_CLKDIVREG23, 16, 5, DEF_DIVFLAG, 10),
+	/* downstream of div_top_axi0 */
+	SG2042_DIV(DIV_CLK_FPLL_100K_EMMC, "clk_div_100k_emmc", "clk_div_top_axi0",
+		   R_CLKDIVREG20, 16, 16, DEF_DIVFLAG, 1000),
+	SG2042_DIV(DIV_CLK_FPLL_100K_SD, "clk_div_100k_sd", "clk_div_top_axi0",
+		   R_CLKDIVREG22, 16, 16, DEF_DIVFLAG, 1000),
+	SG2042_DIV(DIV_CLK_FPLL_GPIO_DB, "clk_div_gpio_db", "clk_div_top_axi0",
+		   R_CLKDIVREG15, 16, 16, DEF_DIVFLAG, 1000),
+
+	SG2042_DIV(DIV_CLK_FPLL_TOP_AXI_HSPERI,
+		   "clk_div_top_axi_hsperi", "fpll_clock",
+		   R_CLKDIVREG24, 16, 5, DEF_DIVFLAG, 4),
+};
+
+#define SG2042_GATE(_id, _name, _parent_name, _flags,	\
+		    _r_enable, _bit_idx) {		\
+		.hw.init = CLK_HW_INIT(			\
+				_name,			\
+				_parent_name,		\
+				NULL,			\
+				_flags),		\
+		.id = _id,				\
+		.offset_enable = _r_enable,		\
+		.bit_idx = _bit_idx,			\
+	}
+
+/*
+ * GATE items in the array are sorted according to the clock-tree diagram,
+ * from top to bottom, from upstream to downstream. Read TRM for details.
+ */
+
+/* Gate clocks which control registers are defined in CLOCK. */
+static const struct sg2042_gate_clock sg2042_gate_clks[] = {
+	SG2042_GATE(GATE_CLK_DDR01_DIV0, "clk_gate_ddr01_div0", "dpll0_clock",
+		    CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		    R_CLKDIVREG27, 4),
+	SG2042_GATE(GATE_CLK_DDR01_DIV1, "clk_gate_ddr01_div1", "fpll_clock",
+		    CLK_IS_CRITICAL,
+		    R_CLKDIVREG28, 4),
+
+	SG2042_GATE(GATE_CLK_DDR23_DIV0, "clk_gate_ddr23_div0", "dpll1_clock",
+		    CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		    R_CLKDIVREG29, 4),
+	SG2042_GATE(GATE_CLK_DDR23_DIV1, "clk_gate_ddr23_div1", "fpll_clock",
+		    CLK_IS_CRITICAL,
+		    R_CLKDIVREG30, 4),
+
+	SG2042_GATE(GATE_CLK_RP_CPU_NORMAL_DIV0, "clk_gate_rp_cpu_normal_div0", "mpll_clock",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKDIVREG0, 4),
+	SG2042_GATE(GATE_CLK_RP_CPU_NORMAL_DIV1,
+		    "clk_gate_rp_cpu_normal_div1", "fpll_clock",
+		    CLK_IS_CRITICAL,
+		    R_CLKDIVREG1, 4),
+
+	SG2042_GATE(GATE_CLK_AXI_DDR_DIV0, "clk_gate_axi_ddr_div0", "mpll_clock",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKDIVREG25, 4),
+	SG2042_GATE(GATE_CLK_AXI_DDR_DIV1, "clk_gate_axi_ddr_div1", "fpll_clock",
+		    CLK_IS_CRITICAL,
+		    R_CLKDIVREG26, 4),
+
+	/* upon are gate clocks as input source for the muxes */
+
+	SG2042_GATE(GATE_CLK_DDR01, "clk_gate_ddr01", "clk_mux_ddr01",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKENREG1, 14),
+
+	SG2042_GATE(GATE_CLK_DDR23, "clk_gate_ddr23", "clk_mux_ddr23",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKENREG1, 15),
+
+	SG2042_GATE(GATE_CLK_RP_CPU_NORMAL,
+		    "clk_gate_rp_cpu_normal", "clk_mux_rp_cpu_normal",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKENREG0, 0),
+
+	SG2042_GATE(GATE_CLK_AXI_DDR, "clk_gate_axi_ddr", "clk_mux_axi_ddr",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKENREG1, 13),
+
+	/* upon are gate clocks directly downstream of muxes */
+
+	/* downstream of clk_div_top_rp_cmn_div2 */
+	SG2042_GATE(GATE_CLK_TOP_RP_CMN_DIV2,
+		    "clk_gate_top_rp_cmn_div2", "clk_div_top_rp_cmn_div2",
+		    CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 2),
+	SG2042_GATE(GATE_CLK_HSDMA, "clk_gate_hsdma", "clk_gate_top_rp_cmn_div2",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 10),
+
+	/*
+	 * downstream of clk_gate_rp_cpu_normal
+	 *
+	 * FIXME: there should be one 1/2 DIV between clk_gate_rp_cpu_normal
+	 * and clk_gate_axi_pcie0/clk_gate_axi_pcie1.
+	 * But the 1/2 DIV is fixed and no configurable register exported, so
+	 * when reading from these two clocks, the rate value are still the
+	 * same as that of clk_gate_rp_cpu_normal, it's not correct.
+	 * This just affects the value read.
+	 */
+	SG2042_GATE(GATE_CLK_AXI_PCIE0,
+		    "clk_gate_axi_pcie0", "clk_gate_rp_cpu_normal",
+		    CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG1, 8),
+	SG2042_GATE(GATE_CLK_AXI_PCIE1,
+		    "clk_gate_axi_pcie1", "clk_gate_rp_cpu_normal",
+		    CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG1, 9),
+
+	/* downstream of div_50m_a53 */
+	SG2042_GATE(GATE_CLK_A53_50M, "clk_gate_a53_50m", "clk_div_50m_a53",
+		    CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 1),
+	SG2042_GATE(GATE_CLK_TIMER1, "clk_gate_timer1", "clk_div_timer1",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 12),
+	SG2042_GATE(GATE_CLK_TIMER2, "clk_gate_timer2", "clk_div_timer2",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 13),
+	SG2042_GATE(GATE_CLK_TIMER3, "clk_gate_timer3", "clk_div_timer3",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 14),
+	SG2042_GATE(GATE_CLK_TIMER4, "clk_gate_timer4", "clk_div_timer4",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 15),
+	SG2042_GATE(GATE_CLK_TIMER5, "clk_gate_timer5", "clk_div_timer5",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 16),
+	SG2042_GATE(GATE_CLK_TIMER6, "clk_gate_timer6", "clk_div_timer6",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 17),
+	SG2042_GATE(GATE_CLK_TIMER7, "clk_gate_timer7", "clk_div_timer7",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 18),
+	SG2042_GATE(GATE_CLK_TIMER8, "clk_gate_timer8", "clk_div_timer8",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 19),
+
+	/* gate clocks downstream from div clocks one-to-one */
+	SG2042_GATE(GATE_CLK_UART_500M, "clk_gate_uart_500m", "clk_div_uart_500m",
+		    CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 4),
+	SG2042_GATE(GATE_CLK_AHB_LPC, "clk_gate_ahb_lpc", "clk_div_ahb_lpc",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 7),
+	SG2042_GATE(GATE_CLK_EFUSE, "clk_gate_efuse", "clk_div_efuse",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 20),
+	SG2042_GATE(GATE_CLK_TX_ETH0, "clk_gate_tx_eth0", "clk_div_tx_eth0",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 30),
+	SG2042_GATE(GATE_CLK_PTP_REF_I_ETH0,
+		    "clk_gate_ptp_ref_i_eth0", "clk_div_ptp_ref_i_eth0",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 0),
+	SG2042_GATE(GATE_CLK_REF_ETH0, "clk_gate_ref_eth0", "clk_div_ref_eth0",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 1),
+	SG2042_GATE(GATE_CLK_EMMC_100M, "clk_gate_emmc", "clk_div_emmc",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 3),
+	SG2042_GATE(GATE_CLK_SD_100M, "clk_gate_sd", "clk_div_sd",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 6),
+
+	/* downstream of clk_div_top_axi0 */
+	SG2042_GATE(GATE_CLK_AHB_ROM, "clk_gate_ahb_rom", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 8),
+	SG2042_GATE(GATE_CLK_AHB_SF, "clk_gate_ahb_sf", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 9),
+	SG2042_GATE(GATE_CLK_AXI_SRAM, "clk_gate_axi_sram", "clk_div_top_axi0",
+		    CLK_IGNORE_UNUSED, R_CLKENREG0, 10),
+	SG2042_GATE(GATE_CLK_APB_TIMER, "clk_gate_apb_timer", "clk_div_top_axi0",
+		    CLK_IGNORE_UNUSED, R_CLKENREG0, 11),
+	SG2042_GATE(GATE_CLK_APB_EFUSE, "clk_gate_apb_efuse", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 21),
+	SG2042_GATE(GATE_CLK_APB_GPIO, "clk_gate_apb_gpio", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 22),
+	SG2042_GATE(GATE_CLK_APB_GPIO_INTR,
+		    "clk_gate_apb_gpio_intr", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 23),
+	SG2042_GATE(GATE_CLK_APB_I2C, "clk_gate_apb_i2c", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 26),
+	SG2042_GATE(GATE_CLK_APB_WDT, "clk_gate_apb_wdt", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 27),
+	SG2042_GATE(GATE_CLK_APB_PWM, "clk_gate_apb_pwm", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 28),
+	SG2042_GATE(GATE_CLK_APB_RTC, "clk_gate_apb_rtc", "clk_div_top_axi0",
+		    0, R_CLKENREG0, 29),
+	SG2042_GATE(GATE_CLK_TOP_AXI0, "clk_gate_top_axi0", "clk_div_top_axi0",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKENREG1, 11),
+	/* downstream of DIV clocks which are sourced from clk_div_top_axi0 */
+	SG2042_GATE(GATE_CLK_GPIO_DB, "clk_gate_gpio_db", "clk_div_gpio_db",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 24),
+	SG2042_GATE(GATE_CLK_100K_EMMC, "clk_gate_100k_emmc", "clk_div_100k_emmc",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 4),
+	SG2042_GATE(GATE_CLK_100K_SD, "clk_gate_100k_sd", "clk_div_100k_sd",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 7),
+
+	/* downstream of clk_div_top_axi_hsperi */
+	SG2042_GATE(GATE_CLK_SYSDMA_AXI,
+		    "clk_gate_sysdma_axi", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 3),
+	SG2042_GATE(GATE_CLK_APB_UART,
+		    "clk_gate_apb_uart", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 5),
+	SG2042_GATE(GATE_CLK_AXI_DBG_I2C,
+		    "clk_gate_axi_dbg_i2c", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 6),
+	SG2042_GATE(GATE_CLK_APB_SPI,
+		    "clk_gate_apb_spi", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 25),
+	SG2042_GATE(GATE_CLK_AXI_ETH0,
+		    "clk_gate_axi_eth0", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT, R_CLKENREG0, 31),
+	SG2042_GATE(GATE_CLK_AXI_EMMC,
+		    "clk_gate_axi_emmc", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 2),
+	SG2042_GATE(GATE_CLK_AXI_SD,
+		    "clk_gate_axi_sd", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT, R_CLKENREG1, 5),
+	SG2042_GATE(GATE_CLK_TOP_AXI_HSPERI,
+		    "clk_gate_top_axi_hsperi", "clk_div_top_axi_hsperi",
+		    CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+		    R_CLKENREG1, 12),
+};
+
+/*
+ * Gate clocks for RP subsystem (including the MP subsystem), which control
+ * registers are defined in SYS_CTRL.
+ */
+static const struct sg2042_gate_clock sg2042_gate_rp[] = {
+	/* downstream of clk_gate_rp_cpu_normal about rxu */
+	SG2042_GATE(GATE_CLK_RXU0, "clk_gate_rxu0", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 0),
+	SG2042_GATE(GATE_CLK_RXU1, "clk_gate_rxu1", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 1),
+	SG2042_GATE(GATE_CLK_RXU2, "clk_gate_rxu2", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 2),
+	SG2042_GATE(GATE_CLK_RXU3, "clk_gate_rxu3", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 3),
+	SG2042_GATE(GATE_CLK_RXU4, "clk_gate_rxu4", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 4),
+	SG2042_GATE(GATE_CLK_RXU5, "clk_gate_rxu5", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 5),
+	SG2042_GATE(GATE_CLK_RXU6, "clk_gate_rxu6", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 6),
+	SG2042_GATE(GATE_CLK_RXU7, "clk_gate_rxu7", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 7),
+	SG2042_GATE(GATE_CLK_RXU8, "clk_gate_rxu8", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 8),
+	SG2042_GATE(GATE_CLK_RXU9, "clk_gate_rxu9", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 9),
+	SG2042_GATE(GATE_CLK_RXU10, "clk_gate_rxu10", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 10),
+	SG2042_GATE(GATE_CLK_RXU11, "clk_gate_rxu11", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 11),
+	SG2042_GATE(GATE_CLK_RXU12, "clk_gate_rxu12", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 12),
+	SG2042_GATE(GATE_CLK_RXU13, "clk_gate_rxu13", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 13),
+	SG2042_GATE(GATE_CLK_RXU14, "clk_gate_rxu14", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 14),
+	SG2042_GATE(GATE_CLK_RXU15, "clk_gate_rxu15", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 15),
+	SG2042_GATE(GATE_CLK_RXU16, "clk_gate_rxu16", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 16),
+	SG2042_GATE(GATE_CLK_RXU17, "clk_gate_rxu17", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 17),
+	SG2042_GATE(GATE_CLK_RXU18, "clk_gate_rxu18", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 18),
+	SG2042_GATE(GATE_CLK_RXU19, "clk_gate_rxu19", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 19),
+	SG2042_GATE(GATE_CLK_RXU20, "clk_gate_rxu20", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 20),
+	SG2042_GATE(GATE_CLK_RXU21, "clk_gate_rxu21", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 21),
+	SG2042_GATE(GATE_CLK_RXU22, "clk_gate_rxu22", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 22),
+	SG2042_GATE(GATE_CLK_RXU23, "clk_gate_rxu23", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 23),
+	SG2042_GATE(GATE_CLK_RXU24, "clk_gate_rxu24", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 24),
+	SG2042_GATE(GATE_CLK_RXU25, "clk_gate_rxu25", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 25),
+	SG2042_GATE(GATE_CLK_RXU26, "clk_gate_rxu26", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 26),
+	SG2042_GATE(GATE_CLK_RXU27, "clk_gate_rxu27", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 27),
+	SG2042_GATE(GATE_CLK_RXU28, "clk_gate_rxu28", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 28),
+	SG2042_GATE(GATE_CLK_RXU29, "clk_gate_rxu29", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 29),
+	SG2042_GATE(GATE_CLK_RXU30, "clk_gate_rxu30", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 30),
+	SG2042_GATE(GATE_CLK_RXU31, "clk_gate_rxu31", "clk_gate_rp_cpu_normal",
+		    0, R_RP_RXU_CLK_ENABLE, 31),
+
+	/* downstream of clk_gate_rp_cpu_normal about mp */
+	SG2042_GATE(GATE_CLK_MP0, "clk_gate_mp0", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP0_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP1, "clk_gate_mp1", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP1_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP2, "clk_gate_mp2", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP2_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP3, "clk_gate_mp3", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP3_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP4, "clk_gate_mp4", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP4_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP5, "clk_gate_mp5", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP5_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP6, "clk_gate_mp6", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP6_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP7, "clk_gate_mp7", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP7_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP8, "clk_gate_mp8", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP8_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP9, "clk_gate_mp9", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP9_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP10, "clk_gate_mp10", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP10_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP11, "clk_gate_mp11", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP11_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP12, "clk_gate_mp12", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP12_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP13, "clk_gate_mp13", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP13_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP14, "clk_gate_mp14", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP14_CONTROL_REG, 0),
+	SG2042_GATE(GATE_CLK_MP15, "clk_gate_mp15", "clk_gate_rp_cpu_normal",
+		    CLK_IS_CRITICAL, R_MP15_CONTROL_REG, 0),
+};
+
+#define SG2042_MUX(_id, _name, _parent_names, _flags, _r_select, _shift, _width) { \
+		.hw.init = CLK_HW_INIT_PARENTS(			\
+				_name,				\
+				_parent_names,			\
+				NULL,				\
+				_flags),			\
+		.id = _id,					\
+		.offset_select = _r_select,			\
+		.shift = _shift,				\
+		.width = _width,				\
+	}
+
+/*
+ * Note: regarding names for mux clock, "0/1" or "div0/div1" means the
+ * first/second parent input source, not the register value.
+ * For example:
+ * "clk_div_ddr01_0" is the name of Clock divider 0 control of DDR01, and
+ * "clk_gate_ddr01_div0" is the gate clock in front of the "clk_div_ddr01_0",
+ * they are both controlled by register CLKDIVREG27;
+ * "clk_div_ddr01_1" is the name of Clock divider 1 control of DDR01, and
+ * "clk_gate_ddr01_div1" is the gate clock in front of the "clk_div_ddr01_1",
+ * they are both controlled by register CLKDIVREG28;
+ * While for register value of mux selection, use Clock Select for DDR01’s clock
+ * as example, see CLKSELREG0, bit[2].
+ * 1: Select in_dpll0_clk as clock source, correspondng to the parent input
+ *    source from "clk_div_ddr01_0".
+ * 0: Select in_fpll_clk as clock source, corresponding to the parent input
+ *    source from "clk_div_ddr01_1".
+ * So we need a table to define the array of register values corresponding to
+ * the parent index and tell CCF about this when registering mux clock.
+ */
+static const u32 sg2042_mux_table[] = {1, 0};
+
+static const char *const clk_mux_ddr01_p[] = {
+			"clk_div_ddr01_0", "clk_div_ddr01_1"};
+static const char *const clk_mux_ddr23_p[] = {
+			"clk_div_ddr23_0", "clk_div_ddr23_1"};
+static const char *const clk_mux_rp_cpu_normal_p[] = {
+			"clk_div_rp_cpu_normal_0", "clk_div_rp_cpu_normal_1"};
+static const char *const clk_mux_axi_ddr_p[] = {
+			"clk_div_axi_ddr_0", "clk_div_axi_ddr_1"};
+
+static struct sg2042_mux_clock sg2042_mux_clks[] = {
+	SG2042_MUX(MUX_CLK_DDR01, "clk_mux_ddr01", clk_mux_ddr01_p,
+		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_MUX_READ_ONLY,
+		   R_CLKSELREG0, 2, 1),
+	SG2042_MUX(MUX_CLK_DDR23, "clk_mux_ddr23", clk_mux_ddr23_p,
+		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_MUX_READ_ONLY,
+		   R_CLKSELREG0, 3, 1),
+	SG2042_MUX(MUX_CLK_RP_CPU_NORMAL, "clk_mux_rp_cpu_normal", clk_mux_rp_cpu_normal_p,
+		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+		   R_CLKSELREG0, 0, 1),
+	SG2042_MUX(MUX_CLK_AXI_DDR, "clk_mux_axi_ddr", clk_mux_axi_ddr_p,
+		   CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+		   R_CLKSELREG0, 1, 1),
+};
+
+static DEFINE_SPINLOCK(sg2042_clk_lock);
+
+static int sg2042_clk_register_plls(struct sg2042_clk_data *clk_data,
+				    struct sg2042_pll_clock pll_clks[],
+				    int num_pll_clks)
+{
+	struct clk_hw *hw;
+	struct sg2042_pll_clock *pll;
+	int i, ret = 0;
+
+	for (i = 0; i < num_pll_clks; i++) {
+		pll = &pll_clks[i];
+		/* assign these for ops usage during registration */
+		pll->base = clk_data->iobase;
+		pll->lock = &sg2042_clk_lock;
+
+		hw = &pll->hw;
+		ret = clk_hw_register(NULL, hw);
+		if (ret) {
+			pr_err("failed to register clock %s\n", pll->hw.init->name);
+			break;
+		}
+
+		clk_data->onecell_data.hws[pll->id] = hw;
+	}
+
+	/* leave unregister to outside if failed */
+	return ret;
+}
+
+static int sg2042_clk_register_divs(struct sg2042_clk_data *clk_data,
+				    struct sg2042_divider_clock div_clks[],
+				    int num_div_clks)
+{
+	struct clk_hw *hw;
+	struct sg2042_divider_clock *div;
+	int i, ret = 0;
+
+	for (i = 0; i < num_div_clks; i++) {
+		div = &div_clks[i];
+
+		if (div->div_flags & CLK_DIVIDER_HIWORD_MASK) {
+			if (div->width + div->shift > 16) {
+				pr_warn("divider value exceeds LOWORD field\n");
+				ret = -EINVAL;
+				break;
+			}
+		}
+
+		div->reg = clk_data->iobase + div->offset_ctrl;
+		div->lock = &sg2042_clk_lock;
+
+		hw = &div->hw;
+		ret = clk_hw_register(NULL, hw);
+		if (ret) {
+			pr_err("failed to register clock %s\n", div->hw.init->name);
+			break;
+		}
+
+		clk_data->onecell_data.hws[div->id] = hw;
+	}
+
+	/* leave unregister to outside if failed */
+	return ret;
+}
+
+static int sg2042_clk_register_gates(struct sg2042_clk_data *clk_data,
+				     const struct sg2042_gate_clock gate_clks[],
+				     int num_gate_clks)
+{
+	struct clk_hw *hw;
+	const struct sg2042_gate_clock *gate;
+	int i, ret = 0;
+
+	for (i = 0; i < num_gate_clks; i++) {
+		gate = &gate_clks[i];
+		hw = clk_hw_register_gate(NULL,
+					  gate->hw.init->name,
+					  gate->hw.init->parent_names[0],
+					  gate->hw.init->flags,
+					  clk_data->iobase + gate->offset_enable,
+					  gate->bit_idx,
+					  0,
+					  &sg2042_clk_lock);
+		if (IS_ERR(hw)) {
+			pr_err("failed to register clock %s\n", gate->hw.init->name);
+			ret = PTR_ERR(hw);
+			break;
+		}
+
+		clk_data->onecell_data.hws[gate->id] = hw;
+	}
+
+	/* leave unregister to outside if failed */
+	return ret;
+}
+
+static int sg2042_mux_notifier_cb(struct notifier_block *nb,
+				  unsigned long event,
+				  void *data)
+{
+	int ret = 0;
+	struct clk_notifier_data *ndata = data;
+	struct clk_hw *hw = __clk_get_hw(ndata->clk);
+	const struct clk_ops *ops = &clk_mux_ops;
+	struct sg2042_mux_clock *mux = to_sg2042_mux_nb(nb);
+
+	/* To switch to fpll before changing rate and restore after that */
+	if (event == PRE_RATE_CHANGE) {
+		mux->original_index = ops->get_parent(hw);
+
+		/*
+		 * "1" is the array index of the second parent input source of
+		 * mux. For SG2042, it's fpll for all mux clocks.
+		 * "0" is the array index of the frist parent input source of
+		 * mux, For SG2042, it's mpll.
+		 * FIXME, any good idea to avoid magic number?
+		 */
+		if (mux->original_index == 0)
+			ret = ops->set_parent(hw, 1);
+	} else if (event == POST_RATE_CHANGE) {
+		ret = ops->set_parent(hw, mux->original_index);
+	}
+
+	return notifier_from_errno(ret);
+}
+
+static int sg2042_clk_register_muxs(struct sg2042_clk_data *clk_data,
+				    struct sg2042_mux_clock mux_clks[],
+				    int num_mux_clks)
+{
+	struct clk_hw *hw;
+	struct sg2042_mux_clock *mux;
+	int i, ret = 0;
+
+	for (i = 0; i < num_mux_clks; i++) {
+		mux = &mux_clks[i];
+
+		hw = clk_hw_register_mux_table(NULL,
+					       mux->hw.init->name,
+					       mux->hw.init->parent_names,
+					       mux->hw.init->num_parents,
+					       mux->hw.init->flags,
+					       clk_data->iobase + mux->offset_select,
+					       mux->shift,
+					       BIT(mux->width) - 1,
+					       0,
+					       sg2042_mux_table,
+					       &sg2042_clk_lock);
+		if (IS_ERR(hw)) {
+			pr_err("failed to register clock %s\n", mux->hw.init->name);
+			ret = PTR_ERR(hw);
+			break;
+		}
+
+		clk_data->onecell_data.hws[mux->id] = hw;
+
+		/*
+		 * FIXME: Theoretically, we should set parent for the
+		 * mux, but seems hardware has done this for us with
+		 * default value, so we don't set parent again here.
+		 */
+
+		if (!(mux->hw.init->flags & CLK_MUX_READ_ONLY)) {
+			mux->clk_nb.notifier_call = sg2042_mux_notifier_cb;
+			ret = clk_notifier_register(hw->clk, &mux->clk_nb);
+			if (ret) {
+				pr_err("failed to register clock notifier for %s\n",
+				       mux->hw.init->name);
+				goto error_cleanup;
+			}
+		}
+	}
+
+	return 0;
+
+error_cleanup:
+	/* unregister notifier and release the memory allocated */
+	for (i = 0; i < num_mux_clks; i++) {
+		mux = &mux_clks[i];
+
+		hw = clk_data->onecell_data.hws[mux->id];
+
+		if (hw)
+			clk_notifier_unregister(hw->clk, &mux->clk_nb);
+	}
+
+	/* leave clk unregister to outside if failed */
+	return ret;
+}
+
+static int sg2042_init_clkdata(struct platform_device *pdev,
+			       int num_clks,
+			       struct sg2042_clk_data **pp_clk_data)
+{
+	struct sg2042_clk_data *clk_data = NULL;
+
+	clk_data = devm_kzalloc(&pdev->dev,
+				struct_size(clk_data, onecell_data.hws, num_clks),
+				GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	clk_data->iobase = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
+	if (WARN_ON(IS_ERR(clk_data->iobase)))
+		return PTR_ERR(clk_data->iobase);
+
+	clk_data->onecell_data.num = num_clks;
+
+	*pp_clk_data = clk_data;
+
+	return 0;
+}
+
+static int sg2042_clkgen_probe(struct platform_device *pdev)
+{
+	struct sg2042_clk_data *clk_data = NULL;
+	int i, ret = 0;
+	int num_clks = 0;
+
+	num_clks = ARRAY_SIZE(sg2042_div_clks) +
+		   ARRAY_SIZE(sg2042_gate_clks) +
+		   ARRAY_SIZE(sg2042_mux_clks);
+	if (num_clks == 0) {
+		ret = -EINVAL;
+		goto error_out;
+	}
+
+	ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);
+	if (ret < 0)
+		goto error_out;
+
+	ret = sg2042_clk_register_divs(clk_data, sg2042_div_clks,
+				       ARRAY_SIZE(sg2042_div_clks));
+	if (ret)
+		goto cleanup;
+
+	ret = sg2042_clk_register_gates(clk_data, sg2042_gate_clks,
+					ARRAY_SIZE(sg2042_gate_clks));
+	if (ret)
+		goto cleanup;
+
+	ret = sg2042_clk_register_muxs(clk_data, sg2042_mux_clks,
+				       ARRAY_SIZE(sg2042_mux_clks));
+	if (ret)
+		goto cleanup;
+
+	return devm_of_clk_add_hw_provider(&pdev->dev,
+					   of_clk_hw_onecell_get,
+					   &clk_data->onecell_data);
+
+cleanup:
+	for (i = 0; i < num_clks; i++) {
+		if (clk_data->onecell_data.hws[i])
+			clk_hw_unregister(clk_data->onecell_data.hws[i]);
+	}
+
+error_out:
+	pr_err("%s failed error number %d\n", __func__, ret);
+	return ret;
+}
+
+static int sg2042_rpgate_probe(struct platform_device *pdev)
+{
+	struct sg2042_clk_data *clk_data = NULL;
+	int i, ret = 0;
+	int num_clks = 0;
+
+	num_clks = ARRAY_SIZE(sg2042_gate_rp);
+	if (num_clks == 0) {
+		ret = -EINVAL;
+		goto error_out;
+	}
+
+	ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);
+	if (ret < 0)
+		goto error_out;
+
+	ret = sg2042_clk_register_gates(clk_data, sg2042_gate_rp,
+					ARRAY_SIZE(sg2042_gate_rp));
+	if (ret)
+		goto cleanup;
+
+	return devm_of_clk_add_hw_provider(&pdev->dev,
+					   of_clk_hw_onecell_get,
+					   &clk_data->onecell_data);
+
+cleanup:
+	for (i = 0; i < num_clks; i++) {
+		if (clk_data->onecell_data.hws[i])
+			clk_hw_unregister(clk_data->onecell_data.hws[i]);
+	}
+
+error_out:
+	pr_err("%s failed error number %d\n", __func__, ret);
+	return ret;
+}
+
+static int sg2042_pll_probe(struct platform_device *pdev)
+{
+	struct sg2042_clk_data *clk_data = NULL;
+	int i, ret = 0;
+	int num_clks = 0;
+
+	num_clks = ARRAY_SIZE(sg2042_pll_clks);
+	if (num_clks == 0) {
+		ret = -EINVAL;
+		goto error_out;
+	}
+
+	ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);
+	if (ret < 0)
+		goto error_out;
+
+	ret = sg2042_clk_register_plls(clk_data, sg2042_pll_clks,
+				       ARRAY_SIZE(sg2042_pll_clks));
+	if (ret)
+		goto cleanup;
+
+	return devm_of_clk_add_hw_provider(&pdev->dev,
+					   of_clk_hw_onecell_get,
+					   &clk_data->onecell_data);
+
+cleanup:
+	for (i = 0; i < num_clks; i++) {
+		if (clk_data->onecell_data.hws[i])
+			clk_hw_unregister(clk_data->onecell_data.hws[i]);
+	}
+
+error_out:
+	pr_err("%s failed error number %d\n", __func__, ret);
+	return ret;
+}
+
+static const struct of_device_id sg2042_clkgen_match[] = {
+	{ .compatible = "sophgo,sg2042-clkgen" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver sg2042_clkgen_driver = {
+	.probe = sg2042_clkgen_probe,
+	.driver = {
+		.name = "clk-sophgo-sg2042-clkgen",
+		.of_match_table = sg2042_clkgen_match,
+		.suppress_bind_attrs = true,
+	},
+};
+builtin_platform_driver(sg2042_clkgen_driver);
+
+static const struct of_device_id sg2042_rpgate_match[] = {
+	{ .compatible = "sophgo,sg2042-rpgate" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver sg2042_rpgate_driver = {
+	.probe = sg2042_rpgate_probe,
+	.driver = {
+		.name = "clk-sophgo-sg2042-rpgate",
+		.of_match_table = sg2042_rpgate_match,
+		.suppress_bind_attrs = true,
+	},
+};
+builtin_platform_driver(sg2042_rpgate_driver);
+
+static const struct of_device_id sg2042_pll_match[] = {
+	{ .compatible = "sophgo,sg2042-pll" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver sg2042_pll_driver = {
+	.probe = sg2042_pll_probe,
+	.driver = {
+		.name = "clk-sophgo-sg2042-pll",
+		.of_match_table = sg2042_pll_match,
+		.suppress_bind_attrs = true,
+	},
+};
+builtin_platform_driver(sg2042_pll_driver);
diff --git a/drivers/clk/sophgo/clk-sophgo-sg2042.h b/drivers/clk/sophgo/clk-sophgo-sg2042.h
new file mode 100644
index 000000000000..407fec6f3f02
--- /dev/null
+++ b/drivers/clk/sophgo/clk-sophgo-sg2042.h
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __CLK_SOPHGO_SG2042_H
+#define __CLK_SOPHGO_SG2042_H
+
+/* Registers defined in SYS_CTRL */
+#define R_PLL_BEGIN		0xC0
+#define R_PLL_STAT		(0xC0 - R_PLL_BEGIN)
+#define R_PLL_CLKEN_CONTROL	(0xC4 - R_PLL_BEGIN)
+#define R_MPLL_CONTROL		(0xE8 - R_PLL_BEGIN)
+#define R_FPLL_CONTROL		(0xF4 - R_PLL_BEGIN)
+#define R_DPLL0_CONTROL		(0xF8 - R_PLL_BEGIN)
+#define R_DPLL1_CONTROL		(0xFC - R_PLL_BEGIN)
+
+#define R_SYSGATE_BEGIN		0x0368
+#define R_RP_RXU_CLK_ENABLE	(0x0368 - R_SYSGATE_BEGIN)
+#define R_MP0_STATUS_REG	(0x0380 - R_SYSGATE_BEGIN)
+#define R_MP0_CONTROL_REG	(0x0384 - R_SYSGATE_BEGIN)
+#define R_MP1_STATUS_REG	(0x0388 - R_SYSGATE_BEGIN)
+#define R_MP1_CONTROL_REG	(0x038C - R_SYSGATE_BEGIN)
+#define R_MP2_STATUS_REG	(0x0390 - R_SYSGATE_BEGIN)
+#define R_MP2_CONTROL_REG	(0x0394 - R_SYSGATE_BEGIN)
+#define R_MP3_STATUS_REG	(0x0398 - R_SYSGATE_BEGIN)
+#define R_MP3_CONTROL_REG	(0x039C - R_SYSGATE_BEGIN)
+#define R_MP4_STATUS_REG	(0x03A0 - R_SYSGATE_BEGIN)
+#define R_MP4_CONTROL_REG	(0x03A4 - R_SYSGATE_BEGIN)
+#define R_MP5_STATUS_REG	(0x03A8 - R_SYSGATE_BEGIN)
+#define R_MP5_CONTROL_REG	(0x03AC - R_SYSGATE_BEGIN)
+#define R_MP6_STATUS_REG	(0x03B0 - R_SYSGATE_BEGIN)
+#define R_MP6_CONTROL_REG	(0x03B4 - R_SYSGATE_BEGIN)
+#define R_MP7_STATUS_REG	(0x03B8 - R_SYSGATE_BEGIN)
+#define R_MP7_CONTROL_REG	(0x03BC - R_SYSGATE_BEGIN)
+#define R_MP8_STATUS_REG	(0x03C0 - R_SYSGATE_BEGIN)
+#define R_MP8_CONTROL_REG	(0x03C4 - R_SYSGATE_BEGIN)
+#define R_MP9_STATUS_REG	(0x03C8 - R_SYSGATE_BEGIN)
+#define R_MP9_CONTROL_REG	(0x03CC - R_SYSGATE_BEGIN)
+#define R_MP10_STATUS_REG	(0x03D0 - R_SYSGATE_BEGIN)
+#define R_MP10_CONTROL_REG	(0x03D4 - R_SYSGATE_BEGIN)
+#define R_MP11_STATUS_REG	(0x03D8 - R_SYSGATE_BEGIN)
+#define R_MP11_CONTROL_REG	(0x03DC - R_SYSGATE_BEGIN)
+#define R_MP12_STATUS_REG	(0x03E0 - R_SYSGATE_BEGIN)
+#define R_MP12_CONTROL_REG	(0x03E4 - R_SYSGATE_BEGIN)
+#define R_MP13_STATUS_REG	(0x03E8 - R_SYSGATE_BEGIN)
+#define R_MP13_CONTROL_REG	(0x03EC - R_SYSGATE_BEGIN)
+#define R_MP14_STATUS_REG	(0x03F0 - R_SYSGATE_BEGIN)
+#define R_MP14_CONTROL_REG	(0x03F4 - R_SYSGATE_BEGIN)
+#define R_MP15_STATUS_REG	(0x03F8 - R_SYSGATE_BEGIN)
+#define R_MP15_CONTROL_REG	(0x03FC - R_SYSGATE_BEGIN)
+
+/* Registers defined in CLOCK */
+#define R_CLKENREG0		0x00
+#define R_CLKENREG1		0x04
+#define R_CLKSELREG0		0x20
+#define R_CLKDIVREG0		0x40
+#define R_CLKDIVREG1		0x44
+#define R_CLKDIVREG2		0x48
+#define R_CLKDIVREG3		0x4C
+#define R_CLKDIVREG4		0x50
+#define R_CLKDIVREG5		0x54
+#define R_CLKDIVREG6		0x58
+#define R_CLKDIVREG7		0x5C
+#define R_CLKDIVREG8		0x60
+#define R_CLKDIVREG9		0x64
+#define R_CLKDIVREG10		0x68
+#define R_CLKDIVREG11		0x6C
+#define R_CLKDIVREG12		0x70
+#define R_CLKDIVREG13		0x74
+#define R_CLKDIVREG14		0x78
+#define R_CLKDIVREG15		0x7C
+#define R_CLKDIVREG16		0x80
+#define R_CLKDIVREG17		0x84
+#define R_CLKDIVREG18		0x88
+#define R_CLKDIVREG19		0x8C
+#define R_CLKDIVREG20		0x90
+#define R_CLKDIVREG21		0x94
+#define R_CLKDIVREG22		0x98
+#define R_CLKDIVREG23		0x9C
+#define R_CLKDIVREG24		0xA0
+#define R_CLKDIVREG25		0xA4
+#define R_CLKDIVREG26		0xA8
+#define R_CLKDIVREG27		0xAC
+#define R_CLKDIVREG28		0xB0
+#define R_CLKDIVREG29		0xB4
+#define R_CLKDIVREG30		0xB8
+
+/*
+ * Common data of clock-controller
+ * Note: this structure will be used both by clkgen & sysclk.
+ * @iobase: base address of clock-controller
+ * @onecell_data: used for adding providers.
+ */
+struct sg2042_clk_data {
+	void __iomem *iobase;
+	struct clk_hw_onecell_data onecell_data;
+};
+
+/*
+ * PLL clock
+ * @hw:				clk_hw for initialization
+ * @id:				used to map clk_onecell_data
+ * @base:			used for readl/writel.
+ *				**NOTE**: PLL registers are all in SYS_CTRL!
+ * @lock:			spinlock to protect register access, modification
+ *				of frequency can only be served one at the time.
+ * @offset_status:		offset of pll status registers
+ * @offset_enable:		offset of pll enable registers
+ * @offset_ctrl:		offset of pll control registers
+ * @shift_status_lock:		shift of XXX_LOCK in pll status register
+ * @shift_status_updating:	shift of UPDATING_XXX in pll status register
+ * @shift_enable:		shift of XXX_CLK_EN in pll enable register
+ */
+struct sg2042_pll_clock {
+	struct clk_hw hw;
+
+	unsigned int id;
+	void __iomem *base;
+	/* protect register access */
+	spinlock_t *lock;
+
+	u32 offset_status;
+	u32 offset_enable;
+	u32 offset_ctrl;
+	u8 shift_status_lock;
+	u8 shift_status_updating;
+	u8 shift_enable;
+};
+
+#define to_sg2042_pll_clk(_hw) container_of(_hw, struct sg2042_pll_clock, hw)
+
+/*
+ * Divider clock
+ * @hw:			clk_hw for initialization
+ * @id:			used to map clk_onecell_data
+ * @reg:		used for readl/writel.
+ *			**NOTE**: DIV registers are ALL in CLOCK!
+ * @lock:		spinlock to protect register access, modification of
+ *			frequency can only be served one at the time
+ * @offset_ctrl:	offset of divider control registers
+ * @shift:		shift of "Clock Divider Factor" in divider control register
+ * @width:		width of "Clock Divider Factor" in divider control register
+ * @div_flags:		private flags for this clock, not for framework-specific
+ * @initval:		In the divider control register, we can configure whether
+ *			to use the value of "Clock Divider Factor" or just use
+ *			the initial value pre-configured by IC. BIT[3] controls
+ *			this and by default (value is 0), means initial value
+ *			is used.
+ *			**NOTE** that we cannot read the initial value (default
+ *			value when poweron) and default value of "Clock Divider
+ *			Factor" is zero, which I think is a hardware design flaw
+ *			and should be sync-ed with the initial value. So in
+ *			software we have to add a configuration item (initval)
+ *			to manually configure this value and use it when BIT[3]
+ *			is zero.
+ */
+struct sg2042_divider_clock {
+	struct clk_hw hw;
+
+	unsigned int id;
+
+	void __iomem *reg;
+	/* protect register access */
+	spinlock_t *lock;
+
+	unsigned long offset_ctrl;
+	u8 shift;
+	u8 width;
+	u8 div_flags;
+	u32 initval;
+};
+
+#define to_sg2042_clk_divider(_hw)	\
+	container_of(_hw, struct sg2042_divider_clock, hw)
+
+/*
+ * Gate clock
+ * @hw:			clk_hw for initialization
+ * @id:			used to map clk_onecell_data
+ * @offset_enable:	offset of gate enable registers
+ * @bit_idx:		which bit in the register controls gating of this clock
+ */
+struct sg2042_gate_clock {
+	struct clk_hw hw;
+
+	unsigned int id;
+
+	unsigned long offset_enable;
+	u8 bit_idx;
+};
+
+/*
+ * Mux clock
+ * @hw:			clk_hw for initialization
+ * @id:			used to map clk_onecell_data
+ * @offset_select:	offset of mux selection registers
+ *			**NOTE**: MUX registers are ALL in CLOCK!
+ * @shift:		shift of "Clock Select" in mux selection register
+ * @width:		width of "Clock Select" in mux selection register
+ * @clk_nb:		used for notification
+ * @original_index:	set by notifier callback
+ */
+struct sg2042_mux_clock {
+	struct clk_hw hw;
+
+	unsigned int id;
+
+	unsigned long offset_select;
+	u8 shift;
+	u8 width;
+
+	struct notifier_block clk_nb;
+	u8 original_index;
+};
+
+#define to_sg2042_mux_nb(_nb) container_of(_nb, struct sg2042_mux_clock, clk_nb)
+
+#endif /* __CLK_SOPHGO_SG2042_H */
-- 
2.25.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox