History

Merge branches 'clk-stm32f4', 'clk-tegra', 'clk-at91', 'clk-sifive-fu540' and 'clk-spdx' into clk-next

- Support for STM32F769 - Rework AT91 sckc DT bindings - Fix slow RC oscillator issue on sama5d3 - AT91 sam9x60 PMC support - SiFive FU540 PRCI and PLL support * clk-stm32f4: clk: stm32mp1: Add ddrperfm clock clk: stm32: Introduce clocks of STM32F769 board * clk-tegra: clk: tegra: divider: Mark Memory Controller clock as read-only clk: tegra: emc: Replace BUG() with WARN_ONCE() clk: tegra: emc: Fix EMC max-rate clamping clk: tegra: emc: Support multiple RAM codes clk: tegra: emc: Don't enable EMC clock manually clk: tegra124: Remove lock-enable bit from PLLM clk: tegra: Fix PLLM programming on Tegra124+ when PMC overrides divider clk: tegra: Don't enable already enabled PLLs * clk-at91: clk: at91: Mark struct clk_range as const clk: at91: add sam9x60 pmc driver dt-bindings: clk: at91: add bindings for SAM9X60 pmc clk: at91: add sam9x60 PLL driver clk: at91: master: Add sam9x60 support clk: at91: usb: Add sam9x60 support clk: at91: allow configuring generated PCR layout clk: at91: allow configuring peripheral PCR layout clk: at91: sckc: handle different RC startup time clk: at91: modernize sckc binding dt-bindings: clock: at91: new sckc bindings * clk-sifive-fu540: clk: sifive: add a driver for the SiFive FU540 PRCI IP block clk: analogbits: add Wide-Range PLL library dt-bindings: clk: add documentation for the SiFive PRCI driver * clk-spdx: clk: sunxi-ng: Use the correct style for SPDX License Identifier clk: sprd: Use the correct style for SPDX License Identifier clk: renesas: Use the correct style for SPDX License Identifier clk: qcom: Use the correct style for SPDX License Identifier clk: davinci: Use the correct style for SPDX License Identifier clk: actions: Use the correct style for SPDX License Identifier

Stephen Boyd committed 7 years ago

Commit ff060016 parents 5816b74 b06df56 e71f4d3 7b4c162 30b8e27 d65530c59 files · +2424 −259Browse files

Unified · Split

59 files
  1. Documentation/devicetree/bindings/clock/at91-clock.txt +14 −19
  2. Documentation/devicetree/bindings/clock/sifive/fu540-prci.txt +46 −0
  3. Documentation/devicetree/bindings/clock/st,stm32-rcc.txt +6 −0
  4. MAINTAINERS +6 −0
  5. drivers/clk/Kconfig +3 −0
  6. drivers/clk/Makefile +2 −0
  7. drivers/clk/actions/owl-common.h +1 −1
  8. drivers/clk/actions/owl-composite.h +1 −1
  9. drivers/clk/actions/owl-divider.h +1 −1
  10. drivers/clk/actions/owl-factor.h +1 −1
  11. drivers/clk/actions/owl-fixed-factor.h +1 −1
  12. drivers/clk/actions/owl-gate.h +1 −1
  13. drivers/clk/actions/owl-mux.h +1 −1
  14. drivers/clk/actions/owl-pll.h +1 −1
  15. drivers/clk/actions/owl-reset.h +1 −1
  16. drivers/clk/analogbits/Kconfig +2 −0
  17. drivers/clk/analogbits/Makefile +3 −0
  18. drivers/clk/analogbits/wrpll-cln28hpc.c +364 −0
  19. drivers/clk/at91/Makefile +2 −0
  20. drivers/clk/at91/at91sam9260.c +7 −7
  21. drivers/clk/at91/at91sam9rl.c +1 −1
  22. drivers/clk/at91/at91sam9x5.c +10 −1
  23. drivers/clk/at91/clk-generated.c +25 −23
  24. drivers/clk/at91/clk-master.c +5 −3
  25. drivers/clk/at91/clk-peripheral.c +24 −22
  26. drivers/clk/at91/clk-sam9x60-pll.c +330 −0
  27. drivers/clk/at91/clk-usb.c +27 −6
  28. drivers/clk/at91/dt-compat.c +11 −1
  29. drivers/clk/at91/pmc.h +24 −1
  30. drivers/clk/at91/sam9x60.c +307 −0
  31. drivers/clk/at91/sama5d2.c +11 −1
  32. drivers/clk/at91/sama5d4.c +9 −1
  33. drivers/clk/at91/sckc.c +47 −87
  34. drivers/clk/clk-stm32f4.c +299 −8
  35. drivers/clk/clk-stm32mp1.c +3 −0
  36. drivers/clk/davinci/pll.h +1 −1
  37. drivers/clk/davinci/psc.h +1 −1
  38. drivers/clk/qcom/clk-regmap-mux-div.h +1 −1
  39. drivers/clk/renesas/rcar-gen2-cpg.h +2 −2
  40. drivers/clk/renesas/rcar-gen3-cpg.h +2 −2
  41. drivers/clk/renesas/renesas-cpg-mssr.h +2 −2
  42. drivers/clk/sifive/Kconfig +18 −0
  43. drivers/clk/sifive/Makefile +1 −0
  44. drivers/clk/sifive/fu540-prci.c +626 −0
  45. drivers/clk/sprd/common.h +1 −1
  46. drivers/clk/sprd/composite.h +1 −1
  47. drivers/clk/sprd/div.h +1 −1
  48. drivers/clk/sprd/gate.h +1 −1
  49. drivers/clk/sprd/mux.h +1 −1
  50. drivers/clk/sprd/pll.h +1 −1
  51. drivers/clk/sunxi-ng/ccu-sun50i-h6.h +1 −1
  52. drivers/clk/sunxi-ng/ccu-suniv-f1c100s.h +2 −2
  53. drivers/clk/tegra/clk-divider.c +2 −1
  54. drivers/clk/tegra/clk-emc.c +35 −22
  55. drivers/clk/tegra/clk-pll.c +39 −15
  56. drivers/clk/tegra/clk-tegra124.c +1 −2
  57. include/dt-bindings/clock/stm32fx-clock.h +5 −2
  58. include/linux/clk/analogbits-wrpll-cln28hpc.h +79 −0
  59. include/linux/clk/at91_pmc.h +3 −9
Documentation/devicetree/bindings/clock/at91-clock.txt+14−19
@@ -8,35 +8,30 @@ Slow Clock controller: · 7 unmodified lines
8 8
9Required properties:9Required properties:
10- compatible : shall be one of the following:10- compatible : shall be one of the following:
11 "atmel,at91sam9x5-sckc" or11 "atmel,at91sam9x5-sckc",
12 "atmel,sama5d3-sckc" or
12 "atmel,sama5d4-sckc":13 "atmel,sama5d4-sckc":
13 at91 SCKC (Slow Clock Controller)14 at91 SCKC (Slow Clock Controller)
14 This node contains the slow clock definitions.15- #clock-cells : shall be 0.
15 16- clocks : shall be the input parent clock phandle for the clock.
16 "atmel,at91sam9x5-clk-slow-osc":
17 at91 slow oscillator
18
19 "atmel,at91sam9x5-clk-slow-rc-osc":
20 at91 internal slow RC oscillator
21- reg : defines the IO memory reserved for the SCKC.
22- #size-cells : shall be 0 (reg is used to encode clk id).
23- #address-cells : shall be 1 (reg is used to encode clk id).
24 17
18Optional properties:
19- atmel,osc-bypass : boolean property. Set this when a clock signal is directly
20 provided on XIN.
25 21
26For example:22For example:
27 sckc: sckc@fffffe50 {23 sckc@fffffe50 {
28 compatible = "atmel,sama5d3-pmc";24 compatible = "atmel,at91sam9x5-sckc";
29 reg = <0xfffffe50 0x4>25 reg = <0xfffffe50 0x4>;
30 #size-cells = <0>;26 clocks = <&slow_xtal>;
31 #address-cells = <1>;27 #clock-cells = <0>;
32
33 /* put at91 slow clocks here */
34 };28 };
35 29
36Power Management Controller (PMC):30Power Management Controller (PMC):
37 31
38Required properties:32Required properties:
39- compatible : shall be "atmel,<chip>-pmc", "syscon":33- compatible : shall be "atmel,<chip>-pmc", "syscon" or
34 "microchip,sam9x60-pmc"
40 <chip> can be: at91rm9200, at91sam9260, at91sam9261,35 <chip> can be: at91rm9200, at91sam9260, at91sam9261,
41 at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9g15,36 at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9g15,
42 at91sam9g25, at91sam9g35, at91sam9x25, at91sam9x35, at91sam9x5,37 at91sam9g25, at91sam9g35, at91sam9x25, at91sam9x35, at91sam9x5,
Documentation/devicetree/bindings/clock/sifive/fu540-prci.txt+46−0
@@ -0,0 +1,46 @@
1SiFive FU540 PRCI bindings
2
3On the FU540 family of SoCs, most system-wide clock and reset integration
4is via the PRCI IP block.
5
6Required properties:
7- compatible: Should be "sifive,<chip>-prci". Only one value is
8 supported: "sifive,fu540-c000-prci"
9- reg: Should describe the PRCI's register target physical address region
10- clocks: Should point to the hfclk device tree node and the rtcclk
11 device tree node. The RTC clock here is not a time-of-day clock,
12 but is instead a high-stability clock source for system timers
13 and cycle counters.
14- #clock-cells: Should be <1>
15
16The clock consumer should specify the desired clock via the clock ID
17macros defined in include/dt-bindings/clock/sifive-fu540-prci.h.
18These macros begin with PRCI_CLK_.
19
20The hfclk and rtcclk nodes are required, and represent physical
21crystals or resonators located on the PCB. These nodes should be present
22underneath /, rather than /soc.
23
24Examples:
25
26/* under /, in PCB-specific DT data */
27hfclk: hfclk {
28 #clock-cells = <0>;
29 compatible = "fixed-clock";
30 clock-frequency = <33333333>;
31 clock-output-names = "hfclk";
32};
33rtcclk: rtcclk {
34 #clock-cells = <0>;
35 compatible = "fixed-clock";
36 clock-frequency = <1000000>;
37 clock-output-names = "rtcclk";
38};
39
40/* under /soc, in SoC-specific DT data */
41prci: clock-controller@10000000 {
42 compatible = "sifive,fu540-c000-prci";
43 reg = <0x0 0x10000000 0x0 0x1000>;
44 clocks = <&hfclk>, <&rtcclk>;
45 #clock-cells = <1>;
46};
Documentation/devicetree/bindings/clock/st,stm32-rcc.txt+6−0
@@ -11,6 +11,8 @@ Required properties: · 10 unmodified lines
11 "st,stm32f42xx-rcc"11 "st,stm32f42xx-rcc"
12 "st,stm32f469-rcc"12 "st,stm32f469-rcc"
13 "st,stm32f746-rcc"13 "st,stm32f746-rcc"
14 "st,stm32f769-rcc"
15
14- reg: should be register base and length as documented in the16- reg: should be register base and length as documented in the
15 datasheet17 datasheet
16- #reset-cells: 1, see below18- #reset-cells: 1, see below
@@ -102,6 +104,10 @@ The secondary index is bound with the following magic numbers: · 85 unmodified lines
102 28 CLK_I2C3104 28 CLK_I2C3
103 29 CLK_I2C4105 29 CLK_I2C4
104 30 CLK_LPTIMER (LPTimer1 clock)106 30 CLK_LPTIMER (LPTimer1 clock)
107 31 CLK_PLL_SRC
108 32 CLK_DFSDM1
109 33 CLK_ADFSDM1
110 34 CLK_F769_DSI
105)111)
106 112
107Example:113Example:
MAINTAINERS+6−0
@@ -960,6 +960,12 @@ F: drivers/iio/adc/ltc2497* · 959 unmodified lines
960X: drivers/iio/*/adjd*960X: drivers/iio/*/adjd*
961F: drivers/staging/iio/*/ad*961F: drivers/staging/iio/*/ad*
962 962
963ANALOGBITS PLL LIBRARIES
964M: Paul Walmsley <paul.walmsley@sifive.com>
965S: Supported
966F: drivers/clk/analogbits/*
967F: include/linux/clk/analogbits*
968
963ANDES ARCHITECTURE969ANDES ARCHITECTURE
964M: Greentime Hu <green.hu@gmail.com>970M: Greentime Hu <green.hu@gmail.com>
965M: Vincent Chen <deanbo422@gmail.com>971M: Vincent Chen <deanbo422@gmail.com>
drivers/clk/Kconfig+3−0
@@ -1,3 +1,4 @@
1# SPDX-License-Identifier: GPL-2.0
1 2
2config CLKDEV_LOOKUP3config CLKDEV_LOOKUP
3 bool4 bool
@@ -304,6 +305,7 @@ config COMMON_CLK_FIXED_MMIO · 300 unmodified lines
304 Support for Memory Mapped IO Fixed clocks305 Support for Memory Mapped IO Fixed clocks
305 306
306source "drivers/clk/actions/Kconfig"307source "drivers/clk/actions/Kconfig"
308source "drivers/clk/analogbits/Kconfig"
307source "drivers/clk/bcm/Kconfig"309source "drivers/clk/bcm/Kconfig"
308source "drivers/clk/hisilicon/Kconfig"310source "drivers/clk/hisilicon/Kconfig"
309source "drivers/clk/imgtec/Kconfig"311source "drivers/clk/imgtec/Kconfig"
@@ -316,6 +318,7 @@ source "drivers/clk/mvebu/Kconfig" · 6 unmodified lines
316source "drivers/clk/qcom/Kconfig"318source "drivers/clk/qcom/Kconfig"
317source "drivers/clk/renesas/Kconfig"319source "drivers/clk/renesas/Kconfig"
318source "drivers/clk/samsung/Kconfig"320source "drivers/clk/samsung/Kconfig"
321source "drivers/clk/sifive/Kconfig"
319source "drivers/clk/sprd/Kconfig"322source "drivers/clk/sprd/Kconfig"
320source "drivers/clk/sunxi/Kconfig"323source "drivers/clk/sunxi/Kconfig"
321source "drivers/clk/sunxi-ng/Kconfig"324source "drivers/clk/sunxi-ng/Kconfig"
drivers/clk/Makefile+2−0
@@ -66,6 +66,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o · 65 unmodified lines
66 66
67# please keep this section sorted lexicographically by directory path name67# please keep this section sorted lexicographically by directory path name
68obj-y += actions/68obj-y += actions/
69obj-y += analogbits/
69obj-$(CONFIG_COMMON_CLK_AT91) += at91/70obj-$(CONFIG_COMMON_CLK_AT91) += at91/
70obj-$(CONFIG_ARCH_ARTPEC) += axis/71obj-$(CONFIG_ARCH_ARTPEC) += axis/
71obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/72obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
@@ -95,6 +96,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ · 23 unmodified lines
95obj-y += renesas/96obj-y += renesas/
96obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/97obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
97obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/98obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
99obj-$(CONFIG_CLK_SIFIVE) += sifive/
98obj-$(CONFIG_ARCH_SIRF) += sirf/100obj-$(CONFIG_ARCH_SIRF) += sirf/
99obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/101obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
100obj-$(CONFIG_PLAT_SPEAR) += spear/102obj-$(CONFIG_PLAT_SPEAR) += spear/
drivers/clk/actions/owl-common.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL common clock driver3// OWL common clock driver
4//4//
drivers/clk/actions/owl-composite.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL composite clock driver3// OWL composite clock driver
4//4//
drivers/clk/actions/owl-divider.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL divider clock driver3// OWL divider clock driver
4//4//
drivers/clk/actions/owl-factor.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL factor clock driver3// OWL factor clock driver
4//4//
drivers/clk/actions/owl-fixed-factor.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL fixed factor clock driver3// OWL fixed factor clock driver
4//4//
drivers/clk/actions/owl-gate.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL gate clock driver3// OWL gate clock driver
4//4//
drivers/clk/actions/owl-mux.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL mux clock driver3// OWL mux clock driver
4//4//
drivers/clk/actions/owl-pll.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2//2//
3// OWL pll clock driver3// OWL pll clock driver
4//4//
drivers/clk/actions/owl-reset.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0-or-later1/* SPDX-License-Identifier: GPL-2.0-or-later */
2//2//
3// Actions Semi Owl SoCs Reset Management Unit driver3// Actions Semi Owl SoCs Reset Management Unit driver
4//4//
drivers/clk/analogbits/Kconfig+2−0
@@ -0,0 +1,2 @@
1config CLK_ANALOGBITS_WRPLL_CLN28HPC
2 bool
drivers/clk/analogbits/Makefile+3−0
@@ -0,0 +1,3 @@
1# SPDX-License-Identifier: GPL-2.0
2
3obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
drivers/clk/analogbits/wrpll-cln28hpc.c+364−0
@@ -0,0 +1,364 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018-2019 SiFive, Inc.
4 * Wesley Terpstra
5 * Paul Walmsley
6 *
7 * This library supports configuration parsing and reprogramming of
8 * the CLN28HPC variant of the Analog Bits Wide Range PLL. The
9 * intention is for this library to be reusable for any device that
10 * integrates this PLL; thus the register structure and programming
11 * details are expected to be provided by a separate IP block driver.
12 *
13 * The bulk of this code is primarily useful for clock configurations
14 * that must operate at arbitrary rates, as opposed to clock configurations
15 * that are restricted by software or manufacturer guidance to a small,
16 * pre-determined set of performance points.
17 *
18 * References:
19 * - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01
20 * - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset"
21 * https://static.dev.sifive.com/FU540-C000-v1.0.pdf
22 */
23
24#include <linux/bug.h>
25#include <linux/err.h>
26#include <linux/log2.h>
27#include <linux/math64.h>
28#include <linux/clk/analogbits-wrpll-cln28hpc.h>
29
30/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
31#define MIN_INPUT_FREQ 7000000
32
33/* MAX_INPUT_FREQ: maximum input clock frequency, in Hz (Fref_max) */
34#define MAX_INPUT_FREQ 600000000
35
36/* MIN_POST_DIVIDE_REF_FREQ: minimum post-divider reference frequency, in Hz */
37#define MIN_POST_DIVR_FREQ 7000000
38
39/* MAX_POST_DIVIDE_REF_FREQ: maximum post-divider reference frequency, in Hz */
40#define MAX_POST_DIVR_FREQ 200000000
41
42/* MIN_VCO_FREQ: minimum VCO frequency, in Hz (Fvco_min) */
43#define MIN_VCO_FREQ 2400000000UL
44
45/* MAX_VCO_FREQ: maximum VCO frequency, in Hz (Fvco_max) */
46#define MAX_VCO_FREQ 4800000000ULL
47
48/* MAX_DIVQ_DIVISOR: maximum output divisor. Selected by DIVQ = 6 */
49#define MAX_DIVQ_DIVISOR 64
50
51/* MAX_DIVR_DIVISOR: maximum reference divisor. Selected by DIVR = 63 */
52#define MAX_DIVR_DIVISOR 64
53
54/* MAX_LOCK_US: maximum PLL lock time, in microseconds (tLOCK_max) */
55#define MAX_LOCK_US 70
56
57/*
58 * ROUND_SHIFT: number of bits to shift to avoid precision loss in the rounding
59 * algorithm
60 */
61#define ROUND_SHIFT 20
62
63/*
64 * Private functions
65 */
66
67/**
68 * __wrpll_calc_filter_range() - determine PLL loop filter bandwidth
69 * @post_divr_freq: input clock rate after the R divider
70 *
71 * Select the value to be presented to the PLL RANGE input signals, based
72 * on the input clock frequency after the post-R-divider @post_divr_freq.
73 * This code follows the recommendations in the PLL datasheet for filter
74 * range selection.
75 *
76 * Return: The RANGE value to be presented to the PLL configuration inputs,
77 * or a negative return code upon error.
78 */
79static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
80{
81 if (post_divr_freq < MIN_POST_DIVR_FREQ ||
82 post_divr_freq > MAX_POST_DIVR_FREQ) {
83 WARN(1, "%s: post-divider reference freq out of range: %lu",
84 __func__, post_divr_freq);
85 return -ERANGE;
86 }
87
88 switch (post_divr_freq) {
89 case 0 ... 10999999:
90 return 1;
91 case 11000000 ... 17999999:
92 return 2;
93 case 18000000 ... 29999999:
94 return 3;
95 case 30000000 ... 49999999:
96 return 4;
97 case 50000000 ... 79999999:
98 return 5;
99 case 80000000 ... 129999999:
100 return 6;
101 }
102
103 return 7;
104}
105
106/**
107 * __wrpll_calc_fbdiv() - return feedback fixed divide value
108 * @c: ptr to a struct wrpll_cfg record to read from
109 *
110 * The internal feedback path includes a fixed by-two divider; the
111 * external feedback path does not. Return the appropriate divider
112 * value (2 or 1) depending on whether internal or external feedback
113 * is enabled. This code doesn't test for invalid configurations
114 * (e.g. both or neither of WRPLL_FLAGS_*_FEEDBACK are set); it relies
115 * on the caller to do so.
116 *
117 * Context: Any context. Caller must protect the memory pointed to by
118 * @c from simultaneous modification.
119 *
120 * Return: 2 if internal feedback is enabled or 1 if external feedback
121 * is enabled.
122 */
123static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c)
124{
125 return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1;
126}
127
128/**
129 * __wrpll_calc_divq() - determine DIVQ based on target PLL output clock rate
130 * @target_rate: target PLL output clock rate
131 * @vco_rate: pointer to a u64 to store the computed VCO rate into
132 *
133 * Determine a reasonable value for the PLL Q post-divider, based on the
134 * target output rate @target_rate for the PLL. Along with returning the
135 * computed Q divider value as the return value, this function stores the
136 * desired target VCO rate into the variable pointed to by @vco_rate.
137 *
138 * Context: Any context. Caller must protect the memory pointed to by
139 * @vco_rate from simultaneous access or modification.
140 *
141 * Return: a positive integer DIVQ value to be programmed into the hardware
142 * upon success, or 0 upon error (since 0 is an invalid DIVQ value)
143 */
144static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate)
145{
146 u64 s;
147 u8 divq = 0;
148
149 if (!vco_rate) {
150 WARN_ON(1);
151 goto wcd_out;
152 }
153
154 s = div_u64(MAX_VCO_FREQ, target_rate);
155 if (s <= 1) {
156 divq = 1;
157 *vco_rate = MAX_VCO_FREQ;
158 } else if (s > MAX_DIVQ_DIVISOR) {
159 divq = ilog2(MAX_DIVQ_DIVISOR);
160 *vco_rate = MIN_VCO_FREQ;
161 } else {
162 divq = ilog2(s);
163 *vco_rate = (u64)target_rate << divq;
164 }
165
166wcd_out:
167 return divq;
168}
169
170/**
171 * __wrpll_update_parent_rate() - update PLL data when parent rate changes
172 * @c: ptr to a struct wrpll_cfg record to write PLL data to
173 * @parent_rate: PLL input refclk rate (pre-R-divider)
174 *
175 * Pre-compute some data used by the PLL configuration algorithm when
176 * the PLL's reference clock rate changes. The intention is to avoid
177 * computation when the parent rate remains constant - expected to be
178 * the common case.
179 *
180 * Returns: 0 upon success or -ERANGE if the reference clock rate is
181 * out of range.
182 */
183static int __wrpll_update_parent_rate(struct wrpll_cfg *c,
184 unsigned long parent_rate)
185{
186 u8 max_r_for_parent;
187
188 if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ)
189 return -ERANGE;
190
191 c->parent_rate = parent_rate;
192 max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ);
193 c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
194
195 c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ);
196
197 return 0;
198}
199
200/**
201 * wrpll_configure() - compute PLL configuration for a target rate
202 * @c: ptr to a struct wrpll_cfg record to write into
203 * @target_rate: target PLL output clock rate (post-Q-divider)
204 * @parent_rate: PLL input refclk rate (pre-R-divider)
205 *
206 * Compute the appropriate PLL signal configuration values and store
207 * in PLL context @c. PLL reprogramming is not glitchless, so the
208 * caller should switch any downstream logic to a different clock
209 * source or clock-gate it before presenting these values to the PLL
210 * configuration signals.
211 *
212 * The caller must pass this function a pre-initialized struct
213 * wrpll_cfg record: either initialized to zero (with the
214 * exception of the .name and .flags fields) or read from the PLL.
215 *
216 * Context: Any context. Caller must protect the memory pointed to by @c
217 * from simultaneous access or modification.
218 *
219 * Return: 0 upon success; anything else upon failure.
220 */
221int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
222 unsigned long parent_rate)
223{
224 unsigned long ratio;
225 u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre;
226 u32 best_f, f, post_divr_freq;
227 u8 fbdiv, divq, best_r, r;
228 int range;
229
230 if (c->flags == 0) {
231 WARN(1, "%s called with uninitialized PLL config", __func__);
232 return -EINVAL;
233 }
234
235 /* Initialize rounding data if it hasn't been initialized already */
236 if (parent_rate != c->parent_rate) {
237 if (__wrpll_update_parent_rate(c, parent_rate)) {
238 pr_err("%s: PLL input rate is out of range\n",
239 __func__);
240 return -ERANGE;
241 }
242 }
243
244 c->flags &= ~WRPLL_FLAGS_RESET_MASK;
245
246 /* Put the PLL into bypass if the user requests the parent clock rate */
247 if (target_rate == parent_rate) {
248 c->flags |= WRPLL_FLAGS_BYPASS_MASK;
249 return 0;
250 }
251
252 c->flags &= ~WRPLL_FLAGS_BYPASS_MASK;
253
254 /* Calculate the Q shift and target VCO rate */
255 divq = __wrpll_calc_divq(target_rate, &target_vco_rate);
256 if (!divq)
257 return -1;
258 c->divq = divq;
259
260 /* Precalculate the pre-Q divider target ratio */
261 ratio = div64_u64((target_vco_rate << ROUND_SHIFT), parent_rate);
262
263 fbdiv = __wrpll_calc_fbdiv(c);
264 best_r = 0;
265 best_f = 0;
266 best_delta = MAX_VCO_FREQ;
267
268 /*
269 * Consider all values for R which land within
270 * [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R
271 */
272 for (r = c->init_r; r <= c->max_r; ++r) {
273 f_pre_div = ratio * r;
274 f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT;
275 f >>= (fbdiv - 1);
276
277 post_divr_freq = div_u64(parent_rate, r);
278 vco_pre = fbdiv * post_divr_freq;
279 vco = vco_pre * f;
280
281 /* Ensure rounding didn't take us out of range */
282 if (vco > target_vco_rate) {
283 --f;
284 vco = vco_pre * f;
285 } else if (vco < MIN_VCO_FREQ) {
286 ++f;
287 vco = vco_pre * f;
288 }
289
290 delta = abs(target_rate - vco);
291 if (delta < best_delta) {
292 best_delta = delta;
293 best_r = r;
294 best_f = f;
295 }
296 }
297
298 c->divr = best_r - 1;
299 c->divf = best_f - 1;
300
301 post_divr_freq = div_u64(parent_rate, best_r);
302
303 /* Pick the best PLL jitter filter */
304 range = __wrpll_calc_filter_range(post_divr_freq);
305 if (range < 0)
306 return range;
307 c->range = range;
308
309 return 0;
310}
311
312/**
313 * wrpll_calc_output_rate() - calculate the PLL's target output rate
314 * @c: ptr to a struct wrpll_cfg record to read from
315 * @parent_rate: PLL refclk rate
316 *
317 * Given a pointer to the PLL's current input configuration @c and the
318 * PLL's input reference clock rate @parent_rate (before the R
319 * pre-divider), calculate the PLL's output clock rate (after the Q
320 * post-divider).
321 *
322 * Context: Any context. Caller must protect the memory pointed to by @c
323 * from simultaneous modification.
324 *
325 * Return: the PLL's output clock rate, in Hz. The return value from
326 * this function is intended to be convenient to pass directly
327 * to the Linux clock framework; thus there is no explicit
328 * error return value.
329 */
330unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
331 unsigned long parent_rate)
332{
333 u8 fbdiv;
334 u64 n;
335
336 if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
337 WARN(1, "external feedback mode not yet supported");
338 return ULONG_MAX;
339 }
340
341 fbdiv = __wrpll_calc_fbdiv(c);
342 n = parent_rate * fbdiv * (c->divf + 1);
343 n = div_u64(n, c->divr + 1);
344 n >>= c->divq;
345
346 return n;
347}
348
349/**
350 * wrpll_calc_max_lock_us() - return the time for the PLL to lock
351 * @c: ptr to a struct wrpll_cfg record to read from
352 *
353 * Return the minimum amount of time (in microseconds) that the caller
354 * must wait after reprogramming the PLL to ensure that it is locked
355 * to the input frequency and stable. This is likely to depend on the DIVR
356 * value; this is under discussion with the manufacturer.
357 *
358 * Return: the minimum amount of time the caller must wait for the PLL
359 * to lock (in microseconds)
360 */
361unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
362{
363 return MAX_LOCK_US;
364}
drivers/clk/at91/Makefile+2−0
@@ -14,6 +14,8 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o · 13 unmodified lines
14obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o14obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
15obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o15obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
16obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o16obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o
17obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o
17obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o18obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o
19obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
18obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o20obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
19obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o21obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o
drivers/clk/at91/at91sam9260.c+7−7
@@ -41,7 +41,7 @@ static u8 sam9260_plla_out[] = { 0, 2 }; · 40 unmodified lines
41 41
42static u16 sam9260_plla_icpll[] = { 1, 1 };42static u16 sam9260_plla_icpll[] = { 1, 1 };
43 43
44static struct clk_range sam9260_plla_outputs[] = {44static const struct clk_range sam9260_plla_outputs[] = {
45 { .min = 80000000, .max = 160000000 },45 { .min = 80000000, .max = 160000000 },
46 { .min = 150000000, .max = 240000000 },46 { .min = 150000000, .max = 240000000 },
47};47};
@@ -58,7 +58,7 @@ static u8 sam9260_pllb_out[] = { 1 }; · 10 unmodified lines
58 58
59static u16 sam9260_pllb_icpll[] = { 1 };59static u16 sam9260_pllb_icpll[] = { 1 };
60 60
61static struct clk_range sam9260_pllb_outputs[] = {61static const struct clk_range sam9260_pllb_outputs[] = {
62 { .min = 70000000, .max = 130000000 },62 { .min = 70000000, .max = 130000000 },
63};63};
64 64
@@ -128,7 +128,7 @@ static u8 sam9g20_plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; · 63 unmodified lines
128 128
129static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };129static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
130 130
131static struct clk_range sam9g20_plla_outputs[] = {131static const struct clk_range sam9g20_plla_outputs[] = {
132 { .min = 745000000, .max = 800000000 },132 { .min = 745000000, .max = 800000000 },
133 { .min = 695000000, .max = 750000000 },133 { .min = 695000000, .max = 750000000 },
134 { .min = 645000000, .max = 700000000 },134 { .min = 645000000, .max = 700000000 },
@@ -151,7 +151,7 @@ static u8 sam9g20_pllb_out[] = { 0 }; · 16 unmodified lines
151 151
152static u16 sam9g20_pllb_icpll[] = { 0 };152static u16 sam9g20_pllb_icpll[] = { 0 };
153 153
154static struct clk_range sam9g20_pllb_outputs[] = {154static const struct clk_range sam9g20_pllb_outputs[] = {
155 { .min = 30000000, .max = 100000000 },155 { .min = 30000000, .max = 100000000 },
156};156};
157 157
@@ -182,7 +182,7 @@ static const struct clk_master_characteristics sam9261_mck_characteristics = { · 24 unmodified lines
182 .divisors = { 1, 2, 4, 0 },182 .divisors = { 1, 2, 4, 0 },
183};183};
184 184
185static struct clk_range sam9261_plla_outputs[] = {185static const struct clk_range sam9261_plla_outputs[] = {
186 { .min = 80000000, .max = 200000000 },186 { .min = 80000000, .max = 200000000 },
187 { .min = 190000000, .max = 240000000 },187 { .min = 190000000, .max = 240000000 },
188};188};
@@ -199,7 +199,7 @@ static u8 sam9261_pllb_out[] = { 1 }; · 10 unmodified lines
199 199
200static u16 sam9261_pllb_icpll[] = { 1 };200static u16 sam9261_pllb_icpll[] = { 1 };
201 201
202static struct clk_range sam9261_pllb_outputs[] = {202static const struct clk_range sam9261_pllb_outputs[] = {
203 { .min = 70000000, .max = 130000000 },203 { .min = 70000000, .max = 130000000 },
204};204};
205 205
@@ -262,7 +262,7 @@ static const struct clk_master_characteristics sam9263_mck_characteristics = { · 56 unmodified lines
262 .divisors = { 1, 2, 4, 0 },262 .divisors = { 1, 2, 4, 0 },
263};263};
264 264
265static struct clk_range sam9263_pll_outputs[] = {265static const struct clk_range sam9263_pll_outputs[] = {
266 { .min = 80000000, .max = 200000000 },266 { .min = 80000000, .max = 200000000 },
267 { .min = 190000000, .max = 240000000 },267 { .min = 190000000, .max = 240000000 },
268};268};
drivers/clk/at91/at91sam9rl.c+1−1
@@ -14,7 +14,7 @@ static const struct clk_master_characteristics sam9rl_mck_characteristics = { · 13 unmodified lines
14 14
15static u8 sam9rl_plla_out[] = { 0, 2 };15static u8 sam9rl_plla_out[] = { 0, 2 };
16 16
17static struct clk_range sam9rl_plla_outputs[] = {17static const struct clk_range sam9rl_plla_outputs[] = {
18 { .min = 80000000, .max = 200000000 },18 { .min = 80000000, .max = 200000000 },
19 { .min = 190000000, .max = 240000000 },19 { .min = 190000000, .max = 240000000 },
20};20};
drivers/clk/at91/at91sam9x5.c+10−1
@@ -17,7 +17,7 @@ static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; · 16 unmodified lines
17 17
18static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };18static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
19 19
20static struct clk_range plla_outputs[] = {20static const struct clk_range plla_outputs[] = {
21 { .min = 745000000, .max = 800000000 },21 { .min = 745000000, .max = 800000000 },
22 { .min = 695000000, .max = 750000000 },22 { .min = 695000000, .max = 750000000 },
23 { .min = 645000000, .max = 700000000 },23 { .min = 645000000, .max = 700000000 },
@@ -49,6 +49,13 @@ static const struct { · 25 unmodified lines
49 { .n = "pck1", .p = "prog1", .id = 9 },49 { .n = "pck1", .p = "prog1", .id = 9 },
50};50};
51 51
52static const struct clk_pcr_layout at91sam9x5_pcr_layout = {
53 .offset = 0x10c,
54 .cmd = BIT(12),
55 .pid_mask = GENMASK(5, 0),
56 .div_mask = GENMASK(17, 16),
57};
58
52struct pck {59struct pck {
53 char *n;60 char *n;
54 u8 id;61 u8 id;
@@ -242,6 +249,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, · 187 unmodified lines
242 249
243 for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) {250 for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) {
244 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,251 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
252 &at91sam9x5_pcr_layout,
245 at91sam9x5_periphck[i].n,253 at91sam9x5_periphck[i].n,
246 "masterck",254 "masterck",
247 at91sam9x5_periphck[i].id,255 at91sam9x5_periphck[i].id,
@@ -254,6 +262,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, · 6 unmodified lines
254 262
255 for (i = 0; extra_pcks[i].id; i++) {263 for (i = 0; extra_pcks[i].id; i++) {
256 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,264 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
265 &at91sam9x5_pcr_layout,
257 extra_pcks[i].n,266 extra_pcks[i].n,
258 "masterck",267 "masterck",
259 extra_pcks[i].id,268 extra_pcks[i].id,
drivers/clk/at91/clk-generated.c+25−23
@@ -11,6 +11,7 @@ · 10 unmodified lines
11 *11 *
12 */12 */
13 13
14#include <linux/bitfield.h>
14#include <linux/clk-provider.h>15#include <linux/clk-provider.h>
15#include <linux/clkdev.h>16#include <linux/clkdev.h>
16#include <linux/clk/at91_pmc.h>17#include <linux/clk/at91_pmc.h>
@@ -31,6 +32,7 @@ struct clk_generated { · 14 unmodified lines
31 spinlock_t *lock;32 spinlock_t *lock;
32 u32 id;33 u32 id;
33 u32 gckdiv;34 u32 gckdiv;
35 const struct clk_pcr_layout *layout;
34 u8 parent_id;36 u8 parent_id;
35 bool audio_pll_allowed;37 bool audio_pll_allowed;
36};38};
@@ -47,14 +49,14 @@ static int clk_generated_enable(struct clk_hw *hw) · 10 unmodified lines
47 __func__, gck->gckdiv, gck->parent_id);49 __func__, gck->gckdiv, gck->parent_id);
48 50
49 spin_lock_irqsave(gck->lock, flags);51 spin_lock_irqsave(gck->lock, flags);
50 regmap_write(gck->regmap, AT91_PMC_PCR,52 regmap_write(gck->regmap, gck->layout->offset,
51 (gck->id & AT91_PMC_PCR_PID_MASK));53 (gck->id & gck->layout->pid_mask));
52 regmap_update_bits(gck->regmap, AT91_PMC_PCR,54 regmap_update_bits(gck->regmap, gck->layout->offset,
53 AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |55 AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask |
54 AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,56 gck->layout->cmd | AT91_PMC_PCR_GCKEN,
55 AT91_PMC_PCR_GCKCSS(gck->parent_id) |57 field_prep(gck->layout->gckcss_mask, gck->parent_id) |
56 AT91_PMC_PCR_CMD |58 gck->layout->cmd |
57 AT91_PMC_PCR_GCKDIV(gck->gckdiv) |59 FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) |
58 AT91_PMC_PCR_GCKEN);60 AT91_PMC_PCR_GCKEN);
59 spin_unlock_irqrestore(gck->lock, flags);61 spin_unlock_irqrestore(gck->lock, flags);
60 return 0;62 return 0;
@@ -66,11 +68,11 @@ static void clk_generated_disable(struct clk_hw *hw) · 5 unmodified lines
66 unsigned long flags;68 unsigned long flags;
67 69
68 spin_lock_irqsave(gck->lock, flags);70 spin_lock_irqsave(gck->lock, flags);
69 regmap_write(gck->regmap, AT91_PMC_PCR,71 regmap_write(gck->regmap, gck->layout->offset,
70 (gck->id & AT91_PMC_PCR_PID_MASK));72 (gck->id & gck->layout->pid_mask));
71 regmap_update_bits(gck->regmap, AT91_PMC_PCR,73 regmap_update_bits(gck->regmap, gck->layout->offset,
72 AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,74 gck->layout->cmd | AT91_PMC_PCR_GCKEN,
73 AT91_PMC_PCR_CMD);75 gck->layout->cmd);
74 spin_unlock_irqrestore(gck->lock, flags);76 spin_unlock_irqrestore(gck->lock, flags);
75}77}
76 78
@@ -81,9 +83,9 @@ static int clk_generated_is_enabled(struct clk_hw *hw) · 4 unmodified lines
81 unsigned int status;83 unsigned int status;
82 84
83 spin_lock_irqsave(gck->lock, flags);85 spin_lock_irqsave(gck->lock, flags);
84 regmap_write(gck->regmap, AT91_PMC_PCR,86 regmap_write(gck->regmap, gck->layout->offset,
85 (gck->id & AT91_PMC_PCR_PID_MASK));87 (gck->id & gck->layout->pid_mask));
86 regmap_read(gck->regmap, AT91_PMC_PCR, &status);88 regmap_read(gck->regmap, gck->layout->offset, &status);
87 spin_unlock_irqrestore(gck->lock, flags);89 spin_unlock_irqrestore(gck->lock, flags);
88 90
89 return status & AT91_PMC_PCR_GCKEN ? 1 : 0;91 return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
@@ -259,19 +261,18 @@ static void clk_generated_startup(struct clk_generated *gck) · 169 unmodified lines
259 unsigned long flags;261 unsigned long flags;
260 262
261 spin_lock_irqsave(gck->lock, flags);263 spin_lock_irqsave(gck->lock, flags);
262 regmap_write(gck->regmap, AT91_PMC_PCR,264 regmap_write(gck->regmap, gck->layout->offset,
263 (gck->id & AT91_PMC_PCR_PID_MASK));265 (gck->id & gck->layout->pid_mask));
264 regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);266 regmap_read(gck->regmap, gck->layout->offset, &tmp);
265 spin_unlock_irqrestore(gck->lock, flags);267 spin_unlock_irqrestore(gck->lock, flags);
266 268
267 gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)269 gck->parent_id = field_get(gck->layout->gckcss_mask, tmp);
268 >> AT91_PMC_PCR_GCKCSS_OFFSET;270 gck->gckdiv = FIELD_GET(AT91_PMC_PCR_GCKDIV_MASK, tmp);
269 gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK)
270 >> AT91_PMC_PCR_GCKDIV_OFFSET;
271}271}
272 272
273struct clk_hw * __init273struct clk_hw * __init
274at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,274at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
275 const struct clk_pcr_layout *layout,
275 const char *name, const char **parent_names,276 const char *name, const char **parent_names,
276 u8 num_parents, u8 id, bool pll_audio,277 u8 num_parents, u8 id, bool pll_audio,
277 const struct clk_range *range)278 const struct clk_range *range)
@@ -298,6 +299,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, · 20 unmodified lines
298 gck->lock = lock;299 gck->lock = lock;
299 gck->range = *range;300 gck->range = *range;
300 gck->audio_pll_allowed = pll_audio;301 gck->audio_pll_allowed = pll_audio;
302 gck->layout = layout;
301 303
302 clk_generated_startup(gck);304 clk_generated_startup(gck);
303 hw = &gck->hw;305 hw = &gck->hw;
drivers/clk/at91/clk-master.c+5−3
@@ -29,6 +29,7 @@ struct clk_master { · 28 unmodified lines
29 struct regmap *regmap;29 struct regmap *regmap;
30 const struct clk_master_layout *layout;30 const struct clk_master_layout *layout;
31 const struct clk_master_characteristics *characteristics;31 const struct clk_master_characteristics *characteristics;
32 u32 mckr;
32};33};
33 34
34static inline bool clk_master_ready(struct regmap *regmap)35static inline bool clk_master_ready(struct regmap *regmap)
@@ -69,7 +70,7 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, · 34 unmodified lines
69 master->characteristics;70 master->characteristics;
70 unsigned int mckr;71 unsigned int mckr;
71 72
72 regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);73 regmap_read(master->regmap, master->layout->offset, &mckr);
73 mckr &= layout->mask;74 mckr &= layout->mask;
74 75
75 pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;76 pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
@@ -95,7 +96,7 @@ static u8 clk_master_get_parent(struct clk_hw *hw) · 19 unmodified lines
95 struct clk_master *master = to_clk_master(hw);96 struct clk_master *master = to_clk_master(hw);
96 unsigned int mckr;97 unsigned int mckr;
97 98
98 regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);99 regmap_read(master->regmap, master->layout->offset, &mckr);
99 100
100 return mckr & AT91_PMC_CSS;101 return mckr & AT91_PMC_CSS;
101}102}
@@ -147,13 +148,14 @@ at91_clk_register_master(struct regmap *regmap, · 45 unmodified lines
147 return hw;148 return hw;
148}149}
149 150
150
151const struct clk_master_layout at91rm9200_master_layout = {151const struct clk_master_layout at91rm9200_master_layout = {
152 .mask = 0x31F,152 .mask = 0x31F,
153 .pres_shift = 2,153 .pres_shift = 2,
154 .offset = AT91_PMC_MCKR,
154};155};
155 156
156const struct clk_master_layout at91sam9x5_master_layout = {157const struct clk_master_layout at91sam9x5_master_layout = {
157 .mask = 0x373,158 .mask = 0x373,
158 .pres_shift = 4,159 .pres_shift = 4,
160 .offset = AT91_PMC_MCKR,
159};161};
drivers/clk/at91/clk-peripheral.c+24−22
@@ -8,6 +8,7 @@ · 7 unmodified lines
8 *8 *
9 */9 */
10 10
11#include <linux/bitops.h>
11#include <linux/clk-provider.h>12#include <linux/clk-provider.h>
12#include <linux/clkdev.h>13#include <linux/clkdev.h>
13#include <linux/clk/at91_pmc.h>14#include <linux/clk/at91_pmc.h>
@@ -23,9 +24,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock); · 9 unmodified lines
23#define PERIPHERAL_ID_MAX 3124#define PERIPHERAL_ID_MAX 31
24#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))25#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
25 26
26#define PERIPHERAL_RSHIFT_MASK 0x3
27#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
28
29#define PERIPHERAL_MAX_SHIFT 327#define PERIPHERAL_MAX_SHIFT 3
30 28
31struct clk_peripheral {29struct clk_peripheral {
@@ -43,6 +41,7 @@ struct clk_sam9x5_peripheral { · 11 unmodified lines
43 spinlock_t *lock;41 spinlock_t *lock;
44 u32 id;42 u32 id;
45 u32 div;43 u32 div;
44 const struct clk_pcr_layout *layout;
46 bool auto_div;45 bool auto_div;
47};46};
48 47
@@ -169,13 +168,13 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) · 120 unmodified lines
169 return 0;168 return 0;
170 169
171 spin_lock_irqsave(periph->lock, flags);170 spin_lock_irqsave(periph->lock, flags);
172 regmap_write(periph->regmap, AT91_PMC_PCR,171 regmap_write(periph->regmap, periph->layout->offset,
173 (periph->id & AT91_PMC_PCR_PID_MASK));172 (periph->id & periph->layout->pid_mask));
174 regmap_update_bits(periph->regmap, AT91_PMC_PCR,173 regmap_update_bits(periph->regmap, periph->layout->offset,
175 AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |174 periph->layout->div_mask | periph->layout->cmd |
176 AT91_PMC_PCR_EN,175 AT91_PMC_PCR_EN,
177 AT91_PMC_PCR_DIV(periph->div) |176 field_prep(periph->layout->div_mask, periph->div) |
178 AT91_PMC_PCR_CMD |177 periph->layout->cmd |
179 AT91_PMC_PCR_EN);178 AT91_PMC_PCR_EN);
180 spin_unlock_irqrestore(periph->lock, flags);179 spin_unlock_irqrestore(periph->lock, flags);
181 180
@@ -191,11 +190,11 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) · 9 unmodified lines
191 return;190 return;
192 191
193 spin_lock_irqsave(periph->lock, flags);192 spin_lock_irqsave(periph->lock, flags);
194 regmap_write(periph->regmap, AT91_PMC_PCR,193 regmap_write(periph->regmap, periph->layout->offset,
195 (periph->id & AT91_PMC_PCR_PID_MASK));194 (periph->id & periph->layout->pid_mask));
196 regmap_update_bits(periph->regmap, AT91_PMC_PCR,195 regmap_update_bits(periph->regmap, periph->layout->offset,
197 AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,196 AT91_PMC_PCR_EN | periph->layout->cmd,
198 AT91_PMC_PCR_CMD);197 periph->layout->cmd);
199 spin_unlock_irqrestore(periph->lock, flags);198 spin_unlock_irqrestore(periph->lock, flags);
200}199}
201 200
@@ -209,9 +208,9 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) · 7 unmodified lines
209 return 1;208 return 1;
210 209
211 spin_lock_irqsave(periph->lock, flags);210 spin_lock_irqsave(periph->lock, flags);
212 regmap_write(periph->regmap, AT91_PMC_PCR,211 regmap_write(periph->regmap, periph->layout->offset,
213 (periph->id & AT91_PMC_PCR_PID_MASK));212 (periph->id & periph->layout->pid_mask));
214 regmap_read(periph->regmap, AT91_PMC_PCR, &status);213 regmap_read(periph->regmap, periph->layout->offset, &status);
215 spin_unlock_irqrestore(periph->lock, flags);214 spin_unlock_irqrestore(periph->lock, flags);
216 215
217 return status & AT91_PMC_PCR_EN ? 1 : 0;216 return status & AT91_PMC_PCR_EN ? 1 : 0;
@@ -229,13 +228,13 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, · 11 unmodified lines
229 return parent_rate;228 return parent_rate;
230 229
231 spin_lock_irqsave(periph->lock, flags);230 spin_lock_irqsave(periph->lock, flags);
232 regmap_write(periph->regmap, AT91_PMC_PCR,231 regmap_write(periph->regmap, periph->layout->offset,
233 (periph->id & AT91_PMC_PCR_PID_MASK));232 (periph->id & periph->layout->pid_mask));
234 regmap_read(periph->regmap, AT91_PMC_PCR, &status);233 regmap_read(periph->regmap, periph->layout->offset, &status);
235 spin_unlock_irqrestore(periph->lock, flags);234 spin_unlock_irqrestore(periph->lock, flags);
236 235
237 if (status & AT91_PMC_PCR_EN) {236 if (status & AT91_PMC_PCR_EN) {
238 periph->div = PERIPHERAL_RSHIFT(status);237 periph->div = field_get(periph->layout->div_mask, status);
239 periph->auto_div = false;238 periph->auto_div = false;
240 } else {239 } else {
241 clk_sam9x5_peripheral_autodiv(periph);240 clk_sam9x5_peripheral_autodiv(periph);
@@ -328,6 +327,7 @@ static const struct clk_ops sam9x5_peripheral_ops = { · 86 unmodified lines
328 327
329struct clk_hw * __init328struct clk_hw * __init
330at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,329at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
330 const struct clk_pcr_layout *layout,
331 const char *name, const char *parent_name,331 const char *name, const char *parent_name,
332 u32 id, const struct clk_range *range)332 u32 id, const struct clk_range *range)
333{333{
@@ -354,7 +354,9 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, · 20 unmodified lines
354 periph->div = 0;354 periph->div = 0;
355 periph->regmap = regmap;355 periph->regmap = regmap;
356 periph->lock = lock;356 periph->lock = lock;
357 periph->auto_div = true;357 if (layout->div_mask)
358 periph->auto_div = true;
359 periph->layout = layout;
358 periph->range = *range;360 periph->range = *range;
359 361
360 hw = &periph->hw;362 hw = &periph->hw;
drivers/clk/at91/clk-sam9x60-pll.c+330−0
@@ -0,0 +1,330 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019 Microchip Technology Inc.
4 *
5 */
6
7#include <linux/bitfield.h>
8#include <linux/clk-provider.h>
9#include <linux/clkdev.h>
10#include <linux/clk/at91_pmc.h>
11#include <linux/of.h>
12#include <linux/mfd/syscon.h>
13#include <linux/regmap.h>
14
15#include "pmc.h"
16
17#define PMC_PLL_CTRL0 0xc
18#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0)
19#define PMC_PLL_CTRL0_ENPLL BIT(28)
20#define PMC_PLL_CTRL0_ENPLLCK BIT(29)
21#define PMC_PLL_CTRL0_ENLOCK BIT(31)
22
23#define PMC_PLL_CTRL1 0x10
24#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0)
25#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24)
26
27#define PMC_PLL_ACR 0x18
28#define PMC_PLL_ACR_DEFAULT 0x1b040010UL
29#define PMC_PLL_ACR_UTMIVR BIT(12)
30#define PMC_PLL_ACR_UTMIBG BIT(13)
31#define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24)
32
33#define PMC_PLL_UPDT 0x1c
34#define PMC_PLL_UPDT_UPDATE BIT(8)
35
36#define PMC_PLL_ISR0 0xec
37
38#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
39#define UPLL_DIV 2
40#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
41
42#define PLL_MAX_ID 1
43
44struct sam9x60_pll {
45 struct clk_hw hw;
46 struct regmap *regmap;
47 spinlock_t *lock;
48 const struct clk_pll_characteristics *characteristics;
49 u32 frac;
50 u8 id;
51 u8 div;
52 u16 mul;
53};
54
55#define to_sam9x60_pll(hw) container_of(hw, struct sam9x60_pll, hw)
56
57static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)
58{
59 unsigned int status;
60
61 regmap_read(regmap, PMC_PLL_ISR0, &status);
62
63 return !!(status & BIT(id));
64}
65
66static int sam9x60_pll_prepare(struct clk_hw *hw)
67{
68 struct sam9x60_pll *pll = to_sam9x60_pll(hw);
69 struct regmap *regmap = pll->regmap;
70 unsigned long flags;
71 u8 div;
72 u16 mul;
73 u32 val;
74
75 spin_lock_irqsave(pll->lock, flags);
76 regmap_write(regmap, PMC_PLL_UPDT, pll->id);
77
78 regmap_read(regmap, PMC_PLL_CTRL0, &val);
79 div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
80
81 regmap_read(regmap, PMC_PLL_CTRL1, &val);
82 mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val);
83
84 if (sam9x60_pll_ready(regmap, pll->id) &&
85 (div == pll->div && mul == pll->mul)) {
86 spin_unlock_irqrestore(pll->lock, flags);
87 return 0;
88 }
89
90 /* Recommended value for PMC_PLL_ACR */
91 val = PMC_PLL_ACR_DEFAULT;
92 regmap_write(regmap, PMC_PLL_ACR, val);
93
94 regmap_write(regmap, PMC_PLL_CTRL1,
95 FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul));
96
97 if (pll->characteristics->upll) {
98 /* Enable the UTMI internal bandgap */
99 val |= PMC_PLL_ACR_UTMIBG;
100 regmap_write(regmap, PMC_PLL_ACR, val);
101
102 udelay(10);
103
104 /* Enable the UTMI internal regulator */
105 val |= PMC_PLL_ACR_UTMIVR;
106 regmap_write(regmap, PMC_PLL_ACR, val);
107
108 udelay(10);
109 }
110
111 regmap_update_bits(regmap, PMC_PLL_UPDT,
112 PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
113
114 regmap_write(regmap, PMC_PLL_CTRL0,
115 PMC_PLL_CTRL0_ENLOCK | PMC_PLL_CTRL0_ENPLL |
116 PMC_PLL_CTRL0_ENPLLCK | pll->div);
117
118 regmap_update_bits(regmap, PMC_PLL_UPDT,
119 PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
120
121 while (!sam9x60_pll_ready(regmap, pll->id))
122 cpu_relax();
123
124 spin_unlock_irqrestore(pll->lock, flags);
125
126 return 0;
127}
128
129static int sam9x60_pll_is_prepared(struct clk_hw *hw)
130{
131 struct sam9x60_pll *pll = to_sam9x60_pll(hw);
132
133 return sam9x60_pll_ready(pll->regmap, pll->id);
134}
135
136static void sam9x60_pll_unprepare(struct clk_hw *hw)
137{
138 struct sam9x60_pll *pll = to_sam9x60_pll(hw);
139 unsigned long flags;
140
141 spin_lock_irqsave(pll->lock, flags);
142
143 regmap_write(pll->regmap, PMC_PLL_UPDT, pll->id);
144
145 regmap_update_bits(pll->regmap, PMC_PLL_CTRL0,
146 PMC_PLL_CTRL0_ENPLLCK, 0);
147
148 regmap_update_bits(pll->regmap, PMC_PLL_UPDT,
149 PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
150
151 regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, PMC_PLL_CTRL0_ENPLL, 0);
152
153 if (pll->characteristics->upll)
154 regmap_update_bits(pll->regmap, PMC_PLL_ACR,
155 PMC_PLL_ACR_UTMIBG | PMC_PLL_ACR_UTMIVR, 0);
156
157 regmap_update_bits(pll->regmap, PMC_PLL_UPDT,
158 PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
159
160 spin_unlock_irqrestore(pll->lock, flags);
161}
162
163static unsigned long sam9x60_pll_recalc_rate(struct clk_hw *hw,
164 unsigned long parent_rate)
165{
166 struct sam9x60_pll *pll = to_sam9x60_pll(hw);
167
168 return (parent_rate * (pll->mul + 1)) / (pll->div + 1);
169}
170
171static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll,
172 unsigned long rate,
173 unsigned long parent_rate,
174 bool update)
175{
176 const struct clk_pll_characteristics *characteristics =
177 pll->characteristics;
178 unsigned long bestremainder = ULONG_MAX;
179 unsigned long maxdiv, mindiv, tmpdiv;
180 long bestrate = -ERANGE;
181 unsigned long bestdiv = 0;
182 unsigned long bestmul = 0;
183 unsigned long bestfrac = 0;
184
185 if (rate < characteristics->output[0].min ||
186 rate > characteristics->output[0].max)
187 return -ERANGE;
188
189 if (!pll->characteristics->upll) {
190 mindiv = parent_rate / rate;
191 if (mindiv < 2)
192 mindiv = 2;
193
194 maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate);
195 if (maxdiv > PLL_DIV_MAX)
196 maxdiv = PLL_DIV_MAX;
197 } else {
198 mindiv = maxdiv = UPLL_DIV;
199 }
200
201 for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
202 unsigned long remainder;
203 unsigned long tmprate;
204 unsigned long tmpmul;
205 unsigned long tmpfrac = 0;
206
207 /*
208 * Calculate the multiplier associated with the current
209 * divider that provide the closest rate to the requested one.
210 */
211 tmpmul = mult_frac(rate, tmpdiv, parent_rate);
212 tmprate = mult_frac(parent_rate, tmpmul, tmpdiv);
213 remainder = rate - tmprate;
214
215 if (remainder) {
216 tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22),
217 parent_rate);
218
219 tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate,
220 tmpdiv * (1 << 22));
221
222 if (tmprate > rate)
223 remainder = tmprate - rate;
224 else
225 remainder = rate - tmprate;
226 }
227
228 /*
229 * Compare the remainder with the best remainder found until
230 * now and elect a new best multiplier/divider pair if the
231 * current remainder is smaller than the best one.
232 */
233 if (remainder < bestremainder) {
234 bestremainder = remainder;
235 bestdiv = tmpdiv;
236 bestmul = tmpmul;
237 bestrate = tmprate;
238 bestfrac = tmpfrac;
239 }
240
241 /* We've found a perfect match! */
242 if (!remainder)
243 break;
244 }
245
246 /* Check if bestrate is a valid output rate */
247 if (bestrate < characteristics->output[0].min &&
248 bestrate > characteristics->output[0].max)
249 return -ERANGE;
250
251 if (update) {
252 pll->div = bestdiv - 1;
253 pll->mul = bestmul - 1;
254 pll->frac = bestfrac;
255 }
256
257 return bestrate;
258}
259
260static long sam9x60_pll_round_rate(struct clk_hw *hw, unsigned long rate,
261 unsigned long *parent_rate)
262{
263 struct sam9x60_pll *pll = to_sam9x60_pll(hw);
264
265 return sam9x60_pll_get_best_div_mul(pll, rate, *parent_rate, false);
266}
267
268static int sam9x60_pll_set_rate(struct clk_hw *hw, unsigned long rate,
269 unsigned long parent_rate)
270{
271 struct sam9x60_pll *pll = to_sam9x60_pll(hw);
272
273 return sam9x60_pll_get_best_div_mul(pll, rate, parent_rate, true);
274}
275
276static const struct clk_ops pll_ops = {
277 .prepare = sam9x60_pll_prepare,
278 .unprepare = sam9x60_pll_unprepare,
279 .is_prepared = sam9x60_pll_is_prepared,
280 .recalc_rate = sam9x60_pll_recalc_rate,
281 .round_rate = sam9x60_pll_round_rate,
282 .set_rate = sam9x60_pll_set_rate,
283};
284
285struct clk_hw * __init
286sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock,
287 const char *name, const char *parent_name, u8 id,
288 const struct clk_pll_characteristics *characteristics)
289{
290 struct sam9x60_pll *pll;
291 struct clk_hw *hw;
292 struct clk_init_data init;
293 unsigned int pllr;
294 int ret;
295
296 if (id > PLL_MAX_ID)
297 return ERR_PTR(-EINVAL);
298
299 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
300 if (!pll)
301 return ERR_PTR(-ENOMEM);
302
303 init.name = name;
304 init.ops = &pll_ops;
305 init.parent_names = &parent_name;
306 init.num_parents = 1;
307 init.flags = CLK_SET_RATE_GATE;
308
309 pll->id = id;
310 pll->hw.init = &init;
311 pll->characteristics = characteristics;
312 pll->regmap = regmap;
313 pll->lock = lock;
314
315 regmap_write(regmap, PMC_PLL_UPDT, id);
316 regmap_read(regmap, PMC_PLL_CTRL0, &pllr);
317 pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr);
318 regmap_read(regmap, PMC_PLL_CTRL1, &pllr);
319 pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr);
320
321 hw = &pll->hw;
322 ret = clk_hw_register(NULL, hw);
323 if (ret) {
324 kfree(pll);
325 hw = ERR_PTR(ret);
326 }
327
328 return hw;
329}
330
drivers/clk/at91/clk-usb.c+27−6
@@ -23,9 +23,13 @@ · 22 unmodified lines
23#define RM9200_USB_DIV_SHIFT 2823#define RM9200_USB_DIV_SHIFT 28
24#define RM9200_USB_DIV_TAB_SIZE 424#define RM9200_USB_DIV_TAB_SIZE 4
25 25
26#define SAM9X5_USBS_MASK GENMASK(0, 0)
27#define SAM9X60_USBS_MASK GENMASK(1, 0)
28
26struct at91sam9x5_clk_usb {29struct at91sam9x5_clk_usb {
27 struct clk_hw hw;30 struct clk_hw hw;
28 struct regmap *regmap;31 struct regmap *regmap;
32 u32 usbs_mask;
29};33};
30 34
31#define to_at91sam9x5_clk_usb(hw) \35#define to_at91sam9x5_clk_usb(hw) \
@@ -111,8 +115,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) · 79 unmodified lines
111 if (index > 1)115 if (index > 1)
112 return -EINVAL;116 return -EINVAL;
113 117
114 regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,118 regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index);
115 index ? AT91_PMC_USBS : 0);
116 119
117 return 0;120 return 0;
118}121}
@@ -124,7 +127,7 @@ static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) · 5 unmodified lines
124 127
125 regmap_read(usb->regmap, AT91_PMC_USB, &usbr);128 regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
126 129
127 return usbr & AT91_PMC_USBS;130 return usbr & usb->usbs_mask;
128}131}
129 132
130static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,133static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -190,9 +193,10 @@ static const struct clk_ops at91sam9n12_usb_ops = { · 59 unmodified lines
190 .set_rate = at91sam9x5_clk_usb_set_rate,193 .set_rate = at91sam9x5_clk_usb_set_rate,
191};194};
192 195
193struct clk_hw * __init196static struct clk_hw * __init
194at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,197_at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
195 const char **parent_names, u8 num_parents)198 const char **parent_names, u8 num_parents,
199 u32 usbs_mask)
196{200{
197 struct at91sam9x5_clk_usb *usb;201 struct at91sam9x5_clk_usb *usb;
198 struct clk_hw *hw;202 struct clk_hw *hw;
@@ -212,6 +216,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, · 13 unmodified lines
212 216
213 usb->hw.init = &init;217 usb->hw.init = &init;
214 usb->regmap = regmap;218 usb->regmap = regmap;
219 usb->usbs_mask = SAM9X5_USBS_MASK;
215 220
216 hw = &usb->hw;221 hw = &usb->hw;
217 ret = clk_hw_register(NULL, &usb->hw);222 ret = clk_hw_register(NULL, &usb->hw);
@@ -223,6 +228,22 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, · 5 unmodified lines
223 return hw;228 return hw;
224}229}
225 230
231struct clk_hw * __init
232at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
233 const char **parent_names, u8 num_parents)
234{
235 return _at91sam9x5_clk_register_usb(regmap, name, parent_names,
236 num_parents, SAM9X5_USBS_MASK);
237}
238
239struct clk_hw * __init
240sam9x60_clk_register_usb(struct regmap *regmap, const char *name,
241 const char **parent_names, u8 num_parents)
242{
243 return _at91sam9x5_clk_register_usb(regmap, name, parent_names,
244 num_parents, SAM9X60_USBS_MASK);
245}
246
226struct clk_hw * __init247struct clk_hw * __init
227at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,248at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
228 const char *parent_name)249 const char *parent_name)
drivers/clk/at91/dt-compat.c+11−1
@@ -93,6 +93,14 @@ CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, · 92 unmodified lines
93 of_sama5d2_clk_audio_pll_pmc_setup);93 of_sama5d2_clk_audio_pll_pmc_setup);
94#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */94#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */
95 95
96static const struct clk_pcr_layout dt_pcr_layout = {
97 .offset = 0x10c,
98 .cmd = BIT(12),
99 .pid_mask = GENMASK(5, 0),
100 .div_mask = GENMASK(17, 16),
101 .gckcss_mask = GENMASK(10, 8),
102};
103
96#ifdef CONFIG_HAVE_AT91_GENERATED_CLK104#ifdef CONFIG_HAVE_AT91_GENERATED_CLK
97#define GENERATED_SOURCE_MAX 6105#define GENERATED_SOURCE_MAX 6
98 106
@@ -146,7 +154,8 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) · 47 unmodified lines
146 id == GCK_ID_CLASSD))154 id == GCK_ID_CLASSD))
147 pll_audio = true;155 pll_audio = true;
148 156
149 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,157 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
158 &dt_pcr_layout, name,
150 parent_names, num_parents,159 parent_names, num_parents,
151 id, pll_audio, &range);160 id, pll_audio, &range);
152 if (IS_ERR(hw))161 if (IS_ERR(hw))
@@ -448,6 +457,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) · 295 unmodified lines
448 457
449 hw = at91_clk_register_sam9x5_peripheral(regmap,458 hw = at91_clk_register_sam9x5_peripheral(regmap,
450 &pmc_pcr_lock,459 &pmc_pcr_lock,
460 &dt_pcr_layout,
451 name,461 name,
452 parent_name,462 parent_name,
453 id, &range);463 id, &range);
drivers/clk/at91/pmc.h+24−1
@@ -38,6 +38,7 @@ struct clk_range { · 37 unmodified lines
38#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}38#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
39 39
40struct clk_master_layout {40struct clk_master_layout {
41 u32 offset;
41 u32 mask;42 u32 mask;
42 u8 pres_shift;43 u8 pres_shift;
43};44};
@@ -65,9 +66,10 @@ extern const struct clk_pll_layout sama5d3_pll_layout; · 21 unmodified lines
65struct clk_pll_characteristics {66struct clk_pll_characteristics {
66 struct clk_range input;67 struct clk_range input;
67 int num_output;68 int num_output;
68 struct clk_range *output;69 const struct clk_range *output;
69 u16 *icpll;70 u16 *icpll;
70 u8 *out;71 u8 *out;
72 u8 upll : 1;
71};73};
72 74
73struct clk_programmable_layout {75struct clk_programmable_layout {
@@ -82,6 +84,17 @@ extern const struct clk_programmable_layout at91rm9200_programmable_layout; · 8 unmodified lines
82extern const struct clk_programmable_layout at91sam9g45_programmable_layout;84extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
83extern const struct clk_programmable_layout at91sam9x5_programmable_layout;85extern const struct clk_programmable_layout at91sam9x5_programmable_layout;
84 86
87struct clk_pcr_layout {
88 u32 offset;
89 u32 cmd;
90 u32 div_mask;
91 u32 gckcss_mask;
92 u32 pid_mask;
93};
94
95#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
96#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
97
85#define ndck(a, s) (a[s - 1].id + 1)98#define ndck(a, s) (a[s - 1].id + 1)
86#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)99#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
87struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,100struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
@@ -107,6 +120,7 @@ at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name, · 19 unmodified lines
107 120
108struct clk_hw * __init121struct clk_hw * __init
109at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,122at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
123 const struct clk_pcr_layout *layout,
110 const char *name, const char **parent_names,124 const char *name, const char **parent_names,
111 u8 num_parents, u8 id, bool pll_audio,125 u8 num_parents, u8 id, bool pll_audio,
112 const struct clk_range *range);126 const struct clk_range *range);
@@ -145,6 +159,7 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name, · 32 unmodified lines
145 const char *parent_name, u32 id);159 const char *parent_name, u32 id);
146struct clk_hw * __init160struct clk_hw * __init
147at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,161at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
162 const struct clk_pcr_layout *layout,
148 const char *name, const char *parent_name,163 const char *name, const char *parent_name,
149 u32 id, const struct clk_range *range);164 u32 id, const struct clk_range *range);
150 165
@@ -157,6 +172,11 @@ struct clk_hw * __init · 6 unmodified lines
157at91_clk_register_plldiv(struct regmap *regmap, const char *name,172at91_clk_register_plldiv(struct regmap *regmap, const char *name,
158 const char *parent_name);173 const char *parent_name);
159 174
175struct clk_hw * __init
176sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock,
177 const char *name, const char *parent_name, u8 id,
178 const struct clk_pll_characteristics *characteristics);
179
160struct clk_hw * __init180struct clk_hw * __init
161at91_clk_register_programmable(struct regmap *regmap, const char *name,181at91_clk_register_programmable(struct regmap *regmap, const char *name,
162 const char **parent_names, u8 num_parents, u8 id,182 const char **parent_names, u8 num_parents, u8 id,
@@ -183,6 +203,9 @@ struct clk_hw * __init · 20 unmodified lines
183at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,203at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
184 const char *parent_name);204 const char *parent_name);
185struct clk_hw * __init205struct clk_hw * __init
206sam9x60_clk_register_usb(struct regmap *regmap, const char *name,
207 const char **parent_names, u8 num_parents);
208struct clk_hw * __init
186at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,209at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
187 const char *parent_name, const u32 *divisors);210 const char *parent_name, const u32 *divisors);
188 211
drivers/clk/at91/sam9x60.c+307−0
@@ -0,0 +1,307 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/clk-provider.h>
3#include <linux/mfd/syscon.h>
4#include <linux/slab.h>
5
6#include <dt-bindings/clock/at91.h>
7
8#include "pmc.h"
9
10static DEFINE_SPINLOCK(pmc_pll_lock);
11
12static const struct clk_master_characteristics mck_characteristics = {
13 .output = { .min = 140000000, .max = 200000000 },
14 .divisors = { 1, 2, 4, 3 },
15 .have_div3_pres = 1,
16};
17
18static const struct clk_master_layout sam9x60_master_layout = {
19 .mask = 0x373,
20 .pres_shift = 4,
21 .offset = 0x28,
22};
23
24static const struct clk_range plla_outputs[] = {
25 { .min = 300000000, .max = 600000000 },
26};
27
28static const struct clk_pll_characteristics plla_characteristics = {
29 .input = { .min = 12000000, .max = 48000000 },
30 .num_output = ARRAY_SIZE(plla_outputs),
31 .output = plla_outputs,
32};
33
34static const struct clk_range upll_outputs[] = {
35 { .min = 300000000, .max = 500000000 },
36};
37
38static const struct clk_pll_characteristics upll_characteristics = {
39 .input = { .min = 12000000, .max = 48000000 },
40 .num_output = ARRAY_SIZE(upll_outputs),
41 .output = upll_outputs,
42 .upll = true,
43};
44
45static const struct clk_programmable_layout sam9x60_programmable_layout = {
46 .pres_shift = 8,
47 .css_mask = 0x1f,
48 .have_slck_mck = 0,
49};
50
51static const struct clk_pcr_layout sam9x60_pcr_layout = {
52 .offset = 0x88,
53 .cmd = BIT(31),
54 .gckcss_mask = GENMASK(12, 8),
55 .pid_mask = GENMASK(6, 0),
56};
57
58static const struct {
59 char *n;
60 char *p;
61 u8 id;
62} sam9x60_systemck[] = {
63 { .n = "ddrck", .p = "masterck", .id = 2 },
64 { .n = "uhpck", .p = "usbck", .id = 6 },
65 { .n = "pck0", .p = "prog0", .id = 8 },
66 { .n = "pck1", .p = "prog1", .id = 9 },
67 { .n = "qspick", .p = "masterck", .id = 19 },
68};
69
70static const struct {
71 char *n;
72 u8 id;
73} sam9x60_periphck[] = {
74 { .n = "pioA_clk", .id = 2, },
75 { .n = "pioB_clk", .id = 3, },
76 { .n = "pioC_clk", .id = 4, },
77 { .n = "flex0_clk", .id = 5, },
78 { .n = "flex1_clk", .id = 6, },
79 { .n = "flex2_clk", .id = 7, },
80 { .n = "flex3_clk", .id = 8, },
81 { .n = "flex6_clk", .id = 9, },
82 { .n = "flex7_clk", .id = 10, },
83 { .n = "flex8_clk", .id = 11, },
84 { .n = "sdmmc0_clk", .id = 12, },
85 { .n = "flex4_clk", .id = 13, },
86 { .n = "flex5_clk", .id = 14, },
87 { .n = "flex9_clk", .id = 15, },
88 { .n = "flex10_clk", .id = 16, },
89 { .n = "tcb0_clk", .id = 17, },
90 { .n = "pwm_clk", .id = 18, },
91 { .n = "adc_clk", .id = 19, },
92 { .n = "dma0_clk", .id = 20, },
93 { .n = "matrix_clk", .id = 21, },
94 { .n = "uhphs_clk", .id = 22, },
95 { .n = "udphs_clk", .id = 23, },
96 { .n = "macb0_clk", .id = 24, },
97 { .n = "lcd_clk", .id = 25, },
98 { .n = "sdmmc1_clk", .id = 26, },
99 { .n = "macb1_clk", .id = 27, },
100 { .n = "ssc_clk", .id = 28, },
101 { .n = "can0_clk", .id = 29, },
102 { .n = "can1_clk", .id = 30, },
103 { .n = "flex11_clk", .id = 32, },
104 { .n = "flex12_clk", .id = 33, },
105 { .n = "i2s_clk", .id = 34, },
106 { .n = "qspi_clk", .id = 35, },
107 { .n = "gfx2d_clk", .id = 36, },
108 { .n = "pit64b_clk", .id = 37, },
109 { .n = "trng_clk", .id = 38, },
110 { .n = "aes_clk", .id = 39, },
111 { .n = "tdes_clk", .id = 40, },
112 { .n = "sha_clk", .id = 41, },
113 { .n = "classd_clk", .id = 42, },
114 { .n = "isi_clk", .id = 43, },
115 { .n = "pioD_clk", .id = 44, },
116 { .n = "tcb1_clk", .id = 45, },
117 { .n = "dbgu_clk", .id = 47, },
118 { .n = "mpddr_clk", .id = 49, },
119};
120
121static const struct {
122 char *n;
123 u8 id;
124 struct clk_range r;
125 bool pll;
126} sam9x60_gck[] = {
127 { .n = "flex0_gclk", .id = 5, },
128 { .n = "flex1_gclk", .id = 6, },
129 { .n = "flex2_gclk", .id = 7, },
130 { .n = "flex3_gclk", .id = 8, },
131 { .n = "flex6_gclk", .id = 9, },
132 { .n = "flex7_gclk", .id = 10, },
133 { .n = "flex8_gclk", .id = 11, },
134 { .n = "sdmmc0_gclk", .id = 12, .r = { .min = 0, .max = 105000000 }, },
135 { .n = "flex4_gclk", .id = 13, },
136 { .n = "flex5_gclk", .id = 14, },
137 { .n = "flex9_gclk", .id = 15, },
138 { .n = "flex10_gclk", .id = 16, },
139 { .n = "tcb0_gclk", .id = 17, },
140 { .n = "adc_gclk", .id = 19, },
141 { .n = "lcd_gclk", .id = 25, .r = { .min = 0, .max = 140000000 }, },
142 { .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, },
143 { .n = "flex11_gclk", .id = 32, },
144 { .n = "flex12_gclk", .id = 33, },
145 { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 },
146 .pll = true, },
147 { .n = "pit64b_gclk", .id = 37, },
148 { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 },
149 .pll = true, },
150 { .n = "tcb1_gclk", .id = 45, },
151 { .n = "dbgu_gclk", .id = 47, },
152};
153
154static void __init sam9x60_pmc_setup(struct device_node *np)
155{
156 struct clk_range range = CLK_RANGE(0, 0);
157 const char *td_slck_name, *md_slck_name, *mainxtal_name;
158 struct pmc_data *sam9x60_pmc;
159 const char *parent_names[6];
160 struct regmap *regmap;
161 struct clk_hw *hw;
162 int i;
163 bool bypass;
164
165 i = of_property_match_string(np, "clock-names", "td_slck");
166 if (i < 0)
167 return;
168
169 td_slck_name = of_clk_get_parent_name(np, i);
170
171 i = of_property_match_string(np, "clock-names", "md_slck");
172 if (i < 0)
173 return;
174
175 md_slck_name = of_clk_get_parent_name(np, i);
176
177 i = of_property_match_string(np, "clock-names", "main_xtal");
178 if (i < 0)
179 return;
180 mainxtal_name = of_clk_get_parent_name(np, i);
181
182 regmap = syscon_node_to_regmap(np);
183 if (IS_ERR(regmap))
184 return;
185
186 sam9x60_pmc = pmc_data_allocate(PMC_MAIN + 1,
187 nck(sam9x60_systemck),
188 nck(sam9x60_periphck),
189 nck(sam9x60_gck));
190 if (!sam9x60_pmc)
191 return;
192
193 hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 24000000,
194 50000000);
195 if (IS_ERR(hw))
196 goto err_free;
197
198 bypass = of_property_read_bool(np, "atmel,osc-bypass");
199
200 hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
201 bypass);
202 if (IS_ERR(hw))
203 goto err_free;
204
205 parent_names[0] = "main_rc_osc";
206 parent_names[1] = "main_osc";
207 hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
208 if (IS_ERR(hw))
209 goto err_free;
210
211 sam9x60_pmc->chws[PMC_MAIN] = hw;
212
213 hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "pllack",
214 "mainck", 0, &plla_characteristics);
215 if (IS_ERR(hw))
216 goto err_free;
217
218 hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck",
219 "main_osc", 1, &upll_characteristics);
220 if (IS_ERR(hw))
221 goto err_free;
222
223 sam9x60_pmc->chws[PMC_UTMI] = hw;
224
225 parent_names[0] = md_slck_name;
226 parent_names[1] = "mainck";
227 parent_names[2] = "pllack";
228 hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
229 &sam9x60_master_layout,
230 &mck_characteristics);
231 if (IS_ERR(hw))
232 goto err_free;
233
234 sam9x60_pmc->chws[PMC_MCK] = hw;
235
236 parent_names[0] = "pllack";
237 parent_names[1] = "upllck";
238 parent_names[2] = "mainck";
239 parent_names[3] = "mainck";
240 hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4);
241 if (IS_ERR(hw))
242 goto err_free;
243
244 parent_names[0] = md_slck_name;
245 parent_names[1] = td_slck_name;
246 parent_names[2] = "mainck";
247 parent_names[3] = "masterck";
248 parent_names[4] = "pllack";
249 parent_names[5] = "upllck";
250 for (i = 0; i < 8; i++) {
251 char name[6];
252
253 snprintf(name, sizeof(name), "prog%d", i);
254
255 hw = at91_clk_register_programmable(regmap, name,
256 parent_names, 6, i,
257 &sam9x60_programmable_layout);
258 if (IS_ERR(hw))
259 goto err_free;
260 }
261
262 for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) {
263 hw = at91_clk_register_system(regmap, sam9x60_systemck[i].n,
264 sam9x60_systemck[i].p,
265 sam9x60_systemck[i].id);
266 if (IS_ERR(hw))
267 goto err_free;
268
269 sam9x60_pmc->shws[sam9x60_systemck[i].id] = hw;
270 }
271
272 for (i = 0; i < ARRAY_SIZE(sam9x60_periphck); i++) {
273 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
274 &sam9x60_pcr_layout,
275 sam9x60_periphck[i].n,
276 "masterck",
277 sam9x60_periphck[i].id,
278 &range);
279 if (IS_ERR(hw))
280 goto err_free;
281
282 sam9x60_pmc->phws[sam9x60_periphck[i].id] = hw;
283 }
284
285 for (i = 0; i < ARRAY_SIZE(sam9x60_gck); i++) {
286 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
287 &sam9x60_pcr_layout,
288 sam9x60_gck[i].n,
289 parent_names, 6,
290 sam9x60_gck[i].id,
291 sam9x60_gck[i].pll,
292 &sam9x60_gck[i].r);
293 if (IS_ERR(hw))
294 goto err_free;
295
296 sam9x60_pmc->ghws[sam9x60_gck[i].id] = hw;
297 }
298
299 of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x60_pmc);
300
301 return;
302
303err_free:
304 pmc_data_free(sam9x60_pmc);
305}
306/* Some clks are used for a clocksource */
307CLK_OF_DECLARE(sam9x60_pmc, "microchip,sam9x60-pmc", sam9x60_pmc_setup);
drivers/clk/at91/sama5d2.c+11−1
@@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 }; · 15 unmodified lines
16 16
17static u16 plla_icpll[] = { 0 };17static u16 plla_icpll[] = { 0 };
18 18
19static struct clk_range plla_outputs[] = {19static const struct clk_range plla_outputs[] = {
20 { .min = 600000000, .max = 1200000000 },20 { .min = 600000000, .max = 1200000000 },
21};21};
22 22
@@ -28,6 +28,13 @@ static const struct clk_pll_characteristics plla_characteristics = { · 5 unmodified lines
28 .out = plla_out,28 .out = plla_out,
29};29};
30 30
31static const struct clk_pcr_layout sama5d2_pcr_layout = {
32 .offset = 0x10c,
33 .cmd = BIT(12),
34 .gckcss_mask = GENMASK(10, 8),
35 .pid_mask = GENMASK(6, 0),
36};
37
31static const struct {38static const struct {
32 char *n;39 char *n;
33 char *p;40 char *p;
@@ -274,6 +281,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) · 240 unmodified lines
274 281
275 for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) {282 for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) {
276 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,283 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
284 &sama5d2_pcr_layout,
277 sama5d2_periphck[i].n,285 sama5d2_periphck[i].n,
278 "masterck",286 "masterck",
279 sama5d2_periphck[i].id,287 sama5d2_periphck[i].id,
@@ -286,6 +294,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) · 6 unmodified lines
286 294
287 for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) {295 for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) {
288 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,296 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
297 &sama5d2_pcr_layout,
289 sama5d2_periph32ck[i].n,298 sama5d2_periph32ck[i].n,
290 "h32mxck",299 "h32mxck",
291 sama5d2_periph32ck[i].id,300 sama5d2_periph32ck[i].id,
@@ -304,6 +313,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) · 12 unmodified lines
304 parent_names[5] = "audiopll_pmcck";313 parent_names[5] = "audiopll_pmcck";
305 for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {314 for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
306 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,315 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
316 &sama5d2_pcr_layout,
307 sama5d2_gck[i].n,317 sama5d2_gck[i].n,
308 parent_names, 6,318 parent_names, 6,
309 sama5d2_gck[i].id,319 sama5d2_gck[i].id,
drivers/clk/at91/sama5d4.c+9−1
@@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 }; · 15 unmodified lines
16 16
17static u16 plla_icpll[] = { 0 };17static u16 plla_icpll[] = { 0 };
18 18
19static struct clk_range plla_outputs[] = {19static const struct clk_range plla_outputs[] = {
20 { .min = 600000000, .max = 1200000000 },20 { .min = 600000000, .max = 1200000000 },
21};21};
22 22
@@ -28,6 +28,12 @@ static const struct clk_pll_characteristics plla_characteristics = { · 5 unmodified lines
28 .out = plla_out,28 .out = plla_out,
29};29};
30 30
31static const struct clk_pcr_layout sama5d4_pcr_layout = {
32 .offset = 0x10c,
33 .cmd = BIT(12),
34 .pid_mask = GENMASK(6, 0),
35};
36
31static const struct {37static const struct {
32 char *n;38 char *n;
33 char *p;39 char *p;
@@ -232,6 +238,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) · 198 unmodified lines
232 238
233 for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) {239 for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) {
234 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,240 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
241 &sama5d4_pcr_layout,
235 sama5d4_periphck[i].n,242 sama5d4_periphck[i].n,
236 "masterck",243 "masterck",
237 sama5d4_periphck[i].id,244 sama5d4_periphck[i].id,
@@ -244,6 +251,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) · 6 unmodified lines
244 251
245 for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) {252 for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) {
246 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,253 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
254 &sama5d4_pcr_layout,
247 sama5d4_periph32ck[i].n,255 sama5d4_periph32ck[i].n,
248 "h32mxck",256 "h32mxck",
249 sama5d4_periph32ck[i].id,257 sama5d4_periph32ck[i].id,
drivers/clk/at91/sckc.c+47−87
@@ -152,28 +152,6 @@ at91_clk_register_slow_osc(void __iomem *sckcr, · 151 unmodified lines
152 return hw;152 return hw;
153}153}
154 154
155static void __init
156of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr)
157{
158 struct clk_hw *hw;
159 const char *parent_name;
160 const char *name = np->name;
161 u32 startup;
162 bool bypass;
163
164 parent_name = of_clk_get_parent_name(np, 0);
165 of_property_read_string(np, "clock-output-names", &name);
166 of_property_read_u32(np, "atmel,startup-time-usec", &startup);
167 bypass = of_property_read_bool(np, "atmel,osc-bypass");
168
169 hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
170 bypass);
171 if (IS_ERR(hw))
172 return;
173
174 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
175}
176
177static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,155static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
178 unsigned long parent_rate)156 unsigned long parent_rate)
179{157{
@@ -266,28 +244,6 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, · 86 unmodified lines
266 return hw;244 return hw;
267}245}
268 246
269static void __init
270of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr)
271{
272 struct clk_hw *hw;
273 u32 frequency = 0;
274 u32 accuracy = 0;
275 u32 startup = 0;
276 const char *name = np->name;
277
278 of_property_read_string(np, "clock-output-names", &name);
279 of_property_read_u32(np, "clock-frequency", &frequency);
280 of_property_read_u32(np, "clock-accuracy", &accuracy);
281 of_property_read_u32(np, "atmel,startup-time-usec", &startup);
282
283 hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
284 startup);
285 if (IS_ERR(hw))
286 return;
287
288 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
289}
290
291static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)247static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
292{248{
293 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);249 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
@@ -365,68 +321,72 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, · 71 unmodified lines
365 return hw;321 return hw;
366}322}
367 323
368static void __init324static void __init at91sam9x5_sckc_register(struct device_node *np,
369of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr)325 unsigned int rc_osc_startup_us)
370{326{
327 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
328 void __iomem *regbase = of_iomap(np, 0);
329 struct device_node *child = NULL;
330 const char *xtal_name;
371 struct clk_hw *hw;331 struct clk_hw *hw;
372 const char *parent_names[2];332 bool bypass;
373 unsigned int num_parents;
374 const char *name = np->name;
375 333
376 num_parents = of_clk_get_parent_count(np);334 if (!regbase)
377 if (num_parents == 0 || num_parents > 2)335 return;
336
337 hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768,
338 50000000, rc_osc_startup_us);
339 if (IS_ERR(hw))
378 return;340 return;
379 341
380 of_clk_parent_fill(np, parent_names, num_parents);342 xtal_name = of_clk_get_parent_name(np, 0);
343 if (!xtal_name) {
344 /* DT backward compatibility */
345 child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
346 if (!child)
347 return;
348
349 xtal_name = of_clk_get_parent_name(child, 0);
350 bypass = of_property_read_bool(child, "atmel,osc-bypass");
351
352 child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
353 } else {
354 bypass = of_property_read_bool(np, "atmel,osc-bypass");
355 }
356
357 if (!xtal_name)
358 return;
381 359
382 of_property_read_string(np, "clock-output-names", &name);360 hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name,
361 1200000, bypass);
362 if (IS_ERR(hw))
363 return;
383 364
384 hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,365 hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
385 num_parents);
386 if (IS_ERR(hw))366 if (IS_ERR(hw))
387 return;367 return;
388 368
389 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);369 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
390}
391 370
392static const struct of_device_id sckc_clk_ids[] __initconst = {371 /* DT backward compatibility */
393 /* Slow clock */372 if (child)
394 {373 of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw);
395 .compatible = "atmel,at91sam9x5-clk-slow-osc",374}
396 .data = of_at91sam9x5_clk_slow_osc_setup,
397 },
398 {
399 .compatible = "atmel,at91sam9x5-clk-slow-rc-osc",
400 .data = of_at91sam9x5_clk_slow_rc_osc_setup,
401 },
402 {
403 .compatible = "atmel,at91sam9x5-clk-slow",
404 .data = of_at91sam9x5_clk_slow_setup,
405 },
406 { /*sentinel*/ }
407};
408 375
409static void __init of_at91sam9x5_sckc_setup(struct device_node *np)376static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
410{377{
411 struct device_node *childnp;378 at91sam9x5_sckc_register(np, 75);
412 void (*clk_setup)(struct device_node *, void __iomem *);
413 const struct of_device_id *clk_id;
414 void __iomem *regbase = of_iomap(np, 0);
415
416 if (!regbase)
417 return;
418
419 for_each_child_of_node(np, childnp) {
420 clk_id = of_match_node(sckc_clk_ids, childnp);
421 if (!clk_id)
422 continue;
423 clk_setup = clk_id->data;
424 clk_setup(childnp, regbase);
425 }
426}379}
427CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",380CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
428 of_at91sam9x5_sckc_setup);381 of_at91sam9x5_sckc_setup);
429 382
383static void __init of_sama5d3_sckc_setup(struct device_node *np)
384{
385 at91sam9x5_sckc_register(np, 500);
386}
387CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
388 of_sama5d3_sckc_setup);
389
430static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)390static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
431{391{
432 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);392 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
drivers/clk/clk-stm32f4.c+299−8
@@ -300,6 +300,85 @@ static const struct stm32f4_gate_data stm32f746_gates[] __initconst = { · 299 unmodified lines
300 { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" },300 { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" },
301};301};
302 302
303static const struct stm32f4_gate_data stm32f769_gates[] __initconst = {
304 { STM32F4_RCC_AHB1ENR, 0, "gpioa", "ahb_div" },
305 { STM32F4_RCC_AHB1ENR, 1, "gpiob", "ahb_div" },
306 { STM32F4_RCC_AHB1ENR, 2, "gpioc", "ahb_div" },
307 { STM32F4_RCC_AHB1ENR, 3, "gpiod", "ahb_div" },
308 { STM32F4_RCC_AHB1ENR, 4, "gpioe", "ahb_div" },
309 { STM32F4_RCC_AHB1ENR, 5, "gpiof", "ahb_div" },
310 { STM32F4_RCC_AHB1ENR, 6, "gpiog", "ahb_div" },
311 { STM32F4_RCC_AHB1ENR, 7, "gpioh", "ahb_div" },
312 { STM32F4_RCC_AHB1ENR, 8, "gpioi", "ahb_div" },
313 { STM32F4_RCC_AHB1ENR, 9, "gpioj", "ahb_div" },
314 { STM32F4_RCC_AHB1ENR, 10, "gpiok", "ahb_div" },
315 { STM32F4_RCC_AHB1ENR, 12, "crc", "ahb_div" },
316 { STM32F4_RCC_AHB1ENR, 18, "bkpsra", "ahb_div" },
317 { STM32F4_RCC_AHB1ENR, 20, "dtcmram", "ahb_div" },
318 { STM32F4_RCC_AHB1ENR, 21, "dma1", "ahb_div" },
319 { STM32F4_RCC_AHB1ENR, 22, "dma2", "ahb_div" },
320 { STM32F4_RCC_AHB1ENR, 23, "dma2d", "ahb_div" },
321 { STM32F4_RCC_AHB1ENR, 25, "ethmac", "ahb_div" },
322 { STM32F4_RCC_AHB1ENR, 26, "ethmactx", "ahb_div" },
323 { STM32F4_RCC_AHB1ENR, 27, "ethmacrx", "ahb_div" },
324 { STM32F4_RCC_AHB1ENR, 28, "ethmacptp", "ahb_div" },
325 { STM32F4_RCC_AHB1ENR, 29, "otghs", "ahb_div" },
326 { STM32F4_RCC_AHB1ENR, 30, "otghsulpi", "ahb_div" },
327
328 { STM32F4_RCC_AHB2ENR, 0, "dcmi", "ahb_div" },
329 { STM32F4_RCC_AHB2ENR, 1, "jpeg", "ahb_div" },
330 { STM32F4_RCC_AHB2ENR, 4, "cryp", "ahb_div" },
331 { STM32F4_RCC_AHB2ENR, 5, "hash", "ahb_div" },
332 { STM32F4_RCC_AHB2ENR, 6, "rng", "pll48" },
333 { STM32F4_RCC_AHB2ENR, 7, "otgfs", "pll48" },
334
335 { STM32F4_RCC_AHB3ENR, 0, "fmc", "ahb_div",
336 CLK_IGNORE_UNUSED },
337 { STM32F4_RCC_AHB3ENR, 1, "qspi", "ahb_div",
338 CLK_IGNORE_UNUSED },
339
340 { STM32F4_RCC_APB1ENR, 0, "tim2", "apb1_mul" },
341 { STM32F4_RCC_APB1ENR, 1, "tim3", "apb1_mul" },
342 { STM32F4_RCC_APB1ENR, 2, "tim4", "apb1_mul" },
343 { STM32F4_RCC_APB1ENR, 3, "tim5", "apb1_mul" },
344 { STM32F4_RCC_APB1ENR, 4, "tim6", "apb1_mul" },
345 { STM32F4_RCC_APB1ENR, 5, "tim7", "apb1_mul" },
346 { STM32F4_RCC_APB1ENR, 6, "tim12", "apb1_mul" },
347 { STM32F4_RCC_APB1ENR, 7, "tim13", "apb1_mul" },
348 { STM32F4_RCC_APB1ENR, 8, "tim14", "apb1_mul" },
349 { STM32F4_RCC_APB1ENR, 10, "rtcapb", "apb1_mul" },
350 { STM32F4_RCC_APB1ENR, 11, "wwdg", "apb1_div" },
351 { STM32F4_RCC_APB1ENR, 13, "can3", "apb1_div" },
352 { STM32F4_RCC_APB1ENR, 14, "spi2", "apb1_div" },
353 { STM32F4_RCC_APB1ENR, 15, "spi3", "apb1_div" },
354 { STM32F4_RCC_APB1ENR, 16, "spdifrx", "apb1_div" },
355 { STM32F4_RCC_APB1ENR, 25, "can1", "apb1_div" },
356 { STM32F4_RCC_APB1ENR, 26, "can2", "apb1_div" },
357 { STM32F4_RCC_APB1ENR, 27, "cec", "apb1_div" },
358 { STM32F4_RCC_APB1ENR, 28, "pwr", "apb1_div" },
359 { STM32F4_RCC_APB1ENR, 29, "dac", "apb1_div" },
360
361 { STM32F4_RCC_APB2ENR, 0, "tim1", "apb2_mul" },
362 { STM32F4_RCC_APB2ENR, 1, "tim8", "apb2_mul" },
363 { STM32F4_RCC_APB2ENR, 7, "sdmmc2", "sdmux2" },
364 { STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" },
365 { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" },
366 { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" },
367 { STM32F4_RCC_APB2ENR, 11, "sdmmc1", "sdmux1" },
368 { STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" },
369 { STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" },
370 { STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" },
371 { STM32F4_RCC_APB2ENR, 16, "tim9", "apb2_mul" },
372 { STM32F4_RCC_APB2ENR, 17, "tim10", "apb2_mul" },
373 { STM32F4_RCC_APB2ENR, 18, "tim11", "apb2_mul" },
374 { STM32F4_RCC_APB2ENR, 20, "spi5", "apb2_div" },
375 { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" },
376 { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" },
377 { STM32F4_RCC_APB2ENR, 23, "sai2", "apb2_div" },
378 { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" },
379 { STM32F4_RCC_APB2ENR, 30, "mdio", "apb2_div" },
380};
381
303/*382/*
304 * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx383 * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
305 * have gate bits associated with them. Its combined hweight is 71.384 * have gate bits associated with them. Its combined hweight is 71.
@@ -318,6 +397,10 @@ static const u64 stm32f746_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, · 12 unmodified lines
318 0x0000000000000003ull,397 0x0000000000000003ull,
319 0x04f77f833e01c9ffull };398 0x04f77f833e01c9ffull };
320 399
400static const u64 stm32f769_gate_map[MAX_GATE_MAP] = { 0x000000f37ef417ffull,
401 0x0000000000000003ull,
402 0x44F77F833E01EDFFull };
403
321static const u64 *stm32f4_gate_map;404static const u64 *stm32f4_gate_map;
322 405
323static struct clk_hw **clks;406static struct clk_hw **clks;
@@ -1048,6 +1131,10 @@ static const char *rtc_parents[4] = { · 724 unmodified lines
1048 "no-clock", "lse", "lsi", "hse-rtc"1131 "no-clock", "lse", "lsi", "hse-rtc"
1049};1132};
1050 1133
1134static const char *pll_src = "pll-src";
1135
1136static const char *pllsrc_parent[2] = { "hsi", NULL };
1137
1051static const char *dsi_parent[2] = { NULL, "pll-r" };1138static const char *dsi_parent[2] = { NULL, "pll-r" };
1052 1139
1053static const char *lcd_parent[1] = { "pllsai-r-div" };1140static const char *lcd_parent[1] = { "pllsai-r-div" };
@@ -1072,6 +1159,9 @@ static const char *uart_parents2[4] = { "apb1_div", "sys", "hsi", "lse" }; · 18 unmodified lines
1072 1159
1073static const char *i2c_parents[4] = { "apb1_div", "sys", "hsi", "no-clock" };1160static const char *i2c_parents[4] = { "apb1_div", "sys", "hsi", "no-clock" };
1074 1161
1162static const char * const dfsdm1_src[] = { "apb2_div", "sys" };
1163static const char * const adsfdm1_parent[] = { "sai1_clk", "sai2_clk" };
1164
1075struct stm32_aux_clk {1165struct stm32_aux_clk {
1076 int idx;1166 int idx;
1077 const char *name;1167 const char *name;
@@ -1313,6 +1403,177 @@ static const struct stm32_aux_clk stm32f746_aux_clk[] = { · 235 unmodified lines
1313 },1403 },
1314};1404};
1315 1405
1406static const struct stm32_aux_clk stm32f769_aux_clk[] = {
1407 {
1408 CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
1409 NO_MUX, 0, 0,
1410 STM32F4_RCC_APB2ENR, 26,
1411 CLK_SET_RATE_PARENT
1412 },
1413 {
1414 CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
1415 STM32F4_RCC_CFGR, 23, 1,
1416 NO_GATE, 0,
1417 CLK_SET_RATE_PARENT
1418 },
1419 {
1420 CLK_SAI1, "sai1_clk", sai_parents, ARRAY_SIZE(sai_parents),
1421 STM32F4_RCC_DCKCFGR, 20, 3,
1422 STM32F4_RCC_APB2ENR, 22,
1423 CLK_SET_RATE_PARENT
1424 },
1425 {
1426 CLK_SAI2, "sai2_clk", sai_parents, ARRAY_SIZE(sai_parents),
1427 STM32F4_RCC_DCKCFGR, 22, 3,
1428 STM32F4_RCC_APB2ENR, 23,
1429 CLK_SET_RATE_PARENT
1430 },
1431 {
1432 NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
1433 STM32F7_RCC_DCKCFGR2, 27, 1,
1434 NO_GATE, 0,
1435 0
1436 },
1437 {
1438 NO_IDX, "sdmux1", sdmux_parents, ARRAY_SIZE(sdmux_parents),
1439 STM32F7_RCC_DCKCFGR2, 28, 1,
1440 NO_GATE, 0,
1441 0
1442 },
1443 {
1444 NO_IDX, "sdmux2", sdmux_parents, ARRAY_SIZE(sdmux_parents),
1445 STM32F7_RCC_DCKCFGR2, 29, 1,
1446 NO_GATE, 0,
1447 0
1448 },
1449 {
1450 CLK_HDMI_CEC, "hdmi-cec",
1451 hdmi_parents, ARRAY_SIZE(hdmi_parents),
1452 STM32F7_RCC_DCKCFGR2, 26, 1,
1453 NO_GATE, 0,
1454 0
1455 },
1456 {
1457 CLK_SPDIF, "spdif-rx",
1458 spdif_parent, ARRAY_SIZE(spdif_parent),
1459 STM32F7_RCC_DCKCFGR2, 22, 3,
1460 STM32F4_RCC_APB2ENR, 23,
1461 CLK_SET_RATE_PARENT
1462 },
1463 {
1464 CLK_USART1, "usart1",
1465 uart_parents1, ARRAY_SIZE(uart_parents1),
1466 STM32F7_RCC_DCKCFGR2, 0, 3,
1467 STM32F4_RCC_APB2ENR, 4,
1468 CLK_SET_RATE_PARENT,
1469 },
1470 {
1471 CLK_USART2, "usart2",
1472 uart_parents2, ARRAY_SIZE(uart_parents1),
1473 STM32F7_RCC_DCKCFGR2, 2, 3,
1474 STM32F4_RCC_APB1ENR, 17,
1475 CLK_SET_RATE_PARENT,
1476 },
1477 {
1478 CLK_USART3, "usart3",
1479 uart_parents2, ARRAY_SIZE(uart_parents1),
1480 STM32F7_RCC_DCKCFGR2, 4, 3,
1481 STM32F4_RCC_APB1ENR, 18,
1482 CLK_SET_RATE_PARENT,
1483 },
1484 {
1485 CLK_UART4, "uart4",
1486 uart_parents2, ARRAY_SIZE(uart_parents1),
1487 STM32F7_RCC_DCKCFGR2, 6, 3,
1488 STM32F4_RCC_APB1ENR, 19,
1489 CLK_SET_RATE_PARENT,
1490 },
1491 {
1492 CLK_UART5, "uart5",
1493 uart_parents2, ARRAY_SIZE(uart_parents1),
1494 STM32F7_RCC_DCKCFGR2, 8, 3,
1495 STM32F4_RCC_APB1ENR, 20,
1496 CLK_SET_RATE_PARENT,
1497 },
1498 {
1499 CLK_USART6, "usart6",
1500 uart_parents1, ARRAY_SIZE(uart_parents1),
1501 STM32F7_RCC_DCKCFGR2, 10, 3,
1502 STM32F4_RCC_APB2ENR, 5,
1503 CLK_SET_RATE_PARENT,
1504 },
1505 {
1506 CLK_UART7, "uart7",
1507 uart_parents2, ARRAY_SIZE(uart_parents1),
1508 STM32F7_RCC_DCKCFGR2, 12, 3,
1509 STM32F4_RCC_APB1ENR, 30,
1510 CLK_SET_RATE_PARENT,
1511 },
1512 {
1513 CLK_UART8, "uart8",
1514 uart_parents2, ARRAY_SIZE(uart_parents1),
1515 STM32F7_RCC_DCKCFGR2, 14, 3,
1516 STM32F4_RCC_APB1ENR, 31,
1517 CLK_SET_RATE_PARENT,
1518 },
1519 {
1520 CLK_I2C1, "i2c1",
1521 i2c_parents, ARRAY_SIZE(i2c_parents),
1522 STM32F7_RCC_DCKCFGR2, 16, 3,
1523 STM32F4_RCC_APB1ENR, 21,
1524 CLK_SET_RATE_PARENT,
1525 },
1526 {
1527 CLK_I2C2, "i2c2",
1528 i2c_parents, ARRAY_SIZE(i2c_parents),
1529 STM32F7_RCC_DCKCFGR2, 18, 3,
1530 STM32F4_RCC_APB1ENR, 22,
1531 CLK_SET_RATE_PARENT,
1532 },
1533 {
1534 CLK_I2C3, "i2c3",
1535 i2c_parents, ARRAY_SIZE(i2c_parents),
1536 STM32F7_RCC_DCKCFGR2, 20, 3,
1537 STM32F4_RCC_APB1ENR, 23,
1538 CLK_SET_RATE_PARENT,
1539 },
1540 {
1541 CLK_I2C4, "i2c4",
1542 i2c_parents, ARRAY_SIZE(i2c_parents),
1543 STM32F7_RCC_DCKCFGR2, 22, 3,
1544 STM32F4_RCC_APB1ENR, 24,
1545 CLK_SET_RATE_PARENT,
1546 },
1547 {
1548 CLK_LPTIMER, "lptim1",
1549 lptim_parent, ARRAY_SIZE(lptim_parent),
1550 STM32F7_RCC_DCKCFGR2, 24, 3,
1551 STM32F4_RCC_APB1ENR, 9,
1552 CLK_SET_RATE_PARENT
1553 },
1554 {
1555 CLK_F769_DSI, "dsi",
1556 dsi_parent, ARRAY_SIZE(dsi_parent),
1557 STM32F7_RCC_DCKCFGR2, 0, 1,
1558 STM32F4_RCC_APB2ENR, 27,
1559 CLK_SET_RATE_PARENT
1560 },
1561 {
1562 CLK_DFSDM1, "dfsdm1",
1563 dfsdm1_src, ARRAY_SIZE(dfsdm1_src),
1564 STM32F4_RCC_DCKCFGR, 25, 1,
1565 STM32F4_RCC_APB2ENR, 29,
1566 CLK_SET_RATE_PARENT
1567 },
1568 {
1569 CLK_ADFSDM1, "adfsdm1",
1570 adsfdm1_parent, ARRAY_SIZE(adsfdm1_parent),
1571 STM32F4_RCC_DCKCFGR, 26, 1,
1572 STM32F4_RCC_APB2ENR, 29,
1573 CLK_SET_RATE_PARENT
1574 },
1575};
1576
1316static const struct stm32f4_clk_data stm32f429_clk_data = {1577static const struct stm32f4_clk_data stm32f429_clk_data = {
1317 .end_primary = END_PRIMARY_CLK,1578 .end_primary = END_PRIMARY_CLK,
1318 .gates_data = stm32f429_gates,1579 .gates_data = stm32f429_gates,
@@ -1343,6 +1604,16 @@ static const struct stm32f4_clk_data stm32f746_clk_data = { · 24 unmodified lines
1343 .aux_clk_num = ARRAY_SIZE(stm32f746_aux_clk),1604 .aux_clk_num = ARRAY_SIZE(stm32f746_aux_clk),
1344};1605};
1345 1606
1607static const struct stm32f4_clk_data stm32f769_clk_data = {
1608 .end_primary = END_PRIMARY_CLK_F7,
1609 .gates_data = stm32f769_gates,
1610 .gates_map = stm32f769_gate_map,
1611 .gates_num = ARRAY_SIZE(stm32f769_gates),
1612 .pll_data = stm32f469_pll,
1613 .aux_clk = stm32f769_aux_clk,
1614 .aux_clk_num = ARRAY_SIZE(stm32f769_aux_clk),
1615};
1616
1346static const struct of_device_id stm32f4_of_match[] = {1617static const struct of_device_id stm32f4_of_match[] = {
1347 {1618 {
1348 .compatible = "st,stm32f42xx-rcc",1619 .compatible = "st,stm32f42xx-rcc",
@@ -1356,6 +1627,10 @@ static const struct of_device_id stm32f4_of_match[] = { · 7 unmodified lines
1356 .compatible = "st,stm32f746-rcc",1627 .compatible = "st,stm32f746-rcc",
1357 .data = &stm32f746_clk_data1628 .data = &stm32f746_clk_data
1358 },1629 },
1630 {
1631 .compatible = "st,stm32f769-rcc",
1632 .data = &stm32f769_clk_data
1633 },
1359 {}1634 {}
1360};1635};
1361 1636
@@ -1427,9 +1702,8 @@ static void __init stm32f4_rcc_init(struct device_node *np) · 65 unmodified lines
1427 int n;1702 int n;
1428 const struct of_device_id *match;1703 const struct of_device_id *match;
1429 const struct stm32f4_clk_data *data;1704 const struct stm32f4_clk_data *data;
1430 unsigned long pllcfgr;
1431 const char *pllsrc;
1432 unsigned long pllm;1705 unsigned long pllm;
1706 struct clk_hw *pll_src_hw;
1433 1707
1434 base = of_iomap(np, 0);1708 base = of_iomap(np, 0);
1435 if (!base) {1709 if (!base) {
@@ -1460,21 +1734,33 @@ static void __init stm32f4_rcc_init(struct device_node *np) · 24 unmodified lines
1460 1734
1461 hse_clk = of_clk_get_parent_name(np, 0);1735 hse_clk = of_clk_get_parent_name(np, 0);
1462 dsi_parent[0] = hse_clk;1736 dsi_parent[0] = hse_clk;
1737 pllsrc_parent[1] = hse_clk;
1463 1738
1464 i2s_in_clk = of_clk_get_parent_name(np, 1);1739 i2s_in_clk = of_clk_get_parent_name(np, 1);
1465 1740
1466 i2s_parents[1] = i2s_in_clk;1741 i2s_parents[1] = i2s_in_clk;
1467 sai_parents[2] = i2s_in_clk;1742 sai_parents[2] = i2s_in_clk;
1468 1743
1744 if (of_device_is_compatible(np, "st,stm32f769-rcc")) {
1745 clk_hw_register_gate(NULL, "dfsdm1_apb", "apb2_div", 0,
1746 base + STM32F4_RCC_APB2ENR, 29,
1747 CLK_IGNORE_UNUSED, &stm32f4_clk_lock);
1748 dsi_parent[0] = pll_src;
1749 sai_parents[3] = pll_src;
1750 }
1751
1469 clks[CLK_HSI] = clk_hw_register_fixed_rate_with_accuracy(NULL, "hsi",1752 clks[CLK_HSI] = clk_hw_register_fixed_rate_with_accuracy(NULL, "hsi",
1470 NULL, 0, 16000000, 160000);1753 NULL, 0, 16000000, 160000);
1471 1754
1472 pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);1755 pll_src_hw = clk_hw_register_mux(NULL, pll_src, pllsrc_parent,
1473 pllsrc = pllcfgr & BIT(22) ? hse_clk : "hsi";1756 ARRAY_SIZE(pllsrc_parent), 0,
1474 pllm = pllcfgr & 0x3f;1757 base + STM32F4_RCC_PLLCFGR, 22, 1, 0,
1758 &stm32f4_clk_lock);
1759
1760 pllm = readl(base + STM32F4_RCC_PLLCFGR) & 0x3f;
1475 1761
1476 clk_hw_register_fixed_factor(NULL, "vco_in", pllsrc,1762 clk_hw_register_fixed_factor(NULL, "vco_in", pll_src,
1477 0, 1, pllm);1763 0, 1, pllm);
1478 1764
1479 stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],1765 stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
1480 &stm32f4_clk_lock);1766 &stm32f4_clk_lock);
@@ -1612,12 +1898,16 @@ static void __init stm32f4_rcc_init(struct device_node *np) · 131 unmodified lines
1612 clks[aux_clk->idx] = hw;1898 clks[aux_clk->idx] = hw;
1613 }1899 }
1614 1900
1615 if (of_device_is_compatible(np, "st,stm32f746-rcc"))1901 if (of_device_is_compatible(np, "st,stm32f746-rcc")) {
1616 1902
1617 clk_hw_register_fixed_factor(NULL, "hsi_div488", "hsi", 0,1903 clk_hw_register_fixed_factor(NULL, "hsi_div488", "hsi", 0,
1618 1, 488);1904 1, 488);
1619 1905
1906 clks[CLK_PLL_SRC] = pll_src_hw;
1907 }
1908
1620 of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);1909 of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
1910
1621 return;1911 return;
1622fail:1912fail:
1623 kfree(clks);1913 kfree(clks);
@@ -1626,3 +1916,4 @@ fail: · 2 unmodified lines
1626CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init);1916CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init);
1627CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init);1917CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init);
1628CLK_OF_DECLARE_DRIVER(stm32f746_rcc, "st,stm32f746-rcc", stm32f4_rcc_init);1918CLK_OF_DECLARE_DRIVER(stm32f746_rcc, "st,stm32f746-rcc", stm32f4_rcc_init);
1919CLK_OF_DECLARE_DRIVER(stm32f769_rcc, "st,stm32f769-rcc", stm32f4_rcc_init);
drivers/clk/clk-stm32mp1.c+3−0
@@ -1402,6 +1402,7 @@ enum { · 1401 unmodified lines
1402 G_CRYP1,1402 G_CRYP1,
1403 G_HASH1,1403 G_HASH1,
1404 G_BKPSRAM,1404 G_BKPSRAM,
1405 G_DDRPERFM,
1405 1406
1406 G_LAST1407 G_LAST
1407};1408};
@@ -1488,6 +1489,7 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { · 80 unmodified lines
1488 K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0),1489 K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0),
1489 K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0),1490 K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0),
1490 K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0),1491 K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0),
1492 K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0),
1491 K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0),1493 K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0),
1492 K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0),1494 K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0),
1493 1495
@@ -1899,6 +1901,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { · 405 unmodified lines
1899 PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1),1901 PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1),
1900 PCLK(USBH, "usbh", "ck_axi", 0, G_USBH),1902 PCLK(USBH, "usbh", "ck_axi", 0, G_USBH),
1901 PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP),1903 PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP),
1904 PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM),
1902 1905
1903 /* Kernel clocks */1906 /* Kernel clocks */
1904 KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12),1907 KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12),
drivers/clk/davinci/pll.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2/*2/*
3 * Clock driver for TI Davinci PSC controllers3 * Clock driver for TI Davinci PSC controllers
4 *4 *
drivers/clk/davinci/psc.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2/*2/*
3 * Clock driver for TI Davinci PSC controllers3 * Clock driver for TI Davinci PSC controllers
4 *4 *
drivers/clk/qcom/clk-regmap-mux-div.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2/*2/*
3 * Copyright (c) 2017, Linaro Limited3 * Copyright (c) 2017, Linaro Limited
4 * Author: Georgi Djakov <georgi.djakov@linaro.org>4 * Author: Georgi Djakov <georgi.djakov@linaro.org>
drivers/clk/renesas/rcar-gen2-cpg.h+2−2
@@ -1,5 +1,5 @@
1/* SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2 *2/*
3 * R-Car Gen2 Clock Pulse Generator3 * R-Car Gen2 Clock Pulse Generator
4 *4 *
5 * Copyright (C) 2016 Cogent Embedded Inc.5 * Copyright (C) 2016 Cogent Embedded Inc.
drivers/clk/renesas/rcar-gen3-cpg.h+2−2
@@ -1,5 +1,5 @@
1/* SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2 *2/*
3 * R-Car Gen3 Clock Pulse Generator3 * R-Car Gen3 Clock Pulse Generator
4 *4 *
5 * Copyright (C) 2015-2018 Glider bvba5 * Copyright (C) 2015-2018 Glider bvba
drivers/clk/renesas/renesas-cpg-mssr.h+2−2
@@ -1,5 +1,5 @@
1/* SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2 *2/*
3 * Renesas Clock Pulse Generator / Module Standby and Software Reset3 * Renesas Clock Pulse Generator / Module Standby and Software Reset
4 *4 *
5 * Copyright (C) 2015 Glider bvba5 * Copyright (C) 2015 Glider bvba
drivers/clk/sifive/Kconfig+18−0
@@ -0,0 +1,18 @@
1# SPDX-License-Identifier: GPL-2.0
2
3menuconfig CLK_SIFIVE
4 bool "SiFive SoC driver support"
5 help
6 SoC drivers for SiFive Linux-capable SoCs.
7
8if CLK_SIFIVE
9
10config CLK_SIFIVE_FU540_PRCI
11 bool "PRCI driver for SiFive FU540 SoCs"
12 select CLK_ANALOGBITS_WRPLL_CLN28HPC
13 help
14 Supports the Power Reset Clock interface (PRCI) IP block found in
15 FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
16 enable this driver.
17
18endif
drivers/clk/sifive/Makefile+1−0
@@ -0,0 +1 @@
1obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o
drivers/clk/sifive/fu540-prci.c+626−0
@@ -0,0 +1,626 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018-2019 SiFive, Inc.
4 * Wesley Terpstra
5 * Paul Walmsley
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * The FU540 PRCI implements clock and reset control for the SiFive
17 * FU540-C000 chip. This driver assumes that it has sole control
18 * over all PRCI resources.
19 *
20 * This driver is based on the PRCI driver written by Wesley Terpstra:
21 * https://github.com/riscv/riscv-linux/commit/999529edf517ed75b56659d456d221b2ee56bb60
22 *
23 * References:
24 * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
25 */
26
27#include <dt-bindings/clock/sifive-fu540-prci.h>
28#include <linux/clkdev.h>
29#include <linux/clk-provider.h>
30#include <linux/clk/analogbits-wrpll-cln28hpc.h>
31#include <linux/delay.h>
32#include <linux/err.h>
33#include <linux/module.h>
34#include <linux/of.h>
35#include <linux/of_clk.h>
36#include <linux/platform_device.h>
37#include <linux/slab.h>
38
39/*
40 * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
41 * hfclk and rtcclk
42 */
43#define EXPECTED_CLK_PARENT_COUNT 2
44
45/*
46 * Register offsets and bitmasks
47 */
48
49/* COREPLLCFG0 */
50#define PRCI_COREPLLCFG0_OFFSET 0x4
51# define PRCI_COREPLLCFG0_DIVR_SHIFT 0
52# define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
53# define PRCI_COREPLLCFG0_DIVF_SHIFT 6
54# define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
55# define PRCI_COREPLLCFG0_DIVQ_SHIFT 15
56# define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
57# define PRCI_COREPLLCFG0_RANGE_SHIFT 18
58# define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
59# define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
60# define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
61# define PRCI_COREPLLCFG0_FSE_SHIFT 25
62# define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
63# define PRCI_COREPLLCFG0_LOCK_SHIFT 31
64# define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
65
66/* DDRPLLCFG0 */
67#define PRCI_DDRPLLCFG0_OFFSET 0xc
68# define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
69# define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
70# define PRCI_DDRPLLCFG0_DIVF_SHIFT 6
71# define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
72# define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15
73# define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
74# define PRCI_DDRPLLCFG0_RANGE_SHIFT 18
75# define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
76# define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24
77# define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
78# define PRCI_DDRPLLCFG0_FSE_SHIFT 25
79# define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
80# define PRCI_DDRPLLCFG0_LOCK_SHIFT 31
81# define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
82
83/* DDRPLLCFG1 */
84#define PRCI_DDRPLLCFG1_OFFSET 0x10
85# define PRCI_DDRPLLCFG1_CKE_SHIFT 24
86# define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
87
88/* GEMGXLPLLCFG0 */
89#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
90# define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
91# define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
92# define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
93# define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
94# define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
95# define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
96# define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
97# define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
98# define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
99# define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
100# define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25
101# define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
102# define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
103# define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
104
105/* GEMGXLPLLCFG1 */
106#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
107# define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24
108# define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
109
110/* CORECLKSEL */
111#define PRCI_CORECLKSEL_OFFSET 0x24
112# define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
113# define PRCI_CORECLKSEL_CORECLKSEL_MASK (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
114
115/* DEVICESRESETREG */
116#define PRCI_DEVICESRESETREG_OFFSET 0x28
117# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0
118# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
119# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1
120# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
121# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2
122# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
123# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3
124# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
125# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5
126# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
127
128/* CLKMUXSTATUSREG */
129#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
130# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
131# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
132
133/*
134 * Private structures
135 */
136
137/**
138 * struct __prci_data - per-device-instance data
139 * @va: base virtual address of the PRCI IP block
140 * @hw_clks: encapsulates struct clk_hw records
141 *
142 * PRCI per-device instance data
143 */
144struct __prci_data {
145 void __iomem *va;
146 struct clk_hw_onecell_data hw_clks;
147};
148
149/**
150 * struct __prci_wrpll_data - WRPLL configuration and integration data
151 * @c: WRPLL current configuration record
152 * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
153 * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
154 * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
155 *
156 * @enable_bypass and @disable_bypass are used for WRPLL instances
157 * that contain a separate external glitchless clock mux downstream
158 * from the PLL. The WRPLL internal bypass mux is not glitchless.
159 */
160struct __prci_wrpll_data {
161 struct wrpll_cfg c;
162 void (*enable_bypass)(struct __prci_data *pd);
163 void (*disable_bypass)(struct __prci_data *pd);
164 u8 cfg0_offs;
165};
166
167/**
168 * struct __prci_clock - describes a clock device managed by PRCI
169 * @name: user-readable clock name string - should match the manual
170 * @parent_name: parent name for this clock
171 * @ops: struct clk_ops for the Linux clock framework to use for control
172 * @hw: Linux-private clock data
173 * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
174 * @pd: PRCI-specific data associated with this clock (if not NULL)
175 *
176 * PRCI clock data. Used by the PRCI driver to register PRCI-provided
177 * clocks to the Linux clock infrastructure.
178 */
179struct __prci_clock {
180 const char *name;
181 const char *parent_name;
182 const struct clk_ops *ops;
183 struct clk_hw hw;
184 struct __prci_wrpll_data *pwd;
185 struct __prci_data *pd;
186};
187
188#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
189
190/*
191 * Private functions
192 */
193
194/**
195 * __prci_readl() - read from a PRCI register
196 * @pd: PRCI context
197 * @offs: register offset to read from (in bytes, from PRCI base address)
198 *
199 * Read the register located at offset @offs from the base virtual
200 * address of the PRCI register target described by @pd, and return
201 * the value to the caller.
202 *
203 * Context: Any context.
204 *
205 * Return: the contents of the register described by @pd and @offs.
206 */
207static u32 __prci_readl(struct __prci_data *pd, u32 offs)
208{
209 return readl_relaxed(pd->va + offs);
210}
211
212static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
213{
214 writel_relaxed(v, pd->va + offs);
215}
216
217/* WRPLL-related private functions */
218
219/**
220 * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
221 * @c: ptr to a struct wrpll_cfg record to write config into
222 * @r: value read from the PRCI PLL configuration register
223 *
224 * Given a value @r read from an FU540 PRCI PLL configuration register,
225 * split it into fields and populate it into the WRPLL configuration record
226 * pointed to by @c.
227 *
228 * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
229 * have the same register layout.
230 *
231 * Context: Any context.
232 */
233static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
234{
235 u32 v;
236
237 v = r & PRCI_COREPLLCFG0_DIVR_MASK;
238 v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
239 c->divr = v;
240
241 v = r & PRCI_COREPLLCFG0_DIVF_MASK;
242 v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
243 c->divf = v;
244
245 v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
246 v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
247 c->divq = v;
248
249 v = r & PRCI_COREPLLCFG0_RANGE_MASK;
250 v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
251 c->range = v;
252
253 c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
254 WRPLL_FLAGS_EXT_FEEDBACK_MASK);
255
256 /* external feedback mode not supported */
257 c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
258}
259
260/**
261 * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
262 * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
263 *
264 * Using a set of WRPLL configuration values pointed to by @c,
265 * assemble a PRCI PLL configuration register value, and return it to
266 * the caller.
267 *
268 * Context: Any context. Caller must ensure that the contents of the
269 * record pointed to by @c do not change during the execution
270 * of this function.
271 *
272 * Returns: a value suitable for writing into a PRCI PLL configuration
273 * register
274 */
275static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
276{
277 u32 r = 0;
278
279 r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
280 r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
281 r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
282 r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
283
284 /* external feedback mode not supported */
285 r |= PRCI_COREPLLCFG0_FSE_MASK;
286
287 return r;
288}
289
290/**
291 * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
292 * @pd: PRCI context
293 * @pwd: PRCI WRPLL metadata
294 *
295 * Read the current configuration of the PLL identified by @pwd from
296 * the PRCI identified by @pd, and store it into the local configuration
297 * cache in @pwd.
298 *
299 * Context: Any context. Caller must prevent the records pointed to by
300 * @pd and @pwd from changing during execution.
301 */
302static void __prci_wrpll_read_cfg(struct __prci_data *pd,
303 struct __prci_wrpll_data *pwd)
304{
305 __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
306}
307
308/**
309 * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
310 * @pd: PRCI context
311 * @pwd: PRCI WRPLL metadata
312 * @c: WRPLL configuration record to write
313 *
314 * Write the WRPLL configuration described by @c into the WRPLL
315 * configuration register identified by @pwd in the PRCI instance
316 * described by @c. Make a cached copy of the WRPLL's current
317 * configuration so it can be used by other code.
318 *
319 * Context: Any context. Caller must prevent the records pointed to by
320 * @pd and @pwd from changing during execution.
321 */
322static void __prci_wrpll_write_cfg(struct __prci_data *pd,
323 struct __prci_wrpll_data *pwd,
324 struct wrpll_cfg *c)
325{
326 __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
327
328 memcpy(&pwd->c, c, sizeof(*c));
329}
330
331/* Core clock mux control */
332
333/**
334 * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
335 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
336 *
337 * Switch the CORECLK mux to the HFCLK input source; return once complete.
338 *
339 * Context: Any context. Caller must prevent concurrent changes to the
340 * PRCI_CORECLKSEL_OFFSET register.
341 */
342static void __prci_coreclksel_use_hfclk(struct __prci_data *pd)
343{
344 u32 r;
345
346 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
347 r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
348 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
349
350 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
351}
352
353/**
354 * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
355 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
356 *
357 * Switch the CORECLK mux to the PLL output clock; return once complete.
358 *
359 * Context: Any context. Caller must prevent concurrent changes to the
360 * PRCI_CORECLKSEL_OFFSET register.
361 */
362static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
363{
364 u32 r;
365
366 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
367 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
368 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
369
370 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
371}
372
373/*
374 * Linux clock framework integration
375 *
376 * See the Linux clock framework documentation for more information on
377 * these functions.
378 */
379
380static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw,
381 unsigned long parent_rate)
382{
383 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
384 struct __prci_wrpll_data *pwd = pc->pwd;
385
386 return wrpll_calc_output_rate(&pwd->c, parent_rate);
387}
388
389static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw,
390 unsigned long rate,
391 unsigned long *parent_rate)
392{
393 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
394 struct __prci_wrpll_data *pwd = pc->pwd;
395 struct wrpll_cfg c;
396
397 memcpy(&c, &pwd->c, sizeof(c));
398
399 wrpll_configure_for_rate(&c, rate, *parent_rate);
400
401 return wrpll_calc_output_rate(&c, *parent_rate);
402}
403
404static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw,
405 unsigned long rate,
406 unsigned long parent_rate)
407{
408 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
409 struct __prci_wrpll_data *pwd = pc->pwd;
410 struct __prci_data *pd = pc->pd;
411 int r;
412
413 r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
414 if (r)
415 return r;
416
417 if (pwd->enable_bypass)
418 pwd->enable_bypass(pd);
419
420 __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
421
422 udelay(wrpll_calc_max_lock_us(&pwd->c));
423
424 if (pwd->disable_bypass)
425 pwd->disable_bypass(pd);
426
427 return 0;
428}
429
430static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
431 .set_rate = sifive_fu540_prci_wrpll_set_rate,
432 .round_rate = sifive_fu540_prci_wrpll_round_rate,
433 .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
434};
435
436static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
437 .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
438};
439
440/* TLCLKSEL clock integration */
441
442static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw,
443 unsigned long parent_rate)
444{
445 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
446 struct __prci_data *pd = pc->pd;
447 u32 v;
448 u8 div;
449
450 v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
451 v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
452 div = v ? 1 : 2;
453
454 return div_u64(parent_rate, div);
455}
456
457static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = {
458 .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
459};
460
461/*
462 * PRCI integration data for each WRPLL instance
463 */
464
465static struct __prci_wrpll_data __prci_corepll_data = {
466 .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
467 .enable_bypass = __prci_coreclksel_use_hfclk,
468 .disable_bypass = __prci_coreclksel_use_corepll,
469};
470
471static struct __prci_wrpll_data __prci_ddrpll_data = {
472 .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
473};
474
475static struct __prci_wrpll_data __prci_gemgxlpll_data = {
476 .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
477};
478
479/*
480 * List of clock controls provided by the PRCI
481 */
482
483static struct __prci_clock __prci_init_clocks[] = {
484 [PRCI_CLK_COREPLL] = {
485 .name = "corepll",
486 .parent_name = "hfclk",
487 .ops = &sifive_fu540_prci_wrpll_clk_ops,
488 .pwd = &__prci_corepll_data,
489 },
490 [PRCI_CLK_DDRPLL] = {
491 .name = "ddrpll",
492 .parent_name = "hfclk",
493 .ops = &sifive_fu540_prci_wrpll_ro_clk_ops,
494 .pwd = &__prci_ddrpll_data,
495 },
496 [PRCI_CLK_GEMGXLPLL] = {
497 .name = "gemgxlpll",
498 .parent_name = "hfclk",
499 .ops = &sifive_fu540_prci_wrpll_clk_ops,
500 .pwd = &__prci_gemgxlpll_data,
501 },
502 [PRCI_CLK_TLCLK] = {
503 .name = "tlclk",
504 .parent_name = "corepll",
505 .ops = &sifive_fu540_prci_tlclksel_clk_ops,
506 },
507};
508
509/**
510 * __prci_register_clocks() - register clock controls in the PRCI with Linux
511 * @dev: Linux struct device *
512 *
513 * Register the list of clock controls described in __prci_init_plls[] with
514 * the Linux clock framework.
515 *
516 * Return: 0 upon success or a negative error code upon failure.
517 */
518static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
519{
520 struct clk_init_data init = { };
521 struct __prci_clock *pic;
522 int parent_count, i, r;
523
524 parent_count = of_clk_get_parent_count(dev->of_node);
525 if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
526 dev_err(dev, "expected only two parent clocks, found %d\n",
527 parent_count);
528 return -EINVAL;
529 }
530
531 /* Register PLLs */
532 for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
533 pic = &__prci_init_clocks[i];
534
535 init.name = pic->name;
536 init.parent_names = &pic->parent_name;
537 init.num_parents = 1;
538 init.ops = pic->ops;
539 pic->hw.init = &init;
540
541 pic->pd = pd;
542
543 if (pic->pwd)
544 __prci_wrpll_read_cfg(pd, pic->pwd);
545
546 r = devm_clk_hw_register(dev, &pic->hw);
547 if (r) {
548 dev_warn(dev, "Failed to register clock %s: %d\n",
549 init.name, r);
550 return r;
551 }
552
553 r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
554 if (r) {
555 dev_warn(dev, "Failed to register clkdev for %s: %d\n",
556 init.name, r);
557 return r;
558 }
559
560 pd->hw_clks.hws[i] = &pic->hw;
561 }
562
563 pd->hw_clks.num = i;
564
565 r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
566 &pd->hw_clks);
567 if (r) {
568 dev_err(dev, "could not add hw_provider: %d\n", r);
569 return r;
570 }
571
572 return 0;
573}
574
575/*
576 * Linux device model integration
577 *
578 * See the Linux device model documentation for more information about
579 * these functions.
580 */
581static int sifive_fu540_prci_probe(struct platform_device *pdev)
582{
583 struct device *dev = &pdev->dev;
584 struct resource *res;
585 struct __prci_data *pd;
586 int r;
587
588 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
589 if (!pd)
590 return -ENOMEM;
591
592 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
593 pd->va = devm_ioremap_resource(dev, res);
594 if (IS_ERR(pd->va))
595 return PTR_ERR(pd->va);
596
597 r = __prci_register_clocks(dev, pd);
598 if (r) {
599 dev_err(dev, "could not register clocks: %d\n", r);
600 return r;
601 }
602
603 dev_dbg(dev, "SiFive FU540 PRCI probed\n");
604
605 return 0;
606}
607
608static const struct of_device_id sifive_fu540_prci_of_match[] = {
609 { .compatible = "sifive,fu540-c000-prci", },
610 {}
611};
612MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match);
613
614static struct platform_driver sifive_fu540_prci_driver = {
615 .driver = {
616 .name = "sifive-fu540-prci",
617 .of_match_table = sifive_fu540_prci_of_match,
618 },
619 .probe = sifive_fu540_prci_probe,
620};
621
622static int __init sifive_fu540_prci_init(void)
623{
624 return platform_driver_register(&sifive_fu540_prci_driver);
625}
626core_initcall(sifive_fu540_prci_init);
drivers/clk/sprd/common.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2//2//
3// Spreadtrum clock infrastructure3// Spreadtrum clock infrastructure
4//4//
drivers/clk/sprd/composite.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2//2//
3// Spreadtrum composite clock driver3// Spreadtrum composite clock driver
4//4//
drivers/clk/sprd/div.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2//2//
3// Spreadtrum divider clock driver3// Spreadtrum divider clock driver
4//4//
drivers/clk/sprd/gate.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2//2//
3// Spreadtrum gate clock driver3// Spreadtrum gate clock driver
4//4//
drivers/clk/sprd/mux.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2//2//
3// Spreadtrum multiplexer clock driver3// Spreadtrum multiplexer clock driver
4//4//
drivers/clk/sprd/pll.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2//2//
3// Spreadtrum pll clock driver3// Spreadtrum pll clock driver
4//4//
drivers/clk/sunxi-ng/ccu-sun50i-h6.h+1−1
@@ -1,4 +1,4 @@
1// SPDX-License-Identifier: GPL-2.01/* SPDX-License-Identifier: GPL-2.0 */
2/*2/*
3 * Copyright 2016 Icenowy Zheng <icenowy@aosc.io>3 * Copyright 2016 Icenowy Zheng <icenowy@aosc.io>
4 */4 */
drivers/clk/sunxi-ng/ccu-suniv-f1c100s.h+2−2
@@ -1,5 +1,5 @@
1/* SPDX-License-Identifier: GPL-2.0+1/* SPDX-License-Identifier: GPL-2.0+ */
2 *2/*
3 * Copyright 2017 Icenowy Zheng <icenowy@aosc.io>3 * Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
4 *4 *
5 */5 */
drivers/clk/tegra/clk-divider.c+2−1
@@ -175,6 +175,7 @@ struct clk *tegra_clk_register_mc(const char *name, const char *parent_name, · 174 unmodified lines
175 void __iomem *reg, spinlock_t *lock)175 void __iomem *reg, spinlock_t *lock)
176{176{
177 return clk_register_divider_table(NULL, name, parent_name,177 return clk_register_divider_table(NULL, name, parent_name,
178 CLK_IS_CRITICAL, reg, 16, 1, 0,178 CLK_IS_CRITICAL,
179 reg, 16, 1, CLK_DIVIDER_READ_ONLY,
179 mc_div_table, lock);180 mc_div_table, lock);
180}181}
drivers/clk/tegra/clk-emc.c+35−22
@@ -121,18 +121,28 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) · 120 unmodified lines
121 struct tegra_clk_emc *tegra;121 struct tegra_clk_emc *tegra;
122 u8 ram_code = tegra_read_ram_code();122 u8 ram_code = tegra_read_ram_code();
123 struct emc_timing *timing = NULL;123 struct emc_timing *timing = NULL;
124 int i;124 int i, k, t;
125 125
126 tegra = container_of(hw, struct tegra_clk_emc, hw);126 tegra = container_of(hw, struct tegra_clk_emc, hw);
127 127
128 for (i = 0; i < tegra->num_timings; i++) {128 for (k = 0; k < tegra->num_timings; k++) {
129 if (tegra->timings[i].ram_code != ram_code)129 if (tegra->timings[k].ram_code == ram_code)
130 continue;130 break;
131 }
132
133 for (t = k; t < tegra->num_timings; t++) {
134 if (tegra->timings[t].ram_code != ram_code)
135 break;
136 }
131 137
138 for (i = k; i < t; i++) {
132 timing = tegra->timings + i;139 timing = tegra->timings + i;
133 140
141 if (timing->rate < req->rate && i != t - 1)
142 continue;
143
134 if (timing->rate > req->max_rate) {144 if (timing->rate > req->max_rate) {
135 i = max(i, 1);145 i = max(i, k + 1);
136 req->rate = tegra->timings[i - 1].rate;146 req->rate = tegra->timings[i - 1].rate;
137 return 0;147 return 0;
138 }148 }
@@ -140,10 +150,8 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) · 1 unmodified line
140 if (timing->rate < req->min_rate)150 if (timing->rate < req->min_rate)
141 continue;151 continue;
142 152
143 if (timing->rate >= req->rate) {153 req->rate = timing->rate;
144 req->rate = timing->rate;154 return 0;
145 return 0;
146 }
147 }155 }
148 156
149 if (timing) {157 if (timing) {
@@ -214,7 +222,10 @@ static int emc_set_timing(struct tegra_clk_emc *tegra, · 64 unmodified lines
214 222
215 if (emc_get_parent(&tegra->hw) == timing->parent_index &&223 if (emc_get_parent(&tegra->hw) == timing->parent_index &&
216 clk_get_rate(timing->parent) != timing->parent_rate) {224 clk_get_rate(timing->parent) != timing->parent_rate) {
217 BUG();225 WARN_ONCE(1, "parent %s rate mismatch %lu %lu\n",
226 __clk_get_name(timing->parent),
227 clk_get_rate(timing->parent),
228 timing->parent_rate);
218 return -EINVAL;229 return -EINVAL;
219 }230 }
220 231
@@ -282,7 +293,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, · 61 unmodified lines
282 for (i = timing_index+1; i < tegra->num_timings; i++) {293 for (i = timing_index+1; i < tegra->num_timings; i++) {
283 timing = tegra->timings + i;294 timing = tegra->timings + i;
284 if (timing->ram_code != ram_code)295 if (timing->ram_code != ram_code)
285 continue;296 break;
286 297
287 if (emc_parent_clk_sources[timing->parent_index] !=298 if (emc_parent_clk_sources[timing->parent_index] !=
288 emc_parent_clk_sources[299 emc_parent_clk_sources[
@@ -293,7 +304,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, · 4 unmodified lines
293 for (i = timing_index-1; i >= 0; --i) {304 for (i = timing_index-1; i >= 0; --i) {
294 timing = tegra->timings + i;305 timing = tegra->timings + i;
295 if (timing->ram_code != ram_code)306 if (timing->ram_code != ram_code)
296 continue;307 break;
297 308
298 if (emc_parent_clk_sources[timing->parent_index] !=309 if (emc_parent_clk_sources[timing->parent_index] !=
299 emc_parent_clk_sources[310 emc_parent_clk_sources[
@@ -433,19 +444,23 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra, · 133 unmodified lines
433 struct device_node *node,444 struct device_node *node,
434 u32 ram_code)445 u32 ram_code)
435{446{
447 struct emc_timing *timings_ptr;
436 struct device_node *child;448 struct device_node *child;
437 int child_count = of_get_child_count(node);449 int child_count = of_get_child_count(node);
438 int i = 0, err;450 int i = 0, err;
451 size_t size;
439 452
440 tegra->timings = kcalloc(child_count, sizeof(struct emc_timing),453 size = (tegra->num_timings + child_count) * sizeof(struct emc_timing);
441 GFP_KERNEL);454
455 tegra->timings = krealloc(tegra->timings, size, GFP_KERNEL);
442 if (!tegra->timings)456 if (!tegra->timings)
443 return -ENOMEM;457 return -ENOMEM;
444 458
445 tegra->num_timings = child_count;459 timings_ptr = tegra->timings + tegra->num_timings;
460 tegra->num_timings += child_count;
446 461
447 for_each_child_of_node(node, child) {462 for_each_child_of_node(node, child) {
448 struct emc_timing *timing = tegra->timings + (i++);463 struct emc_timing *timing = timings_ptr + (i++);
449 464
450 err = load_one_timing_from_dt(tegra, timing, child);465 err = load_one_timing_from_dt(tegra, timing, child);
451 if (err) {466 if (err) {
@@ -456,7 +471,7 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra, · 4 unmodified lines
456 timing->ram_code = ram_code;471 timing->ram_code = ram_code;
457 }472 }
458 473
459 sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing),474 sort(timings_ptr, child_count, sizeof(struct emc_timing),
460 cmp_timings, NULL);475 cmp_timings, NULL);
461 476
462 return 0;477 return 0;
@@ -499,10 +514,10 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, · 36 unmodified lines
499 * fuses until the apbmisc driver is loaded.514 * fuses until the apbmisc driver is loaded.
500 */515 */
501 err = load_timings_from_dt(tegra, node, node_ram_code);516 err = load_timings_from_dt(tegra, node, node_ram_code);
502 of_node_put(node);517 if (err) {
503 if (err)518 of_node_put(node);
504 return ERR_PTR(err);519 return ERR_PTR(err);
505 break;520 }
506 }521 }
507 522
508 if (tegra->num_timings == 0)523 if (tegra->num_timings == 0)
@@ -532,7 +547,5 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, · 23 unmodified lines
532 /* Allow debugging tools to see the EMC clock */547 /* Allow debugging tools to see the EMC clock */
533 clk_register_clkdev(clk, "emc", "tegra-clk-debug");548 clk_register_clkdev(clk, "emc", "tegra-clk-debug");
534 549
535 clk_prepare_enable(clk);
536
537 return clk;550 return clk;
538};551};
drivers/clk/tegra/clk-pll.c+39−15
@@ -444,6 +444,9 @@ static int clk_pll_enable(struct clk_hw *hw) · 443 unmodified lines
444 unsigned long flags = 0;444 unsigned long flags = 0;
445 int ret;445 int ret;
446 446
447 if (clk_pll_is_enabled(hw))
448 return 0;
449
447 if (pll->lock)450 if (pll->lock)
448 spin_lock_irqsave(pll->lock, flags);451 spin_lock_irqsave(pll->lock, flags);
449 452
@@ -663,8 +666,8 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll, · 213 unmodified lines
663 pll_override_writel(val, params->pmc_divp_reg, pll);666 pll_override_writel(val, params->pmc_divp_reg, pll);
664 667
665 val = pll_override_readl(params->pmc_divnm_reg, pll);668 val = pll_override_readl(params->pmc_divnm_reg, pll);
666 val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) |669 val &= ~((divm_mask(pll) << div_nmp->override_divm_shift) |
667 ~(divn_mask(pll) << div_nmp->override_divn_shift);670 (divn_mask(pll) << div_nmp->override_divn_shift));
668 val |= (cfg->m << div_nmp->override_divm_shift) |671 val |= (cfg->m << div_nmp->override_divm_shift) |
669 (cfg->n << div_nmp->override_divn_shift);672 (cfg->n << div_nmp->override_divn_shift);
670 pll_override_writel(val, params->pmc_divnm_reg, pll);673 pll_override_writel(val, params->pmc_divnm_reg, pll);
@@ -940,11 +943,16 @@ static int clk_plle_training(struct tegra_clk_pll *pll) · 269 unmodified lines
940static int clk_plle_enable(struct clk_hw *hw)943static int clk_plle_enable(struct clk_hw *hw)
941{944{
942 struct tegra_clk_pll *pll = to_clk_pll(hw);945 struct tegra_clk_pll *pll = to_clk_pll(hw);
943 unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
944 struct tegra_clk_pll_freq_table sel;946 struct tegra_clk_pll_freq_table sel;
947 unsigned long input_rate;
945 u32 val;948 u32 val;
946 int err;949 int err;
947 950
951 if (clk_pll_is_enabled(hw))
952 return 0;
953
954 input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
955
948 if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))956 if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
949 return -EINVAL;957 return -EINVAL;
950 958
@@ -1355,6 +1363,9 @@ static int clk_pllc_enable(struct clk_hw *hw) · 404 unmodified lines
1355 int ret;1363 int ret;
1356 unsigned long flags = 0;1364 unsigned long flags = 0;
1357 1365
1366 if (clk_pll_is_enabled(hw))
1367 return 0;
1368
1358 if (pll->lock)1369 if (pll->lock)
1359 spin_lock_irqsave(pll->lock, flags);1370 spin_lock_irqsave(pll->lock, flags);
1360 1371
@@ -1567,7 +1578,12 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) · 206 unmodified lines
1567 u32 val;1578 u32 val;
1568 int ret;1579 int ret;
1569 unsigned long flags = 0;1580 unsigned long flags = 0;
1570 unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));1581 unsigned long input_rate;
1582
1583 if (clk_pll_is_enabled(hw))
1584 return 0;
1585
1586 input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
1571 1587
1572 if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))1588 if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
1573 return -EINVAL;1589 return -EINVAL;
@@ -1704,6 +1720,9 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw) · 130 unmodified lines
1704 return -EINVAL;1720 return -EINVAL;
1705 }1721 }
1706 1722
1723 if (clk_pll_is_enabled(hw))
1724 return 0;
1725
1707 input_rate = clk_hw_get_rate(__clk_get_hw(osc));1726 input_rate = clk_hw_get_rate(__clk_get_hw(osc));
1708 1727
1709 if (pll->lock)1728 if (pll->lock)
@@ -2379,6 +2398,16 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name, · 669 unmodified lines
2379 return clk;2398 return clk;
2380}2399}
2381 2400
2401static int clk_plle_tegra210_is_enabled(struct clk_hw *hw)
2402{
2403 struct tegra_clk_pll *pll = to_clk_pll(hw);
2404 u32 val;
2405
2406 val = pll_readl_base(pll);
2407
2408 return val & PLLE_BASE_ENABLE ? 1 : 0;
2409}
2410
2382static int clk_plle_tegra210_enable(struct clk_hw *hw)2411static int clk_plle_tegra210_enable(struct clk_hw *hw)
2383{2412{
2384 struct tegra_clk_pll *pll = to_clk_pll(hw);2413 struct tegra_clk_pll *pll = to_clk_pll(hw);
@@ -2386,7 +2415,12 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw) · 1 unmodified line
2386 u32 val;2415 u32 val;
2387 int ret = 0;2416 int ret = 0;
2388 unsigned long flags = 0;2417 unsigned long flags = 0;
2389 unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));2418 unsigned long input_rate;
2419
2420 if (clk_plle_tegra210_is_enabled(hw))
2421 return 0;
2422
2423 input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
2390 2424
2391 if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))2425 if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
2392 return -EINVAL;2426 return -EINVAL;
@@ -2497,16 +2531,6 @@ out: · 104 unmodified lines
2497 spin_unlock_irqrestore(pll->lock, flags);2531 spin_unlock_irqrestore(pll->lock, flags);
2498}2532}
2499 2533
2500static int clk_plle_tegra210_is_enabled(struct clk_hw *hw)
2501{
2502 struct tegra_clk_pll *pll = to_clk_pll(hw);
2503 u32 val;
2504
2505 val = pll_readl_base(pll);
2506
2507 return val & PLLE_BASE_ENABLE ? 1 : 0;
2508}
2509
2510static const struct clk_ops tegra_clk_plle_tegra210_ops = {2534static const struct clk_ops tegra_clk_plle_tegra210_ops = {
2511 .is_enabled = clk_plle_tegra210_is_enabled,2535 .is_enabled = clk_plle_tegra210_is_enabled,
2512 .enable = clk_plle_tegra210_enable,2536 .enable = clk_plle_tegra210_enable,
drivers/clk/tegra/clk-tegra124.c+1−2
@@ -413,7 +413,6 @@ static struct tegra_clk_pll_params pll_m_params = { · 412 unmodified lines
413 .base_reg = PLLM_BASE,413 .base_reg = PLLM_BASE,
414 .misc_reg = PLLM_MISC,414 .misc_reg = PLLM_MISC,
415 .lock_mask = PLL_BASE_LOCK,415 .lock_mask = PLL_BASE_LOCK,
416 .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
417 .lock_delay = 300,416 .lock_delay = 300,
418 .max_p = 5,417 .max_p = 5,
419 .pdiv_tohw = pllm_p,418 .pdiv_tohw = pllm_p,
@@ -421,7 +420,7 @@ static struct tegra_clk_pll_params pll_m_params = { · 1 unmodified line
421 .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,420 .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
422 .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,421 .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
423 .freq_table = pll_m_freq_table,422 .freq_table = pll_m_freq_table,
424 .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,423 .flags = TEGRA_PLL_USE_LOCK,
425};424};
426 425
427static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {426static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
include/dt-bindings/clock/stm32fx-clock.h+5−2
@@ -54,7 +54,10 @@ · 53 unmodified lines
54#define CLK_I2C3 2854#define CLK_I2C3 28
55#define CLK_I2C4 2955#define CLK_I2C4 29
56#define CLK_LPTIMER 3056#define CLK_LPTIMER 30
57 57#define CLK_PLL_SRC 31
58#define END_PRIMARY_CLK_F7 3158#define CLK_DFSDM1 32
59#define CLK_ADFSDM1 33
60#define CLK_F769_DSI 34
61#define END_PRIMARY_CLK_F7 35
59 62
60#endif63#endif
include/linux/clk/analogbits-wrpll-cln28hpc.h+79−0
@@ -0,0 +1,79 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2018-2019 SiFive, Inc.
4 * Wesley Terpstra
5 * Paul Walmsley
6 */
7
8#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
9#define __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
10
11#include <linux/types.h>
12
13/* DIVQ_VALUES: number of valid DIVQ values */
14#define DIVQ_VALUES 6
15
16/*
17 * Bit definitions for struct wrpll_cfg.flags
18 *
19 * WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be
20 * programmed to enter bypass
21 * WRPLL_FLAGS_RESET_FLAG: if set, the PLL is in reset
22 * WRPLL_FLAGS_INT_FEEDBACK_FLAG: if set, the PLL is configured for internal
23 * feedback mode
24 * WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external
25 * feedback mode (not yet supported by this driver)
26 */
27#define WRPLL_FLAGS_BYPASS_SHIFT 0
28#define WRPLL_FLAGS_BYPASS_MASK BIT(WRPLL_FLAGS_BYPASS_SHIFT)
29#define WRPLL_FLAGS_RESET_SHIFT 1
30#define WRPLL_FLAGS_RESET_MASK BIT(WRPLL_FLAGS_RESET_SHIFT)
31#define WRPLL_FLAGS_INT_FEEDBACK_SHIFT 2
32#define WRPLL_FLAGS_INT_FEEDBACK_MASK BIT(WRPLL_FLAGS_INT_FEEDBACK_SHIFT)
33#define WRPLL_FLAGS_EXT_FEEDBACK_SHIFT 3
34#define WRPLL_FLAGS_EXT_FEEDBACK_MASK BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT)
35
36/**
37 * struct wrpll_cfg - WRPLL configuration values
38 * @divr: reference divider value (6 bits), as presented to the PLL signals
39 * @divf: feedback divider value (9 bits), as presented to the PLL signals
40 * @divq: output divider value (3 bits), as presented to the PLL signals
41 * @flags: PLL configuration flags. See above for more information
42 * @range: PLL loop filter range. See below for more information
43 * @output_rate_cache: cached output rates, swept across DIVQ
44 * @parent_rate: PLL refclk rate for which values are valid
45 * @max_r: maximum possible R divider value, given @parent_rate
46 * @init_r: initial R divider value to start the search from
47 *
48 * @divr, @divq, @divq, @range represent what the PLL expects to see
49 * on its input signals. Thus @divr and @divf are the actual divisors
50 * minus one. @divq is a power-of-two divider; for example, 1 =
51 * divide-by-2 and 6 = divide-by-64. 0 is an invalid @divq value.
52 *
53 * When initially passing a struct wrpll_cfg record, the
54 * record should be zero-initialized with the exception of the @flags
55 * field. The only flag bits that need to be set are either
56 * WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK.
57 */
58struct wrpll_cfg {
59 u8 divr;
60 u8 divq;
61 u8 range;
62 u8 flags;
63 u16 divf;
64/* private: */
65 u32 output_rate_cache[DIVQ_VALUES];
66 unsigned long parent_rate;
67 u8 max_r;
68 u8 init_r;
69};
70
71int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
72 unsigned long parent_rate);
73
74unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c);
75
76unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
77 unsigned long parent_rate);
78
79#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */
include/linux/clk/at91_pmc.h+3−9
@@ -74,6 +74,8 @@ · 73 unmodified lines
74#define AT91_PMC_USBDIV_4 (2 << 28)74#define AT91_PMC_USBDIV_4 (2 << 28)
75#define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */75#define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */
76 76
77#define AT91_PMC_CPU_CKR 0x28 /* CPU Clock Register */
78
77#define AT91_PMC_MCKR 0x30 /* Master Clock Register */79#define AT91_PMC_MCKR 0x30 /* Master Clock Register */
78#define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */80#define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */
79#define AT91_PMC_CSS_SLOW (0 << 0)81#define AT91_PMC_CSS_SLOW (0 << 0)
@@ -187,16 +189,8 @@ · 107 unmodified lines
187 189
188#define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */190#define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */
189#define AT91_PMC_PCR_PID_MASK 0x3f191#define AT91_PMC_PCR_PID_MASK 0x3f
190#define AT91_PMC_PCR_GCKCSS_OFFSET 8
191#define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET)
192#define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */
193#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */192#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */
194#define AT91_PMC_PCR_DIV_OFFSET 16193#define AT91_PMC_PCR_GCKDIV_MASK GENMASK(27, 20)
195#define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET)
196#define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */
197#define AT91_PMC_PCR_GCKDIV_OFFSET 20
198#define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET)
199#define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */
200#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */194#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */
201#define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */195#define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */
202 196

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t