There's not much to see in the core framework this time around. Instead the

majority of the diff is the normal collection of driver additions for new SoCs
 and non-critical clk data fixes and updates. The framework must be middle aged.
 
 The two biggest directories in the diffstat show that the Qualcomm and Unisoc
 support added a handful of big drivers for new SoCs but that's not really the
 whole story because those new drivers tend to add large numbers of lines of clk
 data. There's a handful of AT91 clk drivers added this time around too and a
 bunch of improvements to drivers like the i.MX driver. All around lots of
 updates and fixes in various clk drivers which is good to see.
 
 The core framework has only one real major change which has been baking in next
 for the past couple months. It fixes the framework so that it stops caching a
 clk's phase when the phase clk_op returns an error. Before this change we would
 consider some negative errno as a phase and that just doesn't make sense.
 
 Core:
  - Don't show clk phase when it is invalid
 
 New Drivers:
  - Add support for Unisoc SC9863A clks
  - Qualcomm SM8250 RPMh and MSM8976 RPM clks
  - Qualcomm SM8250 Global Clock Controller (GCC) support
  - Qualcomm SC7180 Modem Clock Controller (MSS CC) support
  - EHRPWM's TimeBase clock(TBCLK) for TI AM654 SoCs
  - Support PMC clks on at91sam9n12, at91rm9200, sama5d3, and at91sam9g45 SoCs
 
 Updates:
  - GPU GX GDSC support on Qualcomm sc7180
  - Fixes and improvements for the Marvell MMP2/MMP3 SoC clk drivers
  - A series from Anson to convert i.MX8 clock bindings to json-schema
  - Update i.MX pll14xx driver to include new frequency entries for pll1443x table,
    and return error for invalid PLL type
  - Add missing of_node_put() call for a number of i.MX clock drivers
  - Drop flag CLK_IS_CRITICAL from 'A53_CORE' mux clock, as we already
    have the flag on its child cpu clock
  - Fix a53 cpu clock for i.MX8 drivers to get it source from ARM PLL
    via CORE_SEL slice, and source from A53 CCM clk root when we need to
    change ARM PLL frequency. Thus, we can support core running above
    1GHz safely
  - Update i.MX pfdv2 driver to check zero rate and use determine_rate for
    getting the best rate
  - Add CLKO2 for imx8mm, SNVS clock for imx8mn, and PXP clock for imx7d
  - Remove PMC clks from Tegra clk driver
  - Improved clock/reset handling for the Renesas R-Car USB2 Clock Selector
  - Conversion to json-schema of the Renesas CPG/MSSR DT bindings
  - Add Crypto clocks on Renesas R-Car M3-W/W+, M3-N, E3, and D3
  - Add RPC (QSPI/HyperFLASH) clocks on Renesas R-Car H3, M3-W/W+, and M3-N
  - Update Amlogic audio clock gate hierarchy for meson8 and gxbb
  - Update Amlogic g12a spicc clock sources
  - Support for Ingenic X1000 TCU clks
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAl6JDxURHHNib3lkQGtl
 cm5lbC5vcmcACgkQrQKIl8bklSU51A/+OzAA4HyywcSwLWMhUbyWI0hWis8/Gdtv
 /tIOPY/+J/Wi+2vFXoZEQWr/GViEEC1ylQwtkc/cm1WklEka/+q+GJFawyyIfX2i
 ovofDWw5lJd4/ACaOqV4ryEppwHnPUvASvoIOUXX6IwauNQzI0dRZWTOLTg2YW7x
 uvI5OtQ8o71+bM+VL1tuhWvN/4Zx9tALNU9yhaRhHdafR+xQ0d4x5bBQo8MG/2E0
 3xIbRqGbhO6XfNiKAjgKcI3jtHn006LK1/1AjyXUETWzu5Zcg2SYb/YAah39RKLZ
 FTV+xY39C8JBLPt6ZLrBu9mPDcoQOWohmnDLki0qm65cfVs/tbDX3kwp3ixCly7y
 jSCqNpl7RuWcbjMe8YesakhJc1IFICQts08KsM6dPipL+7iAv++fNQrfrnXf0cDx
 cPCgDkepos/aRhNXmVFdxf2FRKkIQjYpdAPFdYSvLv6MK0Dk6G7/EhOOXA10Z2BU
 BojY8tUx/YaC8sRbnZlhitYfpqDVFzdihL2G6W31iUbt1sKYR6t6Szhct2EbRTOQ
 69bUy2lw7M8pk1Remp0LqdrVUDYLy0/X3dVaa/teIaZt2Ac1NnWzHw9LMmnlFFEG
 GxuZy5Q5fCKbAf0tSkD4Gzb9z8f0pzAyfdlpGsY7+eEEWloc4yNFCcFcNyzJTXWV
 4kdye0klUPs=
 =ZoI6
 -----END PGP SIGNATURE-----

Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk updates from Stephen Boyd:
 "There's not much to see in the core framework this time around.
  Instead the majority of the diff is the normal collection of driver
  additions for new SoCs and non-critical clk data fixes and updates.
  The framework must be middle aged.

  The two biggest directories in the diffstat show that the Qualcomm and
  Unisoc support added a handful of big drivers for new SoCs but that's
  not really the whole story because those new drivers tend to add large
  numbers of lines of clk data. There's a handful of AT91 clk drivers
  added this time around too and a bunch of improvements to drivers like
  the i.MX driver. All around lots of updates and fixes in various clk
  drivers which is good to see.

  The core framework has only one real major change which has been
  baking in next for the past couple months. It fixes the framework so
  that it stops caching a clk's phase when the phase clk_op returns an
  error. Before this change we would consider some negative errno as a
  phase and that just doesn't make sense.

  Core:
   - Don't show clk phase when it is invalid

  New Drivers:
   - Add support for Unisoc SC9863A clks
   - Qualcomm SM8250 RPMh and MSM8976 RPM clks
   - Qualcomm SM8250 Global Clock Controller (GCC) support
   - Qualcomm SC7180 Modem Clock Controller (MSS CC) support
   - EHRPWM's TimeBase clock(TBCLK) for TI AM654 SoCs
   - Support PMC clks on at91sam9n12, at91rm9200, sama5d3, and
     at91sam9g45 SoCs

  Updates:
   - GPU GX GDSC support on Qualcomm sc7180
   - Fixes and improvements for the Marvell MMP2/MMP3 SoC clk drivers
   - A series from Anson to convert i.MX8 clock bindings to json-schema
   - Update i.MX pll14xx driver to include new frequency entries for
     pll1443x table, and return error for invalid PLL type
   - Add missing of_node_put() call for a number of i.MX clock drivers
   - Drop flag CLK_IS_CRITICAL from 'A53_CORE' mux clock, as we already
     have the flag on its child cpu clock
   - Fix a53 cpu clock for i.MX8 drivers to get it source from ARM PLL
     via CORE_SEL slice, and source from A53 CCM clk root when we need
     to change ARM PLL frequency. Thus, we can support core running
     above 1GHz safely
   - Update i.MX pfdv2 driver to check zero rate and use determine_rate
     for getting the best rate
   - Add CLKO2 for imx8mm, SNVS clock for imx8mn, and PXP clock for
     imx7d
   - Remove PMC clks from Tegra clk driver
   - Improved clock/reset handling for the Renesas R-Car USB2 Clock
     Selector
   - Conversion to json-schema of the Renesas CPG/MSSR DT bindings
   - Add Crypto clocks on Renesas R-Car M3-W/W+, M3-N, E3, and D3
   - Add RPC (QSPI/HyperFLASH) clocks on Renesas R-Car H3, M3-W/W+, and
     M3-N
   - Update Amlogic audio clock gate hierarchy for meson8 and gxbb
   - Update Amlogic g12a spicc clock sources
   - Support for Ingenic X1000 TCU clks"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (146 commits)
  clk: sprd: fix to get a correct ibias of pll
  dt-bindings: imx8mm-clock: Fix the file path
  dt-bindings: imx8mq-clock: Fix the file path
  clk: qcom: rpmh: Drop unnecessary semicolons
  clk: qcom: rpmh: Simplify clk_rpmh_bcm_send_cmd()
  clk: tegra: Use NULL for pointer initialization
  clk: sprd: add clocks support for SC9863A
  clk: sprd: support to get regmap from parent node
  clk: sprd: Add macros for referencing parents without strings
  clk: sprd: Add dt-bindings include file for SC9863A
  dt-bindings: clk: sprd: add bindings for sc9863a clock controller
  dt-bindings: clk: sprd: rename the common file name sprd.txt to SoC specific
  clk: sprd: add gate for pll clocks
  MAINTAINERS: dt: update reference for arm-integrator.txt
  clk: mmp2: Fix bit masks for LCDC I/O and pixel clocks
  clk: mmp2: Add clock for fifth SD HCI on MMP3
  dt-bindings: marvell,mmp2: Add clock id for the fifth SD HCI on MMP3
  clk: mmp2: Add clocks for the thermal sensors
  dt-bindings: marvell,mmp2: Add clock ids for the thermal sensors
  clk: mmp2: add the GPU clocks
  ...
This commit is contained in:
Linus Torvalds 2020-04-05 10:43:32 -07:00
commit 3476195651
131 changed files with 10338 additions and 1136 deletions

View file

@ -0,0 +1,103 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/arm,syscon-icst.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM System Controller ICST Clocks
maintainers:
- Linus Walleij <linusw@kernel.org>
description: |
The ICS525 and ICS307 oscillators are produced by Integrated
Devices Technology (IDT). ARM integrated these oscillators deeply into their
reference designs by adding special control registers that manage such
oscillators to their system controllers.
The various ARM system controllers contain logic to serialize and initialize
an ICST clock request after a write to the 32 bit register at an offset
into the system controller. Furthermore, to even be able to alter one of
these frequencies, the system controller must first be unlocked by
writing a special token to another offset in the system controller.
Some ARM hardware contain special versions of the serial interface that only
connects the low 8 bits of the VDW (missing one bit), hard-wires RDW to
different values and sometimes also hard-wires the output divider. They
therefore have special compatible strings as per this table (the OD value is
the value on the pins, not the resulting output divider).
In the core modules and logic tiles, the ICST is a configurable clock fed
from a 24 MHz clock on the motherboard (usually the main crystal) used for
generating e.g. video clocks. It is located on the core module and there is
only one of these. This clock node must be a subnode of the core module.
Hardware variant RDW OD VDW
Integrator/AP 22 1 Bit 8 0, rest variable
integratorap-cm
Integrator/AP 46 3 Bit 8 0, rest variable
integratorap-sys
Integrator/AP 22 or 1 17 or (33 or 25 MHz)
integratorap-pci 14 1 14
Integrator/CP 22 variable Bit 8 0, rest variable
integratorcp-cm-core
Integrator/CP 22 variable Bit 8 0, rest variable
integratorcp-cm-mem
The ICST oscillator must be provided inside a system controller node.
properties:
"#clock-cells":
const: 0
compatible:
enum:
- arm,syscon-icst525
- arm,syscon-icst307
- arm,syscon-icst525-integratorap-cm
- arm,syscon-icst525-integratorap-sys
- arm,syscon-icst525-integratorap-pci
- arm,syscon-icst525-integratorcp-cm-core
- arm,syscon-icst525-integratorcp-cm-mem
- arm,integrator-cm-auxosc
- arm,versatile-cm-auxosc
- arm,impd-vco1
- arm,impd-vco2
clocks:
description: Parent clock for the ICST VCO
maxItems: 1
clock-output-names:
maxItems: 1
lock-offset:
$ref: '/schemas/types.yaml#/definitions/uint32'
description: Offset to the unlocking register for the oscillator
vco-offset:
$ref: '/schemas/types.yaml#/definitions/uint32'
description: Offset to the VCO register for the oscillator
required:
- "#clock-cells"
- compatible
- clocks
examples:
- |
vco1: clock@00 {
compatible = "arm,impd1-vco1";
#clock-cells = <0>;
lock-offset = <0x08>;
vco-offset = <0x00>;
clocks = <&sysclk>;
clock-output-names = "IM-PD1-VCO1";
};
...

View file

@ -1,34 +0,0 @@
Clock bindings for ARM Integrator and Versatile Core Module clocks
Auxiliary Oscillator Clock
This is a configurable clock fed from a 24 MHz chrystal,
used for generating e.g. video clocks. It is located on the
core module and there is only one of these.
This clock node *must* be a subnode of the core module, since
it obtains the base address for it's address range from its
parent node.
Required properties:
- compatible: must be "arm,integrator-cm-auxosc" or "arm,versatile-cm-auxosc"
- #clock-cells: must be <0>
Optional properties:
- clocks: parent clock(s)
Example:
core-module@10000000 {
xtal24mhz: xtal24mhz@24M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
};
auxosc: cm_aux_osc@25M {
#clock-cells = <0>;
compatible = "arm,integrator-cm-auxosc";
clocks = <&xtal24mhz>;
};
};

View file

@ -1,70 +0,0 @@
ARM System Controller ICST clocks
The ICS525 and ICS307 oscillators are produced by Integrated Devices
Technology (IDT). ARM integrated these oscillators deeply into their
reference designs by adding special control registers that manage such
oscillators to their system controllers.
The various ARM system controllers contain logic to serialize and initialize
an ICST clock request after a write to the 32 bit register at an offset
into the system controller. Furthermore, to even be able to alter one of
these frequencies, the system controller must first be unlocked by
writing a special token to another offset in the system controller.
Some ARM hardware contain special versions of the serial interface that only
connects the low 8 bits of the VDW (missing one bit), hardwires RDW to
different values and sometimes also hardwire the output divider. They
therefore have special compatible strings as per this table (the OD value is
the value on the pins, not the resulting output divider):
Hardware variant: RDW OD VDW
Integrator/AP 22 1 Bit 8 0, rest variable
integratorap-cm
Integrator/AP 46 3 Bit 8 0, rest variable
integratorap-sys
Integrator/AP 22 or 1 17 or (33 or 25 MHz)
integratorap-pci 14 1 14
Integrator/CP 22 variable Bit 8 0, rest variable
integratorcp-cm-core
Integrator/CP 22 variable Bit 8 0, rest variable
integratorcp-cm-mem
The ICST oscillator must be provided inside a system controller node.
Required properties:
- compatible: must be one of
"arm,syscon-icst525"
"arm,syscon-icst307"
"arm,syscon-icst525-integratorap-cm"
"arm,syscon-icst525-integratorap-sys"
"arm,syscon-icst525-integratorap-pci"
"arm,syscon-icst525-integratorcp-cm-core"
"arm,syscon-icst525-integratorcp-cm-mem"
- lock-offset: the offset address into the system controller where the
unlocking register is located
- vco-offset: the offset address into the system controller where the
ICST control register is located (even 32 bit address)
- #clock-cells: must be <0>
- clocks: parent clock, since the ICST needs a parent clock to derive its
frequency from, this attribute is compulsory.
Example:
syscon: syscon@10000000 {
compatible = "syscon";
reg = <0x10000000 0x1000>;
oscclk0: osc0@c {
compatible = "arm,syscon-icst307";
#clock-cells = <0>;
lock-offset = <0x20>;
vco-offset = <0x0c>;
clocks = <&xtal24mhz>;
};
(...)
};

View file

@ -1,29 +0,0 @@
* Clock bindings for NXP i.MX8M Mini
Required properties:
- compatible: Should be "fsl,imx8mm-ccm"
- reg: Address and length of the register set
- #clock-cells: Should be <1>
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- clock-names: should include the following entries:
- "osc_32k"
- "osc_24m"
- "clk_ext1"
- "clk_ext2"
- "clk_ext3"
- "clk_ext4"
clk: clock-controller@30380000 {
compatible = "fsl,imx8mm-ccm";
reg = <0x0 0x30380000 0x0 0x10000>;
#clock-cells = <1>;
clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
<&clk_ext3>, <&clk_ext4>;
clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
"clk_ext3", "clk_ext4";
};
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mm-clock.h
for the full list of i.MX8M Mini clock IDs.

View file

@ -0,0 +1,68 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/imx8mm-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX8M Mini Clock Control Module Binding
maintainers:
- Anson Huang <Anson.Huang@nxp.com>
description: |
NXP i.MX8M Mini clock control module is an integrated clock controller, which
generates and supplies to all modules.
properties:
compatible:
const: fsl,imx8mm-ccm
reg:
maxItems: 1
clocks:
items:
- description: 32k osc
- description: 24m osc
- description: ext1 clock input
- description: ext2 clock input
- description: ext3 clock input
- description: ext4 clock input
clock-names:
items:
- const: osc_32k
- const: osc_24m
- const: clk_ext1
- const: clk_ext2
- const: clk_ext3
- const: clk_ext4
'#clock-cells':
const: 1
description:
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mm-clock.h
for the full list of i.MX8M Mini clock IDs.
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
examples:
# Clock Control Module node:
- |
clk: clock-controller@30380000 {
compatible = "fsl,imx8mm-ccm";
reg = <0x30380000 0x10000>;
#clock-cells = <1>;
clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
<&clk_ext3>, <&clk_ext4>;
clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
"clk_ext3", "clk_ext4";
};
...

View file

@ -40,7 +40,7 @@ properties:
'#clock-cells':
const: 1
description: |
description:
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mn-clock.h
for the full list of i.MX8M Nano clock IDs.
@ -59,7 +59,7 @@ examples:
- |
clk: clock-controller@30380000 {
compatible = "fsl,imx8mn-ccm";
reg = <0x0 0x30380000 0x0 0x10000>;
reg = <0x30380000 0x10000>;
#clock-cells = <1>;
clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>,
<&clk_ext2>, <&clk_ext3>, <&clk_ext4>;
@ -67,48 +67,4 @@ examples:
"clk_ext2", "clk_ext3", "clk_ext4";
};
# Required external clocks for Clock Control Module node:
- |
osc_32k: clock-osc-32k {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
clock-output-names = "osc_32k";
};
osc_24m: clock-osc-24m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24000000>;
clock-output-names = "osc_24m";
};
clk_ext1: clock-ext1 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <133000000>;
clock-output-names = "clk_ext1";
};
clk_ext2: clock-ext2 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <133000000>;
clock-output-names = "clk_ext2";
};
clk_ext3: clock-ext3 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <133000000>;
clock-output-names = "clk_ext3";
};
clk_ext4: clock-ext4 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency= <133000000>;
clock-output-names = "clk_ext4";
};
...

View file

@ -1,20 +0,0 @@
* Clock bindings for NXP i.MX8M Quad
Required properties:
- compatible: Should be "fsl,imx8mq-ccm"
- reg: Address and length of the register set
- #clock-cells: Should be <1>
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- clock-names: should include the following entries:
- "ckil"
- "osc_25m"
- "osc_27m"
- "clk_ext1"
- "clk_ext2"
- "clk_ext3"
- "clk_ext4"
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h
for the full list of i.MX8M Quad clock IDs.

View file

@ -0,0 +1,72 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/imx8mq-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX8M Quad Clock Control Module Binding
maintainers:
- Anson Huang <Anson.Huang@nxp.com>
description: |
NXP i.MX8M Quad clock control module is an integrated clock controller, which
generates and supplies to all modules.
properties:
compatible:
const: fsl,imx8mq-ccm
reg:
maxItems: 1
clocks:
items:
- description: 32k osc
- description: 25m osc
- description: 27m osc
- description: ext1 clock input
- description: ext2 clock input
- description: ext3 clock input
- description: ext4 clock input
clock-names:
items:
- const: ckil
- const: osc_25m
- const: osc_27m
- const: clk_ext1
- const: clk_ext2
- const: clk_ext3
- const: clk_ext4
'#clock-cells':
const: 1
description:
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h
for the full list of i.MX8M Quad clock IDs.
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
examples:
# Clock Control Module node:
- |
clk: clock-controller@30380000 {
compatible = "fsl,imx8mq-ccm";
reg = <0x30380000 0x10000>;
#clock-cells = <1>;
clocks = <&ckil>, <&osc_25m>, <&osc_27m>,
<&clk_ext1>, <&clk_ext2>,
<&clk_ext3>, <&clk_ext4>;
clock-names = "ckil", "osc_25m", "osc_27m",
"clk_ext1", "clk_ext2",
"clk_ext3", "clk_ext4";
};
...

View file

@ -0,0 +1,64 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/marvell,mmp2-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell MMP2 and MMP3 Clock Controller
maintainers:
- Lubomir Rintel <lkundrak@v3.sk>
description: |
The clock subsystem on MMP2 or MMP3 generates and supplies clock to various
controllers within the SoC.
Each clock is assigned an identifier and client nodes use this identifier
to specify the clock which they consume.
All these identifiers could be found in <dt-bindings/clock/marvell,mmp2.h>.
properties:
compatible:
enum:
- marvell,mmp2-clock # controller compatible with MMP2 SoC
- marvell,mmp3-clock # controller compatible with MMP3 SoC
reg:
items:
- description: MPMU register region
- description: APMU register region
- description: APBC register region
reg-names:
items:
- const: mpmu
- const: apmu
- const: apbc
'#clock-cells':
const: 1
'#reset-cells':
const: 1
required:
- compatible
- reg
- reg-names
- '#clock-cells'
- '#reset-cells'
additionalProperties: false
examples:
- |
clock-controller@d4050000 {
compatible = "marvell,mmp2-clock";
reg = <0xd4050000 0x1000>,
<0xd4282800 0x400>,
<0xd4015000 0x1000>;
reg-names = "mpmu", "apmu", "apbc";
#clock-cells = <1>;
#reset-cells = <1>;
};

View file

@ -1,21 +0,0 @@
* Marvell MMP2 Clock Controller
The MMP2 clock subsystem generates and supplies clock to various
controllers within the MMP2 SoC.
Required Properties:
- compatible: should be one of the following.
- "marvell,mmp2-clock" - controller compatible with MMP2 SoC.
- reg: physical base address of the clock subsystem and length of memory mapped
region. There are 3 places in SOC has clock control logic:
"mpmu", "apmu", "apbc". So three reg spaces need to be defined.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Each clock is assigned an identifier and client nodes use this identifier
to specify the clock which they consume.
All these identifiers could be found in <dt-bindings/clock/marvell,mmp2.h>.

View file

@ -0,0 +1,72 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,gcc-sm8250.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Global Clock & Reset Controller Binding for SM8250
maintainers:
- Stephen Boyd <sboyd@kernel.org>
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm global clock control module which supports the clocks, resets and
power domains on SM8250.
See also:
- dt-bindings/clock/qcom,gcc-sm8250.h
properties:
compatible:
const: qcom,gcc-sm8250
clocks:
items:
- description: Board XO source
- description: Sleep clock source
clock-names:
items:
- const: bi_tcxo
- const: sleep_clk
'#clock-cells':
const: 1
'#reset-cells':
const: 1
'#power-domain-cells':
const: 1
reg:
maxItems: 1
protected-clocks:
description:
Protected clock specifier list as per common clock binding.
required:
- compatible
- clocks
- clock-names
- reg
- '#clock-cells'
- '#reset-cells'
- '#power-domain-cells'
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
clock-controller@100000 {
compatible = "qcom,gcc-sm8250";
reg = <0 0x00100000 0 0x1f0000>;
clocks = <&rpmhcc RPMH_CXO_CLK>,
<&sleep_clk>;
clock-names = "bi_tcxo", "sleep_clk";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...

View file

@ -14,7 +14,9 @@ Required properties :
"qcom,rpmcc-apq8060", "qcom,rpmcc"
"qcom,rpmcc-msm8916", "qcom,rpmcc"
"qcom,rpmcc-msm8974", "qcom,rpmcc"
"qcom,rpmcc-msm8976", "qcom,rpmcc"
"qcom,rpmcc-apq8064", "qcom,rpmcc"
"qcom,rpmcc-ipq806x", "qcom,rpmcc"
"qcom,rpmcc-msm8996", "qcom,rpmcc"
"qcom,rpmcc-msm8998", "qcom,rpmcc"
"qcom,rpmcc-qcs404", "qcom,rpmcc"

View file

@ -20,6 +20,7 @@ properties:
- qcom,sc7180-rpmh-clk
- qcom,sdm845-rpmh-clk
- qcom,sm8150-rpmh-clk
- qcom,sm8250-rpmh-clk
clocks:
maxItems: 1

View file

@ -0,0 +1,62 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,sc7180-mss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Modem Clock Controller Binding for SC7180
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm modem clock control module which supports the clocks on SC7180.
See also:
- dt-bindings/clock/qcom,mss-sc7180.h
properties:
compatible:
const: qcom,sc7180-mss
clocks:
items:
- description: gcc_mss_mfab_axi clock from GCC
- description: gcc_mss_nav_axi clock from GCC
- description: gcc_mss_cfg_ahb clock from GCC
clock-names:
items:
- const: gcc_mss_mfab_axis
- const: gcc_mss_nav_axi
- const: cfg_ahb
'#clock-cells':
const: 1
reg:
maxItems: 1
required:
- compatible
- reg
- clocks
- '#clock-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
clock-controller@41a8000 {
compatible = "qcom,sc7180-mss";
reg = <0 0x041a8000 0 0x8000>;
clocks = <&gcc GCC_MSS_MFAB_AXIS_CLK>,
<&gcc GCC_MSS_NAV_AXI_CLK>,
<&gcc GCC_MSS_CFG_AHB_CLK>;
clock-names = "gcc_mss_mfab_axis",
"gcc_mss_nav_axi",
"cfg_ahb";
#clock-cells = <1>;
};
...

View file

@ -1,100 +0,0 @@
* Renesas Clock Pulse Generator / Module Standby and Software Reset
On Renesas ARM SoCs (SH/R-Mobile, R-Car, RZ), the CPG (Clock Pulse Generator)
and MSSR (Module Standby and Software Reset) blocks are intimately connected,
and share the same register block.
They provide the following functionalities:
- The CPG block generates various core clocks,
- The MSSR block provides two functions:
1. Module Standby, providing a Clock Domain to control the clock supply
to individual SoC devices,
2. Reset Control, to perform a software reset of individual SoC devices.
Required Properties:
- compatible: Must be one of:
- "renesas,r7s9210-cpg-mssr" for the r7s9210 SoC (RZ/A2)
- "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M)
- "renesas,r8a7744-cpg-mssr" for the r8a7744 SoC (RZ/G1N)
- "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E)
- "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C)
- "renesas,r8a774a1-cpg-mssr" for the r8a774a1 SoC (RZ/G2M)
- "renesas,r8a774b1-cpg-mssr" for the r8a774b1 SoC (RZ/G2N)
- "renesas,r8a774c0-cpg-mssr" for the r8a774c0 SoC (RZ/G2E)
- "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2)
- "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W)
- "renesas,r8a7792-cpg-mssr" for the r8a7792 SoC (R-Car V2H)
- "renesas,r8a7793-cpg-mssr" for the r8a7793 SoC (R-Car M2-N)
- "renesas,r8a7794-cpg-mssr" for the r8a7794 SoC (R-Car E2)
- "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3)
- "renesas,r8a7796-cpg-mssr" for the r8a77960 SoC (R-Car M3-W)
- "renesas,r8a77961-cpg-mssr" for the r8a77961 SoC (R-Car M3-W+)
- "renesas,r8a77965-cpg-mssr" for the r8a77965 SoC (R-Car M3-N)
- "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M)
- "renesas,r8a77980-cpg-mssr" for the r8a77980 SoC (R-Car V3H)
- "renesas,r8a77990-cpg-mssr" for the r8a77990 SoC (R-Car E3)
- "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3)
- reg: Base address and length of the memory resource used by the CPG/MSSR
block
- clocks: References to external parent clocks, one entry for each entry in
clock-names
- clock-names: List of external parent clock names. Valid names are:
- "extal" (r7s9210, r8a7743, r8a7744, r8a7745, r8a77470, r8a774a1,
r8a774b1, r8a774c0, r8a7790, r8a7791, r8a7792, r8a7793,
r8a7794, r8a7795, r8a77960, r8a77961, r8a77965, r8a77970,
r8a77980, r8a77990, r8a77995)
- "extalr" (r8a774a1, r8a774b1, r8a7795, r8a77960, r8a77961, r8a77965,
r8a77970, r8a77980)
- "usb_extal" (r8a7743, r8a7744, r8a7745, r8a77470, r8a7790, r8a7791,
r8a7793, r8a7794)
- #clock-cells: Must be 2
- For CPG core clocks, the two clock specifier cells must be "CPG_CORE"
and a core clock reference, as defined in
<dt-bindings/clock/*-cpg-mssr.h>.
- For module clocks, the two clock specifier cells must be "CPG_MOD" and
a module number, as defined in the datasheet.
- #power-domain-cells: Must be 0
- SoC devices that are part of the CPG/MSSR Clock Domain and can be
power-managed through Module Standby should refer to the CPG device
node in their "power-domains" property, as documented by the generic PM
Domain bindings in
Documentation/devicetree/bindings/power/power-domain.yaml.
- #reset-cells: Must be 1
- The single reset specifier cell must be the module number, as defined
in the datasheet.
Examples
--------
- CPG device node:
cpg: clock-controller@e6150000 {
compatible = "renesas,r8a7795-cpg-mssr";
reg = <0 0xe6150000 0 0x1000>;
clocks = <&extal_clk>, <&extalr_clk>;
clock-names = "extal", "extalr";
#clock-cells = <2>;
#power-domain-cells = <0>;
#reset-cells = <1>;
};
- CPG/MSSR Clock Domain member device node:
scif2: serial@e6e88000 {
compatible = "renesas,scif-r8a7795", "renesas,scif";
reg = <0 0xe6e88000 0 64>;
interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 310>;
clock-names = "fck";
dmas = <&dmac1 0x13>, <&dmac1 0x12>;
dma-names = "tx", "rx";
power-domains = <&cpg>;
resets = <&cpg 310>;
};

View file

@ -0,0 +1,119 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/clock/renesas,cpg-mssr.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Renesas Clock Pulse Generator / Module Standby and Software Reset
maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be>
description: |
On Renesas ARM SoCs (SH/R-Mobile, R-Car, RZ), the CPG (Clock Pulse Generator)
and MSSR (Module Standby and Software Reset) blocks are intimately connected,
and share the same register block.
They provide the following functionalities:
- The CPG block generates various core clocks,
- The MSSR block provides two functions:
1. Module Standby, providing a Clock Domain to control the clock supply
to individual SoC devices,
2. Reset Control, to perform a software reset of individual SoC devices.
properties:
compatible:
enum:
- renesas,r7s9210-cpg-mssr # RZ/A2
- renesas,r8a7743-cpg-mssr # RZ/G1M
- renesas,r8a7744-cpg-mssr # RZ/G1N
- renesas,r8a7745-cpg-mssr # RZ/G1E
- renesas,r8a77470-cpg-mssr # RZ/G1C
- renesas,r8a774a1-cpg-mssr # RZ/G2M
- renesas,r8a774b1-cpg-mssr # RZ/G2N
- renesas,r8a774c0-cpg-mssr # RZ/G2E
- renesas,r8a7790-cpg-mssr # R-Car H2
- renesas,r8a7791-cpg-mssr # R-Car M2-W
- renesas,r8a7792-cpg-mssr # R-Car V2H
- renesas,r8a7793-cpg-mssr # R-Car M2-N
- renesas,r8a7794-cpg-mssr # R-Car E2
- renesas,r8a7795-cpg-mssr # R-Car H3
- renesas,r8a7796-cpg-mssr # R-Car M3-W
- renesas,r8a77961-cpg-mssr # R-Car M3-W+
- renesas,r8a77965-cpg-mssr # R-Car M3-N
- renesas,r8a77970-cpg-mssr # R-Car V3M
- renesas,r8a77980-cpg-mssr # R-Car V3H
- renesas,r8a77990-cpg-mssr # R-Car E3
- renesas,r8a77995-cpg-mssr # R-Car D3
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
enum:
- extal # All
- extalr # Most R-Car Gen3 and RZ/G2
- usb_extal # Most R-Car Gen2 and RZ/G1
'#clock-cells':
description: |
- For CPG core clocks, the two clock specifier cells must be "CPG_CORE"
and a core clock reference, as defined in
<dt-bindings/clock/*-cpg-mssr.h>
- For module clocks, the two clock specifier cells must be "CPG_MOD" and
a module number, as defined in the datasheet.
const: 2
'#power-domain-cells':
description:
SoC devices that are part of the CPG/MSSR Clock Domain and can be
power-managed through Module Standby should refer to the CPG device node
in their "power-domains" property, as documented by the generic PM Domain
bindings in Documentation/devicetree/bindings/power/power-domain.yaml.
const: 0
'#reset-cells':
description:
The single reset specifier cell must be the module number, as defined in
the datasheet.
const: 1
if:
not:
properties:
compatible:
items:
enum:
- renesas,r7s9210-cpg-mssr
then:
required:
- '#reset-cells'
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
- '#power-domain-cells'
additionalProperties: false
examples:
- |
cpg: clock-controller@e6150000 {
compatible = "renesas,r8a7795-cpg-mssr";
reg = <0xe6150000 0x1000>;
clocks = <&extal_clk>, <&extalr_clk>;
clock-names = "extal", "extalr";
#clock-cells = <2>;
#power-domain-cells = <0>;
#reset-cells = <1>;
};

View file

@ -38,10 +38,17 @@ Required properties:
- reg: offset and length of the USB 2.0 clock selector register block.
- clocks: A list of phandles and specifier pairs.
- clock-names: Name of the clocks.
- The functional clock must be "ehci_ohci"
- The functional clock of USB 2.0 host side must be "ehci_ohci"
- The functional clock of HS-USB side must be "hs-usb-if"
- The USB_EXTAL clock pin must be "usb_extal"
- The USB_XTAL clock pin must be "usb_xtal"
- #clock-cells: Must be 0
- power-domains: A phandle and symbolic PM domain specifier.
See power/renesas,rcar-sysc.yaml.
- resets: A list of phandles and specifier pairs.
- reset-names: Name of the resets.
- The reset of USB 2.0 host side must be "ehci_ohci"
- The reset of HS-USB side must be "hs-usb-if"
Example (R-Car H3):
@ -49,7 +56,11 @@ Example (R-Car H3):
compatible = "renesas,r8a7795-rcar-usb2-clock-sel",
"renesas,rcar-gen3-usb2-clock-sel";
reg = <0 0xe6590630 0 0x02>;
clocks = <&cpg CPG_MOD 703>, <&usb_extal>, <&usb_xtal>;
clock-names = "ehci_ohci", "usb_extal", "usb_xtal";
clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>,
<&usb_extal>, <&usb_xtal>;
clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal";
#clock-cells = <0>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 703>, <&cpg 704>;
reset-names = "ehci_ohci", "hs-usb-if";
};

View file

@ -1,4 +1,4 @@
Spreadtrum Clock Binding
Spreadtrum SC9860 Clock Binding
------------------------
Required properties:

View file

@ -0,0 +1,105 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright 2019 Unisoc Inc.
%YAML 1.2
---
$id: "http://devicetree.org/schemas/clock/sprd,sc9863a-clk.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: SC9863A Clock Control Unit Device Tree Bindings
maintainers:
- Orson Zhai <orsonzhai@gmail.com>
- Baolin Wang <baolin.wang7@gmail.com>
- Chunyan Zhang <zhang.lyra@gmail.com>
properties:
"#clock-cells":
const: 1
compatible :
enum:
- sprd,sc9863a-ap-clk
- sprd,sc9863a-aon-clk
- sprd,sc9863a-apahb-gate
- sprd,sc9863a-pmu-gate
- sprd,sc9863a-aonapb-gate
- sprd,sc9863a-pll
- sprd,sc9863a-mpll
- sprd,sc9863a-rpll
- sprd,sc9863a-dpll
- sprd,sc9863a-mm-gate
- sprd,sc9863a-apapb-gate
clocks:
minItems: 1
maxItems: 4
description: |
The input parent clock(s) phandle for this clock, only list fixed
clocks which are declared in devicetree.
clock-names:
minItems: 1
maxItems: 4
items:
- const: ext-26m
- const: ext-32k
- const: ext-4m
- const: rco-100m
reg:
maxItems: 1
required:
- compatible
- '#clock-cells'
if:
properties:
compatible:
enum:
- sprd,sc9863a-ap-clk
- sprd,sc9863a-aon-clk
then:
required:
- reg
else:
description: |
Other SC9863a clock nodes should be the child of a syscon node in
which compatible string shoule be:
"sprd,sc9863a-glbregs", "syscon", "simple-mfd"
The 'reg' property for the clock node is also required if there is a sub
range of registers for the clocks.
examples:
- |
ap_clk: clock-controller@21500000 {
compatible = "sprd,sc9863a-ap-clk";
reg = <0 0x21500000 0 0x1000>;
clocks = <&ext_26m>, <&ext_32k>;
clock-names = "ext-26m", "ext-32k";
#clock-cells = <1>;
};
- |
soc {
#address-cells = <2>;
#size-cells = <2>;
ap_ahb_regs: syscon@20e00000 {
compatible = "sprd,sc9863a-glbregs", "syscon", "simple-mfd";
reg = <0 0x20e00000 0 0x4000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0 0x20e00000 0x4000>;
apahb_gate: apahb-gate@0 {
compatible = "sprd,sc9863a-apahb-gate";
reg = <0x0 0x1020>;
#clock-cells = <1>;
};
};
};
...

View file

@ -0,0 +1,35 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ti,am654-ehrpwm-tbclk.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI EHRPWM Time Base Clock
maintainers:
- Vignesh Raghavendra <vigneshr@ti.com>
properties:
compatible:
items:
- const: ti,am654-ehrpwm-tbclk
- const: syscon
"#clock-cells":
const: 1
reg:
maxItems: 1
required:
- compatible
- "#clock-cells"
- reg
examples:
- |
ehrpwm_tbclk: syscon@4140 {
compatible = "ti,am654-ehrpwm-tbclk", "syscon";
reg = <0x4140 0x18>;
#clock-cells = <1>;
};

View file

@ -1297,7 +1297,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/arm/arm-boards
F: Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt
F: Documentation/devicetree/bindings/clock/arm-integrator.txt
F: Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml
F: Documentation/devicetree/bindings/i2c/i2c-versatile.txt
F: Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt
F: Documentation/devicetree/bindings/mtd/arm-versatile.txt

View file

@ -15,7 +15,11 @@ obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o
obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o
obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o
obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o
obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o

View file

@ -0,0 +1,199 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
struct sck {
char *n;
char *p;
u8 id;
};
struct pck {
char *n;
u8 id;
};
static const struct clk_master_characteristics rm9200_mck_characteristics = {
.output = { .min = 0, .max = 80000000 },
.divisors = { 1, 2, 3, 4 },
};
static u8 rm9200_pll_out[] = { 0, 2 };
static const struct clk_range rm9200_pll_outputs[] = {
{ .min = 80000000, .max = 160000000 },
{ .min = 150000000, .max = 180000000 },
};
static const struct clk_pll_characteristics rm9200_pll_characteristics = {
.input = { .min = 1000000, .max = 32000000 },
.num_output = ARRAY_SIZE(rm9200_pll_outputs),
.output = rm9200_pll_outputs,
.out = rm9200_pll_out,
};
static const struct sck at91rm9200_systemck[] = {
{ .n = "udpck", .p = "usbck", .id = 2 },
{ .n = "uhpck", .p = "usbck", .id = 4 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
{ .n = "pck2", .p = "prog2", .id = 10 },
{ .n = "pck3", .p = "prog3", .id = 11 },
};
static const struct pck at91rm9200_periphck[] = {
{ .n = "pioA_clk", .id = 2 },
{ .n = "pioB_clk", .id = 3 },
{ .n = "pioC_clk", .id = 4 },
{ .n = "pioD_clk", .id = 5 },
{ .n = "usart0_clk", .id = 6 },
{ .n = "usart1_clk", .id = 7 },
{ .n = "usart2_clk", .id = 8 },
{ .n = "usart3_clk", .id = 9 },
{ .n = "mci0_clk", .id = 10 },
{ .n = "udc_clk", .id = 11 },
{ .n = "twi0_clk", .id = 12 },
{ .n = "spi0_clk", .id = 13 },
{ .n = "ssc0_clk", .id = 14 },
{ .n = "ssc1_clk", .id = 15 },
{ .n = "ssc2_clk", .id = 16 },
{ .n = "tc0_clk", .id = 17 },
{ .n = "tc1_clk", .id = 18 },
{ .n = "tc2_clk", .id = 19 },
{ .n = "tc3_clk", .id = 20 },
{ .n = "tc4_clk", .id = 21 },
{ .n = "tc5_clk", .id = 22 },
{ .n = "ohci_clk", .id = 23 },
{ .n = "macb0_clk", .id = 24 },
};
static void __init at91rm9200_pmc_setup(struct device_node *np)
{
const char *slowxtal_name, *mainxtal_name;
struct pmc_data *at91rm9200_pmc;
u32 usb_div[] = { 1, 2, 0, 0 };
const char *parent_names[6];
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_xtal");
if (i < 0)
return;
slowxtal_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = device_node_to_regmap(np);
if (IS_ERR(regmap))
return;
at91rm9200_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91rm9200_systemck),
nck(at91rm9200_periphck), 0);
if (!at91rm9200_pmc)
return;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_rm9200_main(regmap, "mainck", "main_osc");
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->chws[PMC_MAIN] = hw;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&at91rm9200_pll_layout,
&rm9200_pll_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
&at91rm9200_pll_layout,
&rm9200_pll_characteristics);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slowxtal_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
parent_names[3] = "pllbck";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91rm9200_master_layout,
&rm9200_mck_characteristics);
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->chws[PMC_MCK] = hw;
hw = at91rm9200_clk_register_usb(regmap, "usbck", "pllbck", usb_div);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slowxtal_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
parent_names[3] = "pllbck";
for (i = 0; i < 4; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 4, i,
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(at91rm9200_systemck); i++) {
hw = at91_clk_register_system(regmap, at91rm9200_systemck[i].n,
at91rm9200_systemck[i].p,
at91rm9200_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->shws[at91rm9200_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) {
hw = at91_clk_register_peripheral(regmap,
at91rm9200_periphck[i].n,
"masterck",
at91rm9200_periphck[i].id);
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->phws[at91rm9200_periphck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91rm9200_pmc);
return;
err_free:
pmc_data_free(at91rm9200_pmc);
}
/*
* While the TCB can be used as the clocksource, the system timer is most likely
* to be used instead. However, the pinctrl driver doesn't support probe
* deferring properly. Once this is fixed, this can be switched to a platform
* driver.
*/
CLK_OF_DECLARE_DRIVER(at91rm9200_pmc, "atmel,at91rm9200-pmc",
at91rm9200_pmc_setup);

View file

@ -0,0 +1,220 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 0, .max = 133333333 },
.divisors = { 1, 2, 4, 3 },
};
static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
static const struct clk_range plla_outputs[] = {
{ .min = 745000000, .max = 800000000 },
{ .min = 695000000, .max = 750000000 },
{ .min = 645000000, .max = 700000000 },
{ .min = 595000000, .max = 650000000 },
{ .min = 545000000, .max = 600000000 },
{ .min = 495000000, .max = 555000000 },
{ .min = 445000000, .max = 500000000 },
{ .min = 400000000, .max = 450000000 },
};
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 2000000, .max = 32000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.icpll = plla_icpll,
.out = plla_out,
};
static const struct {
char *n;
char *p;
u8 id;
} at91sam9g45_systemck[] = {
{ .n = "ddrck", .p = "masterck", .id = 2 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
};
static const struct clk_pcr_layout at91sam9g45_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.pid_mask = GENMASK(5, 0),
.div_mask = GENMASK(17, 16),
};
struct pck {
char *n;
u8 id;
};
static const struct pck at91sam9g45_periphck[] = {
{ .n = "pioA_clk", .id = 2, },
{ .n = "pioB_clk", .id = 3, },
{ .n = "pioC_clk", .id = 4, },
{ .n = "pioDE_clk", .id = 5, },
{ .n = "trng_clk", .id = 6, },
{ .n = "usart0_clk", .id = 7, },
{ .n = "usart1_clk", .id = 8, },
{ .n = "usart2_clk", .id = 9, },
{ .n = "usart3_clk", .id = 10, },
{ .n = "mci0_clk", .id = 11, },
{ .n = "twi0_clk", .id = 12, },
{ .n = "twi1_clk", .id = 13, },
{ .n = "spi0_clk", .id = 14, },
{ .n = "spi1_clk", .id = 15, },
{ .n = "ssc0_clk", .id = 16, },
{ .n = "ssc1_clk", .id = 17, },
{ .n = "tcb0_clk", .id = 18, },
{ .n = "pwm_clk", .id = 19, },
{ .n = "adc_clk", .id = 20, },
{ .n = "dma0_clk", .id = 21, },
{ .n = "uhphs_clk", .id = 22, },
{ .n = "lcd_clk", .id = 23, },
{ .n = "ac97_clk", .id = 24, },
{ .n = "macb0_clk", .id = 25, },
{ .n = "isi_clk", .id = 26, },
{ .n = "udphs_clk", .id = 27, },
{ .n = "aestdessha_clk", .id = 28, },
{ .n = "mci1_clk", .id = 29, },
{ .n = "vdec_clk", .id = 30, },
};
static void __init at91sam9g45_pmc_setup(struct device_node *np)
{
const char *slck_name, *mainxtal_name;
struct pmc_data *at91sam9g45_pmc;
const char *parent_names[6];
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_clk");
if (i < 0)
return;
slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
at91sam9g45_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9g45_systemck),
nck(at91sam9g45_periphck), 0);
if (!at91sam9g45_pmc)
return;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_rm9200_main(regmap, "mainck", "main_osc");
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->chws[PMC_MAIN] = hw;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&at91rm9200_pll_layout, &plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91rm9200_master_layout,
&mck_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->chws[PMC_MCK] = hw;
parent_names[0] = "plladivck";
parent_names[1] = "utmick";
hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "masterck";
for (i = 0; i < 2; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
&at91sam9g45_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(at91sam9g45_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9g45_systemck[i].n,
at91sam9g45_systemck[i].p,
at91sam9g45_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->shws[at91sam9g45_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) {
hw = at91_clk_register_peripheral(regmap,
at91sam9g45_periphck[i].n,
"masterck",
at91sam9g45_periphck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->phws[at91sam9g45_periphck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9g45_pmc);
return;
err_free:
pmc_data_free(at91sam9g45_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
* this can't be a platform driver.
*/
CLK_OF_DECLARE_DRIVER(at91sam9g45_pmc, "atmel,at91sam9g45-pmc",
at91sam9g45_pmc_setup);

View file

@ -0,0 +1,238 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 0, .max = 133333333 },
.divisors = { 1, 2, 4, 3 },
.have_div3_pres = 1,
};
static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
static const struct clk_range plla_outputs[] = {
{ .min = 745000000, .max = 800000000 },
{ .min = 695000000, .max = 750000000 },
{ .min = 645000000, .max = 700000000 },
{ .min = 595000000, .max = 650000000 },
{ .min = 545000000, .max = 600000000 },
{ .min = 495000000, .max = 555000000 },
{ .min = 445000000, .max = 500000000 },
{ .min = 400000000, .max = 450000000 },
};
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 2000000, .max = 32000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.icpll = plla_icpll,
.out = plla_out,
};
static u8 pllb_out[] = { 0 };
static const struct clk_range pllb_outputs[] = {
{ .min = 30000000, .max = 100000000 },
};
static const struct clk_pll_characteristics pllb_characteristics = {
.input = { .min = 2000000, .max = 32000000 },
.num_output = ARRAY_SIZE(pllb_outputs),
.output = pllb_outputs,
.out = pllb_out,
};
static const struct {
char *n;
char *p;
u8 id;
} at91sam9n12_systemck[] = {
{ .n = "ddrck", .p = "masterck", .id = 2 },
{ .n = "lcdck", .p = "masterck", .id = 3 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
};
static const struct clk_pcr_layout at91sam9n12_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.pid_mask = GENMASK(5, 0),
.div_mask = GENMASK(17, 16),
};
struct pck {
char *n;
u8 id;
};
static const struct pck at91sam9n12_periphck[] = {
{ .n = "pioAB_clk", .id = 2, },
{ .n = "pioCD_clk", .id = 3, },
{ .n = "fuse_clk", .id = 4, },
{ .n = "usart0_clk", .id = 5, },
{ .n = "usart1_clk", .id = 6, },
{ .n = "usart2_clk", .id = 7, },
{ .n = "usart3_clk", .id = 8, },
{ .n = "twi0_clk", .id = 9, },
{ .n = "twi1_clk", .id = 10, },
{ .n = "mci0_clk", .id = 12, },
{ .n = "spi0_clk", .id = 13, },
{ .n = "spi1_clk", .id = 14, },
{ .n = "uart0_clk", .id = 15, },
{ .n = "uart1_clk", .id = 16, },
{ .n = "tcb_clk", .id = 17, },
{ .n = "pwm_clk", .id = 18, },
{ .n = "adc_clk", .id = 19, },
{ .n = "dma0_clk", .id = 20, },
{ .n = "uhphs_clk", .id = 22, },
{ .n = "udphs_clk", .id = 23, },
{ .n = "lcdc_clk", .id = 25, },
{ .n = "sha_clk", .id = 27, },
{ .n = "ssc0_clk", .id = 28, },
{ .n = "aes_clk", .id = 29, },
{ .n = "trng_clk", .id = 30, },
};
static void __init at91sam9n12_pmc_setup(struct device_node *np)
{
struct clk_range range = CLK_RANGE(0, 0);
const char *slck_name, *mainxtal_name;
struct pmc_data *at91sam9n12_pmc;
const char *parent_names[6];
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_clk");
if (i < 0)
return;
slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
at91sam9n12_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9n12_systemck), 31, 0);
if (!at91sam9n12_pmc)
return;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
50000000);
if (IS_ERR(hw))
goto err_free;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc";
hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->chws[PMC_MAIN] = hw;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&at91rm9200_pll_layout, &plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
&at91rm9200_pll_layout, &pllb_characteristics);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "pllbck";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91sam9x5_master_layout,
&mck_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->chws[PMC_MCK] = hw;
hw = at91sam9n12_clk_register_usb(regmap, "usbck", "pllbck");
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "pllbck";
parent_names[4] = "masterck";
for (i = 0; i < 2; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(at91sam9n12_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9n12_systemck[i].n,
at91sam9n12_systemck[i].p,
at91sam9n12_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->shws[at91sam9n12_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9n12_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&at91sam9n12_pcr_layout,
at91sam9n12_periphck[i].n,
"masterck",
at91sam9n12_periphck[i].id,
&range);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->phws[at91sam9n12_periphck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9n12_pmc);
return;
err_free:
pmc_data_free(at91sam9n12_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
* this can't be a platform driver.
*/
CLK_OF_DECLARE_DRIVER(at91sam9n12_pmc, "atmel,at91sam9n12-pmc",
at91sam9n12_pmc_setup);

View file

@ -25,6 +25,7 @@ struct at91sam9x5_clk_usb {
struct clk_hw hw;
struct regmap *regmap;
u32 usbs_mask;
u8 num_parents;
};
#define to_at91sam9x5_clk_usb(hw) \
@ -75,6 +76,9 @@ static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
tmp_parent_rate = req->rate * div;
tmp_parent_rate = clk_hw_round_rate(parent,
tmp_parent_rate);
if (!tmp_parent_rate)
continue;
tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div);
if (tmp_rate < req->rate)
tmp_diff = req->rate - tmp_rate;
@ -107,7 +111,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
{
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
if (index > 1)
if (index >= usb->num_parents)
return -EINVAL;
regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index);
@ -211,7 +215,8 @@ _at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
usb->hw.init = &init;
usb->regmap = regmap;
usb->usbs_mask = SAM9X5_USBS_MASK;
usb->usbs_mask = usbs_mask;
usb->num_parents = num_parents;
hw = &usb->hw;
ret = clk_hw_register(NULL, &usb->hw);

View file

@ -124,7 +124,6 @@ static const struct {
char *n;
u8 id;
struct clk_range r;
bool pll;
} sam9x60_gck[] = {
{ .n = "flex0_gclk", .id = 5, },
{ .n = "flex1_gclk", .id = 6, },
@ -144,11 +143,9 @@ static const struct {
{ .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, },
{ .n = "flex11_gclk", .id = 32, },
{ .n = "flex12_gclk", .id = 33, },
{ .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 },
.pll = true, },
{ .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, },
{ .n = "pit64b_gclk", .id = 37, },
{ .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 },
.pll = true, },
{ .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, },
{ .n = "tcb1_gclk", .id = 45, },
{ .n = "dbgu_gclk", .id = 47, },
};
@ -237,9 +234,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
parent_names[0] = "pllack";
parent_names[1] = "upllck";
parent_names[2] = "mainck";
parent_names[3] = "mainck";
hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4);
parent_names[2] = "main_osc";
hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
if (IS_ERR(hw))
goto err_free;
@ -290,7 +286,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
sam9x60_gck[i].n,
parent_names, 6,
sam9x60_gck[i].id,
sam9x60_gck[i].pll,
false,
&sam9x60_gck[i].r);
if (IS_ERR(hw))
goto err_free;

240
drivers/clk/at91/sama5d3.c Normal file
View file

@ -0,0 +1,240 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 0, .max = 166000000 },
.divisors = { 1, 2, 4, 3 },
};
static u8 plla_out[] = { 0 };
static u16 plla_icpll[] = { 0 };
static const struct clk_range plla_outputs[] = {
{ .min = 400000000, .max = 1000000000 },
};
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 8000000, .max = 50000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.icpll = plla_icpll,
.out = plla_out,
};
static const struct clk_pcr_layout sama5d3_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.pid_mask = GENMASK(6, 0),
.div_mask = GENMASK(17, 16),
};
static const struct {
char *n;
char *p;
u8 id;
} sama5d3_systemck[] = {
{ .n = "ddrck", .p = "masterck", .id = 2 },
{ .n = "lcdck", .p = "masterck", .id = 3 },
{ .n = "smdck", .p = "smdclk", .id = 4 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
{ .n = "pck2", .p = "prog2", .id = 10 },
};
static const struct {
char *n;
u8 id;
struct clk_range r;
} sama5d3_periphck[] = {
{ .n = "dbgu_clk", .id = 2, },
{ .n = "hsmc_clk", .id = 5, },
{ .n = "pioA_clk", .id = 6, },
{ .n = "pioB_clk", .id = 7, },
{ .n = "pioC_clk", .id = 8, },
{ .n = "pioD_clk", .id = 9, },
{ .n = "pioE_clk", .id = 10, },
{ .n = "usart0_clk", .id = 12, .r = { .min = 0, .max = 83000000 }, },
{ .n = "usart1_clk", .id = 13, .r = { .min = 0, .max = 83000000 }, },
{ .n = "usart2_clk", .id = 14, .r = { .min = 0, .max = 83000000 }, },
{ .n = "usart3_clk", .id = 15, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uart0_clk", .id = 16, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uart1_clk", .id = 17, .r = { .min = 0, .max = 83000000 }, },
{ .n = "twi0_clk", .id = 18, .r = { .min = 0, .max = 41500000 }, },
{ .n = "twi1_clk", .id = 19, .r = { .min = 0, .max = 41500000 }, },
{ .n = "twi2_clk", .id = 20, .r = { .min = 0, .max = 41500000 }, },
{ .n = "mci0_clk", .id = 21, },
{ .n = "mci1_clk", .id = 22, },
{ .n = "mci2_clk", .id = 23, },
{ .n = "spi0_clk", .id = 24, .r = { .min = 0, .max = 166000000 }, },
{ .n = "spi1_clk", .id = 25, .r = { .min = 0, .max = 166000000 }, },
{ .n = "tcb0_clk", .id = 26, .r = { .min = 0, .max = 166000000 }, },
{ .n = "tcb1_clk", .id = 27, .r = { .min = 0, .max = 166000000 }, },
{ .n = "pwm_clk", .id = 28, },
{ .n = "adc_clk", .id = 29, .r = { .min = 0, .max = 83000000 }, },
{ .n = "dma0_clk", .id = 30, },
{ .n = "dma1_clk", .id = 31, },
{ .n = "uhphs_clk", .id = 32, },
{ .n = "udphs_clk", .id = 33, },
{ .n = "macb0_clk", .id = 34, },
{ .n = "macb1_clk", .id = 35, },
{ .n = "lcdc_clk", .id = 36, },
{ .n = "isi_clk", .id = 37, },
{ .n = "ssc0_clk", .id = 38, .r = { .min = 0, .max = 83000000 }, },
{ .n = "ssc1_clk", .id = 39, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can0_clk", .id = 40, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can1_clk", .id = 41, .r = { .min = 0, .max = 83000000 }, },
{ .n = "sha_clk", .id = 42, },
{ .n = "aes_clk", .id = 43, },
{ .n = "tdes_clk", .id = 44, },
{ .n = "trng_clk", .id = 45, },
{ .n = "fuse_clk", .id = 48, },
{ .n = "mpddr_clk", .id = 49, },
};
static void __init sama5d3_pmc_setup(struct device_node *np)
{
const char *slck_name, *mainxtal_name;
struct pmc_data *sama5d3_pmc;
const char *parent_names[5];
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_clk");
if (i < 0)
return;
slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
sama5d3_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(sama5d3_systemck),
nck(sama5d3_periphck), 0);
if (!sama5d3_pmc)
return;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
50000000);
if (IS_ERR(hw))
goto err_free;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc";
hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&sama5d3_pll_layout, &plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91sam9x5_master_layout,
&mck_characteristics);
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->chws[PMC_MCK] = hw;
parent_names[0] = "plladivck";
parent_names[1] = "utmick";
hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "masterck";
for (i = 0; i < 3; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(sama5d3_systemck); i++) {
hw = at91_clk_register_system(regmap, sama5d3_systemck[i].n,
sama5d3_systemck[i].p,
sama5d3_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->shws[sama5d3_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d3_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sama5d3_pcr_layout,
sama5d3_periphck[i].n,
"masterck",
sama5d3_periphck[i].id,
&sama5d3_periphck[i].r);
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->phws[sama5d3_periphck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d3_pmc);
return;
err_free:
pmc_data_free(sama5d3_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
* this can't be a platform driver.
*/
CLK_OF_DECLARE_DRIVER(sama5d3_pmc, "atmel,sama5d3-pmc", sama5d3_pmc_setup);

View file

@ -16,6 +16,8 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
#define SI5341_NUM_INPUTS 4
#define SI5341_MAX_NUM_OUTPUTS 10
#define SI5340_MAX_NUM_OUTPUTS 4
@ -56,8 +58,8 @@ struct clk_si5341 {
struct i2c_client *i2c_client;
struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
struct clk *pxtal;
const char *pxtal_name;
struct clk *input_clk[SI5341_NUM_INPUTS];
const char *input_clk_name[SI5341_NUM_INPUTS];
const u16 *reg_output_offset;
const u16 *reg_rdiv_offset;
u64 freq_vco; /* 1350014256 MHz */
@ -78,10 +80,25 @@ struct clk_si5341_output_config {
#define SI5341_DEVICE_REV 0x0005
#define SI5341_STATUS 0x000C
#define SI5341_SOFT_RST 0x001C
#define SI5341_IN_SEL 0x0021
#define SI5341_XAXB_CFG 0x090E
#define SI5341_IN_EN 0x0949
#define SI5341_INX_TO_PFD_EN 0x094A
/* Input selection */
#define SI5341_IN_SEL_MASK 0x06
#define SI5341_IN_SEL_SHIFT 1
#define SI5341_IN_SEL_REGCTRL 0x01
#define SI5341_INX_TO_PFD_SHIFT 4
/* XTAL config bits */
#define SI5341_XAXB_CFG_EXTCLK_EN BIT(0)
#define SI5341_XAXB_CFG_PDNB BIT(1)
/* Input dividers (48-bit) */
#define SI5341_IN_PDIV(x) (0x0208 + ((x) * 10))
#define SI5341_IN_PSET(x) (0x020E + ((x) * 10))
#define SI5341_PX_UPD 0x0230
/* PLL configuration */
#define SI5341_PLL_M_NUM 0x0235
@ -120,6 +137,10 @@ struct si5341_reg_default {
u8 value;
};
static const char * const si5341_input_clock_names[] = {
"in0", "in1", "in2", "xtal"
};
/* Output configuration registers 0..9 are not quite logically organized */
static const u16 si5341_reg_output_offset[] = {
0x0108,
@ -390,7 +411,112 @@ static unsigned long si5341_clk_recalc_rate(struct clk_hw *hw,
return (unsigned long)res;
}
static int si5341_clk_get_selected_input(struct clk_si5341 *data)
{
int err;
u32 val;
err = regmap_read(data->regmap, SI5341_IN_SEL, &val);
if (err < 0)
return err;
return (val & SI5341_IN_SEL_MASK) >> SI5341_IN_SEL_SHIFT;
}
static u8 si5341_clk_get_parent(struct clk_hw *hw)
{
struct clk_si5341 *data = to_clk_si5341(hw);
int res = si5341_clk_get_selected_input(data);
if (res < 0)
return 0; /* Apparently we cannot report errors */
return res;
}
static int si5341_clk_reparent(struct clk_si5341 *data, u8 index)
{
int err;
u8 val;
val = (index << SI5341_IN_SEL_SHIFT) & SI5341_IN_SEL_MASK;
/* Enable register-based input selection */
val |= SI5341_IN_SEL_REGCTRL;
err = regmap_update_bits(data->regmap,
SI5341_IN_SEL, SI5341_IN_SEL_REGCTRL | SI5341_IN_SEL_MASK, val);
if (err < 0)
return err;
if (index < 3) {
/* Enable input buffer for selected input */
err = regmap_update_bits(data->regmap,
SI5341_IN_EN, 0x07, BIT(index));
if (err < 0)
return err;
/* Enables the input to phase detector */
err = regmap_update_bits(data->regmap, SI5341_INX_TO_PFD_EN,
0x7 << SI5341_INX_TO_PFD_SHIFT,
BIT(index + SI5341_INX_TO_PFD_SHIFT));
if (err < 0)
return err;
/* Power down XTAL oscillator and buffer */
err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG,
SI5341_XAXB_CFG_PDNB, 0);
if (err < 0)
return err;
/*
* Set the P divider to "1". There's no explanation in the
* datasheet of these registers, but the clockbuilder software
* programs a "1" when the input is being used.
*/
err = regmap_write(data->regmap, SI5341_IN_PDIV(index), 1);
if (err < 0)
return err;
err = regmap_write(data->regmap, SI5341_IN_PSET(index), 1);
if (err < 0)
return err;
/* Set update PDIV bit */
err = regmap_write(data->regmap, SI5341_PX_UPD, BIT(index));
if (err < 0)
return err;
} else {
/* Disable all input buffers */
err = regmap_update_bits(data->regmap, SI5341_IN_EN, 0x07, 0);
if (err < 0)
return err;
/* Disable input to phase detector */
err = regmap_update_bits(data->regmap, SI5341_INX_TO_PFD_EN,
0x7 << SI5341_INX_TO_PFD_SHIFT, 0);
if (err < 0)
return err;
/* Power up XTAL oscillator and buffer */
err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG,
SI5341_XAXB_CFG_PDNB, SI5341_XAXB_CFG_PDNB);
if (err < 0)
return err;
}
return 0;
}
static int si5341_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_si5341 *data = to_clk_si5341(hw);
return si5341_clk_reparent(data, index);
}
static const struct clk_ops si5341_clk_ops = {
.set_parent = si5341_clk_set_parent,
.get_parent = si5341_clk_get_parent,
.recalc_rate = si5341_clk_recalc_rate,
};
@ -985,7 +1111,8 @@ static const struct regmap_range si5341_regmap_volatile_range[] = {
regmap_reg_range(0x000C, 0x0012), /* Status */
regmap_reg_range(0x001C, 0x001E), /* reset, finc/fdec */
regmap_reg_range(0x00E2, 0x00FE), /* NVM, interrupts, device ready */
/* Update bits for synth config */
/* Update bits for P divider and synth config */
regmap_reg_range(SI5341_PX_UPD, SI5341_PX_UPD),
regmap_reg_range(SI5341_SYNTH_N_UPD(0), SI5341_SYNTH_N_UPD(0)),
regmap_reg_range(SI5341_SYNTH_N_UPD(1), SI5341_SYNTH_N_UPD(1)),
regmap_reg_range(SI5341_SYNTH_N_UPD(2), SI5341_SYNTH_N_UPD(2)),
@ -1122,6 +1249,7 @@ static int si5341_initialize_pll(struct clk_si5341 *data)
struct device_node *np = data->i2c_client->dev.of_node;
u32 m_num = 0;
u32 m_den = 0;
int sel;
if (of_property_read_u32(np, "silabs,pll-m-num", &m_num)) {
dev_err(&data->i2c_client->dev,
@ -1135,7 +1263,11 @@ static int si5341_initialize_pll(struct clk_si5341 *data)
if (!m_num || !m_den) {
dev_err(&data->i2c_client->dev,
"PLL configuration invalid, assume 14GHz\n");
m_den = clk_get_rate(data->pxtal) / 10;
sel = si5341_clk_get_selected_input(data);
if (sel < 0)
return sel;
m_den = clk_get_rate(data->input_clk[sel]) / 10;
m_num = 1400000000;
}
@ -1143,11 +1275,52 @@ static int si5341_initialize_pll(struct clk_si5341 *data)
SI5341_PLL_M_NUM, m_num, m_den);
}
static int si5341_clk_select_active_input(struct clk_si5341 *data)
{
int res;
int err;
int i;
res = si5341_clk_get_selected_input(data);
if (res < 0)
return res;
/* If the current register setting is invalid, pick the first input */
if (!data->input_clk[res]) {
dev_dbg(&data->i2c_client->dev,
"Input %d not connected, rerouting\n", res);
res = -ENODEV;
for (i = 0; i < SI5341_NUM_INPUTS; ++i) {
if (data->input_clk[i]) {
res = i;
break;
}
}
if (res < 0) {
dev_err(&data->i2c_client->dev,
"No clock input available\n");
return res;
}
}
/* Make sure the selected clock is also enabled and routed */
err = si5341_clk_reparent(data, res);
if (err < 0)
return err;
err = clk_prepare_enable(data->input_clk[res]);
if (err < 0)
return err;
return res;
}
static int si5341_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct clk_si5341 *data;
struct clk_init_data init;
struct clk *input;
const char *root_clock_name;
const char *synth_clock_names[SI5341_NUM_SYNTH];
int err;
@ -1161,12 +1334,16 @@ static int si5341_probe(struct i2c_client *client,
data->i2c_client = client;
data->pxtal = devm_clk_get(&client->dev, "xtal");
if (IS_ERR(data->pxtal)) {
if (PTR_ERR(data->pxtal) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&client->dev, "Missing xtal clock input\n");
for (i = 0; i < SI5341_NUM_INPUTS; ++i) {
input = devm_clk_get(&client->dev, si5341_input_clock_names[i]);
if (IS_ERR(input)) {
if (PTR_ERR(input) == -EPROBE_DEFER)
return -EPROBE_DEFER;
data->input_clk_name[i] = si5341_input_clock_names[i];
} else {
data->input_clk[i] = input;
data->input_clk_name[i] = __clk_get_name(input);
}
}
err = si5341_dt_parse_dt(client, config);
@ -1188,9 +1365,6 @@ static int si5341_probe(struct i2c_client *client,
if (err < 0)
return err;
/* "Activate" the xtal (usually a fixed clock) */
clk_prepare_enable(data->pxtal);
if (of_property_read_bool(client->dev.of_node, "silabs,reprogram")) {
initialization_required = true;
} else {
@ -1223,7 +1397,14 @@ static int si5341_probe(struct i2c_client *client,
ARRAY_SIZE(si5341_reg_defaults));
if (err < 0)
return err;
}
/* Input must be up and running at this point */
err = si5341_clk_select_active_input(data);
if (err < 0)
return err;
if (initialization_required) {
/* PLL configuration is required */
err = si5341_initialize_pll(data);
if (err < 0)
@ -1231,9 +1412,8 @@ static int si5341_probe(struct i2c_client *client,
}
/* Register the PLL */
data->pxtal_name = __clk_get_name(data->pxtal);
init.parent_names = &data->pxtal_name;
init.num_parents = 1; /* For now, only XTAL input supported */
init.parent_names = data->input_clk_name;
init.num_parents = SI5341_NUM_INPUTS;
init.ops = &si5341_clk_ops;
init.flags = 0;
data->hw.init = &init;

View file

@ -488,7 +488,7 @@ unsigned long clk_hw_get_rate(const struct clk_hw *hw)
}
EXPORT_SYMBOL_GPL(clk_hw_get_rate);
static unsigned long __clk_get_accuracy(struct clk_core *core)
static unsigned long clk_core_get_accuracy_no_lock(struct clk_core *core)
{
if (!core)
return 0;
@ -774,7 +774,7 @@ static void clk_core_rate_restore_protect(struct clk_core *core, int count)
* clk_rate_exclusive_get - get exclusivity over the clk rate control
* @clk: the clk over which the exclusity of rate control is requested
*
* clk_rate_exlusive_get() begins a critical section during which a clock
* clk_rate_exclusive_get() begins a critical section during which a clock
* consumer cannot tolerate any other consumer making any operation on the
* clock which could result in a rate change or rate glitch. Exclusive clocks
* cannot have their rate changed, either directly or indirectly due to changes
@ -1517,18 +1517,12 @@ static void __clk_recalc_accuracies(struct clk_core *core)
__clk_recalc_accuracies(child);
}
static long clk_core_get_accuracy(struct clk_core *core)
static long clk_core_get_accuracy_recalc(struct clk_core *core)
{
unsigned long accuracy;
clk_prepare_lock();
if (core && (core->flags & CLK_GET_ACCURACY_NOCACHE))
__clk_recalc_accuracies(core);
accuracy = __clk_get_accuracy(core);
clk_prepare_unlock();
return accuracy;
return clk_core_get_accuracy_no_lock(core);
}
/**
@ -1542,10 +1536,16 @@ static long clk_core_get_accuracy(struct clk_core *core)
*/
long clk_get_accuracy(struct clk *clk)
{
long accuracy;
if (!clk)
return 0;
return clk_core_get_accuracy(clk->core);
clk_prepare_lock();
accuracy = clk_core_get_accuracy_recalc(clk->core);
clk_prepare_unlock();
return accuracy;
}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
@ -1599,19 +1599,12 @@ static void __clk_recalc_rates(struct clk_core *core, unsigned long msg)
__clk_recalc_rates(child, msg);
}
static unsigned long clk_core_get_rate(struct clk_core *core)
static unsigned long clk_core_get_rate_recalc(struct clk_core *core)
{
unsigned long rate;
clk_prepare_lock();
if (core && (core->flags & CLK_GET_RATE_NOCACHE))
__clk_recalc_rates(core, 0);
rate = clk_core_get_rate_nolock(core);
clk_prepare_unlock();
return rate;
return clk_core_get_rate_nolock(core);
}
/**
@ -1624,10 +1617,16 @@ static unsigned long clk_core_get_rate(struct clk_core *core)
*/
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long rate;
if (!clk)
return 0;
return clk_core_get_rate(clk->core);
clk_prepare_lock();
rate = clk_core_get_rate_recalc(clk->core);
clk_prepare_unlock();
return rate;
}
EXPORT_SYMBOL_GPL(clk_get_rate);
@ -2660,12 +2659,14 @@ static int clk_core_get_phase(struct clk_core *core)
{
int ret;
clk_prepare_lock();
lockdep_assert_held(&prepare_lock);
if (!core->ops->get_phase)
return 0;
/* Always try to update cached phase if possible */
if (core->ops->get_phase)
core->phase = core->ops->get_phase(core->hw);
ret = core->phase;
clk_prepare_unlock();
ret = core->ops->get_phase(core->hw);
if (ret >= 0)
core->phase = ret;
return ret;
}
@ -2679,10 +2680,16 @@ static int clk_core_get_phase(struct clk_core *core)
*/
int clk_get_phase(struct clk *clk)
{
int ret;
if (!clk)
return 0;
return clk_core_get_phase(clk->core);
clk_prepare_lock();
ret = clk_core_get_phase(clk->core);
clk_prepare_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(clk_get_phase);
@ -2896,13 +2903,22 @@ static struct hlist_head *orphan_list[] = {
static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
int level)
{
seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n",
int phase;
seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu ",
level * 3 + 1, "",
30 - level * 3, c->name,
c->enable_count, c->prepare_count, c->protect_count,
clk_core_get_rate(c), clk_core_get_accuracy(c),
clk_core_get_phase(c),
clk_core_get_scaled_duty_cycle(c, 100000));
clk_core_get_rate_recalc(c),
clk_core_get_accuracy_recalc(c));
phase = clk_core_get_phase(c);
if (phase >= 0)
seq_printf(s, "%5d", phase);
else
seq_puts(s, "-----");
seq_printf(s, " %6d\n", clk_core_get_scaled_duty_cycle(c, 100000));
}
static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@ -2939,6 +2955,7 @@ DEFINE_SHOW_ATTRIBUTE(clk_summary);
static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
{
int phase;
unsigned long min_rate, max_rate;
clk_core_get_boundaries(c, &min_rate, &max_rate);
@ -2948,11 +2965,13 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
seq_printf(s, "\"enable_count\": %d,", c->enable_count);
seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
seq_printf(s, "\"protect_count\": %d,", c->protect_count);
seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
seq_printf(s, "\"rate\": %lu,", clk_core_get_rate_recalc(c));
seq_printf(s, "\"min_rate\": %lu,", min_rate);
seq_printf(s, "\"max_rate\": %lu,", max_rate);
seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
seq_printf(s, "\"phase\": %d,", clk_core_get_phase(c));
seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy_recalc(c));
phase = clk_core_get_phase(c);
if (phase >= 0)
seq_printf(s, "\"phase\": %d,", phase);
seq_printf(s, "\"duty_cycle\": %u",
clk_core_get_scaled_duty_cycle(c, 100000));
}
@ -3323,7 +3342,9 @@ static void clk_core_reparent_orphans_nolock(void)
static int __clk_core_init(struct clk_core *core)
{
int ret;
struct clk_core *parent;
unsigned long rate;
int phase;
if (!core)
return -EINVAL;
@ -3394,7 +3415,7 @@ static int __clk_core_init(struct clk_core *core)
goto out;
}
core->parent = __clk_init_parent(core);
parent = core->parent = __clk_init_parent(core);
/*
* Populate core->parent if parent has already been clk_core_init'd. If
@ -3406,10 +3427,9 @@ static int __clk_core_init(struct clk_core *core)
* clocks and re-parent any that are children of the clock currently
* being clk_init'd.
*/
if (core->parent) {
hlist_add_head(&core->child_node,
&core->parent->children);
core->orphan = core->parent->orphan;
if (parent) {
hlist_add_head(&core->child_node, &parent->children);
core->orphan = parent->orphan;
} else if (!core->num_parents) {
hlist_add_head(&core->child_node, &clk_root_list);
core->orphan = false;
@ -3427,21 +3447,24 @@ static int __clk_core_init(struct clk_core *core)
*/
if (core->ops->recalc_accuracy)
core->accuracy = core->ops->recalc_accuracy(core->hw,
__clk_get_accuracy(core->parent));
else if (core->parent)
core->accuracy = core->parent->accuracy;
clk_core_get_accuracy_no_lock(parent));
else if (parent)
core->accuracy = parent->accuracy;
else
core->accuracy = 0;
/*
* Set clk's phase.
* Set clk's phase by clk_core_get_phase() caching the phase.
* Since a phase is by definition relative to its parent, just
* query the current clock phase, or just assume it's in phase.
*/
if (core->ops->get_phase)
core->phase = core->ops->get_phase(core->hw);
else
core->phase = 0;
phase = clk_core_get_phase(core);
if (phase < 0) {
ret = phase;
pr_warn("%s: Failed to get phase for clk '%s'\n", __func__,
core->name);
goto out;
}
/*
* Set clk's duty cycle.
@ -3456,9 +3479,9 @@ static int __clk_core_init(struct clk_core *core)
*/
if (core->ops->recalc_rate)
rate = core->ops->recalc_rate(core->hw,
clk_core_get_rate_nolock(core->parent));
else if (core->parent)
rate = core->parent->rate;
clk_core_get_rate_nolock(parent));
else if (parent)
rate = parent->rate;
else
rate = 0;
core->rate = core->req_rate = rate;
@ -4865,8 +4888,8 @@ static int parent_ready(struct device_node *np)
*
* Return: error code or zero on success
*/
int of_clk_detect_critical(struct device_node *np,
int index, unsigned long *flags)
int of_clk_detect_critical(struct device_node *np, int index,
unsigned long *flags)
{
struct property *prop;
const __be32 *cur;

View file

@ -15,6 +15,7 @@
#define PCG_PREDIV_MAX 8
#define PCG_DIV_SHIFT 0
#define PCG_CORE_DIV_WIDTH 3
#define PCG_DIV_WIDTH 6
#define PCG_DIV_MAX 64
@ -91,7 +92,7 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
unsigned long flags = 0;
unsigned long flags;
int prediv_value;
int div_value;
int ret;
@ -126,6 +127,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = {
struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
const char * const *parent_names,
int num_parents, void __iomem *reg,
u32 composite_flags,
unsigned long flags)
{
struct clk_hw *hw = ERR_PTR(-ENOMEM), *mux_hw;
@ -133,6 +135,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
struct clk_divider *div = NULL;
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
const struct clk_ops *divider_ops;
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
@ -150,8 +153,16 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
div_hw = &div->hw;
div->reg = reg;
div->shift = PCG_PREDIV_SHIFT;
div->width = PCG_PREDIV_WIDTH;
if (composite_flags & IMX_COMPOSITE_CORE) {
div->shift = PCG_DIV_SHIFT;
div->width = PCG_CORE_DIV_WIDTH;
divider_ops = &clk_divider_ops;
} else {
div->shift = PCG_PREDIV_SHIFT;
div->width = PCG_PREDIV_WIDTH;
divider_ops = &imx8m_clk_composite_divider_ops;
}
div->lock = &imx_ccm_lock;
div->flags = CLK_DIVIDER_ROUND_CLOSEST;
@ -166,8 +177,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ops, div_hw,
&imx8m_clk_composite_divider_ops,
gate_hw, &clk_gate_ops, flags);
divider_ops, gate_hw, &clk_gate_ops, flags);
if (IS_ERR(hw))
goto fail;

View file

@ -55,7 +55,7 @@ static int clk_fixup_div_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
struct clk_divider *div = to_clk_divider(hw);
unsigned int divider, value;
unsigned long flags = 0;
unsigned long flags;
u32 val;
divider = parent_rate / rate;

View file

@ -42,7 +42,7 @@ static int clk_fixup_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
struct clk_mux *mux = to_clk_mux(hw);
unsigned long flags = 0;
unsigned long flags;
u32 val;
spin_lock_irqsave(mux->lock, flags);

View file

@ -40,7 +40,7 @@ static int clk_gate2_enable(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
u32 reg;
unsigned long flags = 0;
unsigned long flags;
spin_lock_irqsave(gate->lock, flags);
@ -62,7 +62,7 @@ static void clk_gate2_disable(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
u32 reg;
unsigned long flags = 0;
unsigned long flags;
spin_lock_irqsave(gate->lock, flags);
@ -101,7 +101,7 @@ static int clk_gate2_is_enabled(struct clk_hw *hw)
static void clk_gate2_disable_unused(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
unsigned long flags = 0;
unsigned long flags;
u32 reg;
spin_lock_irqsave(gate->lock, flags);
@ -154,7 +154,7 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
gate->hw.init = &init;
hw = &gate->hw;
ret = clk_hw_register(NULL, hw);
ret = clk_hw_register(dev, hw);
if (ret) {
kfree(gate);
return ERR_PTR(ret);

View file

@ -208,6 +208,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
anatop_base = base;
hws[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));

View file

@ -802,6 +802,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_hw_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
hws[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
hws[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
hws[IMX7D_PXP_CLK] = imx_clk_hw_gate4("pxp_clk", "main_axi_root_clk", base + 0x44c0, 0);
hws[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
hws[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
hws[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_hw_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);

View file

@ -8,7 +8,7 @@
*/
#include <dt-bindings/clock/imx7ulp-clock.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>

View file

@ -4,12 +4,10 @@
*/
#include <dt-bindings/clock/imx8mm-clock.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@ -41,6 +39,8 @@ static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
static const char *imx8mm_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m",
"sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", };
static const char * const imx8mm_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
static const char *imx8mm_m4_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m", "sys_pll1_266m",
"sys_pll1_800m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", };
@ -283,8 +283,10 @@ static const char *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_8
static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_out",
"vpu_pll", "sys_pll1_80m", };
static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "dummy", "sys_pll1_200m",
"audio_pll2_out", "sys_pll2_500m", "vpu_pll", "sys_pll1_80m", };
static const char *imx8mm_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_400m", "sys_pll2_166m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out", "osc_32k", };
static struct clk_hw_onecell_data *clk_hw_data;
static struct clk_hw **hws;
@ -322,6 +324,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
base = of_iomap(np, 0);
of_node_put(np);
if (WARN_ON(!base))
return -ENOMEM;
@ -414,20 +417,30 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
/* Core Slice */
hws[IMX8MM_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels));
hws[IMX8MM_CLK_M4_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mm_m4_sels, ARRAY_SIZE(imx8mm_m4_sels));
hws[IMX8MM_CLK_VPU_SRC] = imx_clk_hw_mux2("vpu_src", base + 0x8100, 24, 3, imx8mm_vpu_sels, ARRAY_SIZE(imx8mm_vpu_sels));
hws[IMX8MM_CLK_GPU3D_SRC] = imx_clk_hw_mux2("gpu3d_src", base + 0x8180, 24, 3, imx8mm_gpu3d_sels, ARRAY_SIZE(imx8mm_gpu3d_sels));
hws[IMX8MM_CLK_GPU2D_SRC] = imx_clk_hw_mux2("gpu2d_src", base + 0x8200, 24, 3, imx8mm_gpu2d_sels, ARRAY_SIZE(imx8mm_gpu2d_sels));
hws[IMX8MM_CLK_A53_CG] = imx_clk_hw_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
hws[IMX8MM_CLK_M4_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
hws[IMX8MM_CLK_VPU_CG] = imx_clk_hw_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
hws[IMX8MM_CLK_GPU3D_CG] = imx_clk_hw_gate3("gpu3d_cg", "gpu3d_src", base + 0x8180, 28);
hws[IMX8MM_CLK_GPU2D_CG] = imx_clk_hw_gate3("gpu2d_cg", "gpu2d_src", base + 0x8200, 28);
hws[IMX8MM_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
hws[IMX8MM_CLK_M4_DIV] = imx_clk_hw_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
hws[IMX8MM_CLK_VPU_DIV] = imx_clk_hw_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
hws[IMX8MM_CLK_GPU3D_DIV] = imx_clk_hw_divider2("gpu3d_div", "gpu3d_cg", base + 0x8180, 0, 3);
hws[IMX8MM_CLK_GPU2D_DIV] = imx_clk_hw_divider2("gpu2d_div", "gpu2d_cg", base + 0x8200, 0, 3);
hws[IMX8MM_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mm_m4_sels, base + 0x8080);
hws[IMX8MM_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mm_vpu_sels, base + 0x8100);
hws[IMX8MM_CLK_GPU3D_CORE] = imx8m_clk_hw_composite_core("gpu3d_core", imx8mm_gpu3d_sels, base + 0x8180);
hws[IMX8MM_CLK_GPU2D_CORE] = imx8m_clk_hw_composite_core("gpu2d_core", imx8mm_gpu2d_sels, base + 0x8200);
/* For backwards compatibility */
hws[IMX8MM_CLK_M4_SRC] = hws[IMX8MM_CLK_M4_CORE];
hws[IMX8MM_CLK_M4_CG] = hws[IMX8MM_CLK_M4_CORE];
hws[IMX8MM_CLK_M4_DIV] = hws[IMX8MM_CLK_M4_CORE];
hws[IMX8MM_CLK_VPU_SRC] = hws[IMX8MM_CLK_VPU_CORE];
hws[IMX8MM_CLK_VPU_CG] = hws[IMX8MM_CLK_VPU_CORE];
hws[IMX8MM_CLK_VPU_DIV] = hws[IMX8MM_CLK_VPU_CORE];
hws[IMX8MM_CLK_GPU3D_SRC] = hws[IMX8MM_CLK_GPU3D_CORE];
hws[IMX8MM_CLK_GPU3D_CG] = hws[IMX8MM_CLK_GPU3D_CORE];
hws[IMX8MM_CLK_GPU3D_DIV] = hws[IMX8MM_CLK_GPU3D_CORE];
hws[IMX8MM_CLK_GPU2D_SRC] = hws[IMX8MM_CLK_GPU2D_CORE];
hws[IMX8MM_CLK_GPU2D_CG] = hws[IMX8MM_CLK_GPU2D_CORE];
hws[IMX8MM_CLK_GPU2D_DIV] = hws[IMX8MM_CLK_GPU2D_CORE];
/* CORE SEL */
hws[IMX8MM_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mm_a53_core_sels, ARRAY_SIZE(imx8mm_a53_core_sels));
/* BUS */
hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800);
@ -504,6 +517,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
hws[IMX8MM_CLK_WDOG] = imx8m_clk_hw_composite("wdog", imx8mm_wdog_sels, base + 0xb900);
hws[IMX8MM_CLK_WRCLK] = imx8m_clk_hw_composite("wrclk", imx8mm_wrclk_sels, base + 0xb980);
hws[IMX8MM_CLK_CLKO1] = imx8m_clk_hw_composite("clko1", imx8mm_clko1_sels, base + 0xba00);
hws[IMX8MM_CLK_CLKO2] = imx8m_clk_hw_composite("clko2", imx8mm_clko2_sels, base + 0xba80);
hws[IMX8MM_CLK_DSI_CORE] = imx8m_clk_hw_composite("dsi_core", imx8mm_dsi_core_sels, base + 0xbb00);
hws[IMX8MM_CLK_DSI_PHY_REF] = imx8m_clk_hw_composite("dsi_phy_ref", imx8mm_dsi_phy_sels, base + 0xbb80);
hws[IMX8MM_CLK_DSI_DBI] = imx8m_clk_hw_composite("dsi_dbi", imx8mm_dsi_dbi_sels, base + 0xbc00);
@ -564,7 +578,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
hws[IMX8MM_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
hws[IMX8MM_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
hws[IMX8MM_CLK_USB1_CTRL_ROOT] = imx_clk_hw_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0);
hws[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_div", base + 0x44f0, 0);
hws[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_core", base + 0x44f0, 0);
hws[IMX8MM_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
hws[IMX8MM_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
hws[IMX8MM_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
@ -586,7 +600,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
hws[IMX8MM_CLK_SDMA1_ROOT] = imx_clk_hw_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
hws[IMX8MM_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
hws[IMX8MM_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
hws[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_div", base + 0x4660, 0);
hws[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_core", base + 0x4660, 0);
hws[IMX8MM_CLK_CSI1_ROOT] = imx_clk_hw_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
hws[IMX8MM_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc_24m", 1, 8);
@ -594,11 +608,14 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
hws[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
hws[IMX8MM_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels), CLK_IS_CRITICAL);
hws[IMX8MM_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div",
hws[IMX8MM_CLK_A53_DIV]->clk,
hws[IMX8MM_CLK_A53_SRC]->clk,
hws[IMX8MM_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
hws[IMX8MM_CLK_A53_CORE]->clk,
hws[IMX8MM_CLK_A53_CORE]->clk,
hws[IMX8MM_ARM_PLL_OUT]->clk,
hws[IMX8MM_SYS_PLL1_800M]->clk);
hws[IMX8MM_CLK_A53_DIV]->clk);
clk_hw_set_parent(hws[IMX8MM_CLK_A53_SRC], hws[IMX8MM_SYS_PLL1_800M]);
clk_hw_set_parent(hws[IMX8MM_CLK_A53_CORE], hws[IMX8MM_ARM_PLL_OUT]);
imx_check_clk_hws(hws, IMX8MM_CLK_END);

View file

@ -4,12 +4,10 @@
*/
#include <dt-bindings/clock/imx8mn-clock.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@ -40,6 +38,8 @@ static const char * const imx8mn_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pl
"sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
"audio_pll1_out", "sys_pll3_out", };
static const char * const imx8mn_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
static const char * const imx8mn_gpu_core_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
"sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", };
@ -317,6 +317,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mn-anatop");
base = of_iomap(np, 0);
of_node_put(np);
if (WARN_ON(!base)) {
ret = -ENOMEM;
goto unregister_hws;
@ -413,15 +414,21 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
/* CORE */
hws[IMX8MN_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels));
hws[IMX8MN_CLK_GPU_CORE_SRC] = imx_clk_hw_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mn_gpu_core_sels, ARRAY_SIZE(imx8mn_gpu_core_sels));
hws[IMX8MN_CLK_GPU_SHADER_SRC] = imx_clk_hw_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mn_gpu_shader_sels, ARRAY_SIZE(imx8mn_gpu_shader_sels));
hws[IMX8MN_CLK_A53_CG] = imx_clk_hw_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
hws[IMX8MN_CLK_GPU_CORE_CG] = imx_clk_hw_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28);
hws[IMX8MN_CLK_GPU_SHADER_CG] = imx_clk_hw_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28);
hws[IMX8MN_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
hws[IMX8MN_CLK_GPU_CORE_DIV] = imx_clk_hw_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3);
hws[IMX8MN_CLK_GPU_SHADER_DIV] = imx_clk_hw_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3);
hws[IMX8MN_CLK_GPU_CORE] = imx8m_clk_hw_composite_core("gpu_core", imx8mn_gpu_core_sels, base + 0x8180);
hws[IMX8MN_CLK_GPU_SHADER] = imx8m_clk_hw_composite_core("gpu_shader", imx8mn_gpu_shader_sels, base + 0x8200);
hws[IMX8MN_CLK_GPU_CORE_SRC] = hws[IMX8MN_CLK_GPU_CORE];
hws[IMX8MN_CLK_GPU_CORE_CG] = hws[IMX8MN_CLK_GPU_CORE];
hws[IMX8MN_CLK_GPU_CORE_DIV] = hws[IMX8MN_CLK_GPU_CORE];
hws[IMX8MN_CLK_GPU_SHADER_SRC] = hws[IMX8MN_CLK_GPU_SHADER];
hws[IMX8MN_CLK_GPU_SHADER_CG] = hws[IMX8MN_CLK_GPU_SHADER];
hws[IMX8MN_CLK_GPU_SHADER_DIV] = hws[IMX8MN_CLK_GPU_SHADER];
/* CORE SEL */
hws[IMX8MN_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mn_a53_core_sels, ARRAY_SIZE(imx8mn_a53_core_sels));
/* BUS */
hws[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800);
@ -529,7 +536,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
hws[IMX8MN_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
hws[IMX8MN_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
hws[IMX8MN_CLK_USB1_CTRL_ROOT] = imx_clk_hw_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0);
hws[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_hw_gate4("gpu_core_root_clk", "gpu_core_div", base + 0x44f0, 0);
hws[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_hw_gate4("gpu_core_root_clk", "gpu_core", base + 0x44f0, 0);
hws[IMX8MN_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
hws[IMX8MN_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
hws[IMX8MN_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
@ -552,11 +559,14 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
hws[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
hws[IMX8MN_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div",
hws[IMX8MN_CLK_A53_DIV]->clk,
hws[IMX8MN_CLK_A53_SRC]->clk,
hws[IMX8MN_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
hws[IMX8MN_CLK_A53_CORE]->clk,
hws[IMX8MN_CLK_A53_CORE]->clk,
hws[IMX8MN_ARM_PLL_OUT]->clk,
hws[IMX8MN_SYS_PLL1_800M]->clk);
hws[IMX8MN_CLK_A53_DIV]->clk);
clk_hw_set_parent(hws[IMX8MN_CLK_A53_SRC], hws[IMX8MN_SYS_PLL1_800M]);
clk_hw_set_parent(hws[IMX8MN_CLK_A53_CORE], hws[IMX8MN_ARM_PLL_OUT]);
imx_check_clk_hws(hws, IMX8MN_CLK_END);

View file

@ -4,13 +4,13 @@
*/
#include <dt-bindings/clock/imx8mp-clock.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "clk.h"
@ -34,6 +34,8 @@ static const char * const imx8mp_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pl
"sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
"audio_pll1_out", "sys_pll3_out", };
static const char * const imx8mp_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
static const char * const imx8mp_m7_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m",
"vpu_pll_out", "sys_pll1_800m", "audio_pll1_out",
"video_pll1_out", "sys_pll3_out", };
@ -342,7 +344,7 @@ static const char * const imx8mp_hdmi_fdcc_tst_sels[] = {"osc_24m", "sys_pll1_26
"sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
"audio_pll2_out", "video_pll1_out", };
static const char * const imx8mp_hdmi_27m_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
static const char * const imx8mp_hdmi_24m_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
@ -434,6 +436,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mp-anatop");
anatop_base = of_iomap(np, 0);
of_node_put(np);
if (WARN_ON(!anatop_base))
return -ENOMEM;
@ -553,6 +556,9 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_HSIO_AXI_DIV] = imx_clk_hw_divider2("hsio_axi_div", "hsio_axi_cg", ccm_base + 0x8380, 0, 3);
hws[IMX8MP_CLK_MEDIA_ISP_DIV] = imx_clk_hw_divider2("media_isp_div", "media_isp_cg", ccm_base + 0x8400, 0, 3);
/* CORE SEL */
hws[IMX8MP_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", ccm_base + 0x9880, 24, 1, imx8mp_a53_core_sels, ARRAY_SIZE(imx8mp_a53_core_sels));
hws[IMX8MP_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mp_main_axi_sels, ccm_base + 0x8800);
hws[IMX8MP_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mp_enet_axi_sels, ccm_base + 0x8880);
hws[IMX8MP_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, ccm_base + 0x8900);
@ -631,7 +637,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_IPP_DO_CLKO1] = imx8m_clk_hw_composite("ipp_do_clko1", imx8mp_ipp_do_clko1_sels, ccm_base + 0xba00);
hws[IMX8MP_CLK_IPP_DO_CLKO2] = imx8m_clk_hw_composite("ipp_do_clko2", imx8mp_ipp_do_clko2_sels, ccm_base + 0xba80);
hws[IMX8MP_CLK_HDMI_FDCC_TST] = imx8m_clk_hw_composite("hdmi_fdcc_tst", imx8mp_hdmi_fdcc_tst_sels, ccm_base + 0xbb00);
hws[IMX8MP_CLK_HDMI_27M] = imx8m_clk_hw_composite("hdmi_27m", imx8mp_hdmi_27m_sels, ccm_base + 0xbb80);
hws[IMX8MP_CLK_HDMI_24M] = imx8m_clk_hw_composite("hdmi_24m", imx8mp_hdmi_24m_sels, ccm_base + 0xbb80);
hws[IMX8MP_CLK_HDMI_REF_266M] = imx8m_clk_hw_composite("hdmi_ref_266m", imx8mp_hdmi_ref_266m_sels, ccm_base + 0xbc00);
hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80);
hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00);
@ -671,6 +677,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_I2C2_ROOT] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2", ccm_base + 0x4180, 0);
hws[IMX8MP_CLK_I2C3_ROOT] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3", ccm_base + 0x4190, 0);
hws[IMX8MP_CLK_I2C4_ROOT] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4", ccm_base + 0x41a0, 0);
hws[IMX8MP_CLK_OCOTP_ROOT] = imx_clk_hw_gate4("ocotp_root_clk", "ipg_root", ccm_base + 0x4220, 0);
hws[IMX8MP_CLK_PCIE_ROOT] = imx_clk_hw_gate4("pcie_root_clk", "pcie_aux", ccm_base + 0x4250, 0);
hws[IMX8MP_CLK_PWM1_ROOT] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1", ccm_base + 0x4280, 0);
hws[IMX8MP_CLK_PWM2_ROOT] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2", ccm_base + 0x4290, 0);
@ -722,11 +729,14 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_VPU_ROOT] = imx_clk_hw_gate4("vpu_root_clk", "vpu_bus", ccm_base + 0x4630, 0);
hws[IMX8MP_CLK_AUDIO_ROOT] = imx_clk_hw_gate4("audio_root_clk", "ipg_root", ccm_base + 0x4650, 0);
hws[IMX8MP_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div",
hws[IMX8MP_CLK_A53_DIV]->clk,
hws[IMX8MP_CLK_A53_SRC]->clk,
hws[IMX8MP_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
hws[IMX8MP_CLK_A53_CORE]->clk,
hws[IMX8MP_CLK_A53_CORE]->clk,
hws[IMX8MP_ARM_PLL_OUT]->clk,
hws[IMX8MP_SYS_PLL1_800M]->clk);
hws[IMX8MP_CLK_A53_DIV]->clk);
clk_hw_set_parent(hws[IMX8MP_CLK_A53_SRC], hws[IMX8MP_SYS_PLL1_800M]);
clk_hw_set_parent(hws[IMX8MP_CLK_A53_CORE], hws[IMX8MP_ARM_PLL_OUT]);
imx_check_clk_hws(hws, IMX8MP_CLK_END);

View file

@ -5,7 +5,7 @@
*/
#include <dt-bindings/clock/imx8mq-clock.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
@ -41,6 +41,8 @@ static const char * const video2_pll_out_sels[] = {"video2_pll1_ref_sel", };
static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
"sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll_out", };
static const char * const imx8mq_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
static const char * const imx8mq_arm_m4_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_250m", "sys1_pll_266m",
"sys1_pll_800m", "audio_pll1_out", "video_pll1_out", "sys3_pll_out", };
@ -305,6 +307,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
base = of_iomap(np, 0);
of_node_put(np);
if (WARN_ON(!base))
return -ENOMEM;
@ -403,22 +406,29 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
/* CORE */
hws[IMX8MQ_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
hws[IMX8MQ_CLK_M4_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mq_arm_m4_sels, ARRAY_SIZE(imx8mq_arm_m4_sels));
hws[IMX8MQ_CLK_VPU_SRC] = imx_clk_hw_mux2("vpu_src", base + 0x8100, 24, 3, imx8mq_vpu_sels, ARRAY_SIZE(imx8mq_vpu_sels));
hws[IMX8MQ_CLK_GPU_CORE_SRC] = imx_clk_hw_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mq_gpu_core_sels, ARRAY_SIZE(imx8mq_gpu_core_sels));
hws[IMX8MQ_CLK_GPU_SHADER_SRC] = imx_clk_hw_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mq_gpu_shader_sels, ARRAY_SIZE(imx8mq_gpu_shader_sels));
hws[IMX8MQ_CLK_A53_CG] = imx_clk_hw_gate3_flags("arm_a53_cg", "arm_a53_src", base + 0x8000, 28, CLK_IS_CRITICAL);
hws[IMX8MQ_CLK_M4_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
hws[IMX8MQ_CLK_VPU_CG] = imx_clk_hw_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
hws[IMX8MQ_CLK_GPU_CORE_CG] = imx_clk_hw_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28);
hws[IMX8MQ_CLK_GPU_SHADER_CG] = imx_clk_hw_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28);
hws[IMX8MQ_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
hws[IMX8MQ_CLK_M4_DIV] = imx_clk_hw_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
hws[IMX8MQ_CLK_VPU_DIV] = imx_clk_hw_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
hws[IMX8MQ_CLK_GPU_CORE_DIV] = imx_clk_hw_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3);
hws[IMX8MQ_CLK_GPU_SHADER_DIV] = imx_clk_hw_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3);
hws[IMX8MQ_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mq_arm_m4_sels, base + 0x8080);
hws[IMX8MQ_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mq_vpu_sels, base + 0x8100);
hws[IMX8MQ_CLK_GPU_CORE] = imx8m_clk_hw_composite_core("gpu_core", imx8mq_gpu_core_sels, base + 0x8180);
hws[IMX8MQ_CLK_GPU_SHADER] = imx8m_clk_hw_composite("gpu_shader", imx8mq_gpu_shader_sels, base + 0x8200);
/* For backwards compatibility */
hws[IMX8MQ_CLK_M4_SRC] = hws[IMX8MQ_CLK_M4_CORE];
hws[IMX8MQ_CLK_M4_CG] = hws[IMX8MQ_CLK_M4_CORE];
hws[IMX8MQ_CLK_M4_DIV] = hws[IMX8MQ_CLK_M4_CORE];
hws[IMX8MQ_CLK_VPU_SRC] = hws[IMX8MQ_CLK_VPU_CORE];
hws[IMX8MQ_CLK_VPU_CG] = hws[IMX8MQ_CLK_VPU_CORE];
hws[IMX8MQ_CLK_VPU_DIV] = hws[IMX8MQ_CLK_VPU_CORE];
hws[IMX8MQ_CLK_GPU_CORE_SRC] = hws[IMX8MQ_CLK_GPU_CORE];
hws[IMX8MQ_CLK_GPU_CORE_CG] = hws[IMX8MQ_CLK_GPU_CORE];
hws[IMX8MQ_CLK_GPU_CORE_DIV] = hws[IMX8MQ_CLK_GPU_CORE];
hws[IMX8MQ_CLK_GPU_SHADER_SRC] = hws[IMX8MQ_CLK_GPU_SHADER];
hws[IMX8MQ_CLK_GPU_SHADER_CG] = hws[IMX8MQ_CLK_GPU_SHADER];
hws[IMX8MQ_CLK_GPU_SHADER_DIV] = hws[IMX8MQ_CLK_GPU_SHADER];
/* CORE SEL */
hws[IMX8MQ_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels));
/* BUS */
hws[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800);
@ -567,7 +577,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
hws[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_hw_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
hws[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_hw_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
hws[IMX8MQ_CLK_VPU_G1_ROOT] = imx_clk_hw_gate2_flags("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
hws[IMX8MQ_CLK_GPU_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_core_div", base + 0x4570, 0);
hws[IMX8MQ_CLK_GPU_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_core", base + 0x4570, 0);
hws[IMX8MQ_CLK_VPU_G2_ROOT] = imx_clk_hw_gate2_flags("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
hws[IMX8MQ_CLK_DISP_ROOT] = imx_clk_hw_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_dcss);
hws[IMX8MQ_CLK_DISP_AXI_ROOT] = imx_clk_hw_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_dcss);
@ -583,11 +593,14 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
hws[IMX8MQ_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc_25m", 1, 8);
hws[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
hws[IMX8MQ_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_div",
hws[IMX8MQ_CLK_A53_DIV]->clk,
hws[IMX8MQ_CLK_A53_SRC]->clk,
hws[IMX8MQ_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
hws[IMX8MQ_CLK_A53_CORE]->clk,
hws[IMX8MQ_CLK_A53_CORE]->clk,
hws[IMX8MQ_ARM_PLL_OUT]->clk,
hws[IMX8MQ_SYS1_PLL_800M]->clk);
hws[IMX8MQ_CLK_A53_DIV]->clk);
clk_hw_set_parent(hws[IMX8MQ_CLK_A53_SRC], hws[IMX8MQ_SYS1_PLL_800M]);
clk_hw_set_parent(hws[IMX8MQ_CLK_A53_CORE], hws[IMX8MQ_ARM_PLL_OUT]);
imx_check_clk_hws(hws, IMX8MQ_CLK_END);

View file

@ -98,26 +98,45 @@ static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw,
return tmp;
}
static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
static int clk_pfdv2_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
u64 tmp = *prate;
unsigned long parent_rates[] = {
480000000,
528000000,
req->best_parent_rate
};
unsigned long best_rate = -1UL, rate = req->rate;
unsigned long best_parent_rate = req->best_parent_rate;
u64 tmp;
u8 frac;
int i;
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
frac = tmp;
for (i = 0; i < ARRAY_SIZE(parent_rates); i++) {
tmp = parent_rates[i];
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
frac = tmp;
if (frac < 12)
frac = 12;
else if (frac > 35)
frac = 35;
if (frac < 12)
frac = 12;
else if (frac > 35)
frac = 35;
tmp = *prate;
tmp *= 18;
do_div(tmp, frac);
tmp = parent_rates[i];
tmp *= 18;
do_div(tmp, frac);
return tmp;
if (abs(tmp - req->rate) < abs(best_rate - req->rate)) {
best_rate = tmp;
best_parent_rate = parent_rates[i];
}
}
req->best_parent_rate = best_parent_rate;
req->rate = best_rate;
return 0;
}
static int clk_pfdv2_is_enabled(struct clk_hw *hw)
@ -139,6 +158,12 @@ static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate,
u32 val;
u8 frac;
if (!rate)
return -EINVAL;
/* PFD can NOT change rate without gating */
WARN_ON(clk_pfdv2_is_enabled(hw));
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
frac = tmp;
@ -161,7 +186,7 @@ static const struct clk_ops clk_pfdv2_ops = {
.enable = clk_pfdv2_enable,
.disable = clk_pfdv2_disable,
.recalc_rate = clk_pfdv2_recalc_rate,
.round_rate = clk_pfdv2_round_rate,
.determine_rate = clk_pfdv2_determine_rate,
.set_rate = clk_pfdv2_set_rate,
.is_enabled = clk_pfdv2_is_enabled,
};
@ -189,7 +214,7 @@ struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
init.ops = &clk_pfdv2_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE;
init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
pfd->hw.init = &init;

View file

@ -55,8 +55,10 @@ static const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = {
};
static const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {
PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384),
PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
PLL_1443X_RATE(519750000U, 173, 2, 2, 16384),
PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
};
@ -408,6 +410,8 @@ struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
default:
pr_err("%s: Unknown pll type for pll clk %s\n",
__func__, name);
kfree(pll);
return ERR_PTR(-EINVAL);
};
pll->base = base;

View file

@ -54,7 +54,7 @@ static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll)
csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US);
}
static int clk_pllv4_is_enabled(struct clk_hw *hw)
static int clk_pllv4_is_prepared(struct clk_hw *hw)
{
struct clk_pllv4 *pll = to_clk_pllv4(hw);
@ -175,7 +175,7 @@ static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
static int clk_pllv4_enable(struct clk_hw *hw)
static int clk_pllv4_prepare(struct clk_hw *hw)
{
u32 val;
struct clk_pllv4 *pll = to_clk_pllv4(hw);
@ -187,7 +187,7 @@ static int clk_pllv4_enable(struct clk_hw *hw)
return clk_pllv4_wait_lock(pll);
}
static void clk_pllv4_disable(struct clk_hw *hw)
static void clk_pllv4_unprepare(struct clk_hw *hw)
{
u32 val;
struct clk_pllv4 *pll = to_clk_pllv4(hw);
@ -201,9 +201,9 @@ static const struct clk_ops clk_pllv4_ops = {
.recalc_rate = clk_pllv4_recalc_rate,
.round_rate = clk_pllv4_round_rate,
.set_rate = clk_pllv4_set_rate,
.enable = clk_pllv4_enable,
.disable = clk_pllv4_disable,
.is_enabled = clk_pllv4_is_enabled,
.prepare = clk_pllv4_prepare,
.unprepare = clk_pllv4_unprepare,
.is_prepared = clk_pllv4_is_prepared,
};
struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,

View file

@ -195,10 +195,10 @@ static int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup,
uint64_t ref)
{
int ret = -EINVAL;
int ret;
if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)
return ret;
return -EINVAL;
temp_setup->vco1 = ref;
@ -254,10 +254,10 @@ static int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup,
uint64_t ref)
{
int ret = -EINVAL;
int ret;
if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)
return ret;
return -EINVAL;
temp_setup->ref = ref;
@ -428,7 +428,7 @@ static int __clk_sscg_pll_determine_rate(struct clk_hw *hw,
struct clk_sscg_pll_setup *setup = &pll->setup;
struct clk_hw *parent_hw = NULL;
int bypass_parent_index;
int ret = -EINVAL;
int ret;
req->max_rate = max;
req->min_rate = min;
@ -467,10 +467,10 @@ static int clk_sscg_pll_determine_rate(struct clk_hw *hw,
uint64_t rate = req->rate;
uint64_t min = req->min_rate;
uint64_t max = req->max_rate;
int ret = -EINVAL;
int ret;
if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ)
return ret;
return -EINVAL;
ret = __clk_sscg_pll_determine_rate(hw, req, req->rate, req->rate,
rate, PLL_BYPASS2);

View file

@ -477,20 +477,29 @@ struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
#define IMX_COMPOSITE_CORE BIT(0)
struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
const char * const *parent_names,
int num_parents,
void __iomem *reg,
u32 composite_flags,
unsigned long flags);
#define imx8m_clk_hw_composite_core(name, parent_names, reg) \
imx8m_clk_hw_composite_flags(name, parent_names, \
ARRAY_SIZE(parent_names), reg, \
IMX_COMPOSITE_CORE, \
CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
#define imx8m_clk_composite_flags(name, parent_names, num_parents, reg, \
flags) \
to_clk(imx8m_clk_hw_composite_flags(name, parent_names, \
num_parents, reg, flags))
num_parents, reg, 0, flags))
#define __imx8m_clk_hw_composite(name, parent_names, reg, flags) \
imx8m_clk_hw_composite_flags(name, parent_names, \
ARRAY_SIZE(parent_names), reg, \
ARRAY_SIZE(parent_names), reg, 0, \
flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
#define __imx8m_clk_composite(name, parent_names, reg, flags) \

View file

@ -432,8 +432,10 @@ static void __init jz4770_cgu_init(struct device_node *np)
cgu = ingenic_cgu_new(jz4770_cgu_clocks,
ARRAY_SIZE(jz4770_cgu_clocks), np);
if (!cgu)
if (!cgu) {
pr_err("%s: failed to initialise CGU\n", __func__);
return;
}
retval = ingenic_cgu_register_clocks(cgu);
if (retval)

View file

@ -9,14 +9,16 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <dt-bindings/clock/jz4780-cgu.h>
#include "cgu.h"
#include "pm.h"
/* CGU register offsets */
#define CGU_REG_CLOCKCONTROL 0x00
#define CGU_REG_PLLCONTROL 0x0c
#define CGU_REG_LCR 0x04
#define CGU_REG_APLL 0x10
#define CGU_REG_MPLL 0x14
#define CGU_REG_EPLL 0x18
@ -46,8 +48,8 @@
#define CGU_REG_CLOCKSTATUS 0xd4
/* bits within the OPCR register */
#define OPCR_SPENDN0 (1 << 7)
#define OPCR_SPENDN1 (1 << 6)
#define OPCR_SPENDN0 BIT(7)
#define OPCR_SPENDN1 BIT(6)
/* bits within the USBPCR register */
#define USBPCR_USB_MODE BIT(31)
@ -88,6 +90,13 @@
#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
#define USBVBFIL_USBVBFIL_MASK (0xffff)
/* bits within the LCR register */
#define LCR_PD_SCPU BIT(31)
#define LCR_SCPUS BIT(27)
/* bits within the CLKGR1 register */
#define CLKGR1_CORE1 BIT(15)
static struct ingenic_cgu *cgu;
static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
@ -205,6 +214,42 @@ static const struct clk_ops jz4780_otg_phy_ops = {
.set_rate = jz4780_otg_phy_set_rate,
};
static int jz4780_core1_enable(struct clk_hw *hw)
{
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const unsigned int timeout = 5000;
unsigned long flags;
int retval;
u32 lcr, clkgr1;
spin_lock_irqsave(&cgu->lock, flags);
lcr = readl(cgu->base + CGU_REG_LCR);
lcr &= ~LCR_PD_SCPU;
writel(lcr, cgu->base + CGU_REG_LCR);
clkgr1 = readl(cgu->base + CGU_REG_CLKGR1);
clkgr1 &= ~CLKGR1_CORE1;
writel(clkgr1, cgu->base + CGU_REG_CLKGR1);
spin_unlock_irqrestore(&cgu->lock, flags);
/* wait for the CPU to be powered up */
retval = readl_poll_timeout(cgu->base + CGU_REG_LCR, lcr,
!(lcr & LCR_SCPUS), 10, timeout);
if (retval == -ETIMEDOUT) {
pr_err("%s: Wait for power up core1 timeout\n", __func__);
return retval;
}
return 0;
}
static const struct clk_ops jz4780_core1_ops = {
.enable = jz4780_core1_enable,
};
static const s8 pll_od_encoding[16] = {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
@ -699,9 +744,9 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = {
},
[JZ4780_CLK_CORE1] = {
"core1", CGU_CLK_GATE,
"core1", CGU_CLK_CUSTOM,
.parents = { JZ4780_CLK_CPU, -1, -1, -1 },
.gate = { CGU_REG_CLKGR1, 15 },
.custom = { &jz4780_core1_ops },
},
};

View file

@ -189,7 +189,7 @@ static long ingenic_tcu_round_rate(struct clk_hw *hw, unsigned long req_rate,
u8 prescale;
if (req_rate > rate)
return -EINVAL;
return rate;
prescale = ingenic_tcu_get_prescale(rate, req_rate);
@ -317,10 +317,17 @@ static const struct ingenic_soc_info jz4770_soc_info = {
.has_tcu_clk = false,
};
static const struct ingenic_soc_info x1000_soc_info = {
.num_channels = 8,
.has_ost = false, /* X1000 has OST, but it not belong TCU */
.has_tcu_clk = false,
};
static const struct of_device_id ingenic_tcu_of_match[] __initconst = {
{ .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
{ .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, },
{ .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, },
{ .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, },
{ /* sentinel */ }
};
@ -471,3 +478,4 @@ static void __init ingenic_tcu_init(struct device_node *np)
CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init);
CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", ingenic_tcu_init);
CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", ingenic_tcu_init);
CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", ingenic_tcu_init);

View file

@ -26,3 +26,11 @@ config TI_SCI_CLK_PROBE_FROM_FW
This is mostly only useful for debugging purposes, and will
increase the boot time of the device. If you want the clocks probed
from firmware, say Y. Otherwise, say N.
config TI_SYSCON_CLK
tristate "Syscon based clock driver for K2/K3 SoCs"
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
default ARCH_KEYSTONE || ARCH_K3
help
This adds clock driver support for syscon based gate
clocks on TI's K2 and K3 SoCs.

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += pll.o gate.o
obj-$(CONFIG_TI_SCI_CLK) += sci-clk.o
obj-$(CONFIG_TI_SYSCON_CLK) += syscon-clk.o

View file

@ -0,0 +1,172 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
*/
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
struct ti_syscon_gate_clk_priv {
struct clk_hw hw;
struct regmap *regmap;
u32 reg;
u32 idx;
};
struct ti_syscon_gate_clk_data {
char *name;
u32 offset;
u32 bit_idx;
};
static struct
ti_syscon_gate_clk_priv *to_ti_syscon_gate_clk_priv(struct clk_hw *hw)
{
return container_of(hw, struct ti_syscon_gate_clk_priv, hw);
}
static int ti_syscon_gate_clk_enable(struct clk_hw *hw)
{
struct ti_syscon_gate_clk_priv *priv = to_ti_syscon_gate_clk_priv(hw);
return regmap_write_bits(priv->regmap, priv->reg, priv->idx,
priv->idx);
}
static void ti_syscon_gate_clk_disable(struct clk_hw *hw)
{
struct ti_syscon_gate_clk_priv *priv = to_ti_syscon_gate_clk_priv(hw);
regmap_write_bits(priv->regmap, priv->reg, priv->idx, 0);
}
static int ti_syscon_gate_clk_is_enabled(struct clk_hw *hw)
{
unsigned int val;
struct ti_syscon_gate_clk_priv *priv = to_ti_syscon_gate_clk_priv(hw);
regmap_read(priv->regmap, priv->reg, &val);
return !!(val & priv->idx);
}
static const struct clk_ops ti_syscon_gate_clk_ops = {
.enable = ti_syscon_gate_clk_enable,
.disable = ti_syscon_gate_clk_disable,
.is_enabled = ti_syscon_gate_clk_is_enabled,
};
static struct clk_hw
*ti_syscon_gate_clk_register(struct device *dev, struct regmap *regmap,
const struct ti_syscon_gate_clk_data *data)
{
struct ti_syscon_gate_clk_priv *priv;
struct clk_init_data init;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
init.name = data->name;
init.ops = &ti_syscon_gate_clk_ops;
init.parent_names = NULL;
init.num_parents = 0;
init.flags = 0;
priv->regmap = regmap;
priv->reg = data->offset;
priv->idx = BIT(data->bit_idx);
priv->hw.init = &init;
ret = devm_clk_hw_register(dev, &priv->hw);
if (ret)
return ERR_PTR(ret);
return &priv->hw;
}
static int ti_syscon_gate_clk_probe(struct platform_device *pdev)
{
const struct ti_syscon_gate_clk_data *data, *p;
struct clk_hw_onecell_data *hw_data;
struct device *dev = &pdev->dev;
struct regmap *regmap;
int num_clks, i;
data = device_get_match_data(dev);
if (!data)
return -EINVAL;
regmap = syscon_node_to_regmap(dev->of_node);
if (IS_ERR(regmap)) {
if (PTR_ERR(regmap) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(dev, "failed to find parent regmap\n");
return PTR_ERR(regmap);
}
num_clks = 0;
for (p = data; p->name; p++)
num_clks++;
hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, num_clks),
GFP_KERNEL);
if (!hw_data)
return -ENOMEM;
hw_data->num = num_clks;
for (i = 0; i < num_clks; i++) {
hw_data->hws[i] = ti_syscon_gate_clk_register(dev, regmap,
&data[i]);
if (IS_ERR(hw_data->hws[i]))
dev_warn(dev, "failed to register %s\n",
data[i].name);
}
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
hw_data);
}
#define TI_SYSCON_CLK_GATE(_name, _offset, _bit_idx) \
{ \
.name = _name, \
.offset = (_offset), \
.bit_idx = (_bit_idx), \
}
static const struct ti_syscon_gate_clk_data am654_clk_data[] = {
TI_SYSCON_CLK_GATE("ehrpwm_tbclk0", 0x0, 0),
TI_SYSCON_CLK_GATE("ehrpwm_tbclk1", 0x4, 0),
TI_SYSCON_CLK_GATE("ehrpwm_tbclk2", 0x8, 0),
TI_SYSCON_CLK_GATE("ehrpwm_tbclk3", 0xc, 0),
TI_SYSCON_CLK_GATE("ehrpwm_tbclk4", 0x10, 0),
TI_SYSCON_CLK_GATE("ehrpwm_tbclk5", 0x14, 0),
{ /* Sentinel */ },
};
static const struct of_device_id ti_syscon_gate_clk_ids[] = {
{
.compatible = "ti,am654-ehrpwm-tbclk",
.data = &am654_clk_data,
},
{ }
};
MODULE_DEVICE_TABLE(of, ti_syscon_gate_clk_ids);
static struct platform_driver ti_syscon_gate_clk_driver = {
.probe = ti_syscon_gate_clk_probe,
.driver = {
.name = "ti-syscon-gate-clk",
.of_match_table = ti_syscon_gate_clk_ids,
},
};
module_platform_driver(ti_syscon_gate_clk_driver);
MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");
MODULE_DESCRIPTION("Syscon backed gate-clock driver");
MODULE_LICENSE("GPL");

View file

@ -3862,6 +3862,111 @@ static struct clk_regmap g12a_ts = {
},
};
/* SPICC SCLK source clock */
static const struct clk_parent_data spicc_sclk_parent_data[] = {
{ .fw_name = "xtal", },
{ .hw = &g12a_clk81.hw },
{ .hw = &g12a_fclk_div4.hw },
{ .hw = &g12a_fclk_div3.hw },
{ .hw = &g12a_fclk_div5.hw },
{ .hw = &g12a_fclk_div7.hw },
};
static struct clk_regmap g12a_spicc0_sclk_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_SPICC_CLK_CNTL,
.mask = 7,
.shift = 7,
},
.hw.init = &(struct clk_init_data){
.name = "spicc0_sclk_sel",
.ops = &clk_regmap_mux_ops,
.parent_data = spicc_sclk_parent_data,
.num_parents = ARRAY_SIZE(spicc_sclk_parent_data),
},
};
static struct clk_regmap g12a_spicc0_sclk_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_SPICC_CLK_CNTL,
.shift = 0,
.width = 6,
},
.hw.init = &(struct clk_init_data){
.name = "spicc0_sclk_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (const struct clk_hw *[]) {
&g12a_spicc0_sclk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap g12a_spicc0_sclk = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_SPICC_CLK_CNTL,
.bit_idx = 6,
},
.hw.init = &(struct clk_init_data){
.name = "spicc0_sclk",
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) {
&g12a_spicc0_sclk_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap g12a_spicc1_sclk_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_SPICC_CLK_CNTL,
.mask = 7,
.shift = 23,
},
.hw.init = &(struct clk_init_data){
.name = "spicc1_sclk_sel",
.ops = &clk_regmap_mux_ops,
.parent_data = spicc_sclk_parent_data,
.num_parents = ARRAY_SIZE(spicc_sclk_parent_data),
},
};
static struct clk_regmap g12a_spicc1_sclk_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_SPICC_CLK_CNTL,
.shift = 16,
.width = 6,
},
.hw.init = &(struct clk_init_data){
.name = "spicc1_sclk_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (const struct clk_hw *[]) {
&g12a_spicc1_sclk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap g12a_spicc1_sclk = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_SPICC_CLK_CNTL,
.bit_idx = 22,
},
.hw.init = &(struct clk_init_data){
.name = "spicc1_sclk",
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) {
&g12a_spicc1_sclk_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
#define MESON_GATE(_name, _reg, _bit) \
MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw)
@ -4159,6 +4264,12 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
[CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw,
[CLKID_TS_DIV] = &g12a_ts_div.hw,
[CLKID_TS] = &g12a_ts.hw,
[CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw,
[CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw,
[CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw,
[CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw,
[CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw,
[CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -4408,6 +4519,12 @@ static struct clk_hw_onecell_data g12b_hw_onecell_data = {
[CLKID_CPUB_CLK_AXI] = &g12b_cpub_clk_axi.hw,
[CLKID_CPUB_CLK_TRACE_SEL] = &g12b_cpub_clk_trace_sel.hw,
[CLKID_CPUB_CLK_TRACE] = &g12b_cpub_clk_trace.hw,
[CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw,
[CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw,
[CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw,
[CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw,
[CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw,
[CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -4642,6 +4759,12 @@ static struct clk_hw_onecell_data sm1_hw_onecell_data = {
[CLKID_CPU1_CLK] = &sm1_cpu1_clk.hw,
[CLKID_CPU2_CLK] = &sm1_cpu2_clk.hw,
[CLKID_CPU3_CLK] = &sm1_cpu3_clk.hw,
[CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw,
[CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw,
[CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw,
[CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw,
[CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw,
[CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -4877,6 +5000,12 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
&sm1_cpu1_clk,
&sm1_cpu2_clk,
&sm1_cpu3_clk,
&g12a_spicc0_sclk_sel,
&g12a_spicc0_sclk_div,
&g12a_spicc0_sclk,
&g12a_spicc1_sclk_sel,
&g12a_spicc1_sclk_div,
&g12a_spicc1_sclk,
};
static const struct reg_sequence g12a_init_regs[] = {

View file

@ -255,8 +255,12 @@
#define CLKID_DSU_CLK_DYN1 249
#define CLKID_DSU_CLK_DYN 250
#define CLKID_DSU_CLK_FINAL 251
#define CLKID_SPICC0_SCLK_SEL 256
#define CLKID_SPICC0_SCLK_DIV 257
#define CLKID_SPICC1_SCLK_SEL 259
#define CLKID_SPICC1_SCLK_DIV 260
#define NR_CLKS 256
#define NR_CLKS 262
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/g12a-clkc.h>

View file

@ -2613,19 +2613,12 @@ static MESON_GATE(gxbb_assist_misc, HHI_GCLK_MPEG0, 23);
static MESON_GATE(gxbb_emmc_a, HHI_GCLK_MPEG0, 24);
static MESON_GATE(gxbb_emmc_b, HHI_GCLK_MPEG0, 25);
static MESON_GATE(gxbb_emmc_c, HHI_GCLK_MPEG0, 26);
static MESON_GATE(gxl_acodec, HHI_GCLK_MPEG0, 28);
static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30);
static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2);
static MESON_GATE(gxbb_eth, HHI_GCLK_MPEG1, 3);
static MESON_GATE(gxbb_demux, HHI_GCLK_MPEG1, 4);
static MESON_GATE(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6);
static MESON_GATE(gxbb_iec958, HHI_GCLK_MPEG1, 7);
static MESON_GATE(gxbb_i2s_out, HHI_GCLK_MPEG1, 8);
static MESON_GATE(gxbb_amclk, HHI_GCLK_MPEG1, 9);
static MESON_GATE(gxbb_aififo2, HHI_GCLK_MPEG1, 10);
static MESON_GATE(gxbb_mixer, HHI_GCLK_MPEG1, 11);
static MESON_GATE(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12);
static MESON_GATE(gxbb_adc, HHI_GCLK_MPEG1, 13);
static MESON_GATE(gxbb_blkmv, HHI_GCLK_MPEG1, 14);
static MESON_GATE(gxbb_aiu, HHI_GCLK_MPEG1, 15);
static MESON_GATE(gxbb_uart1, HHI_GCLK_MPEG1, 16);
@ -2680,6 +2673,16 @@ static MESON_GATE(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2);
static MESON_GATE(gxbb_ao_iface, HHI_GCLK_AO, 3);
static MESON_GATE(gxbb_ao_i2c, HHI_GCLK_AO, 4);
/* AIU gates */
static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw);
static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw);
static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw);
static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw);
static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw);
static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw);
static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw);
static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw);
/* Array of all clocks provided by this provider */
static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
@ -3100,6 +3103,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[CLKID_HDMI_SEL] = &gxbb_hdmi_sel.hw,
[CLKID_HDMI_DIV] = &gxbb_hdmi_div.hw,
[CLKID_HDMI] = &gxbb_hdmi.hw,
[CLKID_ACODEC] = &gxl_acodec.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -3491,6 +3495,7 @@ static struct clk_regmap *const gxl_clk_regmaps[] = {
&gxl_hdmi_pll_od,
&gxl_hdmi_pll_od2,
&gxl_hdmi_pll_dco,
&gxl_acodec,
};
static const struct meson_eeclkc_data gxbb_clkc_data = {

View file

@ -188,7 +188,7 @@
#define CLKID_HDMI_SEL 203
#define CLKID_HDMI_DIV 204
#define NR_CLKS 206
#define NR_CLKS 207
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/gxbb-clkc.h>

View file

@ -2605,14 +2605,6 @@ static MESON_GATE(meson8b_spi, HHI_GCLK_MPEG0, 30);
static MESON_GATE(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2);
static MESON_GATE(meson8b_eth, HHI_GCLK_MPEG1, 3);
static MESON_GATE(meson8b_demux, HHI_GCLK_MPEG1, 4);
static MESON_GATE(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6);
static MESON_GATE(meson8b_iec958, HHI_GCLK_MPEG1, 7);
static MESON_GATE(meson8b_i2s_out, HHI_GCLK_MPEG1, 8);
static MESON_GATE(meson8b_amclk, HHI_GCLK_MPEG1, 9);
static MESON_GATE(meson8b_aififo2, HHI_GCLK_MPEG1, 10);
static MESON_GATE(meson8b_mixer, HHI_GCLK_MPEG1, 11);
static MESON_GATE(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12);
static MESON_GATE(meson8b_adc, HHI_GCLK_MPEG1, 13);
static MESON_GATE(meson8b_blkmv, HHI_GCLK_MPEG1, 14);
static MESON_GATE(meson8b_aiu, HHI_GCLK_MPEG1, 15);
static MESON_GATE(meson8b_uart1, HHI_GCLK_MPEG1, 16);
@ -2659,6 +2651,19 @@ static MESON_GATE(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25);
static MESON_GATE(meson8b_vclk2_other, HHI_GCLK_OTHER, 26);
static MESON_GATE(meson8b_edp, HHI_GCLK_OTHER, 31);
/* AIU gates */
#define MESON_AIU_GLUE_GATE(_name, _reg, _bit) \
MESON_PCLK(_name, _reg, _bit, &meson8b_aiu_glue.hw)
static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, &meson8b_aiu.hw);
static MESON_AIU_GLUE_GATE(meson8b_iec958, HHI_GCLK_MPEG1, 7);
static MESON_AIU_GLUE_GATE(meson8b_i2s_out, HHI_GCLK_MPEG1, 8);
static MESON_AIU_GLUE_GATE(meson8b_amclk, HHI_GCLK_MPEG1, 9);
static MESON_AIU_GLUE_GATE(meson8b_aififo2, HHI_GCLK_MPEG1, 10);
static MESON_AIU_GLUE_GATE(meson8b_mixer, HHI_GCLK_MPEG1, 11);
static MESON_AIU_GLUE_GATE(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12);
static MESON_AIU_GLUE_GATE(meson8b_adc, HHI_GCLK_MPEG1, 13);
/* Always On (AO) domain gates */
static MESON_GATE(meson8b_ao_media_cpu, HHI_GCLK_AO, 0);

View file

@ -8,7 +8,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o
obj-$(CONFIG_RESET_CONTROLLER) += reset.o
obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o
obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o
obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o

View file

@ -441,7 +441,7 @@ const struct clk_ops mmp_clk_mix_ops = {
struct clk *mmp_clk_register_mix(struct device *dev,
const char *name,
const char **parent_names,
const char * const *parent_names,
u8 num_parents,
unsigned long flags,
struct mmp_clk_mix_config *config,

View file

@ -3,6 +3,7 @@
*
* Copyright (C) 2012 Marvell
* Chao Xie <xiechao.mail@gmail.com>
* Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@ -48,17 +49,39 @@
#define APMU_SDH1 0x58
#define APMU_SDH2 0xe8
#define APMU_SDH3 0xec
#define APMU_SDH4 0x15c
#define APMU_USB 0x5c
#define APMU_DISP0 0x4c
#define APMU_DISP1 0x110
#define APMU_CCIC0 0x50
#define APMU_CCIC1 0xf4
#define APBC_THERMAL0 0x90
#define APBC_THERMAL1 0x98
#define APBC_THERMAL2 0x9c
#define APBC_THERMAL3 0xa0
#define APMU_USBHSIC0 0xf8
#define APMU_USBHSIC1 0xfc
#define MPMU_UART_PLL 0x14
#define APMU_GPU 0xcc
#define MPMU_FCCR 0x8
#define MPMU_POSR 0x10
#define MPMU_UART_PLL 0x14
#define MPMU_PLL2_CR 0x34
/* MMP3 specific below */
#define MPMU_PLL3_CR 0x50
#define MPMU_PLL3_CTRL1 0x58
#define MPMU_PLL1_CTRL 0x5c
#define MPMU_PLL_DIFF_CTRL 0x68
#define MPMU_PLL2_CTRL1 0x414
enum mmp2_clk_model {
CLK_MODEL_MMP2,
CLK_MODEL_MMP3,
};
struct mmp2_clk_unit {
struct mmp_clk_unit unit;
enum mmp2_clk_model model;
void __iomem *mpmu_base;
void __iomem *apmu_base;
void __iomem *apbc_base;
@ -67,11 +90,22 @@ struct mmp2_clk_unit {
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
{MMP2_CLK_CLK32, "clk32", NULL, 0, 32768},
{MMP2_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000},
{MMP2_CLK_PLL1, "pll1", NULL, 0, 800000000},
{MMP2_CLK_PLL2, "pll2", NULL, 0, 960000000},
{MMP2_CLK_USB_PLL, "usb_pll", NULL, 0, 480000000},
};
static struct mmp_param_pll_clk pll_clks[] = {
{MMP2_CLK_PLL1, "pll1", 797330000, MPMU_FCCR, 0x4000, MPMU_POSR, 0},
{MMP2_CLK_PLL2, "pll2", 0, MPMU_PLL2_CR, 0x0300, MPMU_PLL2_CR, 10},
};
static struct mmp_param_pll_clk mmp3_pll_clks[] = {
{MMP2_CLK_PLL2, "pll1", 797330000, MPMU_FCCR, 0x4000, MPMU_POSR, 0, 26000000, MPMU_PLL1_CTRL, 25},
{MMP2_CLK_PLL2, "pll2", 0, MPMU_PLL2_CR, 0x0300, MPMU_PLL2_CR, 10, 26000000, MPMU_PLL2_CTRL1, 25},
{MMP3_CLK_PLL1_P, "pll1_p", 0, MPMU_PLL_DIFF_CTRL, 0x0010, 0, 0, 797330000, MPMU_PLL_DIFF_CTRL, 0},
{MMP3_CLK_PLL2_P, "pll2_p", 0, MPMU_PLL_DIFF_CTRL, 0x0100, MPMU_PLL2_CR, 10, 26000000, MPMU_PLL_DIFF_CTRL, 5},
{MMP3_CLK_PLL3, "pll3", 0, MPMU_PLL3_CR, 0x0300, MPMU_PLL3_CR, 10, 26000000, MPMU_PLL3_CTRL1, 25},
};
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
{MMP2_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0},
{MMP2_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
@ -113,6 +147,16 @@ static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit)
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
ARRAY_SIZE(fixed_rate_clks));
if (pxa_unit->model == CLK_MODEL_MMP3) {
mmp_register_pll_clks(unit, mmp3_pll_clks,
pxa_unit->mpmu_base,
ARRAY_SIZE(mmp3_pll_clks));
} else {
mmp_register_pll_clks(unit, pll_clks,
pxa_unit->mpmu_base,
ARRAY_SIZE(pll_clks));
}
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
ARRAY_SIZE(fixed_factor_clks));
@ -127,16 +171,16 @@ static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit)
static DEFINE_SPINLOCK(uart0_lock);
static DEFINE_SPINLOCK(uart1_lock);
static DEFINE_SPINLOCK(uart2_lock);
static const char *uart_parent_names[] = {"uart_pll", "vctcxo"};
static const char * const uart_parent_names[] = {"uart_pll", "vctcxo"};
static DEFINE_SPINLOCK(ssp0_lock);
static DEFINE_SPINLOCK(ssp1_lock);
static DEFINE_SPINLOCK(ssp2_lock);
static DEFINE_SPINLOCK(ssp3_lock);
static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
static const char * const ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
static DEFINE_SPINLOCK(timer_lock);
static const char *timer_parent_names[] = {"clk32", "vctcxo_4", "vctcxo_2", "vctcxo"};
static const char * const timer_parent_names[] = {"clk32", "vctcxo_4", "vctcxo_2", "vctcxo"};
static DEFINE_SPINLOCK(reset_lock);
@ -176,6 +220,13 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = {
{MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock},
{MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock},
{MMP2_CLK_TIMER, "timer_clk", "timer_mux", CLK_SET_RATE_PARENT, APBC_TIMER, 0x7, 0x3, 0x0, 0, &timer_lock},
{MMP2_CLK_THERMAL0, "thermal0_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL0, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
};
static struct mmp_param_gate_clk mmp3_apbc_gate_clks[] = {
{MMP3_CLK_THERMAL1, "thermal1_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL1, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
{MMP3_CLK_THERMAL2, "thermal2_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL2, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
{MMP3_CLK_THERMAL3, "thermal3_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_THERMAL3, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
};
static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
@ -187,10 +238,15 @@ static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_gate_clks));
if (pxa_unit->model == CLK_MODEL_MMP3) {
mmp_register_gate_clks(unit, mmp3_apbc_gate_clks, pxa_unit->apbc_base,
ARRAY_SIZE(mmp3_apbc_gate_clks));
}
}
static DEFINE_SPINLOCK(sdh_lock);
static const char *sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
static const char * const sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
static struct mmp_clk_mix_config sdh_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(4, 10, 2, 8, 32),
};
@ -201,11 +257,20 @@ static DEFINE_SPINLOCK(usbhsic1_lock);
static DEFINE_SPINLOCK(disp0_lock);
static DEFINE_SPINLOCK(disp1_lock);
static const char *disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
static const char * const disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
static DEFINE_SPINLOCK(ccic0_lock);
static DEFINE_SPINLOCK(ccic1_lock);
static const char *ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"};
static const char * const ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"};
static DEFINE_SPINLOCK(gpu_lock);
static const char * const mmp2_gpu_gc_parent_names[] = {"pll1_2", "pll1_3", "pll2_2", "pll2_3", "pll2", "usb_pll"};
static u32 mmp2_gpu_gc_parent_table[] = { 0x0000, 0x0040, 0x0080, 0x00c0, 0x1000, 0x1040 };
static const char * const mmp2_gpu_bus_parent_names[] = {"pll1_4", "pll2", "pll2_2", "usb_pll"};
static u32 mmp2_gpu_bus_parent_table[] = { 0x0000, 0x0020, 0x0030, 0x4020 };
static const char * const mmp3_gpu_bus_parent_names[] = {"pll1_4", "pll1_6", "pll1_2", "pll2_2"};
static const char * const mmp3_gpu_gc_parent_names[] = {"pll1", "pll2", "pll1_p", "pll2_p"};
static struct mmp_clk_mix_config ccic0_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32),
};
@ -218,6 +283,15 @@ static struct mmp_param_mux_clk apmu_mux_clks[] = {
{MMP2_CLK_DISP1_MUX, "disp1_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP1, 6, 2, 0, &disp1_lock},
};
static struct mmp_param_mux_clk mmp3_apmu_mux_clks[] = {
{0, "gpu_bus_mux", mmp3_gpu_bus_parent_names, ARRAY_SIZE(mmp3_gpu_bus_parent_names),
CLK_SET_RATE_PARENT, APMU_GPU, 4, 2, 0, &gpu_lock},
{0, "gpu_3d_mux", mmp3_gpu_gc_parent_names, ARRAY_SIZE(mmp3_gpu_gc_parent_names),
CLK_SET_RATE_PARENT, APMU_GPU, 6, 2, 0, &gpu_lock},
{0, "gpu_2d_mux", mmp3_gpu_gc_parent_names, ARRAY_SIZE(mmp3_gpu_gc_parent_names),
CLK_SET_RATE_PARENT, APMU_GPU, 12, 2, 0, &gpu_lock},
};
static struct mmp_param_div_clk apmu_div_clks[] = {
{0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, 0, &disp0_lock},
{0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 15, 5, 0, &disp0_lock},
@ -226,6 +300,11 @@ static struct mmp_param_div_clk apmu_div_clks[] = {
{0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 10, 5, 0, &ccic1_lock},
};
static struct mmp_param_div_clk mmp3_apmu_div_clks[] = {
{0, "gpu_3d_div", "gpu_3d_mux", CLK_SET_RATE_PARENT, APMU_GPU, 24, 4, 0, &gpu_lock},
{0, "gpu_2d_div", "gpu_2d_mux", CLK_SET_RATE_PARENT, APMU_GPU, 28, 4, 0, &gpu_lock},
};
static struct mmp_param_gate_clk apmu_gate_clks[] = {
{MMP2_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
{MMP2_CLK_USBHSIC0, "usbhsic0_clk", "usb_pll", 0, APMU_USBHSIC0, 0x1b, 0x1b, 0x0, 0, &usbhsic0_lock},
@ -235,8 +314,8 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = {
{MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x09, 0x09, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP0_LCDC, "disp0_lcdc_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x12, 0x12, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x12, 0x12, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP0_LCDC, "disp0_lcdc_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x09, 0x09, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x09, 0x09, 0x0, 0, &disp1_lock},
{MMP2_CLK_CCIC_ARBITER, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1800, 0x1800, 0x0, 0, &ccic0_lock},
@ -246,6 +325,17 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = {
{MMP2_CLK_CCIC1, "ccic1_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x1b, 0x1b, 0x0, 0, &ccic1_lock},
{MMP2_CLK_CCIC1_PHY, "ccic1_phy_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x24, 0x24, 0x0, 0, &ccic1_lock},
{MMP2_CLK_CCIC1_SPHY, "ccic1_sphy_clk", "ccic1_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x300, 0x300, 0x0, 0, &ccic1_lock},
{MMP2_CLK_GPU_BUS, "gpu_bus_clk", "gpu_bus_mux", CLK_SET_RATE_PARENT, APMU_GPU, 0xa, 0xa, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock},
};
static struct mmp_param_gate_clk mmp2_apmu_gate_clks[] = {
{MMP2_CLK_GPU_3D, "gpu_3d_clk", "gpu_3d_mux", CLK_SET_RATE_PARENT, APMU_GPU, 0x5, 0x5, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock},
};
static struct mmp_param_gate_clk mmp3_apmu_gate_clks[] = {
{MMP3_CLK_SDH4, "sdh4_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH4, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP3_CLK_GPU_3D, "gpu_3d_clk", "gpu_3d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x5, 0x5, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock},
{MMP3_CLK_GPU_2D, "gpu_2d_clk", "gpu_2d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x1c0000, 0x1c0000, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock},
};
static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
@ -281,6 +371,34 @@ static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_gate_clks));
if (pxa_unit->model == CLK_MODEL_MMP3) {
mmp_register_mux_clks(unit, mmp3_apmu_mux_clks, pxa_unit->apmu_base,
ARRAY_SIZE(mmp3_apmu_mux_clks));
mmp_register_div_clks(unit, mmp3_apmu_div_clks, pxa_unit->apmu_base,
ARRAY_SIZE(mmp3_apmu_div_clks));
mmp_register_gate_clks(unit, mmp3_apmu_gate_clks, pxa_unit->apmu_base,
ARRAY_SIZE(mmp3_apmu_gate_clks));
} else {
clk_register_mux_table(NULL, "gpu_3d_mux", mmp2_gpu_gc_parent_names,
ARRAY_SIZE(mmp2_gpu_gc_parent_names),
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_GPU,
0, 0x10c0, 0,
mmp2_gpu_gc_parent_table, &gpu_lock);
clk_register_mux_table(NULL, "gpu_bus_mux", mmp2_gpu_bus_parent_names,
ARRAY_SIZE(mmp2_gpu_bus_parent_names),
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_GPU,
0, 0x4030, 0,
mmp2_gpu_bus_parent_table, &gpu_lock);
mmp_register_gate_clks(unit, mmp2_apmu_gate_clks, pxa_unit->apmu_base,
ARRAY_SIZE(mmp2_apmu_gate_clks));
}
}
static void mmp2_clk_reset_init(struct device_node *np,
@ -313,6 +431,11 @@ static void __init mmp2_clk_init(struct device_node *np)
if (!pxa_unit)
return;
if (of_device_is_compatible(np, "marvell,mmp3-clock"))
pxa_unit->model = CLK_MODEL_MMP3;
else
pxa_unit->model = CLK_MODEL_MMP2;
pxa_unit->mpmu_base = of_iomap(np, 0);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map mpmu registers\n");
@ -352,3 +475,4 @@ static void __init mmp2_clk_init(struct device_node *np)
}
CLK_OF_DECLARE(mmp2_clk, "marvell,mmp2-clock", mmp2_clk_init);
CLK_OF_DECLARE(mmp3_clk, "marvell,mmp3-clock", mmp2_clk_init);

139
drivers/clk/mmp/clk-pll.c Normal file
View file

@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MMP PLL clock rate calculation
*
* Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
*/
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "clk.h"
#define to_clk_mmp_pll(hw) container_of(hw, struct mmp_clk_pll, hw)
struct mmp_clk_pll {
struct clk_hw hw;
unsigned long default_rate;
void __iomem *enable_reg;
u32 enable;
void __iomem *reg;
u8 shift;
unsigned long input_rate;
void __iomem *postdiv_reg;
u8 postdiv_shift;
};
static int mmp_clk_pll_is_enabled(struct clk_hw *hw)
{
struct mmp_clk_pll *pll = to_clk_mmp_pll(hw);
u32 val;
val = readl_relaxed(pll->enable_reg);
if ((val & pll->enable) == pll->enable)
return 1;
/* Some PLLs, if not software controlled, output default clock. */
if (pll->default_rate > 0)
return 1;
return 0;
}
static unsigned long mmp_clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct mmp_clk_pll *pll = to_clk_mmp_pll(hw);
u32 fbdiv, refdiv, postdiv;
u64 rate;
u32 val;
val = readl_relaxed(pll->enable_reg);
if ((val & pll->enable) != pll->enable)
return pll->default_rate;
if (pll->reg) {
val = readl_relaxed(pll->reg);
fbdiv = (val >> pll->shift) & 0x1ff;
refdiv = (val >> (pll->shift + 9)) & 0x1f;
} else {
fbdiv = 2;
refdiv = 1;
}
if (pll->postdiv_reg) {
/* MMP3 clock rate calculation */
static const u8 postdivs[] = {2, 3, 4, 5, 6, 8, 10, 12, 16};
val = readl_relaxed(pll->postdiv_reg);
postdiv = (val >> pll->postdiv_shift) & 0x7;
rate = pll->input_rate;
rate *= 2 * fbdiv;
do_div(rate, refdiv);
do_div(rate, postdivs[postdiv]);
} else {
/* MMP2 clock rate calculation */
if (refdiv == 3) {
rate = 19200000;
} else if (refdiv == 4) {
rate = 26000000;
} else {
pr_err("bad refdiv: %d (0x%08x)\n", refdiv, val);
return 0;
}
rate *= fbdiv + 2;
do_div(rate, refdiv + 2);
}
return (unsigned long)rate;
}
static const struct clk_ops mmp_clk_pll_ops = {
.is_enabled = mmp_clk_pll_is_enabled,
.recalc_rate = mmp_clk_pll_recalc_rate,
};
struct clk *mmp_clk_register_pll(char *name,
unsigned long default_rate,
void __iomem *enable_reg, u32 enable,
void __iomem *reg, u8 shift,
unsigned long input_rate,
void __iomem *postdiv_reg, u8 postdiv_shift)
{
struct mmp_clk_pll *pll;
struct clk *clk;
struct clk_init_data init;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &mmp_clk_pll_ops;
init.flags = 0;
init.parent_names = NULL;
init.num_parents = 0;
pll->default_rate = default_rate;
pll->enable_reg = enable_reg;
pll->enable = enable;
pll->reg = reg;
pll->shift = shift;
pll->input_rate = input_rate;
pll->postdiv_reg = postdiv_reg;
pll->postdiv_shift = postdiv_shift;
pll->hw.init = &init;
clk = clk_register(NULL, &pll->hw);
if (IS_ERR(clk))
kfree(pll);
return clk;
}

View file

@ -176,6 +176,37 @@ void mmp_register_div_clks(struct mmp_clk_unit *unit,
}
}
void mmp_register_pll_clks(struct mmp_clk_unit *unit,
struct mmp_param_pll_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
void __iomem *reg = NULL;
if (clks[i].offset)
reg = base + clks[i].offset;
clk = mmp_clk_register_pll(clks[i].name,
clks[i].default_rate,
base + clks[i].enable_offset,
clks[i].enable,
reg, clks[i].shift,
clks[i].input_rate,
base + clks[i].postdiv_offset,
clks[i].postdiv_shift);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
struct clk *clk)
{

View file

@ -97,7 +97,7 @@ struct mmp_clk_mix {
extern const struct clk_ops mmp_clk_mix_ops;
extern struct clk *mmp_clk_register_mix(struct device *dev,
const char *name,
const char **parent_names,
const char * const *parent_names,
u8 num_parents,
unsigned long flags,
struct mmp_clk_mix_config *config,
@ -124,9 +124,6 @@ extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
u32 val_disable, unsigned int gate_flags,
spinlock_t *lock);
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
const char *parent_name, void __iomem *base,
unsigned int delay, unsigned int apbc_flags, spinlock_t *lock);
@ -196,7 +193,7 @@ void mmp_register_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_mux_clk {
unsigned int id;
char *name;
const char **parent_name;
const char * const *parent_name;
u8 num_parents;
unsigned long flags;
unsigned long offset;
@ -224,6 +221,30 @@ void mmp_register_div_clks(struct mmp_clk_unit *unit,
struct mmp_param_div_clk *clks,
void __iomem *base, int size);
struct mmp_param_pll_clk {
unsigned int id;
char *name;
unsigned long default_rate;
unsigned long enable_offset;
u32 enable;
unsigned long offset;
u8 shift;
/* MMP3 specific: */
unsigned long input_rate;
unsigned long postdiv_offset;
unsigned long postdiv_shift;
};
void mmp_register_pll_clks(struct mmp_clk_unit *unit,
struct mmp_param_pll_clk *clks,
void __iomem *base, int size);
extern struct clk *mmp_clk_register_pll(char *name,
unsigned long default_rate,
void __iomem *enable_reg, u32 enable,
void __iomem *reg, u8 shift,
unsigned long input_rate,
void __iomem *postdiv_reg, u8 postdiv_shift);
#define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc) \
{ \
.width_div = (w_d), \

View file

@ -280,6 +280,15 @@ config SC_GPUCC_7180
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
config SC_MSS_7180
tristate "SC7180 Modem Clock Controller"
select SC_GCC_7180
help
Support for the Modem Subsystem clock controller on Qualcomm
Technologies, Inc on SC7180 devices.
Say Y if you want to use the Modem branch clocks of the Modem
subsystem clock controller to reset the MSS subsystem.
config SC_VIDEOCC_7180
tristate "SC7180 Video Clock Controller"
select SC_GCC_7180
@ -366,6 +375,13 @@ config SM_GCC_8150
Say Y if you want to use peripheral devices such as UART,
SPI, I2C, USB, SD/UFS, PCIe etc.
config SM_GCC_8250
tristate "SM8250 Global Clock Controller"
help
Support for the global clock controller on SM8250 devices.
Say Y if you want to use peripheral devices such as UART,
SPI, I2C, USB, SD/UFS, PCIe etc.
config SPMI_PMIC_CLKDIV
tristate "SPMI PMIC clkdiv Support"
depends on SPMI || COMPILE_TEST

View file

@ -50,6 +50,7 @@ obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o
obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o
obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o
obj-$(CONFIG_SC_MSS_7180) += mss-sc7180.o
obj-$(CONFIG_SC_VIDEOCC_7180) += videocc-sc7180.o
obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o
@ -59,6 +60,7 @@ obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o
obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o
obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o

View file

@ -52,6 +52,7 @@
#define PLL_CONFIG_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U1])
#define PLL_TEST_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL])
#define PLL_TEST_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U])
#define PLL_TEST_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U1])
#define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS])
#define PLL_OPMODE(p) ((p)->offset + (p)->regs[PLL_OFF_OPMODE])
#define PLL_FRAC(p) ((p)->offset + (p)->regs[PLL_OFF_FRAC])
@ -116,6 +117,22 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
[PLL_OFF_ALPHA_VAL] = 0x40,
[PLL_OFF_CAL_VAL] = 0x44,
},
[CLK_ALPHA_PLL_TYPE_LUCID] = {
[PLL_OFF_L_VAL] = 0x04,
[PLL_OFF_CAL_L_VAL] = 0x08,
[PLL_OFF_USER_CTL] = 0x0c,
[PLL_OFF_USER_CTL_U] = 0x10,
[PLL_OFF_USER_CTL_U1] = 0x14,
[PLL_OFF_CONFIG_CTL] = 0x18,
[PLL_OFF_CONFIG_CTL_U] = 0x1c,
[PLL_OFF_CONFIG_CTL_U1] = 0x20,
[PLL_OFF_TEST_CTL] = 0x24,
[PLL_OFF_TEST_CTL_U] = 0x28,
[PLL_OFF_TEST_CTL_U1] = 0x2c,
[PLL_OFF_STATUS] = 0x30,
[PLL_OFF_OPMODE] = 0x38,
[PLL_OFF_ALPHA_VAL] = 0x40,
},
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
@ -134,15 +151,14 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
#define PLL_HUAYRA_N_MASK 0xff
#define PLL_HUAYRA_ALPHA_WIDTH 16
#define FABIA_OPMODE_STANDBY 0x0
#define FABIA_OPMODE_RUN 0x1
#define PLL_STANDBY 0x0
#define PLL_RUN 0x1
#define PLL_OUT_MASK 0x7
#define PLL_RATE_MARGIN 500
#define FABIA_PLL_OUT_MASK 0x7
#define FABIA_PLL_RATE_MARGIN 500
#define TRION_PLL_STANDBY 0x0
#define TRION_PLL_RUN 0x1
#define TRION_PLL_OUT_MASK 0x7
/* LUCID PLL specific settings and offsets */
#define LUCID_PLL_CAL_VAL 0x44
#define LUCID_PCAL_DONE BIT(26)
#define pll_alpha_width(p) \
((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \
@ -544,7 +560,8 @@ static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
vco = alpha_pll_find_vco(pll, rate);
if (pll->vco_table && !vco) {
pr_err("alpha pll not in a valid vco range\n");
pr_err("%s: alpha pll not in a valid vco range\n",
clk_hw_get_name(hw));
return -EINVAL;
}
@ -722,7 +739,7 @@ static int alpha_pll_huayra_set_rate(struct clk_hw *hw, unsigned long rate,
*/
if (clk_alpha_pll_is_enabled(hw)) {
if (cur_alpha != a) {
pr_err("clock needs to be gated %s\n",
pr_err("%s: clock needs to be gated\n",
clk_hw_get_name(hw));
return -EBUSY;
}
@ -765,7 +782,7 @@ static int trion_pll_is_enabled(struct clk_alpha_pll *pll,
if (ret)
return 0;
return ((opmode_regval & TRION_PLL_RUN) && (mode_regval & PLL_OUTCTRL));
return ((opmode_regval & PLL_RUN) && (mode_regval & PLL_OUTCTRL));
}
static int clk_trion_pll_is_enabled(struct clk_hw *hw)
@ -795,7 +812,7 @@ static int clk_trion_pll_enable(struct clk_hw *hw)
}
/* Set operation mode to RUN */
regmap_write(regmap, PLL_OPMODE(pll), TRION_PLL_RUN);
regmap_write(regmap, PLL_OPMODE(pll), PLL_RUN);
ret = wait_for_pll_enable_lock(pll);
if (ret)
@ -803,7 +820,7 @@ static int clk_trion_pll_enable(struct clk_hw *hw)
/* Enable the PLL outputs */
ret = regmap_update_bits(regmap, PLL_USER_CTL(pll),
TRION_PLL_OUT_MASK, TRION_PLL_OUT_MASK);
PLL_OUT_MASK, PLL_OUT_MASK);
if (ret)
return ret;
@ -836,12 +853,12 @@ static void clk_trion_pll_disable(struct clk_hw *hw)
/* Disable the PLL outputs */
ret = regmap_update_bits(regmap, PLL_USER_CTL(pll),
TRION_PLL_OUT_MASK, 0);
PLL_OUT_MASK, 0);
if (ret)
return;
/* Place the PLL mode in STANDBY */
regmap_write(regmap, PLL_OPMODE(pll), TRION_PLL_STANDBY);
regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY);
regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
}
@ -849,33 +866,12 @@ static unsigned long
clk_trion_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
struct regmap *regmap = pll->clkr.regmap;
u32 l, frac;
u64 prate = parent_rate;
u32 l, frac, alpha_width = pll_alpha_width(pll);
regmap_read(regmap, PLL_L_VAL(pll), &l);
regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac);
regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac);
return alpha_pll_calc_rate(prate, l, frac, ALPHA_REG_16BIT_WIDTH);
}
static long clk_trion_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
unsigned long min_freq, max_freq;
u32 l;
u64 a;
rate = alpha_pll_round_rate(rate, *prate,
&l, &a, ALPHA_REG_16BIT_WIDTH);
if (!pll->vco_table || alpha_pll_find_vco(pll, rate))
return rate;
min_freq = pll->vco_table[0].min_freq;
max_freq = pll->vco_table[pll->num_vco - 1].max_freq;
return clamp(rate, min_freq, max_freq);
return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width);
}
const struct clk_ops clk_alpha_pll_fixed_ops = {
@ -921,7 +917,7 @@ const struct clk_ops clk_trion_fixed_pll_ops = {
.disable = clk_trion_pll_disable,
.is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_trion_pll_round_rate,
.round_rate = clk_alpha_pll_round_rate,
};
EXPORT_SYMBOL_GPL(clk_trion_fixed_pll_ops);
@ -1088,14 +1084,14 @@ static int alpha_pll_fabia_enable(struct clk_hw *hw)
return ret;
/* Skip If PLL is already running */
if ((opmode_val & FABIA_OPMODE_RUN) && (val & PLL_OUTCTRL))
if ((opmode_val & PLL_RUN) && (val & PLL_OUTCTRL))
return 0;
ret = regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0);
if (ret)
return ret;
ret = regmap_write(regmap, PLL_OPMODE(pll), FABIA_OPMODE_STANDBY);
ret = regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY);
if (ret)
return ret;
@ -1104,7 +1100,7 @@ static int alpha_pll_fabia_enable(struct clk_hw *hw)
if (ret)
return ret;
ret = regmap_write(regmap, PLL_OPMODE(pll), FABIA_OPMODE_RUN);
ret = regmap_write(regmap, PLL_OPMODE(pll), PLL_RUN);
if (ret)
return ret;
@ -1113,7 +1109,7 @@ static int alpha_pll_fabia_enable(struct clk_hw *hw)
return ret;
ret = regmap_update_bits(regmap, PLL_USER_CTL(pll),
FABIA_PLL_OUT_MASK, FABIA_PLL_OUT_MASK);
PLL_OUT_MASK, PLL_OUT_MASK);
if (ret)
return ret;
@ -1143,13 +1139,12 @@ static void alpha_pll_fabia_disable(struct clk_hw *hw)
return;
/* Disable main outputs */
ret = regmap_update_bits(regmap, PLL_USER_CTL(pll), FABIA_PLL_OUT_MASK,
0);
ret = regmap_update_bits(regmap, PLL_USER_CTL(pll), PLL_OUT_MASK, 0);
if (ret)
return;
/* Place the PLL in STANDBY */
regmap_write(regmap, PLL_OPMODE(pll), FABIA_OPMODE_STANDBY);
regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY);
}
static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw,
@ -1170,7 +1165,7 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
u32 l, alpha_width = pll_alpha_width(pll);
u64 a;
unsigned long rrate;
unsigned long rrate, max = rate + PLL_RATE_MARGIN;
rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
@ -1178,8 +1173,9 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate,
* Due to limited number of bits for fractional rate programming, the
* rounded up rate could be marginally higher than the requested rate.
*/
if (rrate > (rate + FABIA_PLL_RATE_MARGIN) || rrate < rate) {
pr_err("Call set rate on the PLL with rounded rates!\n");
if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) {
pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n",
clk_hw_get_name(hw), rrate, rate, max);
return -EINVAL;
}
@ -1196,6 +1192,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw)
struct clk_hw *parent_hw;
unsigned long cal_freq, rrate;
u32 cal_l, val, alpha_width = pll_alpha_width(pll);
const char *name = clk_hw_get_name(hw);
u64 a;
int ret;
@ -1210,7 +1207,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw)
vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw));
if (!vco) {
pr_err("alpha pll: not in a valid vco range\n");
pr_err("%s: alpha pll not in a valid vco range\n", name);
return -EINVAL;
}
@ -1227,7 +1224,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw)
* Due to a limited number of bits for fractional rate programming, the
* rounded up rate could be marginally higher than the requested rate.
*/
if (rrate > (cal_freq + FABIA_PLL_RATE_MARGIN) || rrate < cal_freq)
if (rrate > (cal_freq + PLL_RATE_MARGIN) || rrate < cal_freq)
return -EINVAL;
/* Setup PLL for calibration frequency */
@ -1236,7 +1233,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw)
/* Bringup the PLL at calibration frequency */
ret = clk_alpha_pll_enable(hw);
if (ret) {
pr_err("alpha pll calibration failed\n");
pr_err("%s: alpha pll calibration failed\n", name);
return ret;
}
@ -1394,3 +1391,175 @@ const struct clk_ops clk_alpha_pll_postdiv_fabia_ops = {
.set_rate = clk_alpha_pll_postdiv_fabia_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
/**
* clk_lucid_pll_configure - configure the lucid pll
*
* @pll: clk alpha pll
* @regmap: register map
* @config: configuration to apply for pll
*/
void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config)
{
if (config->l)
regmap_write(regmap, PLL_L_VAL(pll), config->l);
regmap_write(regmap, PLL_CAL_L_VAL(pll), LUCID_PLL_CAL_VAL);
if (config->alpha)
regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha);
if (config->config_ctl_val)
regmap_write(regmap, PLL_CONFIG_CTL(pll),
config->config_ctl_val);
if (config->config_ctl_hi_val)
regmap_write(regmap, PLL_CONFIG_CTL_U(pll),
config->config_ctl_hi_val);
if (config->config_ctl_hi1_val)
regmap_write(regmap, PLL_CONFIG_CTL_U1(pll),
config->config_ctl_hi1_val);
if (config->user_ctl_val)
regmap_write(regmap, PLL_USER_CTL(pll),
config->user_ctl_val);
if (config->user_ctl_hi_val)
regmap_write(regmap, PLL_USER_CTL_U(pll),
config->user_ctl_hi_val);
if (config->user_ctl_hi1_val)
regmap_write(regmap, PLL_USER_CTL_U1(pll),
config->user_ctl_hi1_val);
if (config->test_ctl_val)
regmap_write(regmap, PLL_TEST_CTL(pll),
config->test_ctl_val);
if (config->test_ctl_hi_val)
regmap_write(regmap, PLL_TEST_CTL_U(pll),
config->test_ctl_hi_val);
if (config->test_ctl_hi1_val)
regmap_write(regmap, PLL_TEST_CTL_U1(pll),
config->test_ctl_hi1_val);
regmap_update_bits(regmap, PLL_MODE(pll), PLL_UPDATE_BYPASS,
PLL_UPDATE_BYPASS);
/* Disable PLL output */
regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0);
/* Set operation mode to OFF */
regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY);
/* Place the PLL in STANDBY mode */
regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
}
EXPORT_SYMBOL_GPL(clk_lucid_pll_configure);
/*
* The Lucid PLL requires a power-on self-calibration which happens when the
* PLL comes out of reset. Calibrate in case it is not completed.
*/
static int alpha_pll_lucid_prepare(struct clk_hw *hw)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
u32 regval;
int ret;
/* Return early if calibration is not needed. */
regmap_read(pll->clkr.regmap, PLL_STATUS(pll), &regval);
if (regval & LUCID_PCAL_DONE)
return 0;
/* On/off to calibrate */
ret = clk_trion_pll_enable(hw);
if (!ret)
clk_trion_pll_disable(hw);
return ret;
}
static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long prate)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
unsigned long rrate;
u32 regval, l, alpha_width = pll_alpha_width(pll);
u64 a;
int ret;
rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
/*
* Due to a limited number of bits for fractional rate programming, the
* rounded up rate could be marginally higher than the requested rate.
*/
if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) {
pr_err("Call set rate on the PLL with rounded rates!\n");
return -EINVAL;
}
regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
/* Latch the PLL input */
ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll),
PLL_UPDATE, PLL_UPDATE);
if (ret)
return ret;
/* Wait for 2 reference cycles before checking the ACK bit. */
udelay(1);
regmap_read(pll->clkr.regmap, PLL_MODE(pll), &regval);
if (!(regval & ALPHA_PLL_ACK_LATCH)) {
pr_err("Lucid PLL latch failed. Output may be unstable!\n");
return -EINVAL;
}
/* Return the latch input to 0 */
ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll),
PLL_UPDATE, 0);
if (ret)
return ret;
if (clk_hw_is_enabled(hw)) {
ret = wait_for_pll_enable_lock(pll);
if (ret)
return ret;
}
/* Wait for PLL output to stabilize */
udelay(100);
return 0;
}
const struct clk_ops clk_alpha_pll_lucid_ops = {
.prepare = alpha_pll_lucid_prepare,
.enable = clk_trion_pll_enable,
.disable = clk_trion_pll_disable,
.is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
.set_rate = alpha_pll_lucid_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops);
const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
.enable = clk_trion_pll_enable,
.disable = clk_trion_pll_disable,
.is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_lucid_ops);
const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = {
.recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate,
.round_rate = clk_alpha_pll_postdiv_fabia_round_rate,
.set_rate = clk_alpha_pll_postdiv_fabia_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_ops);

View file

@ -14,6 +14,7 @@ enum {
CLK_ALPHA_PLL_TYPE_BRAMMO,
CLK_ALPHA_PLL_TYPE_FABIA,
CLK_ALPHA_PLL_TYPE_TRION,
CLK_ALPHA_PLL_TYPE_LUCID,
CLK_ALPHA_PLL_TYPE_MAX,
};
@ -30,6 +31,7 @@ enum {
PLL_OFF_CONFIG_CTL_U1,
PLL_OFF_TEST_CTL,
PLL_OFF_TEST_CTL_U,
PLL_OFF_TEST_CTL_U1,
PLL_OFF_STATUS,
PLL_OFF_OPMODE,
PLL_OFF_FRAC,
@ -94,10 +96,13 @@ struct alpha_pll_config {
u32 alpha_hi;
u32 config_ctl_val;
u32 config_ctl_hi_val;
u32 config_ctl_hi1_val;
u32 user_ctl_val;
u32 user_ctl_hi_val;
u32 user_ctl_hi1_val;
u32 test_ctl_val;
u32 test_ctl_hi_val;
u32 test_ctl_hi1_val;
u32 main_output_mask;
u32 aux_output_mask;
u32 aux2_output_mask;
@ -123,10 +128,17 @@ extern const struct clk_ops clk_alpha_pll_fabia_ops;
extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_fabia_ops;
extern const struct clk_ops clk_alpha_pll_lucid_ops;
extern const struct clk_ops clk_alpha_pll_fixed_lucid_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops;
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config);
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config);
void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config);
extern const struct clk_ops clk_trion_fixed_pll_ops;
extern const struct clk_ops clk_trion_pll_postdiv_ops;

View file

@ -543,10 +543,45 @@ static const struct rpm_clk_desc rpm_clk_apq8064 = {
.num_clks = ARRAY_SIZE(apq8064_clks),
};
/* ipq806x */
DEFINE_CLK_RPM(ipq806x, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK);
DEFINE_CLK_RPM(ipq806x, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK);
DEFINE_CLK_RPM(ipq806x, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK);
DEFINE_CLK_RPM(ipq806x, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK);
DEFINE_CLK_RPM(ipq806x, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK);
DEFINE_CLK_RPM(ipq806x, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK);
DEFINE_CLK_RPM(ipq806x, nss_fabric_0_clk, nss_fabric_0_a_clk, QCOM_RPM_NSS_FABRIC_0_CLK);
DEFINE_CLK_RPM(ipq806x, nss_fabric_1_clk, nss_fabric_1_a_clk, QCOM_RPM_NSS_FABRIC_1_CLK);
static struct clk_rpm *ipq806x_clks[] = {
[RPM_APPS_FABRIC_CLK] = &ipq806x_afab_clk,
[RPM_APPS_FABRIC_A_CLK] = &ipq806x_afab_a_clk,
[RPM_CFPB_CLK] = &ipq806x_cfpb_clk,
[RPM_CFPB_A_CLK] = &ipq806x_cfpb_a_clk,
[RPM_DAYTONA_FABRIC_CLK] = &ipq806x_daytona_clk,
[RPM_DAYTONA_FABRIC_A_CLK] = &ipq806x_daytona_a_clk,
[RPM_EBI1_CLK] = &ipq806x_ebi1_clk,
[RPM_EBI1_A_CLK] = &ipq806x_ebi1_a_clk,
[RPM_SYS_FABRIC_CLK] = &ipq806x_sfab_clk,
[RPM_SYS_FABRIC_A_CLK] = &ipq806x_sfab_a_clk,
[RPM_SFPB_CLK] = &ipq806x_sfpb_clk,
[RPM_SFPB_A_CLK] = &ipq806x_sfpb_a_clk,
[RPM_NSS_FABRIC_0_CLK] = &ipq806x_nss_fabric_0_clk,
[RPM_NSS_FABRIC_0_A_CLK] = &ipq806x_nss_fabric_0_a_clk,
[RPM_NSS_FABRIC_1_CLK] = &ipq806x_nss_fabric_1_clk,
[RPM_NSS_FABRIC_1_A_CLK] = &ipq806x_nss_fabric_1_a_clk,
};
static const struct rpm_clk_desc rpm_clk_ipq806x = {
.clks = ipq806x_clks,
.num_clks = ARRAY_SIZE(ipq806x_clks),
};
static const struct of_device_id rpm_clk_match_table[] = {
{ .compatible = "qcom,rpmcc-msm8660", .data = &rpm_clk_msm8660 },
{ .compatible = "qcom,rpmcc-apq8060", .data = &rpm_clk_msm8660 },
{ .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 },
{ .compatible = "qcom,rpmcc-ipq806x", .data = &rpm_clk_ipq806x },
{ }
};
MODULE_DEVICE_TABLE(of, rpm_clk_match_table);

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
@ -143,12 +143,22 @@ static inline bool has_state_changed(struct clk_rpmh *c, u32 state)
!= (c->aggr_state & BIT(state));
}
static int clk_rpmh_send(struct clk_rpmh *c, enum rpmh_state state,
struct tcs_cmd *cmd, bool wait)
{
if (wait)
return rpmh_write(c->dev, state, cmd, 1);
return rpmh_write_async(c->dev, state, cmd, 1);
}
static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c)
{
struct tcs_cmd cmd = { 0 };
u32 cmd_state, on_val;
enum rpmh_state state = RPMH_SLEEP_STATE;
int ret;
bool wait;
cmd.addr = c->res_addr;
cmd_state = c->aggr_state;
@ -159,7 +169,8 @@ static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c)
if (cmd_state & BIT(state))
cmd.data = on_val;
ret = rpmh_write_async(c->dev, state, &cmd, 1);
wait = cmd_state && state == RPMH_ACTIVE_ONLY_STATE;
ret = clk_rpmh_send(c, state, &cmd, wait);
if (ret) {
dev_err(c->dev, "set %s state of %s failed: (%d)\n",
!state ? "sleep" :
@ -216,7 +227,7 @@ static int clk_rpmh_prepare(struct clk_hw *hw)
mutex_unlock(&rpmh_clk_lock);
return ret;
};
}
static void clk_rpmh_unprepare(struct clk_hw *hw)
{
@ -248,38 +259,33 @@ static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable)
{
struct tcs_cmd cmd = { 0 };
u32 cmd_state;
int ret;
int ret = 0;
mutex_lock(&rpmh_clk_lock);
cmd_state = 0;
if (enable) {
cmd_state = 1;
if (c->aggr_state)
cmd_state = c->aggr_state;
} else {
cmd_state = 0;
}
if (c->last_sent_aggr_state == cmd_state) {
mutex_unlock(&rpmh_clk_lock);
return 0;
if (c->last_sent_aggr_state != cmd_state) {
cmd.addr = c->res_addr;
cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state);
ret = clk_rpmh_send(c, RPMH_ACTIVE_ONLY_STATE, &cmd, enable);
if (ret) {
dev_err(c->dev, "set active state of %s failed: (%d)\n",
c->res_name, ret);
} else {
c->last_sent_aggr_state = cmd_state;
}
}
cmd.addr = c->res_addr;
cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state);
ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1);
if (ret) {
dev_err(c->dev, "set active state of %s failed: (%d)\n",
c->res_name, ret);
mutex_unlock(&rpmh_clk_lock);
return ret;
}
c->last_sent_aggr_state = cmd_state;
mutex_unlock(&rpmh_clk_lock);
return 0;
return ret;
}
static int clk_rpmh_bcm_prepare(struct clk_hw *hw)
@ -287,14 +293,14 @@ static int clk_rpmh_bcm_prepare(struct clk_hw *hw)
struct clk_rpmh *c = to_clk_rpmh(hw);
return clk_rpmh_bcm_send_cmd(c, true);
};
}
static void clk_rpmh_bcm_unprepare(struct clk_hw *hw)
{
struct clk_rpmh *c = to_clk_rpmh(hw);
clk_rpmh_bcm_send_cmd(c, false);
};
}
static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
@ -310,7 +316,7 @@ static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate,
clk_rpmh_bcm_send_cmd(c, true);
return 0;
};
}
static long clk_rpmh_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
@ -404,6 +410,28 @@ static const struct clk_rpmh_desc clk_rpmh_sc7180 = {
.num_clks = ARRAY_SIZE(sc7180_rpmh_clocks),
};
DEFINE_CLK_RPMH_VRM(sm8250, ln_bb_clk1, ln_bb_clk1_ao, "lnbclka1", 2);
static struct clk_hw *sm8250_rpmh_clocks[] = {
[RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw,
[RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw,
[RPMH_LN_BB_CLK1] = &sm8250_ln_bb_clk1.hw,
[RPMH_LN_BB_CLK1_A] = &sm8250_ln_bb_clk1_ao.hw,
[RPMH_LN_BB_CLK2] = &sdm845_ln_bb_clk2.hw,
[RPMH_LN_BB_CLK2_A] = &sdm845_ln_bb_clk2_ao.hw,
[RPMH_LN_BB_CLK3] = &sdm845_ln_bb_clk3.hw,
[RPMH_LN_BB_CLK3_A] = &sdm845_ln_bb_clk3_ao.hw,
[RPMH_RF_CLK1] = &sdm845_rf_clk1.hw,
[RPMH_RF_CLK1_A] = &sdm845_rf_clk1_ao.hw,
[RPMH_RF_CLK3] = &sdm845_rf_clk3.hw,
[RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw,
};
static const struct clk_rpmh_desc clk_rpmh_sm8250 = {
.clks = sm8250_rpmh_clocks,
.num_clks = ARRAY_SIZE(sm8250_rpmh_clocks),
};
static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec,
void *data)
{
@ -490,6 +518,7 @@ static const struct of_device_id clk_rpmh_match_table[] = {
{ .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180},
{ .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845},
{ .compatible = "qcom,sm8150-rpmh-clk", .data = &clk_rpmh_sm8150},
{ .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250},
{ }
};
MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);

View file

@ -525,6 +525,55 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
.num_clks = ARRAY_SIZE(msm8974_clks),
};
/* msm8976 */
DEFINE_CLK_SMD_RPM(msm8976, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8976, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8976, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk,
QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM(msm8976, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8976, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM_QDSS(msm8976, qdss_clk, qdss_a_clk,
QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, bb_clk1, bb_clk1_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, bb_clk2, bb_clk2_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, rf_clk2, rf_clk2_a, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, div_clk2, div_clk2_a, 12);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8976, bb_clk1_pin, bb_clk1_a_pin, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8976, bb_clk2_pin, bb_clk2_a_pin, 2);
static struct clk_smd_rpm *msm8976_clks[] = {
[RPM_SMD_PCNOC_CLK] = &msm8976_pcnoc_clk,
[RPM_SMD_PCNOC_A_CLK] = &msm8976_pcnoc_a_clk,
[RPM_SMD_SNOC_CLK] = &msm8976_snoc_clk,
[RPM_SMD_SNOC_A_CLK] = &msm8976_snoc_a_clk,
[RPM_SMD_BIMC_CLK] = &msm8976_bimc_clk,
[RPM_SMD_BIMC_A_CLK] = &msm8976_bimc_a_clk,
[RPM_SMD_QDSS_CLK] = &msm8976_qdss_clk,
[RPM_SMD_QDSS_A_CLK] = &msm8976_qdss_a_clk,
[RPM_SMD_BB_CLK1] = &msm8976_bb_clk1,
[RPM_SMD_BB_CLK1_A] = &msm8976_bb_clk1_a,
[RPM_SMD_BB_CLK2] = &msm8976_bb_clk2,
[RPM_SMD_BB_CLK2_A] = &msm8976_bb_clk2_a,
[RPM_SMD_RF_CLK2] = &msm8976_rf_clk2,
[RPM_SMD_RF_CLK2_A] = &msm8976_rf_clk2_a,
[RPM_SMD_BB_CLK1_PIN] = &msm8976_bb_clk1_pin,
[RPM_SMD_BB_CLK1_A_PIN] = &msm8976_bb_clk1_a_pin,
[RPM_SMD_BB_CLK2_PIN] = &msm8976_bb_clk2_pin,
[RPM_SMD_BB_CLK2_A_PIN] = &msm8976_bb_clk2_a_pin,
[RPM_SMD_MMSSNOC_AHB_CLK] = &msm8976_mmssnoc_ahb_clk,
[RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8976_mmssnoc_ahb_a_clk,
[RPM_SMD_DIV_CLK2] = &msm8976_div_clk2,
[RPM_SMD_DIV_A_CLK2] = &msm8976_div_clk2_a,
[RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
[RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8976 = {
.clks = msm8976_clks,
.num_clks = ARRAY_SIZE(msm8976_clks),
};
/* msm8996 */
DEFINE_CLK_SMD_RPM(msm8996, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8996, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
@ -720,6 +769,7 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8998 = {
static const struct of_device_id rpm_smd_clk_match_table[] = {
{ .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 },
{ .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 },
{ .compatible = "qcom,rpmcc-msm8976", .data = &rpm_clk_msm8976 },
{ .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 },
{ .compatible = "qcom,rpmcc-msm8998", .data = &rpm_clk_msm8998 },
{ .compatible = "qcom,rpmcc-qcs404", .data = &rpm_clk_qcs404 },

View file

@ -1224,6 +1224,8 @@ static struct clk_rcg prng_src = {
.parent_map = gcc_pxo_pll8_map,
},
.clkr = {
.enable_reg = 0x2e80,
.enable_mask = BIT(11),
.hw.init = &(struct clk_init_data){
.name = "prng_src",
.parent_names = gcc_pxo_pll8,

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
@ -2165,6 +2165,71 @@ static struct clk_branch gcc_video_xo_clk = {
},
};
static struct clk_branch gcc_mss_cfg_ahb_clk = {
.halt_reg = 0x8a000,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x8a000,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mss_cfg_ahb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_mss_mfab_axis_clk = {
.halt_reg = 0x8a004,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x8a004,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mss_mfab_axis_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_mss_nav_axi_clk = {
.halt_reg = 0x8a00c,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x8a00c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mss_nav_axi_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_mss_snoc_axi_clk = {
.halt_reg = 0x8a150,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x8a150,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mss_snoc_axi_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_mss_q6_memnoc_axi_clk = {
.halt_reg = 0x8a154,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x8a154,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mss_q6_memnoc_axi_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct gdsc ufs_phy_gdsc = {
.gdscr = 0x77004,
.pd = {
@ -2336,6 +2401,11 @@ static struct clk_regmap *gcc_sc7180_clocks[] = {
[GPLL7] = &gpll7.clkr,
[GPLL4] = &gpll4.clkr,
[GPLL1] = &gpll1.clkr,
[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
[GCC_MSS_MFAB_AXIS_CLK] = &gcc_mss_mfab_axis_clk.clkr,
[GCC_MSS_NAV_AXI_CLK] = &gcc_mss_nav_axi_clk.clkr,
[GCC_MSS_Q6_MEMNOC_AXI_CLK] = &gcc_mss_q6_memnoc_axi_clk.clkr,
[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
};
static const struct qcom_reset_map gcc_sc7180_resets[] = {

View file

@ -21,6 +21,7 @@
#include "clk-rcg.h"
#include "clk-regmap.h"
#include "reset.h"
#include "gdsc.h"
enum {
P_BI_TCXO,
@ -3171,6 +3172,18 @@ static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
},
};
static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0xf058,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_pipe_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_usb3_sec_clkref_clk = {
.halt_reg = 0x8c028,
.halt_check = BRANCH_HALT,
@ -3218,6 +3231,18 @@ static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = {
},
};
static struct clk_branch gcc_usb3_sec_phy_pipe_clk = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x10058,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_sec_phy_pipe_clk",
.ops = &clk_branch2_ops,
},
},
};
/*
* Clock ON depends on external parent 'config noc', so cant poll
* delay and also mark as crtitical for video boot
@ -3292,6 +3317,24 @@ static struct clk_branch gcc_video_xo_clk = {
},
};
static struct gdsc usb30_prim_gdsc = {
.gdscr = 0xf004,
.pd = {
.name = "usb30_prim_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = POLL_CFG_GDSCR,
};
static struct gdsc usb30_sec_gdsc = {
.gdscr = 0x10004,
.pd = {
.name = "usb30_sec_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = POLL_CFG_GDSCR,
};
static struct clk_regmap *gcc_sm8150_clocks[] = {
[GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr,
[GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr,
@ -3480,10 +3523,12 @@ static struct clk_regmap *gcc_sm8150_clocks[] = {
[GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr,
[GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
[GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
[GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
[GCC_USB3_SEC_CLKREF_CLK] = &gcc_usb3_sec_clkref_clk.clkr,
[GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr,
[GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr,
[GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr,
[GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr,
[GCC_VIDEO_AHB_CLK] = &gcc_video_ahb_clk.clkr,
[GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
[GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr,
@ -3527,6 +3572,11 @@ static const struct qcom_reset_map gcc_sm8150_resets[] = {
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
};
static struct gdsc *gcc_sm8150_gdscs[] = {
[USB30_PRIM_GDSC] = &usb30_prim_gdsc,
[USB30_SEC_GDSC] = &usb30_sec_gdsc,
};
static const struct regmap_config gcc_sm8150_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@ -3541,6 +3591,8 @@ static const struct qcom_cc_desc gcc_sm8150_desc = {
.num_clks = ARRAY_SIZE(gcc_sm8150_clocks),
.resets = gcc_sm8150_resets,
.num_resets = ARRAY_SIZE(gcc_sm8150_resets),
.gdscs = gcc_sm8150_gdscs,
.num_gdscs = ARRAY_SIZE(gcc_sm8150_gdscs),
};
static const struct of_device_id gcc_sm8150_match_table[] = {

File diff suppressed because it is too large Load diff

View file

@ -170,8 +170,45 @@ static struct gdsc cx_gdsc = {
.flags = VOTABLE,
};
/*
* On SC7180 the GPU GX domain is *almost* entirely controlled by the GMU
* running in the CX domain so the CPU doesn't need to know anything about the
* GX domain EXCEPT....
*
* Hardware constraints dictate that the GX be powered down before the CX. If
* the GMU crashes it could leave the GX on. In order to successfully bring back
* the device the CPU needs to disable the GX headswitch. There being no sane
* way to reach in and touch that register from deep inside the GPU driver we
* need to set up the infrastructure to be able to ensure that the GPU can
* ensure that the GX is off during this super special case. We do this by
* defining a GX gdsc with a dummy enable function and a "default" disable
* function.
*
* This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
* driver. During power up, nothing will happen from the CPU (and the GMU will
* power up normally but during power down this will ensure that the GX domain
* is *really* off - this gives us a semi standard way of doing what we need.
*/
static int gx_gdsc_enable(struct generic_pm_domain *domain)
{
/* Do nothing but give genpd the impression that we were successful */
return 0;
}
static struct gdsc gx_gdsc = {
.gdscr = 0x100c,
.clamp_io_ctrl = 0x1508,
.pd = {
.name = "gx_gdsc",
.power_on = gx_gdsc_enable,
},
.pwrsts = PWRSTS_OFF_ON,
.flags = CLAMP_IO,
};
static struct gdsc *gpu_cc_sc7180_gdscs[] = {
[CX_GDSC] = &cx_gdsc,
[GX_GDSC] = &gx_gdsc,
};
static struct clk_regmap *gpu_cc_sc7180_clocks[] = {

View file

@ -0,0 +1,143 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/qcom,mss-sc7180.h>
#include "clk-regmap.h"
#include "clk-branch.h"
#include "common.h"
static struct clk_branch mss_axi_nav_clk = {
.halt_reg = 0x20bc,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x20bc,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mss_axi_nav_clk",
.parent_data = &(const struct clk_parent_data){
.fw_name = "gcc_mss_nav_axi",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch mss_axi_crypto_clk = {
.halt_reg = 0x20cc,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x20cc,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mss_axi_crypto_clk",
.parent_data = &(const struct clk_parent_data){
.fw_name = "gcc_mss_mfab_axis",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
},
},
};
static const struct regmap_config mss_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
.max_register = 0x41aa0cc,
};
static struct clk_regmap *mss_sc7180_clocks[] = {
[MSS_AXI_CRYPTO_CLK] = &mss_axi_crypto_clk.clkr,
[MSS_AXI_NAV_CLK] = &mss_axi_nav_clk.clkr,
};
static const struct qcom_cc_desc mss_sc7180_desc = {
.config = &mss_regmap_config,
.clks = mss_sc7180_clocks,
.num_clks = ARRAY_SIZE(mss_sc7180_clocks),
};
static int mss_sc7180_probe(struct platform_device *pdev)
{
int ret;
pm_runtime_enable(&pdev->dev);
ret = pm_clk_create(&pdev->dev);
if (ret)
goto disable_pm_runtime;
ret = pm_clk_add(&pdev->dev, "cfg_ahb");
if (ret < 0) {
dev_err(&pdev->dev, "failed to acquire iface clock\n");
goto destroy_pm_clk;
}
ret = qcom_cc_probe(pdev, &mss_sc7180_desc);
if (ret < 0)
goto destroy_pm_clk;
return 0;
destroy_pm_clk:
pm_clk_destroy(&pdev->dev);
disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
return ret;
}
static int mss_sc7180_remove(struct platform_device *pdev)
{
pm_clk_destroy(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
static const struct dev_pm_ops mss_sc7180_pm_ops = {
SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
};
static const struct of_device_id mss_sc7180_match_table[] = {
{ .compatible = "qcom,sc7180-mss" },
{ }
};
MODULE_DEVICE_TABLE(of, mss_sc7180_match_table);
static struct platform_driver mss_sc7180_driver = {
.probe = mss_sc7180_probe,
.remove = mss_sc7180_remove,
.driver = {
.name = "sc7180-mss",
.of_match_table = mss_sc7180_match_table,
.pm = &mss_sc7180_pm_ops,
},
};
static int __init mss_sc7180_init(void)
{
return platform_driver_register(&mss_sc7180_driver);
}
subsys_initcall(mss_sc7180_init);
static void __exit mss_sc7180_exit(void)
{
platform_driver_unregister(&mss_sc7180_driver);
}
module_exit(mss_sc7180_exit);
MODULE_DESCRIPTION("QTI MSS SC7180 Driver");
MODULE_LICENSE("GPL v2");

View file

@ -20,7 +20,7 @@ config CLK_RENESAS
select CLK_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793
select CLK_R8A7792 if ARCH_R8A7792
select CLK_R8A7794 if ARCH_R8A7794
select CLK_R8A7795 if ARCH_R8A77950 || ARCH_R8A77951 || ARCH_R8A7795
select CLK_R8A7795 if ARCH_R8A77950 || ARCH_R8A77951
select CLK_R8A77960 if ARCH_R8A77960
select CLK_R8A77961 if ARCH_R8A77961
select CLK_R8A77965 if ARCH_R8A77965
@ -161,6 +161,7 @@ config CLK_RCAR_GEN3_CPG
config CLK_RCAR_USB2_CLOCK_SEL
bool "Renesas R-Car USB2 clock selector support"
depends on ARCH_RENESAS || COMPILE_TEST
select RESET_CONTROLLER
help
This is a driver for R-Car USB2 clock selector

View file

@ -44,6 +44,7 @@ enum clk_ids {
CLK_S3,
CLK_SDSRC,
CLK_SSPSRC,
CLK_RPCSRC,
CLK_RINT,
/* Module Clocks */
@ -70,6 +71,12 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
DEF_BASE("rpc", R8A7795_CLK_RPC, CLK_TYPE_GEN3_RPC,
CLK_RPCSRC),
DEF_BASE("rpcd2", R8A7795_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
R8A7795_CLK_RPC),
DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
@ -242,6 +249,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
DEF_MOD("can-fd", 914, R8A7795_CLK_S3D2),
DEF_MOD("can-if1", 915, R8A7795_CLK_S3D4),
DEF_MOD("can-if0", 916, R8A7795_CLK_S3D4),
DEF_MOD("rpc-if", 917, R8A7795_CLK_RPCD2),
DEF_MOD("i2c6", 918, R8A7795_CLK_S0D6),
DEF_MOD("i2c5", 919, R8A7795_CLK_S0D6),
DEF_MOD("i2c-dvfs", 926, R8A7795_CLK_CP),

View file

@ -46,6 +46,7 @@ enum clk_ids {
CLK_S3,
CLK_SDSRC,
CLK_SSPSRC,
CLK_RPCSRC,
CLK_RINT,
/* Module Clocks */
@ -72,6 +73,12 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
DEF_BASE("rpc", R8A7796_CLK_RPC, CLK_TYPE_GEN3_RPC,
CLK_RPCSRC),
DEF_BASE("rpcd2", R8A7796_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
R8A7796_CLK_RPC),
DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
@ -105,6 +112,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cr", R8A7796_CLK_CR, CLK_PLL1_DIV4, 2, 1),
DEF_FIXED("cp", R8A7796_CLK_CP, CLK_EXTAL, 2, 1),
DEF_FIXED("cpex", R8A7796_CLK_CPEX, CLK_EXTAL, 2, 1),
@ -132,6 +140,7 @@ static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = {
DEF_MOD("sys-dmac2", 217, R8A7796_CLK_S3D1),
DEF_MOD("sys-dmac1", 218, R8A7796_CLK_S3D1),
DEF_MOD("sys-dmac0", 219, R8A7796_CLK_S0D3),
DEF_MOD("sceg-pub", 229, R8A7796_CLK_CR),
DEF_MOD("cmt3", 300, R8A7796_CLK_R),
DEF_MOD("cmt2", 301, R8A7796_CLK_R),
DEF_MOD("cmt1", 302, R8A7796_CLK_R),
@ -215,6 +224,7 @@ static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = {
DEF_MOD("can-fd", 914, R8A7796_CLK_S3D2),
DEF_MOD("can-if1", 915, R8A7796_CLK_S3D4),
DEF_MOD("can-if0", 916, R8A7796_CLK_S3D4),
DEF_MOD("rpc-if", 917, R8A7796_CLK_RPCD2),
DEF_MOD("i2c6", 918, R8A7796_CLK_S0D6),
DEF_MOD("i2c5", 919, R8A7796_CLK_S0D6),
DEF_MOD("i2c-dvfs", 926, R8A7796_CLK_CP),

View file

@ -43,6 +43,7 @@ enum clk_ids {
CLK_S3,
CLK_SDSRC,
CLK_SSPSRC,
CLK_RPCSRC,
CLK_RINT,
/* Module Clocks */
@ -68,6 +69,12 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = {
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
DEF_BASE("rpc", R8A77965_CLK_RPC, CLK_TYPE_GEN3_RPC,
CLK_RPCSRC),
DEF_BASE("rpcd2", R8A77965_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
R8A77965_CLK_RPC),
DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
@ -99,7 +106,8 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = {
DEF_GEN3_SD("sd2", R8A77965_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A77965_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_FIXED("cl", R8A77965_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cl", R8A77965_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cr", R8A77965_CLK_CR, CLK_PLL1_DIV4, 2, 1),
DEF_FIXED("cp", R8A77965_CLK_CP, CLK_EXTAL, 2, 1),
DEF_FIXED("cpex", R8A77965_CLK_CPEX, CLK_EXTAL, 2, 1),
@ -127,6 +135,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
DEF_MOD("sys-dmac2", 217, R8A77965_CLK_S3D1),
DEF_MOD("sys-dmac1", 218, R8A77965_CLK_S3D1),
DEF_MOD("sys-dmac0", 219, R8A77965_CLK_S0D3),
DEF_MOD("sceg-pub", 229, R8A77965_CLK_CR),
DEF_MOD("cmt3", 300, R8A77965_CLK_R),
DEF_MOD("cmt2", 301, R8A77965_CLK_R),
@ -215,6 +224,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
DEF_MOD("can-fd", 914, R8A77965_CLK_S3D2),
DEF_MOD("can-if1", 915, R8A77965_CLK_S3D4),
DEF_MOD("can-if0", 916, R8A77965_CLK_S3D4),
DEF_MOD("rpc-if", 917, R8A77965_CLK_RPCD2),
DEF_MOD("i2c6", 918, R8A77965_CLK_S0D6),
DEF_MOD("i2c5", 919, R8A77965_CLK_S0D6),
DEF_MOD("i2c-dvfs", 926, R8A77965_CLK_CP),

View file

@ -105,6 +105,7 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = {
DEF_GEN3_SD("sd3", R8A77990_CLK_SD3, CLK_SDSRC, 0x026c),
DEF_FIXED("cl", R8A77990_CLK_CL, CLK_PLL1, 48, 1),
DEF_FIXED("cr", R8A77990_CLK_CR, CLK_PLL1D2, 2, 1),
DEF_FIXED("cp", R8A77990_CLK_CP, CLK_EXTAL, 2, 1),
DEF_FIXED("cpex", R8A77990_CLK_CPEX, CLK_EXTAL, 4, 1),
@ -135,6 +136,7 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = {
DEF_MOD("sys-dmac2", 217, R8A77990_CLK_S3D1),
DEF_MOD("sys-dmac1", 218, R8A77990_CLK_S3D1),
DEF_MOD("sys-dmac0", 219, R8A77990_CLK_S3D1),
DEF_MOD("sceg-pub", 229, R8A77990_CLK_CR),
DEF_MOD("cmt3", 300, R8A77990_CLK_R),
DEF_MOD("cmt2", 301, R8A77990_CLK_R),

View file

@ -91,6 +91,7 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
DEF_FIXED("s3d4", R8A77995_CLK_S3D4, CLK_S3, 4, 1),
DEF_FIXED("cl", R8A77995_CLK_CL, CLK_PLL1, 48, 1),
DEF_FIXED("cr", R8A77995_CLK_CR, CLK_PLL1D2, 2, 1),
DEF_FIXED("cp", R8A77995_CLK_CP, CLK_EXTAL, 2, 1),
DEF_FIXED("cpex", R8A77995_CLK_CPEX, CLK_EXTAL, 4, 1),
@ -122,6 +123,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
DEF_MOD("sys-dmac2", 217, R8A77995_CLK_S3D1),
DEF_MOD("sys-dmac1", 218, R8A77995_CLK_S3D1),
DEF_MOD("sys-dmac0", 219, R8A77995_CLK_S3D1),
DEF_MOD("sceg-pub", 229, R8A77995_CLK_CR),
DEF_MOD("cmt3", 300, R8A77995_CLK_R),
DEF_MOD("cmt2", 301, R8A77995_CLK_R),
DEF_MOD("cmt1", 302, R8A77995_CLK_R),

View file

@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h>
#define USB20_CLKSET0 0x00
@ -26,9 +27,16 @@
#define CLKSET0_PRIVATE BIT(0)
#define CLKSET0_EXTAL_ONLY (CLKSET0_INTCLK_EN | CLKSET0_PRIVATE)
static const struct clk_bulk_data rcar_usb2_clocks[] = {
{ .id = "ehci_ohci", },
{ .id = "hs-usb-if", },
};
struct usb2_clock_sel_priv {
void __iomem *base;
struct clk_hw hw;
struct clk_bulk_data clks[ARRAY_SIZE(rcar_usb2_clocks)];
struct reset_control *rsts;
bool extal;
bool xtal;
};
@ -53,14 +61,32 @@ static void usb2_clock_sel_disable_extal_only(struct usb2_clock_sel_priv *priv)
static int usb2_clock_sel_enable(struct clk_hw *hw)
{
usb2_clock_sel_enable_extal_only(to_priv(hw));
struct usb2_clock_sel_priv *priv = to_priv(hw);
int ret;
ret = reset_control_deassert(priv->rsts);
if (ret)
return ret;
ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clks), priv->clks);
if (ret) {
reset_control_assert(priv->rsts);
return ret;
}
usb2_clock_sel_enable_extal_only(priv);
return 0;
}
static void usb2_clock_sel_disable(struct clk_hw *hw)
{
usb2_clock_sel_disable_extal_only(to_priv(hw));
struct usb2_clock_sel_priv *priv = to_priv(hw);
usb2_clock_sel_disable_extal_only(priv);
clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clks), priv->clks);
reset_control_assert(priv->rsts);
}
/*
@ -119,6 +145,7 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
struct usb2_clock_sel_priv *priv;
struct clk *clk;
struct clk_init_data init;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@ -128,6 +155,15 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
memcpy(priv->clks, rcar_usb2_clocks, sizeof(priv->clks));
ret = devm_clk_bulk_get(dev, ARRAY_SIZE(priv->clks), priv->clks);
if (ret < 0)
return ret;
priv->rsts = devm_reset_control_array_get(dev, true, false);
if (IS_ERR(priv->rsts))
return PTR_ERR(priv->rsts);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);

View file

@ -51,9 +51,9 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
u16 degrees;
u32 delay_num = 0;
/* See the comment for rockchip_mmc_set_phase below */
/* Constant signal, no measurable phase shift */
if (!rate)
return -EINVAL;
return 0;
raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);

View file

@ -356,10 +356,6 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
}
ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
if (!ctx) {
panic("%s: unable to allocate ctx\n", __func__);
return ctx;
}
if (cmu->pll_clks)
samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,

View file

@ -65,54 +65,49 @@ static const struct clk_ops dbgclk_ops = {
.get_parent = socfpga_gate_get_parent,
};
struct clk *s10_register_gate(const char *name, const char *parent_name,
const char * const *parent_names,
u8 num_parents, unsigned long flags,
void __iomem *regbase, unsigned long gate_reg,
unsigned long gate_idx, unsigned long div_reg,
unsigned long div_offset, u8 div_width,
unsigned long bypass_reg, u8 bypass_shift,
u8 fixed_div)
struct clk *s10_register_gate(const struct stratix10_gate_clock *clks, void __iomem *regbase)
{
struct clk *clk;
struct socfpga_gate_clk *socfpga_clk;
struct clk_init_data init;
const char * const *parent_names = clks->parent_names;
const char *parent_name = clks->parent_name;
socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
if (!socfpga_clk)
return NULL;
socfpga_clk->hw.reg = regbase + gate_reg;
socfpga_clk->hw.bit_idx = gate_idx;
socfpga_clk->hw.reg = regbase + clks->gate_reg;
socfpga_clk->hw.bit_idx = clks->gate_idx;
gateclk_ops.enable = clk_gate_ops.enable;
gateclk_ops.disable = clk_gate_ops.disable;
socfpga_clk->fixed_div = fixed_div;
socfpga_clk->fixed_div = clks->fixed_div;
if (div_reg)
socfpga_clk->div_reg = regbase + div_reg;
if (clks->div_reg)
socfpga_clk->div_reg = regbase + clks->div_reg;
else
socfpga_clk->div_reg = NULL;
socfpga_clk->width = div_width;
socfpga_clk->shift = div_offset;
socfpga_clk->width = clks->div_width;
socfpga_clk->shift = clks->div_offset;
if (bypass_reg)
socfpga_clk->bypass_reg = regbase + bypass_reg;
if (clks->bypass_reg)
socfpga_clk->bypass_reg = regbase + clks->bypass_reg;
else
socfpga_clk->bypass_reg = NULL;
socfpga_clk->bypass_shift = bypass_shift;
socfpga_clk->bypass_shift = clks->bypass_shift;
if (streq(name, "cs_pdbg_clk"))
if (streq(clks->name, "cs_pdbg_clk"))
init.ops = &dbgclk_ops;
else
init.ops = &gateclk_ops;
init.name = name;
init.flags = flags;
init.name = clks->name;
init.flags = clks->flags;
init.num_parents = num_parents;
init.num_parents = clks->num_parents;
init.parent_names = parent_names ? parent_names : &parent_name;
socfpga_clk->hw.hw.init = &init;
@ -121,6 +116,5 @@ struct clk *s10_register_gate(const char *name, const char *parent_name,
kfree(socfpga_clk);
return NULL;
}
return clk;
}

View file

@ -73,26 +73,27 @@ static const struct clk_ops peri_cnt_clk_ops = {
.get_parent = clk_periclk_get_parent,
};
struct clk *s10_register_periph(const char *name, const char *parent_name,
const char * const *parent_names,
u8 num_parents, unsigned long flags,
void __iomem *reg, unsigned long offset)
struct clk *s10_register_periph(const struct stratix10_perip_c_clock *clks,
void __iomem *reg)
{
struct clk *clk;
struct socfpga_periph_clk *periph_clk;
struct clk_init_data init;
const char *name = clks->name;
const char *parent_name = clks->parent_name;
const char * const *parent_names = clks->parent_names;
periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
if (WARN_ON(!periph_clk))
return NULL;
periph_clk->hw.reg = reg + offset;
periph_clk->hw.reg = reg + clks->offset;
init.name = name;
init.ops = &peri_c_clk_ops;
init.flags = flags;
init.flags = clks->flags;
init.num_parents = num_parents;
init.num_parents = clks->num_parents;
init.parent_names = parent_names ? parent_names : &parent_name;
periph_clk->hw.hw.init = &init;
@ -105,38 +106,37 @@ struct clk *s10_register_periph(const char *name, const char *parent_name,
return clk;
}
struct clk *s10_register_cnt_periph(const char *name, const char *parent_name,
const char * const *parent_names,
u8 num_parents, unsigned long flags,
void __iomem *regbase, unsigned long offset,
u8 fixed_divider, unsigned long bypass_reg,
unsigned long bypass_shift)
struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,
void __iomem *regbase)
{
struct clk *clk;
struct socfpga_periph_clk *periph_clk;
struct clk_init_data init;
const char *name = clks->name;
const char *parent_name = clks->parent_name;
const char * const *parent_names = clks->parent_names;
periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
if (WARN_ON(!periph_clk))
return NULL;
if (offset)
periph_clk->hw.reg = regbase + offset;
if (clks->offset)
periph_clk->hw.reg = regbase + clks->offset;
else
periph_clk->hw.reg = NULL;
if (bypass_reg)
periph_clk->bypass_reg = regbase + bypass_reg;
if (clks->bypass_reg)
periph_clk->bypass_reg = regbase + clks->bypass_reg;
else
periph_clk->bypass_reg = NULL;
periph_clk->bypass_shift = bypass_shift;
periph_clk->fixed_div = fixed_divider;
periph_clk->bypass_shift = clks->bypass_shift;
periph_clk->fixed_div = clks->fixed_divider;
init.name = name;
init.ops = &peri_cnt_clk_ops;
init.flags = flags;
init.flags = clks->flags;
init.num_parents = num_parents;
init.num_parents = clks->num_parents;
init.parent_names = parent_names ? parent_names : &parent_name;
periph_clk->hw.hw.init = &init;

View file

@ -39,7 +39,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
/* read VCO1 reg for numerator and denominator */
reg = readl(socfpgaclk->hw.reg);
refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
vco_freq = (unsigned long long)parent_rate / refdiv;
vco_freq = parent_rate;
do_div(vco_freq, refdiv);
/* Read mdiv and fdiv from the fdbck register */
reg = readl(socfpgaclk->hw.reg + 0x4);
@ -108,19 +110,20 @@ static struct clk_ops clk_boot_ops = {
.prepare = clk_pll_prepare,
};
struct clk *s10_register_pll(const char *name, const char * const *parent_names,
u8 num_parents, unsigned long flags,
void __iomem *reg, unsigned long offset)
struct clk *s10_register_pll(const struct stratix10_pll_clock *clks,
void __iomem *reg)
{
struct clk *clk;
struct socfpga_pll *pll_clk;
struct clk_init_data init;
const char *name = clks->name;
const char * const *parent_names = clks->parent_names;
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
if (WARN_ON(!pll_clk))
return NULL;
pll_clk->hw.reg = reg + offset;
pll_clk->hw.reg = reg + clks->offset;
if (streq(name, SOCFPGA_BOOT_CLK))
init.ops = &clk_boot_ops;
@ -128,9 +131,9 @@ struct clk *s10_register_pll(const char *name, const char * const *parent_names,
init.ops = &clk_pll_ops;
init.name = name;
init.flags = flags;
init.flags = clks->flags;
init.num_parents = num_parents;
init.num_parents = clks->num_parents;
init.parent_names = parent_names;
pll_clk->hw.hw.init = &init;

View file

@ -177,9 +177,7 @@ static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks,
int i;
for (i = 0; i < nums; i++) {
clk = s10_register_periph(clks[i].name, clks[i].parent_name,
clks[i].parent_names, clks[i].num_parents,
clks[i].flags, base, clks[i].offset);
clk = s10_register_periph(&clks[i], base);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
@ -198,14 +196,7 @@ static int s10_clk_register_cnt_perip(const struct stratix10_perip_cnt_clock *cl
int i;
for (i = 0; i < nums; i++) {
clk = s10_register_cnt_periph(clks[i].name, clks[i].parent_name,
clks[i].parent_names,
clks[i].num_parents,
clks[i].flags, base,
clks[i].offset,
clks[i].fixed_divider,
clks[i].bypass_reg,
clks[i].bypass_shift);
clk = s10_register_cnt_periph(&clks[i], base);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
@ -225,16 +216,7 @@ static int s10_clk_register_gate(const struct stratix10_gate_clock *clks,
int i;
for (i = 0; i < nums; i++) {
clk = s10_register_gate(clks[i].name, clks[i].parent_name,
clks[i].parent_names,
clks[i].num_parents,
clks[i].flags, base,
clks[i].gate_reg,
clks[i].gate_idx, clks[i].div_reg,
clks[i].div_offset, clks[i].div_width,
clks[i].bypass_reg,
clks[i].bypass_shift,
clks[i].fixed_div);
clk = s10_register_gate(&clks[i], base);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
@ -254,10 +236,7 @@ static int s10_clk_register_pll(const struct stratix10_pll_clock *clks,
int i;
for (i = 0; i < nums; i++) {
clk = s10_register_pll(clks[i].name, clks[i].parent_names,
clks[i].num_parents,
clks[i].flags, base,
clks[i].offset);
clk = s10_register_pll(&clks[i], base);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);

View file

@ -60,21 +60,12 @@ struct stratix10_gate_clock {
u8 fixed_div;
};
struct clk *s10_register_pll(const char *, const char *const *, u8,
unsigned long, void __iomem *, unsigned long);
struct clk *s10_register_periph(const char *, const char *,
const char * const *, u8, unsigned long,
void __iomem *, unsigned long);
struct clk *s10_register_cnt_periph(const char *, const char *,
const char * const *, u8,
unsigned long, void __iomem *,
unsigned long, u8, unsigned long,
unsigned long);
struct clk *s10_register_gate(const char *, const char *,
const char * const *, u8,
unsigned long, void __iomem *,
unsigned long, unsigned long,
unsigned long, unsigned long, u8,
unsigned long, u8, u8);
struct clk *s10_register_pll(const struct stratix10_pll_clock *,
void __iomem *);
struct clk *s10_register_periph(const struct stratix10_perip_c_clock *,
void __iomem *);
struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *,
void __iomem *);
struct clk *s10_register_gate(const struct stratix10_gate_clock *,
void __iomem *);
#endif /* __STRATIX10_CLK_H */

View file

@ -13,4 +13,12 @@ config SPRD_SC9860_CLK
tristate "Support for the Spreadtrum SC9860 clocks"
depends on (ARM64 && ARCH_SPRD) || COMPILE_TEST
default ARM64 && ARCH_SPRD
config SPRD_SC9863A_CLK
tristate "Support for the Spreadtrum SC9863A clocks"
depends on (ARM64 && ARCH_SPRD) || COMPILE_TEST
default ARM64 && ARCH_SPRD
help
Support for the global clock controller on sc9863a devices.
Say Y if you want to use peripheral devices on sc9863a SoC.
endif

View file

@ -10,3 +10,4 @@ clk-sprd-y += pll.o
## SoC support
obj-$(CONFIG_SPRD_SC9860_CLK) += sc9860-clk.o
obj-$(CONFIG_SPRD_SC9863A_CLK) += sc9863a-clk.o

View file

@ -40,7 +40,8 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
const struct sprd_clk_desc *desc)
{
void __iomem *base;
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct regmap *regmap;
if (of_find_property(node, "sprd,syscon", NULL)) {
@ -49,6 +50,13 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
pr_err("%s: failed to get syscon regmap\n", __func__);
return PTR_ERR(regmap);
}
} else if (of_device_is_compatible(of_get_parent(dev->of_node),
"syscon")) {
regmap = device_node_to_regmap(of_get_parent(dev->of_node));
if (IS_ERR(regmap)) {
dev_err(dev, "failed to get regmap from its parent.\n");
return PTR_ERR(regmap);
}
} else {
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))

View file

@ -18,26 +18,43 @@ struct sprd_comp {
struct sprd_clk_common common;
};
#define SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, _table, \
_mshift, _mwidth, _dshift, _dwidth, _flags) \
#define SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \
_mshift, _mwidth, _dshift, _dwidth, \
_flags, _fn) \
struct sprd_comp _struct = { \
.mux = _SPRD_MUX_CLK(_mshift, _mwidth, _table), \
.div = _SPRD_DIV_CLK(_dshift, _dwidth), \
.common = { \
.regmap = NULL, \
.reg = _reg, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parent, \
&sprd_comp_ops, \
_flags), \
.hw.init = _fn(_name, _parent, \
&sprd_comp_ops, _flags), \
} \
}
#define SPRD_COMP_CLK(_struct, _name, _parent, _reg, _mshift, \
_mwidth, _dshift, _dwidth, _flags) \
SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, \
NULL, _mshift, _mwidth, \
_dshift, _dwidth, _flags)
#define SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, _table, \
_mshift, _mwidth, _dshift, _dwidth, _flags) \
SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \
_mshift, _mwidth, _dshift, _dwidth, \
_flags, CLK_HW_INIT_PARENTS)
#define SPRD_COMP_CLK(_struct, _name, _parent, _reg, _mshift, \
_mwidth, _dshift, _dwidth, _flags) \
SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, NULL, \
_mshift, _mwidth, _dshift, _dwidth, _flags)
#define SPRD_COMP_CLK_DATA_TABLE(_struct, _name, _parent, _reg, _table, \
_mshift, _mwidth, _dshift, \
_dwidth, _flags) \
SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \
_mshift, _mwidth, _dshift, _dwidth, \
_flags, CLK_HW_INIT_PARENTS_DATA)
#define SPRD_COMP_CLK_DATA(_struct, _name, _parent, _reg, _mshift, \
_mwidth, _dshift, _dwidth, _flags) \
SPRD_COMP_CLK_DATA_TABLE(_struct, _name, _parent, _reg, NULL, \
_mshift, _mwidth, _dshift, _dwidth, \
_flags)
static inline struct sprd_comp *hw_to_sprd_comp(const struct clk_hw *hw)
{

View file

@ -35,20 +35,28 @@ struct sprd_div {
struct sprd_clk_common common;
};
#define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \
_shift, _width, _flags) \
#define SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
_shift, _width, _flags, _fn) \
struct sprd_div _struct = { \
.div = _SPRD_DIV_CLK(_shift, _width), \
.common = { \
.regmap = NULL, \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&sprd_div_ops, \
_flags), \
.hw.init = _fn(_name, _parent, \
&sprd_div_ops, _flags), \
} \
}
#define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \
_shift, _width, _flags) \
SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
_shift, _width, _flags, CLK_HW_INIT)
#define SPRD_DIV_CLK_HW(_struct, _name, _parent, _reg, \
_shift, _width, _flags) \
SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
_shift, _width, _flags, CLK_HW_INIT_HW)
static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw)
{
struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);

View file

@ -79,6 +79,17 @@ static int sprd_sc_gate_enable(struct clk_hw *hw)
return 0;
}
static int sprd_pll_sc_gate_prepare(struct clk_hw *hw)
{
struct sprd_gate *sg = hw_to_sprd_gate(hw);
clk_sc_gate_toggle(sg, true);
udelay(sg->udelay);
return 0;
}
static int sprd_gate_is_enabled(struct clk_hw *hw)
{
struct sprd_gate *sg = hw_to_sprd_gate(hw);
@ -109,3 +120,9 @@ const struct clk_ops sprd_sc_gate_ops = {
};
EXPORT_SYMBOL_GPL(sprd_sc_gate_ops);
const struct clk_ops sprd_pll_sc_gate_ops = {
.unprepare = sprd_sc_gate_disable,
.prepare = sprd_pll_sc_gate_prepare,
.is_enabled = sprd_gate_is_enabled,
};
EXPORT_SYMBOL_GPL(sprd_pll_sc_gate_ops);

View file

@ -14,37 +14,136 @@ struct sprd_gate {
u32 enable_mask;
u16 flags;
u16 sc_offset;
u16 udelay;
struct sprd_clk_common common;
};
#define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \
_enable_mask, _flags, _gate_flags, _ops) \
#define SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay, _ops, _fn) \
struct sprd_gate _struct = { \
.enable_mask = _enable_mask, \
.sc_offset = _sc_offset, \
.flags = _gate_flags, \
.udelay = _udelay, \
.common = { \
.regmap = NULL, \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
_ops, \
_flags), \
.hw.init = _fn(_name, _parent, \
_ops, _flags), \
} \
}
#define SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay, _ops) \
SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay, _ops, CLK_HW_INIT)
#define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \
_enable_mask, _flags, _gate_flags, _ops) \
SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, 0, _ops)
#define SPRD_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \
_enable_mask, _flags, _gate_flags) \
SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \
_enable_mask, _flags, _gate_flags, \
&sprd_sc_gate_ops)
#define SPRD_GATE_CLK(_struct, _name, _parent, _reg, \
_enable_mask, _flags, _gate_flags) \
SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, 0, \
_enable_mask, _flags, _gate_flags, \
&sprd_gate_ops)
#define SPRD_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \
_enable_mask, _flags, _gate_flags) \
SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \
#define SPRD_PLL_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \
_enable_mask, _flags, _gate_flags, \
&sprd_sc_gate_ops)
_udelay) \
SPRD_SC_GATE_CLK_OPS_UDELAY(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay, \
&sprd_pll_sc_gate_ops)
#define SPRD_SC_GATE_CLK_HW_OPS_UDELAY(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, \
_flags, _gate_flags, \
_udelay, _ops) \
SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay, _ops, \
CLK_HW_INIT_HW)
#define SPRD_SC_GATE_CLK_HW_OPS(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _ops) \
SPRD_SC_GATE_CLK_HW_OPS_UDELAY(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, \
_flags, _gate_flags, 0, _ops)
#define SPRD_SC_GATE_CLK_HW(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags) \
SPRD_SC_GATE_CLK_HW_OPS(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, &sprd_sc_gate_ops)
#define SPRD_GATE_CLK_HW(_struct, _name, _parent, _reg, \
_enable_mask, _flags, _gate_flags) \
SPRD_SC_GATE_CLK_HW_OPS(_struct, _name, _parent, _reg, 0, \
_enable_mask, _flags, _gate_flags, \
&sprd_gate_ops)
#define SPRD_PLL_SC_GATE_CLK_HW(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay) \
SPRD_SC_GATE_CLK_HW_OPS_UDELAY(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, \
_flags, _gate_flags, _udelay, \
&sprd_pll_sc_gate_ops)
#define SPRD_SC_GATE_CLK_FW_NAME_OPS_UDELAY(_struct, _name, _parent, \
_reg, _sc_offset, \
_enable_mask, _flags, \
_gate_flags, _udelay, _ops) \
SPRD_SC_GATE_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay, _ops, \
CLK_HW_INIT_FW_NAME)
#define SPRD_SC_GATE_CLK_FW_NAME_OPS(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _ops) \
SPRD_SC_GATE_CLK_FW_NAME_OPS_UDELAY(_struct, _name, _parent, \
_reg, _sc_offset, \
_enable_mask, _flags, \
_gate_flags, 0, _ops)
#define SPRD_SC_GATE_CLK_FW_NAME(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags) \
SPRD_SC_GATE_CLK_FW_NAME_OPS(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, &sprd_sc_gate_ops)
#define SPRD_GATE_CLK_FW_NAME(_struct, _name, _parent, _reg, \
_enable_mask, _flags, _gate_flags) \
SPRD_SC_GATE_CLK_FW_NAME_OPS(_struct, _name, _parent, _reg, 0, \
_enable_mask, _flags, _gate_flags, \
&sprd_gate_ops)
#define SPRD_PLL_SC_GATE_CLK_FW_NAME(_struct, _name, _parent, _reg, \
_sc_offset, _enable_mask, _flags, \
_gate_flags, _udelay) \
SPRD_SC_GATE_CLK_FW_NAME_OPS_UDELAY(_struct, _name, _parent, \
_reg, _sc_offset, \
_enable_mask, _flags, \
_gate_flags, _udelay, \
&sprd_pll_sc_gate_ops)
static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw)
{
@ -55,5 +154,6 @@ static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw)
extern const struct clk_ops sprd_gate_ops;
extern const struct clk_ops sprd_sc_gate_ops;
extern const struct clk_ops sprd_pll_sc_gate_ops;
#endif /* _SPRD_GATE_H_ */

View file

@ -36,26 +36,40 @@ struct sprd_mux {
.table = _table, \
}
#define SPRD_MUX_CLK_TABLE(_struct, _name, _parents, _table, \
_reg, _shift, _width, \
_flags) \
#define SPRD_MUX_CLK_HW_INIT_FN(_struct, _name, _parents, _table, \
_reg, _shift, _width, _flags, _fn) \
struct sprd_mux _struct = { \
.mux = _SPRD_MUX_CLK(_shift, _width, _table), \
.common = { \
.regmap = NULL, \
.reg = _reg, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&sprd_mux_ops, \
_flags), \
.hw.init = _fn(_name, _parents, \
&sprd_mux_ops, _flags), \
} \
}
#define SPRD_MUX_CLK_TABLE(_struct, _name, _parents, _table, \
_reg, _shift, _width, _flags) \
SPRD_MUX_CLK_HW_INIT_FN(_struct, _name, _parents, _table, \
_reg, _shift, _width, _flags, \
CLK_HW_INIT_PARENTS)
#define SPRD_MUX_CLK(_struct, _name, _parents, _reg, \
_shift, _width, _flags) \
SPRD_MUX_CLK_TABLE(_struct, _name, _parents, NULL, \
_reg, _shift, _width, _flags)
#define SPRD_MUX_CLK_DATA_TABLE(_struct, _name, _parents, _table, \
_reg, _shift, _width, _flags) \
SPRD_MUX_CLK_HW_INIT_FN(_struct, _name, _parents, _table, \
_reg, _shift, _width, _flags, \
CLK_HW_INIT_PARENTS_DATA)
#define SPRD_MUX_CLK_DATA(_struct, _name, _parents, _reg, \
_shift, _width, _flags) \
SPRD_MUX_CLK_DATA_TABLE(_struct, _name, _parents, NULL, \
_reg, _shift, _width, _flags)
static inline struct sprd_mux *hw_to_sprd_mux(const struct clk_hw *hw)
{
struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);

View file

@ -87,11 +87,12 @@ static u32 pll_get_ibias(u64 rate, const u64 *table)
{
u32 i, num = table[0];
for (i = 1; i < num + 1; i++)
if (rate <= table[i])
/* table[0] indicates the number of items in this table */
for (i = 0; i < num; i++)
if (rate <= table[i + 1])
break;
return (i == num + 1) ? num : i;
return i == num ? num - 1 : i;
}
static unsigned long _sprd_pll_recalc_rate(const struct sprd_pll *pll,

View file

@ -61,27 +61,33 @@ struct sprd_pll {
struct sprd_clk_common common;
};
#define SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, \
_regs_num, _itable, _factors, \
_udelay, _k1, _k2, _fflag, \
_fvco, _fn) \
struct sprd_pll _struct = { \
.regs_num = _regs_num, \
.itable = _itable, \
.factors = _factors, \
.udelay = _udelay, \
.k1 = _k1, \
.k2 = _k2, \
.fflag = _fflag, \
.fvco = _fvco, \
.common = { \
.regmap = NULL, \
.reg = _reg, \
.hw.init = _fn(_name, _parent, \
&sprd_pll_ops, 0),\
}, \
}
#define SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \
_regs_num, _itable, _factors, \
_udelay, _k1, _k2, _fflag, _fvco) \
struct sprd_pll _struct = { \
.regs_num = _regs_num, \
.itable = _itable, \
.factors = _factors, \
.udelay = _udelay, \
.k1 = _k1, \
.k2 = _k2, \
.fflag = _fflag, \
.fvco = _fvco, \
.common = { \
.regmap = NULL, \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&sprd_pll_ops, \
0), \
}, \
}
SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, _regs_num, \
_itable, _factors, _udelay, _k1, _k2, \
_fflag, _fvco, CLK_HW_INIT)
#define SPRD_PLL_WITH_ITABLE_K(_struct, _name, _parent, _reg, \
_regs_num, _itable, _factors, \
@ -96,6 +102,19 @@ struct sprd_pll {
_regs_num, _itable, _factors, \
_udelay, 1000, 1000, 0, 0)
#define SPRD_PLL_FW_NAME(_struct, _name, _parent, _reg, _regs_num, \
_itable, _factors, _udelay, _k1, _k2, \
_fflag, _fvco) \
SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, _regs_num, \
_itable, _factors, _udelay, _k1, _k2, \
_fflag, _fvco, CLK_HW_INIT_FW_NAME)
#define SPRD_PLL_HW(_struct, _name, _parent, _reg, _regs_num, _itable, \
_factors, _udelay, _k1, _k2, _fflag, _fvco) \
SPRD_PLL_HW_INIT_FN(_struct, _name, _parent, _reg, _regs_num, \
_itable, _factors, _udelay, _k1, _k2, \
_fflag, _fvco, CLK_HW_INIT_HW)
static inline struct sprd_pll *hw_to_sprd_pll(struct clk_hw *hw)
{
struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);

Some files were not shown because too many files have changed in this diff Show more