]> git.codelabs.ch Git - muen/linux.git/commitdiff
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Sep 2017 19:24:20 +0000 (12:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Sep 2017 19:24:20 +0000 (12:24 -0700)
Pull perf fixes from Ingo Molnar:
 "A handful of tooling fixes"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf stat: Wait for the correct child
  perf tools: Support running perf binaries with a dash in their name
  perf config: Check not only section->from_system_config but also item's
  perf ui progress: Fix progress update
  perf ui progress: Make sure we always define step value
  perf tools: Open perf.data with O_CLOEXEC flag
  tools lib api: Fix make DEBUG=1 build
  perf tests: Fix compile when libunwind's unwind.h is available
  tools include linux: Guard against redefinition of some macros

246 files changed:
Documentation/conf.py
Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt
Documentation/devicetree/bindings/clock/at91-clock.txt
Documentation/devicetree/bindings/clock/idt,versaclock5.txt
Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/rockchip,rk3128-cru.txt
Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/snps,pll-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi-ccu.txt
Documentation/devicetree/bindings/clock/uniphier-clock.txt
Documentation/devicetree/bindings/power/wakeup-source.txt
Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/isil,isl12057.txt
Documentation/devicetree/bindings/rtc/realtek,rtd119x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
Documentation/devicetree/bindings/sound/atmel-classd.txt
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
Documentation/translations/ko_KR/memory-barriers.txt
MAINTAINERS
arch/arm/mach-at91/Kconfig
arch/openrisc/include/asm/pgtable.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/special_insns.h
arch/x86/include/uapi/asm/hyperv.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kvm/vmx.c
arch/x86/mm/init.c
arch/x86/mm/pgtable.c
arch/x86/mm/tlb.c
arch/x86/power/hibernate_64.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/mmu_pv.c
block/blk-core.c
block/blk-lib.c
block/blk-mq.c
block/blk-mq.h
block/opal_proto.h
block/sed-opal.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/Makefile
drivers/clk/at91/clk-audio-pll.c [new file with mode: 0644]
drivers/clk/at91/clk-generated.c
drivers/clk/axs10x/Makefile
drivers/clk/axs10x/pll_clock.c [new file with mode: 0644]
drivers/clk/berlin/bg2.c
drivers/clk/berlin/bg2q.c
drivers/clk/clk-asm9260.c
drivers/clk/clk-conf.c
drivers/clk/clk-cs2000-cp.c
drivers/clk/clk-divider.c
drivers/clk/clk-fractional-divider.c
drivers/clk/clk-gate.c
drivers/clk/clk-gemini.c
drivers/clk/clk-hsdk-pll.c [new file with mode: 0644]
drivers/clk/clk-mb86s7x.c [deleted file]
drivers/clk/clk-moxart.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-si5351.c
drivers/clk/clk-stm32f4.c
drivers/clk/clk-stm32h7.c [new file with mode: 0644]
drivers/clk/clk-versaclock5.c
drivers/clk/clk-xgene.c
drivers/clk/clk.c
drivers/clk/clkdev.c
drivers/clk/hisilicon/clk-hi6220.c
drivers/clk/imx/clk-imx51-imx53.c
drivers/clk/imx/clk-imx6sl.c
drivers/clk/imx/clk-imx6sx.c
drivers/clk/imx/clk-imx6ul.c
drivers/clk/imx/clk-imx7d.c
drivers/clk/imx/clk-vf610.c
drivers/clk/mediatek/clk-cpumux.c
drivers/clk/mediatek/clk-mtk.c
drivers/clk/mediatek/reset.c
drivers/clk/meson/Kconfig
drivers/clk/meson/Makefile
drivers/clk/meson/gxbb-aoclk-32k.c [new file with mode: 0644]
drivers/clk/meson/gxbb-aoclk-regmap.c [new file with mode: 0644]
drivers/clk/meson/gxbb-aoclk.c
drivers/clk/meson/gxbb-aoclk.h [new file with mode: 0644]
drivers/clk/meson/gxbb.c
drivers/clk/meson/meson8b.c
drivers/clk/meson/meson8b.h
drivers/clk/mmp/clk.c
drivers/clk/nxp/clk-lpc32xx.c
drivers/clk/qcom/clk-smd-rpm.c
drivers/clk/qcom/gcc-msm8916.c
drivers/clk/qcom/gcc-msm8996.c
drivers/clk/renesas/Kconfig
drivers/clk/renesas/Makefile
drivers/clk/renesas/clk-div6.c
drivers/clk/renesas/clk-mstp.c
drivers/clk/renesas/clk-rcar-gen2.c
drivers/clk/renesas/r8a7792-cpg-mssr.c
drivers/clk/renesas/r8a7795-cpg-mssr.c
drivers/clk/renesas/r8a7796-cpg-mssr.c
drivers/clk/renesas/r8a77995-cpg-mssr.c [new file with mode: 0644]
drivers/clk/renesas/rcar-gen3-cpg.c
drivers/clk/renesas/rcar-gen3-cpg.h
drivers/clk/renesas/rcar-usb2-clock-sel.c [new file with mode: 0644]
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/renesas/renesas-cpg-mssr.h
drivers/clk/rockchip/clk-rk3128.c
drivers/clk/rockchip/clk-rk3228.c
drivers/clk/rockchip/clk-rv1108.c
drivers/clk/rockchip/clk.c
drivers/clk/samsung/clk-exynos-audss.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/sunxi-ng/Kconfig
drivers/clk/sunxi-ng/Makefile
drivers/clk/sunxi-ng/ccu-sun4i-a10.c [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun4i-a10.h [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun5i.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/sunxi-ng/ccu-sun8i-a23.c
drivers/clk/sunxi-ng/ccu-sun8i-a33.c
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
drivers/clk/sunxi-ng/ccu-sun8i-r.c
drivers/clk/sunxi-ng/ccu-sun8i-r.h
drivers/clk/sunxi-ng/ccu-sun8i-r40.c [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun8i-r40.h [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
drivers/clk/sunxi-ng/ccu_div.c
drivers/clk/sunxi-ng/ccu_div.h
drivers/clk/sunxi-ng/ccu_frac.c
drivers/clk/sunxi-ng/ccu_frac.h
drivers/clk/sunxi-ng/ccu_mult.c
drivers/clk/sunxi-ng/ccu_nkm.c
drivers/clk/sunxi-ng/ccu_nkm.h
drivers/clk/sunxi-ng/ccu_nm.c
drivers/clk/sunxi/clk-sun8i-bus-gates.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/tegra/clk-emc.c
drivers/clk/tegra/clk-pll.c
drivers/clk/tegra/clk-tegra-periph.c
drivers/clk/tegra/clk-tegra-super-gen4.c
drivers/clk/tegra/clk-tegra210.c
drivers/clk/tegra/clk.h
drivers/clk/ti/adpll.c
drivers/clk/ti/apll.c
drivers/clk/ti/clockdomain.c
drivers/clk/ti/fapll.c
drivers/clk/uniphier/clk-uniphier-core.c
drivers/clk/uniphier/clk-uniphier-mio.c
drivers/clk/uniphier/clk-uniphier-sys.c
drivers/clk/uniphier/clk-uniphier.h
drivers/clk/ux500/clk-prcc.c
drivers/clk/ux500/clk-prcmu.c
drivers/clk/ux500/clk-sysctrl.c
drivers/clk/versatile/clk-vexpress-osc.c
drivers/clk/zte/clk-zx296718.c
drivers/nvme/host/core.c
drivers/nvme/host/lightnvm.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1672.c
drivers/rtc/rtc-em3027.c
drivers/rtc/rtc-goldfish.c [new file with mode: 0644]
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-max6900.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-puv3.c
drivers/rtc/rtc-pxa.c
drivers/rtc/rtc-rtd119x.c [new file with mode: 0644]
drivers/rtc/rtc-rv3029c2.c
drivers/rtc/rtc-s35390a.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sun6i.c
drivers/rtc/rtc-vr41xx.c
drivers/scsi/Kconfig
drivers/scsi/hosts.c
fs/fuse/cuse.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/inode.c
fs/internal.h
fs/namespace.c
fs/open.c
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/readdir.c
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/xattr.c
include/dt-bindings/clock/qcom,gcc-msm8996.h
include/dt-bindings/clock/r8a77995-cpg-mssr.h [new file with mode: 0644]
include/dt-bindings/clock/rk3228-cru.h
include/dt-bindings/clock/rv1108-cru.h
include/dt-bindings/clock/stm32h7-clks.h [new file with mode: 0644]
include/dt-bindings/clock/sun4i-a10-ccu.h [new file with mode: 0644]
include/dt-bindings/clock/sun7i-a20-ccu.h [new file with mode: 0644]
include/dt-bindings/clock/sun8i-r40-ccu.h [new file with mode: 0644]
include/dt-bindings/mfd/stm32h7-rcc.h [new file with mode: 0644]
include/dt-bindings/reset/sun4i-a10-ccu.h [new file with mode: 0644]
include/dt-bindings/reset/sun8i-r40-ccu.h [new file with mode: 0644]
include/linux/clk-provider.h
include/linux/clk/at91_pmc.h
include/linux/dcache.h
include/linux/fs.h
include/linux/module.h
include/linux/nvme.h
include/linux/rtc.h
include/linux/string.h
include/scsi/scsi_host.h
include/trace/events/block.h
kernel/module.c
kernel/sched/core.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/sched.h
kernel/sched/topology.c
mm/backing-dev.c
scripts/mod/modpost.c
scripts/sphinx-pre-install
sound/core/device.c
sound/core/seq_device.c
sound/firewire/motu/motu-stream.c
sound/pci/asihpi/asihpi.c
sound/pci/maestro3.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/soc/atmel/atmel-classd.c
sound/usb/6fire/chip.c
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usb_stream.c

index f9054ab60cb1117b12f0f15c07a8199bb3a0ab37..63857d33778ce253b0b90dea8198ddab52a2bbe7 100644 (file)
@@ -271,10 +271,29 @@ latex_elements = {
 
 # Additional stuff for the LaTeX preamble.
     'preamble': '''
-        \\usepackage{ifthen}
+       % Use some font with UTF-8 support with XeLaTeX
+        \\usepackage{fontspec}
+        \\setsansfont{DejaVu Serif}
+        \\setromanfont{DejaVu Sans}
+        \\setmonofont{DejaVu Sans Mono}
+
+     '''
+}
+
+# Fix reference escape troubles with Sphinx 1.4.x
+if major == 1 and minor > 3:
+    latex_elements['preamble']  += '\\renewcommand*{\\DUrole}[2]{ #2 }\n'
+
+if major == 1 and minor <= 4:
+    latex_elements['preamble']  += '\\usepackage[margin=0.5in, top=1in, bottom=1in]{geometry}'
+elif major == 1 and (minor > 5 or (minor == 5 and patch >= 3)):
+    latex_elements['sphinxsetup'] = 'hmargin=0.5in, vmargin=1in'
+    latex_elements['preamble']  += '\\fvset{fontsize=auto}\n'
 
-        % Allow generate some pages in landscape
-        \\usepackage{lscape}
+# Customize notice background colors on Sphinx < 1.6:
+if major == 1 and minor < 6:
+   latex_elements['preamble']  += '''
+        \\usepackage{ifthen}
 
         % Put notes in color and let them be inside a table
        \\definecolor{NoteColor}{RGB}{204,255,255}
@@ -325,27 +344,26 @@ latex_elements = {
         }
        \\makeatother
 
-       % Use some font with UTF-8 support with XeLaTeX
-        \\usepackage{fontspec}
-        \\setsansfont{DejaVu Serif}
-        \\setromanfont{DejaVu Sans}
-        \\setmonofont{DejaVu Sans Mono}
-
-       % To allow adjusting table sizes
-       \\usepackage{adjustbox}
-
      '''
-}
-
-# Fix reference escape troubles with Sphinx 1.4.x
-if major == 1 and minor > 3:
-    latex_elements['preamble']  += '\\renewcommand*{\\DUrole}[2]{ #2 }\n'
 
-if major == 1 and minor <= 4:
-    latex_elements['preamble']  += '\\usepackage[margin=0.5in, top=1in, bottom=1in]{geometry}'
-elif major == 1 and (minor > 5 or (minor == 5 and patch >= 3)):
-    latex_elements['sphinxsetup'] = 'hmargin=0.5in, vmargin=1in'
-    latex_elements['preamble']  += '\\fvset{fontsize=auto}\n'
+# With Sphinx 1.6, it is possible to change the Bg color directly
+# by using:
+#      \definecolor{sphinxnoteBgColor}{RGB}{204,255,255}
+#      \definecolor{sphinxwarningBgColor}{RGB}{255,204,204}
+#      \definecolor{sphinxattentionBgColor}{RGB}{255,255,204}
+#      \definecolor{sphinximportantBgColor}{RGB}{192,255,204}
+#
+# However, it require to use sphinx heavy box with:
+#
+#      \renewenvironment{sphinxlightbox} {%
+#              \\begin{sphinxheavybox}
+#      }
+#              \\end{sphinxheavybox}
+#      }
+#
+# Unfortunately, the implementation is buggy: if a note is inside a
+# table, it isn't displayed well. So, for now, let's use boring
+# black and white notes.
 
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title,
index faa6d8ac583412557118a53c3bebb22ea0ab159a..786dc39ca904ddd02ede6af5b7617fb9ef2e7d32 100644 (file)
@@ -5,9 +5,11 @@ controllers within the Always-On part of the SoC.
 
 Required Properties:
 
-- compatible: should be "amlogic,gxbb-aoclkc"
-- reg: physical base address of the clock controller and length of memory
-       mapped region.
+- compatible: value should be different for each SoC family as :
+       - GXBB (S905) : "amlogic,meson-gxbb-aoclkc"
+       - GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
+       - GXM (S912) : "amlogic,meson-gxm-aoclkc"
+       followed by the common "amlogic,meson-gx-aoclkc"
 
 - #clock-cells: should be 1.
 
@@ -23,14 +25,22 @@ to specify the reset which they consume. All available resets are defined as
 preprocessor macros in the dt-bindings/reset/gxbb-aoclkc.h header and can be
 used in device tree sources.
 
+Parent node should have the following properties :
+- compatible: "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd"
+- reg: base address and size of the AO system control register space.
+
 Example: AO Clock controller node:
 
-       clkc_AO: clock-controller@040 {
-               compatible = "amlogic,gxbb-aoclkc";
-               reg = <0x0 0x040 0x0 0x4>;
+ao_sysctrl: sys-ctrl@0 {
+       compatible = "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd";
+       reg =  <0x0 0x0 0x0 0x100>;
+
+       clkc_AO: clock-controller {
+               compatible = "amlogic,meson-gxbb-aoclkc", "amlogic,meson-gx-aoclkc";
                #clock-cells = <1>;
                #reset-cells = <1>;
        };
+};
 
 Example: UART controller node that consumes the clock and reset generated
   by the clock controller:
index 5f3ad65daf69d48b8fc0f6cffc59e4f4210293cc..51c259a92d0294e31be12a2b4552e074b7d38e70 100644 (file)
@@ -81,6 +81,16 @@ Required properties:
        "atmel,sama5d2-clk-generated":
                at91 generated clock
 
+       "atmel,sama5d2-clk-audio-pll-frac":
+               at91 audio fractional pll
+
+       "atmel,sama5d2-clk-audio-pll-pad":
+               at91 audio pll CLK_AUDIO output pin
+
+       "atmel,sama5d2-clk-audio-pll-pmc"
+               at91 audio pll output on AUDIOPLLCLK that feeds the PMC
+               and can be used by peripheral clock or generic clock
+
 Required properties for SCKC node:
 - reg : defines the IO memory reserved for the SCKC.
 - #size-cells : shall be 0 (reg is used to encode clk id).
index 53d7e50ed875ae0db438af18f9f3354c2548c705..05a245c9df08fe48738a1d3e27e6bd45711b4a50 100644 (file)
@@ -1,24 +1,32 @@
-Binding for IDT VersaClock5 programmable i2c clock generator.
+Binding for IDT VersaClock 5,6 programmable i2c clock generators.
 
-The IDT VersaClock5 are programmable i2c clock generators providing
-from 3 to 12 output clocks.
+The IDT VersaClock 5 and VersaClock 6 are programmable i2c clock
+generators providing from 3 to 12 output clocks.
 
 ==I2C device node==
 
 Required properties:
-- compatible:  shall be one of "idt,5p49v5923" , "idt,5p49v5933" ,
-               "idt,5p49v5935".
+- compatible:  shall be one of
+               "idt,5p49v5923"
+               "idt,5p49v5925"
+               "idt,5p49v5933"
+               "idt,5p49v5935"
+               "idt,5p49v6901"
 - reg:         i2c device address, shall be 0x68 or 0x6a.
 - #clock-cells:        from common clock binding; shall be set to 1.
 - clocks:      from common clock binding; list of parent clock handles,
-               - 5p49v5923: (required) either or both of XTAL or CLKIN
+               - 5p49v5923 and
+                 5p49v5925 and
+                 5p49v6901: (required) either or both of XTAL or CLKIN
                                        reference clock.
                - 5p49v5933 and
                - 5p49v5935: (optional) property not present (internal
                                        Xtal used) or CLKIN reference
                                        clock.
 - clock-names: from common clock binding; clock input names, can be
-               - 5p49v5923: (required) either or both of "xin", "clkin".
+               - 5p49v5923 and
+                 5p49v5925 and
+                 5p49v6901: (required) either or both of "xin", "clkin".
                - 5p49v5933 and
                - 5p49v5935: (optional) property not present or "clkin".
 
@@ -37,6 +45,7 @@ clock specifier, the following mapping applies:
        1 -- OUT1
        2 -- OUT4
 
+5P49V5925 and
 5P49V5935:
        0 -- OUT0_SEL_I2CB
        1 -- OUT1
@@ -44,6 +53,13 @@ clock specifier, the following mapping applies:
        3 -- OUT3
        4 -- OUT4
 
+5P49V6901:
+       0 -- OUT0_SEL_I2CB
+       1 -- OUT1
+       2 -- OUT2
+       3 -- OUT3
+       4 -- OUT4
+
 ==Example==
 
 /* 25MHz reference crystal */
index 707a686d8d3e1341376b9f94de0296e43ba6c77b..316e136865688b7c4fe0c6f1d7b23934d66634d1 100644 (file)
@@ -22,6 +22,7 @@ Required Properties:
       - "renesas,r8a7794-cpg-mssr" for the r8a7794 SoC (R-Car E2)
       - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3)
       - "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W)
+      - "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3)
 
   - reg: Base address and length of the memory resource used by the CPG/MSSR
     block
@@ -30,7 +31,7 @@ Required Properties:
     clock-names
   - clock-names: List of external parent clock names. Valid names are:
       - "extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794,
-                r8a7795, r8a7796)
+                r8a7795, r8a7796, r8a77995)
       - "extalr" (r8a7795, r8a7796)
       - "usb_extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7793, r8a7794)
 
diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt
new file mode 100644 (file)
index 0000000..e96e085
--- /dev/null
@@ -0,0 +1,55 @@
+* Renesas R-Car USB 2.0 clock selector
+
+This file provides information on what the device node for the R-Car USB 2.0
+clock selector.
+
+If you connect an external clock to the USB_EXTAL pin only, you should set
+the clock rate to "usb_extal" node only.
+If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module
+is not needed because this is default setting. (Of course, you can set the
+clock rates to both "usb_extal" and "usb_xtal" nodes.
+
+Case 1: An external clock connects to R-Car SoC
+       +----------+   +--- R-Car ---------------------+
+       |External  |---|USB_EXTAL ---> all usb channels|
+       |clock     |   |USB_XTAL                       |
+       +----------+   +-------------------------------+
+In this case, we need this driver with "usb_extal" clock.
+
+Case 2: An oscillator connects to R-Car SoC
+       +----------+   +--- R-Car ---------------------+
+       |Oscillator|---|USB_EXTAL -+-> all usb channels|
+       |          |---|USB_XTAL --+                   |
+       +----------+   +-------------------------------+
+In this case, we don't need this selector.
+
+Required properties:
+- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of
+             an R8A7795 SoC.
+             "renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of
+             an R8A7796 SoC.
+             "renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3
+             compatible device.
+
+             When compatible with the generic version, nodes must list the
+             SoC-specific version corresponding to the platform first
+             followed by the generic version.
+
+- reg: offset and length of the USB 2.0 clock selector register block.
+- clocks: A list of phandles and specifier pairs.
+- clock-names: Name of the clocks.
+ - The functional clock must be "ehci_ohci"
+ - The USB_EXTAL clock pin must be "usb_extal"
+ - The USB_XTAL clock pin must be "usb_xtal"
+- #clock-cells: Must be 0
+
+Example (R-Car H3):
+
+       usb2_clksel: clock-controller@e6590630 {
+               compatible = "renesas,r8a77950-rcar-usb2-clock-sel",
+                            "renesas,rcar-gen3-usb2-clock-sel";
+               reg = <0 0xe6590630 0 0x02>;
+               clocks = <&cpg CPG_MOD 703>, <&usb_extal>, <&usb_xtal>;
+               clock-names = "ehci_ohci", "usb_extal", "usb_xtal";
+               #clock-cells = <0>;
+       };
index 455a9a00a623155dea4acd74e47b2153871b8904..6f8744fd301b23609f924873f325b9fc4e0c98a0 100644 (file)
@@ -1,12 +1,14 @@
-* Rockchip RK3128 Clock and Reset Unit
+* Rockchip RK3126/RK3128 Clock and Reset Unit
 
-The RK3128 clock controller generates and supplies clock to various
+The RK3126/RK3128 clock controller generates and supplies clock to various
 controllers within the SoC and also implements a reset controller for SoC
 peripherals.
 
 Required Properties:
 
-- compatible: should be "rockchip,rk3128-cru"
+- compatible: should be "rockchip,rk3126-cru" or "rockchip,rk3128-cru"
+  "rockchip,rk3126-cru" - controller compatible with RK3126 SoC.
+  "rockchip,rk3128-cru" - controller compatible with RK3128 SoC.
 - reg: physical base address of the controller and length of memory mapped
   region.
 - #clock-cells: should be 1.
diff --git a/Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt
new file mode 100644 (file)
index 0000000..c56c755
--- /dev/null
@@ -0,0 +1,28 @@
+Binding for the HSDK Generic PLL clock
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible: should be "snps,hsdk-<name>-pll-clock"
+  "snps,hsdk-core-pll-clock"
+  "snps,hsdk-gp-pll-clock"
+  "snps,hsdk-hdmi-pll-clock"
+- reg : should contain base register location and length.
+- clocks: shall be the input parent clock phandle for the PLL.
+- #clock-cells: from common clock binding; Should always be set to 0.
+
+Example:
+       input_clk: input-clk {
+               clock-frequency = <33333333>;
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+       };
+
+       cpu_clk: cpu-clk@0 {
+               compatible = "snps,hsdk-core-pll-clock";
+               reg = <0x00 0x10>;
+               #clock-cells = <0>;
+               clocks = <&input_clk>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
new file mode 100644 (file)
index 0000000..11fe487
--- /dev/null
@@ -0,0 +1,28 @@
+Binding for the AXS10X Generic PLL clock
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible: should be "snps,axs10x-<name>-pll-clock"
+  "snps,axs10x-arc-pll-clock"
+  "snps,axs10x-pgu-pll-clock"
+- reg: should always contain 2 pairs address - length: first for PLL config
+registers and second for corresponding LOCK CGU register.
+- clocks: shall be the input parent clock phandle for the PLL.
+- #clock-cells: from common clock binding; Should always be set to 0.
+
+Example:
+       input-clk: input-clk {
+               clock-frequency = <33333333>;
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+       };
+
+       core-clk: core-clk@80 {
+               compatible = "snps,axs10x-arc-pll-clock";
+               reg = <0x80 0x10>, <0x100 0x10>;
+               #clock-cells = <0>;
+               clocks = <&input-clk>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
new file mode 100644 (file)
index 0000000..a135504
--- /dev/null
@@ -0,0 +1,71 @@
+STMicroelectronics STM32H7 Reset and Clock Controller
+=====================================================
+
+The RCC IP is both a reset and a clock controller.
+
+Please refer to clock-bindings.txt for common clock controller binding usage.
+Please also refer to reset.txt for common reset controller binding usage.
+
+Required properties:
+- compatible: Should be:
+  "st,stm32h743-rcc"
+
+- reg: should be register base and length as documented in the
+  datasheet
+
+- #reset-cells: 1, see below
+
+- #clock-cells : from common clock binding; shall be set to 1
+
+- clocks: External oscillator clock phandle
+  - high speed external clock signal (HSE)
+  - low speed external clock signal (LSE)
+  - external I2S clock (I2S_CKIN)
+
+Optional properties:
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+  write protection (RTC clock).
+
+Example:
+
+       rcc: reset-clock-controller@58024400 {
+               compatible = "st,stm32h743-rcc", "st,stm32-rcc";
+               reg = <0x58024400 0x400>;
+               #reset-cells = <1>;
+               #clock-cells = <2>;
+               clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s_ckin>;
+
+               st,syscfg = <&pwrcfg>;
+};
+
+The peripheral clock consumer should specify the desired clock by
+having the clock ID in its "clocks" phandle cell.
+
+Example:
+
+               timer5: timer@40000c00 {
+                       compatible = "st,stm32-timer";
+                       reg = <0x40000c00 0x400>;
+                       interrupts = <50>;
+                       clocks = <&rcc TIM5_CK>;
+               };
+
+Specifying softreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the reset device node and an index specifying
+which channel to use.
+The index is the bit number within the RCC registers bank, starting from RCC
+base address.
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
+Where bit_offset is the bit offset within the register.
+
+For example, for CRC reset:
+  crc = AHB4RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x88 / 4 * 32 + 19 = 1107
+
+Example:
+
+       timer2 {
+               resets  = <&rcc STM32H7_APB1L_RESET(TIM2)>;
+       };
index df9fad58facdc22b995e9066275cac3344724a6d..7eda08eb8a1e336cf0756baa62a91f21fd58bce6 100644 (file)
@@ -3,18 +3,24 @@ Allwinner Clock Control Unit Binding
 
 Required properties :
 - compatible: must contain one of the following compatibles:
+               - "allwinner,sun4i-a10-ccu"
+               - "allwinner,sun5i-a10s-ccu"
+               - "allwinner,sun5i-a13-ccu"
                - "allwinner,sun6i-a31-ccu"
+               - "allwinner,sun7i-a20-ccu"
                - "allwinner,sun8i-a23-ccu"
                - "allwinner,sun8i-a33-ccu"
                - "allwinner,sun8i-a83t-ccu"
                - "allwinner,sun8i-a83t-r-ccu"
                - "allwinner,sun8i-h3-ccu"
                - "allwinner,sun8i-h3-r-ccu"
++              - "allwinner,sun8i-r40-ccu"
                - "allwinner,sun8i-v3s-ccu"
                - "allwinner,sun9i-a80-ccu"
                - "allwinner,sun50i-a64-ccu"
                - "allwinner,sun50i-a64-r-ccu"
                - "allwinner,sun50i-h5-ccu"
+               - "nextthing,gr8-ccu"
 
 - reg: Must contain the registers base address and length
 - clocks: phandle to the oscillators feeding the CCU. Two are needed:
index 812163060fa3e4cb4e4f39fe22c9fbd2aeb41d9f..7b5f602765fe2fc318fef07c8c4ffc5168ddd5d8 100644 (file)
@@ -6,7 +6,6 @@ System clock
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-clock" - for sLD3 SoC.
     "socionext,uniphier-ld4-clock"  - for LD4 SoC.
     "socionext,uniphier-pro4-clock" - for Pro4 SoC.
     "socionext,uniphier-sld8-clock" - for sLD8 SoC.
@@ -14,6 +13,7 @@ Required properties:
     "socionext,uniphier-pxs2-clock" - for PXs2/LD6b SoC.
     "socionext,uniphier-ld11-clock" - for LD11 SoC.
     "socionext,uniphier-ld20-clock" - for LD20 SoC.
+    "socionext,uniphier-pxs3-clock" - for PXs3 SoC
 - #clock-cells: should be 1.
 
 Example:
@@ -48,7 +48,6 @@ Media I/O (MIO) clock, SD clock
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-mio-clock" - for sLD3 SoC.
     "socionext,uniphier-ld4-mio-clock"  - for LD4 SoC.
     "socionext,uniphier-pro4-mio-clock" - for Pro4 SoC.
     "socionext,uniphier-sld8-mio-clock" - for sLD8 SoC.
@@ -56,6 +55,7 @@ Required properties:
     "socionext,uniphier-pxs2-sd-clock"  - for PXs2/LD6b SoC.
     "socionext,uniphier-ld11-mio-clock" - for LD11 SoC.
     "socionext,uniphier-ld20-sd-clock"  - for LD20 SoC.
+    "socionext,uniphier-pxs3-sd-clock"  - for PXs3 SoC
 - #clock-cells: should be 1.
 
 Example:
@@ -82,11 +82,9 @@ Provided clocks:
  8: USB2 ch0 host
  9: USB2 ch1 host
 10: USB2 ch2 host
-11: USB2 ch3 host
 12: USB2 ch0 PHY
 13: USB2 ch1 PHY
 14: USB2 ch2 PHY
-15: USB2 ch3 PHY
 
 
 Peripheral clock
@@ -94,7 +92,6 @@ Peripheral clock
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-peri-clock" - for sLD3 SoC.
     "socionext,uniphier-ld4-peri-clock"  - for LD4 SoC.
     "socionext,uniphier-pro4-peri-clock" - for Pro4 SoC.
     "socionext,uniphier-sld8-peri-clock" - for sLD8 SoC.
@@ -102,6 +99,7 @@ Required properties:
     "socionext,uniphier-pxs2-peri-clock" - for PXs2/LD6b SoC.
     "socionext,uniphier-ld11-peri-clock" - for LD11 SoC.
     "socionext,uniphier-ld20-peri-clock" - for LD20 SoC.
+    "socionext,uniphier-pxs3-peri-clock" - for PXs3 SoC
 - #clock-cells: should be 1.
 
 Example:
index 963c6dfd484df2d7e898427f8d62459410cb78da..3c81f78b5c27d50bb809cf6bbf13766a779024f5 100644 (file)
@@ -20,13 +20,12 @@ List of legacy properties and respective binding document
 1. "enable-sdio-wakeup"                Documentation/devicetree/bindings/mmc/mmc.txt
 2. "gpio-key,wakeup"           Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
 3. "has-tpo"                   Documentation/devicetree/bindings/rtc/rtc-opal.txt
-4. "isil,irq2-can-wakeup-machine" Documentation/devicetree/bindings/rtc/isil,isl12057.txt
-5. "linux,wakeup"              Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
+4. "linux,wakeup"              Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
                                Documentation/devicetree/bindings/mfd/tc3589x.txt
                                Documentation/devicetree/bindings/input/ads7846.txt
-6. "linux,keypad-wakeup"       Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
-7. "linux,input-wakeup"                Documentation/devicetree/bindings/input/samsung-keypad.txt
-8. "nvidia,wakeup-source"      Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
+5. "linux,keypad-wakeup"       Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
+6. "linux,input-wakeup"                Documentation/devicetree/bindings/input/samsung-keypad.txt
+7. "nvidia,wakeup-source"      Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
 
 Examples
 --------
diff --git a/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt b/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt
new file mode 100644 (file)
index 0000000..634312d
--- /dev/null
@@ -0,0 +1,17 @@
+Android Goldfish RTC
+
+Android Goldfish RTC device used by Android emulator.
+
+Required properties:
+
+- compatible : should contain "google,goldfish-rtc"
+- reg        : <registers mapping>
+- interrupts : <interrupt mapping>
+
+Example:
+
+       goldfish_timer@9020000 {
+               compatible = "google,goldfish-rtc";
+               reg = <0x9020000 0x1000>;
+               interrupts = <0x3>;
+       };
index cf83e0940302cbf3b1795be0a06df1a8191220ef..fbbdd92e5af93142fcad51b58dd48d3387efac10 100644 (file)
@@ -24,7 +24,6 @@ Optional properties:
 
  - "wakeup-source": mark the chip as a wakeup source, independently of
     the availability of an IRQ line connected to the SoC.
-    (Legacy property supported: "isil,irq2-can-wakeup-machine")
 
  - "interrupt-parent", "interrupts": for passing the interrupt line
    of the SoC connected to IRQ#2 of the RTC chip.
diff --git a/Documentation/devicetree/bindings/rtc/realtek,rtd119x.txt b/Documentation/devicetree/bindings/rtc/realtek,rtd119x.txt
new file mode 100644 (file)
index 0000000..bbf1ccb
--- /dev/null
@@ -0,0 +1,16 @@
+Realtek RTD129x Real-Time Clock
+===============================
+
+Required properties:
+- compatible :  Should be "realtek,rtd1295-rtc"
+- reg        :  Specifies the physical base address and size
+- clocks     :  Specifies the clock gate
+
+
+Example:
+
+       rtc@9801b600 {
+               compatible = "realtek,rtd1295-clk";
+               reg = <0x9801b600 0x100>;
+               clocks = <&clkc RTD1295_CLK_EN_MISC_RTC>;
+       };
index 945934918b71fc127da6729f38b6498884ad5fca..d5e26d313f62624abb929c1334d2a9b1b77a73b2 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
 
 Required properties for new device trees
 - clocks       : phandle to the 32kHz external oscillator
-- clock-output-names : name of the LOSC clock created
+- clock-output-names : names of the LOSC and its external output clocks created
 - #clock-cells  : must be equals to 1. The RTC provides two clocks: the
                  LOSC and its external output, with index 0 and 1
                  respectively.
@@ -21,7 +21,7 @@ rtc: rtc@01f00000 {
        compatible = "allwinner,sun6i-a31-rtc";
        reg = <0x01f00000 0x54>;
        interrupts = <0 40 4>, <0 41 4>;
-       clock-output-names = "osc32k";
+       clock-output-names = "osc32k", "osc32k-out";
        clocks = <&ext_osc32k>;
        #clock-cells = <1>;
 };
index 549e701cb7a1c58620863fc0a5e5b08c313ff4ef..898551076382abef7941b3772cbbc5511a8ac476 100644 (file)
@@ -13,13 +13,11 @@ Required properties:
        Must be "tx".
 - clock-names
        Tuple listing input clock names.
-       Required elements: "pclk", "gclk" and "aclk".
+       Required elements: "pclk" and "gclk".
 - clocks
        Please refer to clock-bindings.txt.
 - assigned-clocks
        Should be <&classd_gclk>.
-- assigned-clock-parents
-       Should be <&audio_pll_pmc>.
 
 Optional properties:
 - pinctrl-names, pinctrl-0
@@ -45,10 +43,9 @@ classd: classd@fc048000 {
                        (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
                        | AT91_XDMAC_DT_PERID(47))>;
                dma-names = "tx";
-               clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>;
-               clock-names = "pclk", "gclk", "aclk";
+               clocks = <&classd_clk>, <&classd_gclk>;
+               clock-names = "pclk", "gclk";
                assigned-clocks = <&classd_gclk>;
-               assigned-clock-parents = <&audio_pll_pmc>;
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_classd_default>;
index fe25787ff6d49748c3e1ecc494f17e401a60916a..75d2d57e2c4421122434aa855444e8a344c38f21 100644 (file)
@@ -22,7 +22,7 @@ prototypes:
        struct vfsmount *(*d_automount)(struct path *path);
        int (*d_manage)(const struct path *, bool);
        struct dentry *(*d_real)(struct dentry *, const struct inode *,
-                                unsigned int);
+                                unsigned int, unsigned int);
 
 locking rules:
                rename_lock     ->d_lock        may block       rcu-walk
index 405a3df759b33938dc9b6cc4e819673538f973a1..5fd325df59e2233df60cbf6da6c92230aa0c26ef 100644 (file)
@@ -988,7 +988,7 @@ struct dentry_operations {
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(const struct path *, bool);
        struct dentry *(*d_real)(struct dentry *, const struct inode *,
-                                unsigned int);
+                                unsigned int, unsigned int);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
index bc80fc0e210f0634891b8252c48fcfc0350a712a..a7a813258013e7812ad6197c5da62af6cd03dad7 100644 (file)
@@ -523,11 +523,11 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
      즉, ACQUIRE 는 최소한의 "취득" 동작처럼, 그리고 RELEASE 는 최소한의 "공개"
      처럼 동작한다는 의미입니다.
 
-core-api/atomic_ops.rst 에서 설명되는 어토믹 오퍼레이션들 중에는 완전히
-순서잡힌 것들과 (배리어를 사용하지 않는) 완화된 순서의 것들 외에 ACQUIRE 와
-RELEASE 부류의 것들도 존재합니다.  로드와 스토어를 모두 수행하는 조합된 어토믹
-오퍼레이션에서, ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE 는
-해당 오퍼레이션의 스토어 부분에만 적용됩니다.
+atomic_t.txt 에 설명된 어토믹 오퍼레이션들 중 일부는 완전히 순서잡힌 것들과
+(배리어를 사용하지 않는) 완화된 순서의 것들 외에 ACQUIRE 와 RELEASE 부류의
+것들도 존재합니다.  로드와 스토어를 모두 수행하는 조합된 어토믹 오퍼레이션에서,
+ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE 는 해당
+오퍼레이션의 스토어 부분에만 적용됩니다.
 
 메모리 배리어들은 두 CPU 간, 또는 CPU 와 디바이스 간에 상호작용의 가능성이 있을
 때에만 필요합니다.  만약 어떤 코드에 그런 상호작용이 없을 것이 보장된다면, 해당
@@ -617,7 +617,22 @@ RELEASE 부류의 것들도 존재합니다.  로드와 스토어를 모두 수
 이 변경은 앞의 처음 두가지 결과 중 하나만이 발생할 수 있고, 세번째의 결과는
 발생할 수 없도록 합니다.
 
-데이터 의존성 배리어는 의존적 쓰기에 대해서도 순서를 잡아줍니다:
+
+[!] 이 상당히 반직관적인 상황은 분리된 캐시를 가지는 기계들에서 가장 잘
+발생하는데, 예를 들면 한 캐시 뱅크는 짝수 번호의 캐시 라인들을 처리하고, 다른
+뱅크는 홀수 번호의 캐시 라인들을 처리하는 경우임을 알아두시기 바랍니다.  포인터
+P 는 짝수 번호 캐시 라인에 저장되어 있고, 변수 B 는 홀수 번호 캐시 라인에
+저장되어 있을 수 있습니다.  여기서 값을 읽어오는 CPU 의 캐시의 홀수 번호 처리
+뱅크는 열심히 일감을 처리중인 반면 홀수 번호 처리 뱅크는 할 일 없이 한가한
+중이라면 포인터 P (&B) 의 새로운 값과 변수 B 의 기존 값 (2) 를 볼 수 있습니다.
+
+
+의존적 쓰기들의 순서를 맞추는데에는 데이터 의존성 배리어가 필요치 않은데, 이는
+리눅스 커널이 지원하는 CPU 들은 (1) 쓰기가 정말로 일어날지, (2) 쓰기가 어디에
+이루어질지, 그리고 (3) 쓰여질 값을 확실히 알기 전까지는 쓰기를 수행하지 않기
+때문입니다.  하지만 "컨트롤 의존성" 섹션과
+Documentation/RCU/rcu_dereference.txt 파일을 주의 깊게 읽어 주시기 바랍니다:
+컴파일러는 매우 창의적인 많은 방법으로 종속성을 깰 수 있습니다.
 
        CPU 1                 CPU 2
        ===============       ===============
@@ -626,28 +641,19 @@ RELEASE 부류의 것들도 존재합니다.  로드와 스토어를 모두 수
        <쓰기 배리어>
        WRITE_ONCE(P, &B);
                              Q = READ_ONCE(P);
-                             <데이터 의존성 배리어>
-                             *Q = 5;
+                             WRITE_ONCE(*Q, 5);
 
-이 데이터 의존성 배리어는 Q 로의 읽기가 *Q 로의 스토어와 순서를 맞추게
-해줍니다.  이는 다음과 같은 결과를 막습니다:
+따라서, Q 로의 읽기와 *Q 로의 쓰기 사이에는 데이터 종속성 배리어가 필요치
+않습니다.  달리 말하면, 데이터 종속성 배리어가 없더라도 다음 결과는 생기지
+않습니다:
 
        (Q == &B) && (B == 4)
 
 이런 패턴은 드물게 사용되어야 함을 알아 두시기 바랍니다.  무엇보다도, 의존성
 순서 규칙의 의도는 쓰기 작업을 -예방- 해서 그로 인해 발생하는 비싼 캐시 미스도
 없애려는 것입니다.  이 패턴은 드물게 발생하는 에러 조건 같은것들을 기록하는데
-사용될 수 있고, 이렇게 배리어를 사용해 순서를 지키게 함으로써 그런 기록이
-사라지는 것을 막습니다.
-
-
-[!] 상당히 비직관적인 이 상황은 분리된 캐시를 가진 기계, 예를 들어 한 캐시
-뱅크가 짝수번 캐시 라인을 처리하고 다른 뱅크는 홀수번 캐시 라인을 처리하는 기계
-등에서 가장 잘 발생합니다.  포인터 P 는 홀수 번호의 캐시 라인에 있고, 변수 B 는
-짝수 번호 캐시 라인에 있다고 생각해 봅시다.  그런 상태에서 읽기 작업을 하는 CPU
-의 짝수번 뱅크는 할 일이 쌓여 매우 바쁘지만 홀수번 뱅크는 할 일이 없어 아무
-일도 하지 않고  있었다면, 포인터 P 는 새 값 (&B) 을, 그리고 변수 B 는 옛날 값
-(2) 을 가지고 있는 상태가 보여질 수도 있습니다.
+사용될 수 있으며, CPU의 자연적인 순서 보장이 그런 기록들을 사라지지 않게
+해줍니다.
 
 
 데이터 의존성 배리어는 매우 중요한데, 예를 들어 RCU 시스템에서 그렇습니다.
@@ -1848,8 +1854,7 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
      이 코드는 객체의 업데이트된 death 마크가 레퍼런스 카운터 감소 동작
      *전에* 보일 것을 보장합니다.
 
-     더 많은 정보를 위해선 Documentation/core-api/atomic_ops.rst 문서를 참고하세요.
-     어디서 이것들을 사용해야 할지 궁금하다면 "어토믹 오퍼레이션" 서브섹션을
+     더 많은 정보를 위해선 Documentation/atomic_{t,bitops}.txt 문서를
      참고하세요.
 
 
@@ -2468,86 +2473,7 @@ _않습니다_.
 전체 메모리 배리어를 내포하고 또 일부는 내포하지 않지만, 커널에서 상당히
 의존적으로 사용하는 기능 중 하나입니다.
 
-메모리의 어떤 상태를 수정하고 해당 상태에 대한 (예전의 또는 최신의) 정보를
-리턴하는 어토믹 오퍼레이션은 모두 SMP-조건적 범용 메모리 배리어(smp_mb())를
-실제 오퍼레이션의 앞과 뒤에 내포합니다.  이런 오퍼레이션은 다음의 것들을
-포함합니다:
-
-       xchg();
-       atomic_xchg();                  atomic_long_xchg();
-       atomic_inc_return();            atomic_long_inc_return();
-       atomic_dec_return();            atomic_long_dec_return();
-       atomic_add_return();            atomic_long_add_return();
-       atomic_sub_return();            atomic_long_sub_return();
-       atomic_inc_and_test();          atomic_long_inc_and_test();
-       atomic_dec_and_test();          atomic_long_dec_and_test();
-       atomic_sub_and_test();          atomic_long_sub_and_test();
-       atomic_add_negative();          atomic_long_add_negative();
-       test_and_set_bit();
-       test_and_clear_bit();
-       test_and_change_bit();
-
-       /* exchange 조건이 성공할 때 */
-       cmpxchg();
-       atomic_cmpxchg();               atomic_long_cmpxchg();
-       atomic_add_unless();            atomic_long_add_unless();
-
-이것들은 메모리 배리어 효과가 필요한 ACQUIRE 부류와 RELEASE 부류 오퍼레이션들을
-구현할 때, 그리고 객체 해제를 위해 레퍼런스 카운터를 조정할 때, 암묵적 메모리
-배리어 효과가 필요한 곳 등에 사용됩니다.
-
-
-다음의 오퍼레이션들은 메모리 배리어를 내포하지 _않기_ 때문에 문제가 될 수
-있지만, RELEASE 부류의 오퍼레이션들과 같은 것들을 구현할 때 사용될 수도
-있습니다:
-
-       atomic_set();
-       set_bit();
-       clear_bit();
-       change_bit();
-
-이것들을 사용할 때에는 필요하다면 적절한 (예를 들면 smp_mb__before_atomic()
-같은) 메모리 배리어가 명시적으로 함께 사용되어야 합니다.
-
-
-아래의 것들도 메모리 배리어를 내포하지 _않기_ 때문에, 일부 환경에서는 (예를
-들면 smp_mb__before_atomic() 과 같은) 명시적인 메모리 배리어 사용이 필요합니다.
-
-       atomic_add();
-       atomic_sub();
-       atomic_inc();
-       atomic_dec();
-
-이것들이 통계 생성을 위해 사용된다면, 그리고 통계 데이터 사이에 관계가 존재하지
-않는다면 메모리 배리어는 필요치 않을 겁니다.
-
-객체의 수명을 관리하기 위해 레퍼런스 카운팅 목적으로 사용된다면, 레퍼런스
-카운터는 락으로 보호되는 섹션에서만 조정되거나 호출하는 쪽이 이미 충분한
-레퍼런스를 잡고 있을 것이기 때문에 메모리 배리어는 아마 필요 없을 겁니다.
-
-만약 어떤 락을 구성하기 위해 사용된다면, 락 관련 동작은 일반적으로 작업을 특정
-순서대로 진행해야 하므로 메모리 배리어가 필요할 수 있습니다.
-
-기본적으로, 각 사용처에서는 메모리 배리어가 필요한지 아닌지 충분히 고려해야
-합니다.
-
-아래의 오퍼레이션들은 특별한 락 관련 동작들입니다:
-
-       test_and_set_bit_lock();
-       clear_bit_unlock();
-       __clear_bit_unlock();
-
-이것들은 ACQUIRE 류와 RELEASE 류의 오퍼레이션들을 구현합니다.  락 관련 도구를
-구현할 때에는 이것들을 좀 더 선호하는 편이 나은데, 이것들의 구현은 많은
-아키텍쳐에서 최적화 될 수 있기 때문입니다.
-
-[!] 이런 상황에 사용할 수 있는 특수한 메모리 배리어 도구들이 있습니다만, 일부
-CPU 에서는 사용되는 어토믹 인스트럭션 자체에 메모리 배리어가 내포되어 있어서
-어토믹 오퍼레이션과 메모리 배리어를 함께 사용하는 게 불필요한 일이 될 수
-있는데, 그런 경우에 이 특수 메모리 배리어 도구들은 no-op 이 되어 실질적으로
-아무일도 하지 않습니다.
-
-더 많은 내용을 위해선 Documentation/core-api/atomic_ops.rst 를 참고하세요.
+더 많은 내용을 위해선 Documentation/atomic_t.txt 를 참고하세요.
 
 
 디바이스 액세스
index f46a3225e3985bf38dc30c77cc8b34a1e2b6a1a2..209306019483c88ece7c990b9d3fe85f77837535 100644 (file)
@@ -855,6 +855,12 @@ S: Supported
 F:     drivers/android/
 F:     drivers/staging/android/
 
+ANDROID GOLDFISH RTC DRIVER
+M:     Miodrag Dinic <miodrag.dinic@imgtec.com>
+S:     Supported
+F:     Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt
+F:     drivers/rtc/rtc-goldfish.c
+
 ANDROID ION DRIVER
 M:     Laura Abbott <labbott@redhat.com>
 M:     Sumit Semwal <sumit.semwal@linaro.org>
@@ -4385,6 +4391,12 @@ S:       Supported
 F:     drivers/gpu/drm/nouveau/
 F:     include/uapi/drm/nouveau_drm.h
 
+DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
+M:     Noralf Trønnes <noralf@tronnes.org>
+S:     Maintained
+F:     drivers/gpu/drm/tinydrm/repaper.c
+F:     Documentation/devicetree/bindings/display/repaper.txt
+
 DRM DRIVER FOR QEMU'S CIRRUS DEVICE
 M:     Dave Airlie <airlied@redhat.com>
 M:     Gerd Hoffmann <kraxel@redhat.com>
@@ -4403,12 +4415,6 @@ S:       Maintained
 F:     drivers/gpu/drm/qxl/
 F:     include/uapi/drm/qxl_drm.h
 
-DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
-M:     Noralf Trønnes <noralf@tronnes.org>
-S:     Maintained
-F:     drivers/gpu/drm/tinydrm/repaper.c
-F:     Documentation/devicetree/bindings/display/repaper.txt
-
 DRM DRIVER FOR RAGE 128 VIDEO CARDS
 S:     Orphan / Obsolete
 F:     drivers/gpu/drm/r128/
@@ -6202,22 +6208,22 @@ F:      include/uapi/linux/if_hippi.h
 F:     net/802/hippi.c
 F:     drivers/net/hippi/
 
-HISILICON NETWORK SUBSYSTEM DRIVER
+HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3)
 M:     Yisen Zhuang <yisen.zhuang@huawei.com>
 M:     Salil Mehta <salil.mehta@huawei.com>
 L:     netdev@vger.kernel.org
 W:     http://www.hisilicon.com
 S:     Maintained
-F:     drivers/net/ethernet/hisilicon/
-F:     Documentation/devicetree/bindings/net/hisilicon*.txt
+F:     drivers/net/ethernet/hisilicon/hns3/
 
-HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3)
+HISILICON NETWORK SUBSYSTEM DRIVER
 M:     Yisen Zhuang <yisen.zhuang@huawei.com>
 M:     Salil Mehta <salil.mehta@huawei.com>
 L:     netdev@vger.kernel.org
 W:     http://www.hisilicon.com
 S:     Maintained
-F:     drivers/net/ethernet/hisilicon/hns3/
+F:     drivers/net/ethernet/hisilicon/
+F:     Documentation/devicetree/bindings/net/hisilicon*.txt
 
 HISILICON ROCE DRIVER
 M:     Lijun Ou <oulijun@huawei.com>
@@ -6234,6 +6240,13 @@ S:       Supported
 F:     drivers/scsi/hisi_sas/
 F:     Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
 
+HMM - Heterogeneous Memory Management
+M:     Jérôme Glisse <jglisse@redhat.com>
+L:     linux-mm@kvack.org
+S:     Maintained
+F:     mm/hmm*
+F:     include/linux/hmm*
+
 HOST AP DRIVER
 M:     Jouni Malinen <j@w1.fi>
 L:     linux-wireless@vger.kernel.org
@@ -7500,19 +7513,6 @@ F:       include/kvm/iodev.h
 F:     virt/kvm/*
 F:     tools/kvm/
 
-KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
-M:     Paolo Bonzini <pbonzini@redhat.com>
-M:     Radim KrÄmář <rkrcmar@redhat.com>
-L:     kvm@vger.kernel.org
-W:     http://www.linux-kvm.org
-T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
-S:     Supported
-F:     arch/x86/kvm/
-F:     arch/x86/include/uapi/asm/kvm*
-F:     arch/x86/include/asm/kvm*
-F:     arch/x86/kernel/kvm.c
-F:     arch/x86/kernel/kvmclock.c
-
 KERNEL VIRTUAL MACHINE FOR AMD-V (KVM/amd)
 M:     Joerg Roedel <joro@8bytes.org>
 L:     kvm@vger.kernel.org
@@ -7535,17 +7535,6 @@ F:       arch/arm/kvm/
 F:     virt/kvm/arm/
 F:     include/kvm/arm_*
 
-KERNEL VIRTUAL MACHINE FOR POWERPC (KVM/powerpc)
-M:     Alexander Graf <agraf@suse.com>
-L:     kvm-ppc@vger.kernel.org
-W:     http://www.linux-kvm.org/
-T:     git git://github.com/agraf/linux-2.6.git
-S:     Supported
-F:     arch/powerpc/include/uapi/asm/kvm*
-F:     arch/powerpc/include/asm/kvm*
-F:     arch/powerpc/kvm/
-F:     arch/powerpc/kernel/kvm*
-
 KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
 M:     Christoffer Dall <christoffer.dall@linaro.org>
 M:     Marc Zyngier <marc.zyngier@arm.com>
@@ -7564,6 +7553,17 @@ F:       arch/mips/include/uapi/asm/kvm*
 F:     arch/mips/include/asm/kvm*
 F:     arch/mips/kvm/
 
+KERNEL VIRTUAL MACHINE FOR POWERPC (KVM/powerpc)
+M:     Alexander Graf <agraf@suse.com>
+L:     kvm-ppc@vger.kernel.org
+W:     http://www.linux-kvm.org/
+T:     git git://github.com/agraf/linux-2.6.git
+S:     Supported
+F:     arch/powerpc/include/uapi/asm/kvm*
+F:     arch/powerpc/include/asm/kvm*
+F:     arch/powerpc/kvm/
+F:     arch/powerpc/kernel/kvm*
+
 KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
 M:     Christian Borntraeger <borntraeger@de.ibm.com>
 M:     Cornelia Huck <cohuck@redhat.com>
@@ -7577,6 +7577,19 @@ F:       arch/s390/include/asm/kvm*
 F:     arch/s390/kvm/
 F:     arch/s390/mm/gmap.c
 
+KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
+M:     Paolo Bonzini <pbonzini@redhat.com>
+M:     Radim Krčmář <rkrcmar@redhat.com>
+L:     kvm@vger.kernel.org
+W:     http://www.linux-kvm.org
+T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
+S:     Supported
+F:     arch/x86/kvm/
+F:     arch/x86/include/uapi/asm/kvm*
+F:     arch/x86/include/asm/kvm*
+F:     arch/x86/kernel/kvm.c
+F:     arch/x86/kernel/kvmclock.c
+
 KERNFS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:     Tejun Heo <tj@kernel.org>
@@ -7816,13 +7829,6 @@ M:       Sasha Levin <alexander.levin@verizon.com>
 S:     Maintained
 F:     tools/lib/lockdep/
 
-HMM - Heterogeneous Memory Management
-M:     Jérôme Glisse <jglisse@redhat.com>
-L:     linux-mm@kvack.org
-S:     Maintained
-F:     mm/hmm*
-F:     include/linux/hmm*
-
 LIBNVDIMM BLK: MMIO-APERTURE DRIVER
 M:     Ross Zwisler <ross.zwisler@linux.intel.com>
 L:     linux-nvdimm@lists.01.org
@@ -8417,6 +8423,14 @@ T:       git git://linuxtv.org/media_tree.git
 S:     Supported
 F:     drivers/media/dvb-frontends/cxd2841er*
 
+MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES
+M:     Daniel Scheller <d.scheller.oss@gmail.com>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/pci/ddbridge/*
+
 MEDIA DRIVERS FOR FREESCALE IMX
 M:     Steve Longerbeam <slongerbeam@gmail.com>
 M:     Philipp Zabel <p.zabel@pengutronix.de>
@@ -8538,14 +8552,6 @@ T:       git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/dvb-frontends/stv6111*
 
-MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES
-M:     Daniel Scheller <d.scheller.oss@gmail.com>
-L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
-F:     drivers/media/pci/ddbridge/*
-
 MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
 M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
@@ -8569,6 +8575,11 @@ F:       include/uapi/linux/meye.h
 F:     include/uapi/linux/ivtv*
 F:     include/uapi/linux/uvcvideo.h
 
+MEDIATEK CIR DRIVER
+M:     Sean Wang <sean.wang@mediatek.com>
+S:     Maintained
+F:     drivers/media/rc/mtk-cir.c
+
 MEDIATEK ETHERNET DRIVER
 M:     Felix Fietkau <nbd@openwrt.org>
 M:     John Crispin <john@phrozen.org>
@@ -8609,11 +8620,6 @@ L:       linux-wireless@vger.kernel.org
 S:     Maintained
 F:     drivers/net/wireless/mediatek/mt7601u/
 
-MEDIATEK CIR DRIVER
-M:     Sean Wang <sean.wang@mediatek.com>
-S:     Maintained
-F:     drivers/media/rc/mtk-cir.c
-
 MEDIATEK RANDOM NUMBER GENERATOR SUPPORT
 M:     Sean Wang <sean.wang@mediatek.com>
 S:     Maintained
@@ -10129,7 +10135,7 @@ F:      include/uapi/linux/ppdev.h
 F:     Documentation/parport*.txt
 
 PARAVIRT_OPS INTERFACE
-M:     Jeremy Fitzhardinge <jeremy@goop.org>
+M:     Juergen Gross <jgross@suse.com>
 M:     Chris Wright <chrisw@sous-sol.org>
 M:     Alok Kataria <akataria@vmware.com>
 M:     Rusty Russell <rusty@rustcorp.com.au>
@@ -10137,7 +10143,7 @@ L:      virtualization@lists.linux-foundation.org
 S:     Supported
 F:     Documentation/virtual/paravirt_ops.txt
 F:     arch/*/kernel/paravirt*
-F:     arch/*/include/asm/paravirt.h
+F:     arch/*/include/asm/paravirt*.h
 F:     include/linux/hypervisor.h
 
 PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
@@ -12836,6 +12842,18 @@ F:     drivers/clocksource/arc_timer.c
 F:     drivers/tty/serial/arc_uart.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
 
+SYNOPSYS ARC HSDK SDP pll clock driver
+M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+S:     Supported
+F:     drivers/clk/clk-hsdk-pll.c
+F:     Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt
+
+SYNOPSYS ARC SDP clock driver
+M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+S:     Supported
+F:     drivers/clk/axs10x/*
+F:     Documentation/devicetree/bindings/clock/snps,pll-clock.txt
+
 SYNOPSYS ARC SDP platform support
 M:     Alexey Brodkin <abrodkin@synopsys.com>
 S:     Supported
index 195da38cb9a220f22c2f890c5bcb8fc1f2c7c621..6d870421a7a64d2e3aa615746307e4d4254058f8 100644 (file)
@@ -26,6 +26,7 @@ config SOC_SAMA5D2
        select HAVE_AT91_USB_CLK
        select HAVE_AT91_H32MX
        select HAVE_AT91_GENERATED_CLK
+       select HAVE_AT91_AUDIO_PLL
        select PINCTRL_AT91PIO4
        help
          Select this if ou are using one of Atmel's SAMA5D2 family SoC.
@@ -125,6 +126,9 @@ config HAVE_AT91_H32MX
 config HAVE_AT91_GENERATED_CLK
        bool
 
+config HAVE_AT91_AUDIO_PLL
+       bool
+
 config SOC_SAM_V4_V5
        bool
 
index ff97374ca0693d526582b8c34e7f9f421f43ed48..71a6f08de8f21a896f955f7a95792b7e62054a3a 100644 (file)
@@ -414,6 +414,8 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */
 
+struct vm_area_struct;
+
 /*
  * or32 doesn't have any external MMU info: the kernel page
  * tables contain all the necessary information.
index 1a2ba368da39ff4fbf24a922415490e1a2be68e6..9d0e13738ed3d3ea9cc9200c62153c101624a7b7 100644 (file)
@@ -121,7 +121,6 @@ static inline int desc_empty(const void *ptr)
 #define load_ldt(ldt)                          asm volatile("lldt %0"::"m" (ldt))
 
 #define store_gdt(dtr)                         native_store_gdt(dtr)
-#define store_idt(dtr)                         native_store_idt(dtr)
 #define store_tr(tr)                           (tr = native_store_tr())
 
 #define load_TLS(t, cpu)                       native_load_tls(t, cpu)
@@ -228,7 +227,7 @@ static inline void native_store_gdt(struct desc_ptr *dtr)
        asm volatile("sgdt %0":"=m" (*dtr));
 }
 
-static inline void native_store_idt(struct desc_ptr *dtr)
+static inline void store_idt(struct desc_ptr *dtr)
 {
        asm volatile("sidt %0":"=m" (*dtr));
 }
index c25dd22f7c70e97f293ecb086c1be572087ae0b3..12deec722cf0a14374d794b037eb26bf2e02ad51 100644 (file)
@@ -71,11 +71,6 @@ static inline void write_cr3(unsigned long x)
        PVOP_VCALL1(pv_mmu_ops.write_cr3, x);
 }
 
-static inline unsigned long __read_cr4(void)
-{
-       return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr4);
-}
-
 static inline void __write_cr4(unsigned long x)
 {
        PVOP_VCALL1(pv_cpu_ops.write_cr4, x);
@@ -228,10 +223,6 @@ static inline void set_ldt(const void *addr, unsigned entries)
 {
        PVOP_VCALL2(pv_cpu_ops.set_ldt, addr, entries);
 }
-static inline void store_idt(struct desc_ptr *dtr)
-{
-       PVOP_VCALL1(pv_cpu_ops.store_idt, dtr);
-}
 static inline unsigned long paravirt_store_tr(void)
 {
        return PVOP_CALL0(unsigned long, pv_cpu_ops.store_tr);
@@ -365,12 +356,6 @@ static inline void paravirt_release_p4d(unsigned long pfn)
        PVOP_VCALL1(pv_mmu_ops.release_p4d, pfn);
 }
 
-static inline void pte_update(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep)
-{
-       PVOP_VCALL3(pv_mmu_ops.pte_update, mm, addr, ptep);
-}
-
 static inline pte_t __pte(pteval_t val)
 {
        pteval_t ret;
@@ -472,28 +457,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                PVOP_VCALL4(pv_mmu_ops.set_pte_at, mm, addr, ptep, pte.pte);
 }
 
-static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
-                             pmd_t *pmdp, pmd_t pmd)
-{
-       if (sizeof(pmdval_t) > sizeof(long))
-               /* 5 arg words */
-               pv_mmu_ops.set_pmd_at(mm, addr, pmdp, pmd);
-       else
-               PVOP_VCALL4(pv_mmu_ops.set_pmd_at, mm, addr, pmdp,
-                           native_pmd_val(pmd));
-}
-
-static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
-                             pud_t *pudp, pud_t pud)
-{
-       if (sizeof(pudval_t) > sizeof(long))
-               /* 5 arg words */
-               pv_mmu_ops.set_pud_at(mm, addr, pudp, pud);
-       else
-               PVOP_VCALL4(pv_mmu_ops.set_pud_at, mm, addr, pudp,
-                           native_pud_val(pud));
-}
-
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
        pmdval_t val = native_pmd_val(pmd);
index 6b64fc6367f2520858cce6e0c31d111836f1e509..42873edd9f9d20cda2d1cfcb92b3798c4a75b3aa 100644 (file)
@@ -107,7 +107,6 @@ struct pv_cpu_ops {
        unsigned long (*read_cr0)(void);
        void (*write_cr0)(unsigned long);
 
-       unsigned long (*read_cr4)(void);
        void (*write_cr4)(unsigned long);
 
 #ifdef CONFIG_X86_64
@@ -119,8 +118,6 @@ struct pv_cpu_ops {
        void (*load_tr_desc)(void);
        void (*load_gdt)(const struct desc_ptr *);
        void (*load_idt)(const struct desc_ptr *);
-       /* store_gdt has been removed. */
-       void (*store_idt)(struct desc_ptr *);
        void (*set_ldt)(const void *desc, unsigned entries);
        unsigned long (*store_tr)(void);
        void (*load_tls)(struct thread_struct *t, unsigned int cpu);
@@ -245,12 +242,6 @@ struct pv_mmu_ops {
        void (*set_pte_at)(struct mm_struct *mm, unsigned long addr,
                           pte_t *ptep, pte_t pteval);
        void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval);
-       void (*set_pmd_at)(struct mm_struct *mm, unsigned long addr,
-                          pmd_t *pmdp, pmd_t pmdval);
-       void (*set_pud_at)(struct mm_struct *mm, unsigned long addr,
-                          pud_t *pudp, pud_t pudval);
-       void (*pte_update)(struct mm_struct *mm, unsigned long addr,
-                          pte_t *ptep);
 
        pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr,
                                        pte_t *ptep);
index 5b4c44d419c55cafbafbddc8562e5c4b8d074c29..b714934512b391905ed37400b6acb37ce6529ca2 100644 (file)
@@ -55,8 +55,6 @@ extern pmdval_t early_pmd_flags;
 #else  /* !CONFIG_PARAVIRT */
 #define set_pte(ptep, pte)             native_set_pte(ptep, pte)
 #define set_pte_at(mm, addr, ptep, pte)        native_set_pte_at(mm, addr, ptep, pte)
-#define set_pmd_at(mm, addr, pmdp, pmd)        native_set_pmd_at(mm, addr, pmdp, pmd)
-#define set_pud_at(mm, addr, pudp, pud)        native_set_pud_at(mm, addr, pudp, pud)
 
 #define set_pte_atomic(ptep, pte)                                      \
        native_set_pte_atomic(ptep, pte)
@@ -87,8 +85,6 @@ extern pmdval_t early_pmd_flags;
 #define pte_clear(mm, addr, ptep)      native_pte_clear(mm, addr, ptep)
 #define pmd_clear(pmd)                 native_pmd_clear(pmd)
 
-#define pte_update(mm, addr, ptep)              do { } while (0)
-
 #define pgd_val(x)     native_pgd_val(x)
 #define __pgd(x)       native_make_pgd(x)
 
@@ -979,31 +975,18 @@ static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
        native_set_pte(ptep, pte);
 }
 
-static inline void native_set_pmd_at(struct mm_struct *mm, unsigned long addr,
-                                    pmd_t *pmdp , pmd_t pmd)
+static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+                             pmd_t *pmdp, pmd_t pmd)
 {
        native_set_pmd(pmdp, pmd);
 }
 
-static inline void native_set_pud_at(struct mm_struct *mm, unsigned long addr,
-                                    pud_t *pudp, pud_t pud)
+static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
+                             pud_t *pudp, pud_t pud)
 {
        native_set_pud(pudp, pud);
 }
 
-#ifndef CONFIG_PARAVIRT
-/*
- * Rules for using pte_update - it must be called after any PTE update which
- * has not been done using the set_pte / clear_pte interfaces.  It is used by
- * shadow mode hypervisors to resynchronize the shadow page tables.  Kernel PTE
- * updates should either be sets, clears, or set_pte_atomic for P->P
- * transitions, which means this hook should only be called for user PTEs.
- * This hook implies a P->P protection or access change has taken place, which
- * requires a subsequent TLB flush.
- */
-#define pte_update(mm, addr, ptep)             do { } while (0)
-#endif
-
 /*
  * We only update the dirty/accessed state if we set
  * the dirty bit by hand in the kernel, since the hardware
@@ -1031,7 +1014,6 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
                                       pte_t *ptep)
 {
        pte_t pte = native_ptep_get_and_clear(ptep);
-       pte_update(mm, addr, ptep);
        return pte;
 }
 
@@ -1058,7 +1040,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm,
                                      unsigned long addr, pte_t *ptep)
 {
        clear_bit(_PAGE_BIT_RW, (unsigned long *)&ptep->pte);
-       pte_update(mm, addr, ptep);
 }
 
 #define flush_tlb_fix_spurious_fault(vma, address) do { } while (0)
index 9efaabf5b54be04d722295dea1fd20a6e2515825..a24dfcf79f4acadd7b49f47c5138bc05cc50aa56 100644 (file)
@@ -135,6 +135,11 @@ static inline void native_wbinvd(void)
 
 extern asmlinkage void native_load_gs_index(unsigned);
 
+static inline unsigned long __read_cr4(void)
+{
+       return native_read_cr4();
+}
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
@@ -173,11 +178,6 @@ static inline void write_cr3(unsigned long x)
        native_write_cr3(x);
 }
 
-static inline unsigned long __read_cr4(void)
-{
-       return native_read_cr4();
-}
-
 static inline void __write_cr4(unsigned long x)
 {
        native_write_cr4(x);
index 7032f4d8dff30be9557eedb26f6dcb779b26d3eb..f65d12504e8051f2e47aae2a0076a883c1ce535e 100644 (file)
 /* Recommend using the newer ExProcessorMasks interface */
 #define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED  (1 << 11)
 
-/*
- * HV_VP_SET available
- */
-#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED  (1 << 11)
-
-
 /*
  * Crash notification flag.
  */
index fb1d3358a4af5bde82e5d8dd751b2db3271a2c82..775f10100d7febac27a84bb9c8deab24e119a8c8 100644 (file)
@@ -169,21 +169,21 @@ static int __init x86_mpx_setup(char *s)
 __setup("nompx", x86_mpx_setup);
 
 #ifdef CONFIG_X86_64
-static int __init x86_pcid_setup(char *s)
+static int __init x86_nopcid_setup(char *s)
 {
-       /* require an exact match without trailing characters */
-       if (strlen(s))
-               return 0;
+       /* nopcid doesn't accept parameters */
+       if (s)
+               return -EINVAL;
 
        /* do not emit a message if the feature is not present */
        if (!boot_cpu_has(X86_FEATURE_PCID))
-               return 1;
+               return 0;
 
        setup_clear_cpu_cap(X86_FEATURE_PCID);
        pr_info("nopcid: PCID feature disabled\n");
-       return 1;
+       return 0;
 }
-__setup("nopcid", x86_pcid_setup);
+early_param("nopcid", x86_nopcid_setup);
 #endif
 
 static int __init x86_noinvpcid_setup(char *s)
@@ -329,38 +329,6 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)
        }
 }
 
-static void setup_pcid(struct cpuinfo_x86 *c)
-{
-       if (cpu_has(c, X86_FEATURE_PCID)) {
-               if (cpu_has(c, X86_FEATURE_PGE)) {
-                       /*
-                        * We'd like to use cr4_set_bits_and_update_boot(),
-                        * but we can't.  CR4.PCIDE is special and can only
-                        * be set in long mode, and the early CPU init code
-                        * doesn't know this and would try to restore CR4.PCIDE
-                        * prior to entering long mode.
-                        *
-                        * Instead, we rely on the fact that hotplug, resume,
-                        * etc all fully restore CR4 before they write anything
-                        * that could have nonzero PCID bits to CR3.  CR4.PCIDE
-                        * has no effect on the page tables themselves, so we
-                        * don't need it to be restored early.
-                        */
-                       cr4_set_bits(X86_CR4_PCIDE);
-               } else {
-                       /*
-                        * flush_tlb_all(), as currently implemented, won't
-                        * work if PCID is on but PGE is not.  Since that
-                        * combination doesn't exist on real hardware, there's
-                        * no reason to try to fully support it, but it's
-                        * polite to avoid corrupting data if we're on
-                        * an improperly configured VM.
-                        */
-                       clear_cpu_cap(c, X86_FEATURE_PCID);
-               }
-       }
-}
-
 /*
  * Protection Keys are not available in 32-bit mode.
  */
@@ -1175,9 +1143,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
        setup_smep(c);
        setup_smap(c);
 
-       /* Set up PCID */
-       setup_pcid(c);
-
        /*
         * The vendor-specific functions might have changed features.
         * Now we do "generic changes."
index 3b3f713e15e5fea418ebc8eae3bc7a948570dd73..236324e83a3ae0755c4de2a087983759793c0add 100644 (file)
@@ -59,8 +59,6 @@ void hyperv_vector_handler(struct pt_regs *regs)
 void hv_setup_vmbus_irq(void (*handler)(void))
 {
        vmbus_handler = handler;
-       /* Setup the IDT for hypervisor callback */
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
 }
 
 void hv_remove_vmbus_irq(void)
@@ -251,6 +249,8 @@ static void __init ms_hyperv_init_platform(void)
         */
        x86_platform.apic_post_init = hyperv_init;
        hyperv_setup_mmu_ops();
+       /* Setup the IDT for hypervisor callback */
+       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
 #endif
 }
 
index a14df9eecfed16598e131c41c3df4967a18f2871..19a3e8f961c772af6572f80a860e1c892ad31a32 100644 (file)
@@ -327,7 +327,6 @@ __visible struct pv_cpu_ops pv_cpu_ops = {
        .set_debugreg = native_set_debugreg,
        .read_cr0 = native_read_cr0,
        .write_cr0 = native_write_cr0,
-       .read_cr4 = native_read_cr4,
        .write_cr4 = native_write_cr4,
 #ifdef CONFIG_X86_64
        .read_cr8 = native_read_cr8,
@@ -343,7 +342,6 @@ __visible struct pv_cpu_ops pv_cpu_ops = {
        .set_ldt = native_set_ldt,
        .load_gdt = native_load_gdt,
        .load_idt = native_load_idt,
-       .store_idt = native_store_idt,
        .store_tr = native_store_tr,
        .load_tls = native_load_tls,
 #ifdef CONFIG_X86_64
@@ -411,8 +409,6 @@ struct pv_mmu_ops pv_mmu_ops __ro_after_init = {
        .set_pte = native_set_pte,
        .set_pte_at = native_set_pte_at,
        .set_pmd = native_set_pmd,
-       .set_pmd_at = native_set_pmd_at,
-       .pte_update = paravirt_nop,
 
        .ptep_modify_prot_start = __ptep_modify_prot_start,
        .ptep_modify_prot_commit = __ptep_modify_prot_commit,
@@ -424,7 +420,6 @@ struct pv_mmu_ops pv_mmu_ops __ro_after_init = {
        .pmd_clear = native_pmd_clear,
 #endif
        .set_pud = native_set_pud,
-       .set_pud_at = native_set_pud_at,
 
        .pmd_val = PTE_IDENT,
        .make_pmd = PTE_IDENT,
index d84afb0a322dd8515fb91424eef6cc42fcbfaee2..0957dd73d127554803f35d5be45dcddb845ca741 100644 (file)
@@ -1178,8 +1178,11 @@ void __init setup_arch(char **cmdline_p)
         * with the current CR4 value.  This may not be necessary, but
         * auditing all the early-boot CR4 manipulation would be needed to
         * rule it out.
+        *
+        * Mask off features that don't work outside long mode (just
+        * PCIDE for now).
         */
-       mmu_cr4_features = __read_cr4();
+       mmu_cr4_features = __read_cr4() & ~X86_CR4_PCIDE;
 
        memblock_set_current_limit(get_max_mapped());
 
index cd6622c3204e6b4c5c159a659b0b23f4728da34a..0854ff1692745adf4831e2deea0cb203977847d9 100644 (file)
@@ -226,10 +226,12 @@ static int enable_start_cpu0;
 static void notrace start_secondary(void *unused)
 {
        /*
-        * Don't put *anything* before cpu_init(), SMP booting is too
-        * fragile that we want to limit the things done here to the
-        * most necessary things.
+        * Don't put *anything* except direct CPU state initialization
+        * before cpu_init(), SMP booting is too fragile that we want to
+        * limit the things done here to the most necessary things.
         */
+       if (boot_cpu_has(X86_FEATURE_PCID))
+               __write_cr4(__read_cr4() | X86_CR4_PCIDE);
        cpu_init();
        x86_cpuinit.early_percpu_clock_init();
        preempt_disable();
index 4253adef9044c10429094495e01074da46b0d864..699704d4bc9e7716e04da7298ec7f4491b436af1 100644 (file)
@@ -5192,7 +5192,7 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
        vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
        vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */
 
-       native_store_idt(&dt);
+       store_idt(&dt);
        vmcs_writel(HOST_IDTR_BASE, dt.address);   /* 22.2.4 */
        vmx->host_idt_base = dt.address;
 
index 7777ccc0e9f979dc76cc9d520885eea02114223e..af5c1ed21d43ac651ecbe02e7a58dc7baa884168 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/microcode.h>
 #include <asm/kaslr.h>
 #include <asm/hypervisor.h>
+#include <asm/cpufeature.h>
 
 /*
  * We need to define the tracepoints somewhere, and tlb.c
@@ -193,6 +194,38 @@ static void __init probe_page_size_mask(void)
        }
 }
 
+static void setup_pcid(void)
+{
+#ifdef CONFIG_X86_64
+       if (boot_cpu_has(X86_FEATURE_PCID)) {
+               if (boot_cpu_has(X86_FEATURE_PGE)) {
+                       /*
+                        * This can't be cr4_set_bits_and_update_boot() --
+                        * the trampoline code can't handle CR4.PCIDE and
+                        * it wouldn't do any good anyway.  Despite the name,
+                        * cr4_set_bits_and_update_boot() doesn't actually
+                        * cause the bits in question to remain set all the
+                        * way through the secondary boot asm.
+                        *
+                        * Instead, we brute-force it and set CR4.PCIDE
+                        * manually in start_secondary().
+                        */
+                       cr4_set_bits(X86_CR4_PCIDE);
+               } else {
+                       /*
+                        * flush_tlb_all(), as currently implemented, won't
+                        * work if PCID is on but PGE is not.  Since that
+                        * combination doesn't exist on real hardware, there's
+                        * no reason to try to fully support it, but it's
+                        * polite to avoid corrupting data if we're on
+                        * an improperly configured VM.
+                        */
+                       setup_clear_cpu_cap(X86_FEATURE_PCID);
+               }
+       }
+#endif
+}
+
 #ifdef CONFIG_X86_32
 #define NR_RANGE_MR 3
 #else /* CONFIG_X86_64 */
@@ -592,6 +625,7 @@ void __init init_mem_mapping(void)
        unsigned long end;
 
        probe_page_size_mask();
+       setup_pcid();
 
 #ifdef CONFIG_X86_64
        end = max_pfn << PAGE_SHIFT;
index 218834a3e9adde25ea3ddf3ef2b3f513846ce1c7..b372f3442bbf3b5cff5782001e5c79b46d49edc6 100644 (file)
@@ -426,10 +426,8 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
 {
        int changed = !pte_same(*ptep, entry);
 
-       if (changed && dirty) {
+       if (changed && dirty)
                *ptep = entry;
-               pte_update(vma->vm_mm, address, ptep);
-       }
 
        return changed;
 }
@@ -486,9 +484,6 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma,
                ret = test_and_clear_bit(_PAGE_BIT_ACCESSED,
                                         (unsigned long *) &ptep->pte);
 
-       if (ret)
-               pte_update(vma->vm_mm, addr, ptep);
-
        return ret;
 }
 
index 37689a7cc03b493927f50b2d14be5f72b3981a02..1ab3821f9e2629df571544077d63be950361bc20 100644 (file)
@@ -121,8 +121,28 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
         * hypothetical buggy code that directly switches to swapper_pg_dir
         * without going through leave_mm() / switch_mm_irqs_off() or that
         * does something like write_cr3(read_cr3_pa()).
+        *
+        * Only do this check if CONFIG_DEBUG_VM=y because __read_cr3()
+        * isn't free.
         */
-       VM_BUG_ON(__read_cr3() != (__sme_pa(real_prev->pgd) | prev_asid));
+#ifdef CONFIG_DEBUG_VM
+       if (WARN_ON_ONCE(__read_cr3() !=
+                        (__sme_pa(real_prev->pgd) | prev_asid))) {
+               /*
+                * If we were to BUG here, we'd be very likely to kill
+                * the system so hard that we don't see the call trace.
+                * Try to recover instead by ignoring the error and doing
+                * a global flush to minimize the chance of corruption.
+                *
+                * (This is far from being a fully correct recovery.
+                *  Architecturally, the CPU could prefetch something
+                *  back into an incorrect ASID slot and leave it there
+                *  to cause trouble down the road.  It's better than
+                *  nothing, though.)
+                */
+               __flush_tlb_all();
+       }
+#endif
 
        if (real_prev == next) {
                VM_BUG_ON(this_cpu_read(cpu_tlbstate.ctxs[prev_asid].ctx_id) !=
index f2598d81cd55067ffd695a18bde0352a5d98264b..f910c514438f168a5f09afbd312311498abe2c50 100644 (file)
@@ -295,7 +295,26 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
                return -EOVERFLOW;
        rdr->jump_address = (unsigned long)restore_registers;
        rdr->jump_address_phys = __pa_symbol(restore_registers);
-       rdr->cr3 = restore_cr3;
+
+       /*
+        * The restore code fixes up CR3 and CR4 in the following sequence:
+        *
+        * [in hibernation asm]
+        * 1. CR3 <= temporary page tables
+        * 2. CR4 <= mmu_cr4_features (from the kernel that restores us)
+        * 3. CR3 <= rdr->cr3
+        * 4. CR4 <= mmu_cr4_features (from us, i.e. the image kernel)
+        * [in restore_processor_state()]
+        * 5. CR4 <= saved CR4
+        * 6. CR3 <= saved CR3
+        *
+        * Our mmu_cr4_features has CR4.PCIDE=0, and toggling
+        * CR4.PCIDE while CR3's PCID bits are nonzero is illegal, so
+        * rdr->cr3 needs to point to valid page tables but must not
+        * have any of the PCID bits set.
+        */
+       rdr->cr3 = restore_cr3 & ~CR3_PCID_MASK;
+
        rdr->magic = RESTORE_MAGIC;
 
        hibernation_e820_save(rdr->e820_digest);
index ae2a2e2d636286f36e570dde5b4cb9d29dc55f5b..69b9deff7e5c84c4133064ada0606eb872908152 100644 (file)
@@ -1038,7 +1038,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .read_cr0 = xen_read_cr0,
        .write_cr0 = xen_write_cr0,
 
-       .read_cr4 = native_read_cr4,
        .write_cr4 = xen_write_cr4,
 
 #ifdef CONFIG_X86_64
@@ -1073,7 +1072,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .alloc_ldt = xen_alloc_ldt,
        .free_ldt = xen_free_ldt,
 
-       .store_idt = native_store_idt,
        .store_tr = xen_store_tr,
 
        .write_ldt_entry = xen_write_ldt_entry,
index 6b983b300666bd178c5b898f35e6c8c134d2a800..509f560bd0c6d4731cac96fc64296184e6818b9c 100644 (file)
@@ -2409,8 +2409,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
        .flush_tlb_single = xen_flush_tlb_single,
        .flush_tlb_others = xen_flush_tlb_others,
 
-       .pte_update = paravirt_nop,
-
        .pgd_alloc = xen_pgd_alloc,
        .pgd_free = xen_pgd_free,
 
index d709c0e3a2ac012c989549bd32ff47306a2ff2a5..aebe676225e6fdf360f39760cacf7326cf78cd9f 100644 (file)
@@ -2342,7 +2342,12 @@ blk_status_t blk_insert_cloned_request(struct request_queue *q, struct request *
        if (q->mq_ops) {
                if (blk_queue_io_stat(q))
                        blk_account_io_start(rq, true);
-               blk_mq_sched_insert_request(rq, false, true, false, false);
+               /*
+                * Since we have a scheduler attached on the top device,
+                * bypass a potential scheduler on the bottom device for
+                * insert.
+                */
+               blk_mq_request_bypass_insert(rq);
                return BLK_STS_OK;
        }
 
index e01adb5145b3a0e82e17aa3f72c58074c6a05893..62240f8832ca6e62f8f3e5dddedb9428a978250d 100644 (file)
@@ -269,9 +269,9 @@ static int __blkdev_issue_write_zeroes(struct block_device *bdev,
  */
 static unsigned int __blkdev_sectors_to_bio_pages(sector_t nr_sects)
 {
-       sector_t bytes = (nr_sects << 9) + PAGE_SIZE - 1;
+       sector_t pages = DIV_ROUND_UP_SECTOR_T(nr_sects, PAGE_SIZE / 512);
 
-       return min(bytes >> PAGE_SHIFT, (sector_t)BIO_MAX_PAGES);
+       return min(pages, (sector_t)BIO_MAX_PAGES);
 }
 
 /**
index 3f18cff80050331ece90da34aec20819ae2e3245..98a18609755e94494b4239012f3c57c1503635bf 100644 (file)
@@ -1401,6 +1401,22 @@ void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
        blk_mq_hctx_mark_pending(hctx, ctx);
 }
 
+/*
+ * Should only be used carefully, when the caller knows we want to
+ * bypass a potential IO scheduler on the target device.
+ */
+void blk_mq_request_bypass_insert(struct request *rq)
+{
+       struct blk_mq_ctx *ctx = rq->mq_ctx;
+       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(rq->q, ctx->cpu);
+
+       spin_lock(&hctx->lock);
+       list_add_tail(&rq->queuelist, &hctx->dispatch);
+       spin_unlock(&hctx->lock);
+
+       blk_mq_run_hw_queue(hctx, false);
+}
+
 void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
                            struct list_head *list)
 
index 98252b79b80b65aef059f8376bce689928e21b6b..ef15b3414da548f4b5c8d2a438d8b52a54cf8e36 100644 (file)
@@ -54,6 +54,7 @@ int blk_mq_alloc_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
  */
 void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
                                bool at_head);
+void blk_mq_request_bypass_insert(struct request *rq);
 void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
                                struct list_head *list);
 
index f40c9acf88955df7d23bbf669127fa0e5236d80a..e20be82588542918a0440ddc9bb1bde1d5bf5f8b 100644 (file)
@@ -46,6 +46,7 @@ enum opal_response_token {
 #define GENERIC_HOST_SESSION_NUM 0x41
 
 #define TPER_SYNC_SUPPORTED 0x01
+#define MBR_ENABLED_MASK 0x10
 
 #define TINY_ATOM_DATA_MASK 0x3F
 #define TINY_ATOM_SIGNED 0x40
index 9b30ae5ab843b0508494cae08a78ae831c67e58b..9ed51d0c6b1d171fc2eab785ef854b64f93721fe 100644 (file)
@@ -80,6 +80,7 @@ struct parsed_resp {
 
 struct opal_dev {
        bool supported;
+       bool mbr_enabled;
 
        void *data;
        sec_send_recv *send_recv;
@@ -283,6 +284,14 @@ static bool check_tper(const void *data)
        return true;
 }
 
+static bool check_mbrenabled(const void *data)
+{
+       const struct d0_locking_features *lfeat = data;
+       u8 sup_feat = lfeat->supported_features;
+
+       return !!(sup_feat & MBR_ENABLED_MASK);
+}
+
 static bool check_sum(const void *data)
 {
        const struct d0_single_user_mode *sum = data;
@@ -417,6 +426,7 @@ static int opal_discovery0_end(struct opal_dev *dev)
        u32 hlen = be32_to_cpu(hdr->length);
 
        print_buffer(dev->resp, hlen);
+       dev->mbr_enabled = false;
 
        if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
                pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
@@ -442,6 +452,8 @@ static int opal_discovery0_end(struct opal_dev *dev)
                        check_geometry(dev, body);
                        break;
                case FC_LOCKING:
+                       dev->mbr_enabled = check_mbrenabled(body->features);
+                       break;
                case FC_ENTERPRISE:
                case FC_DATASTORE:
                        /* some ignored properties */
@@ -2190,6 +2202,21 @@ static int __opal_lock_unlock(struct opal_dev *dev,
        return next(dev);
 }
 
+static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
+{
+       u8 mbr_done_tf = 1;
+       const struct opal_step mbrdone_step [] = {
+               { opal_discovery0, },
+               { start_admin1LSP_opal_session, key },
+               { set_mbr_done, &mbr_done_tf },
+               { end_opal_session, },
+               { NULL, }
+       };
+
+       dev->steps = mbrdone_step;
+       return next(dev);
+}
+
 static int opal_lock_unlock(struct opal_dev *dev,
                            struct opal_lock_unlock *lk_unlk)
 {
@@ -2345,6 +2372,11 @@ bool opal_unlock_from_suspend(struct opal_dev *dev)
                                 suspend->unlk.session.sum);
                        was_failure = true;
                }
+               if (dev->mbr_enabled) {
+                       ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
+                       if (ret)
+                               pr_debug("Failed to set MBR Done in S3 resume\n");
+               }
        }
        mutex_unlock(&dev->dev_lock);
        return was_failure;
index 68ca2d9fcd73b3277fec4309996fbd5373b58bbd..1c4e1aa6767ee9f755dea6b1d115d7d1c0bce666 100644 (file)
@@ -31,6 +31,13 @@ config COMMON_CLK_WM831X
 
 source "drivers/clk/versatile/Kconfig"
 
+config CLK_HSDK
+       bool "PLL Driver for HSDK platform"
+       depends on OF || COMPILE_TEST
+       ---help---
+         This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs
+         control.
+
 config COMMON_CLK_MAX77686
        tristate "Clock driver for Maxim 77620/77686/77802 MFD"
        depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
@@ -39,10 +46,10 @@ config COMMON_CLK_MAX77686
          clock.
 
 config COMMON_CLK_RK808
-       tristate "Clock driver for RK808/RK818"
+       tristate "Clock driver for RK805/RK808/RK818"
        depends on MFD_RK808
        ---help---
-         This driver supports RK808 and RK818 crystal oscillator clock. These
+         This driver supports RK805, RK808 and RK818 crystal oscillator clock. These
          multi-function devices have two fixed-rate oscillators,
          clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
          by control register.
@@ -210,14 +217,14 @@ config COMMON_CLK_OXNAS
          Support for the OXNAS SoC Family clocks.
 
 config COMMON_CLK_VC5
-       tristate "Clock driver for IDT VersaClock5 devices"
+       tristate "Clock driver for IDT VersaClock 5,6 devices"
        depends on I2C
        depends on OF
        select REGMAP_I2C
        help
        ---help---
-         This driver supports the IDT VersaClock5 programmable clock
-         generator.
+         This driver supports the IDT VersaClock 5 and VersaClock 6
+         programmable clock generators.
 
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
index cd376b3fb47adc2bd87c64dddb7ec775e51f8e21..c99f363826f02f683c6018ddf02a0d4d3a58033f 100644 (file)
@@ -27,8 +27,8 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP)    += clk-cs2000-cp.o
 obj-$(CONFIG_ARCH_EFM32)               += clk-efm32gg.o
 obj-$(CONFIG_COMMON_CLK_GEMINI)                += clk-gemini.o
 obj-$(CONFIG_ARCH_HIGHBANK)            += clk-highbank.o
+obj-$(CONFIG_CLK_HSDK)                 += clk-hsdk-pll.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)      += clk-max77686.o
-obj-$(CONFIG_ARCH_MB86S7X)             += clk-mb86s7x.o
 obj-$(CONFIG_ARCH_MOXART)              += clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)             += clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)              += clk-nspire.o
@@ -44,6 +44,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351)               += clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)         += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI570)         += clk-si570.o
 obj-$(CONFIG_ARCH_STM32)               += clk-stm32f4.o
+obj-$(CONFIG_ARCH_STM32)               += clk-stm32h7.o
 obj-$(CONFIG_ARCH_TANGO)               += clk-tango4.o
 obj-$(CONFIG_CLK_TWL6040)              += clk-twl6040.o
 obj-$(CONFIG_ARCH_U300)                        += clk-u300.o
index 13e67bd35cff3c8c56eb86229a35a58f40bcf834..c68947b65a4c4a176f7f679459f97b60c57ea1e3 100644 (file)
@@ -6,6 +6,7 @@ obj-y += pmc.o sckc.o
 obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
 obj-y += clk-system.o clk-peripheral.o clk-programmable.o
 
+obj-$(CONFIG_HAVE_AT91_AUDIO_PLL)      += clk-audio-pll.o
 obj-$(CONFIG_HAVE_AT91_UTMI)           += clk-utmi.o
 obj-$(CONFIG_HAVE_AT91_USB_CLK)                += clk-usb.o
 obj-$(CONFIG_HAVE_AT91_SMD)            += clk-smd.o
diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c
new file mode 100644 (file)
index 0000000..da7bafc
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ *  Copyright (C) 2016 Atmel Corporation,
+ *                    Songjun Wu <songjun.wu@atmel.com>,
+ *                     Nicolas Ferre <nicolas.ferre@atmel.com>
+ *  Copyright (C) 2017 Free Electrons,
+ *                    Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Sama5d2 SoC has two audio PLLs (PMC and PAD) that shares the same parent
+ * (FRAC). FRAC can output between 620 and 700MHz and only multiply the rate of
+ * its own parent. PMC and PAD can then divide the FRAC rate to best match the
+ * asked rate.
+ *
+ * Traits of FRAC clock:
+ * enable - clk_enable writes nd, fracr parameters and enables PLL
+ * rate - rate is adjustable.
+ *        clk->rate = parent->rate * ((nd + 1) + (fracr / 2^22))
+ * parent - fixed parent.  No clk_set_parent support
+ *
+ * Traits of PMC clock:
+ * enable - clk_enable writes qdpmc, and enables PMC output
+ * rate - rate is adjustable.
+ *        clk->rate = parent->rate / (qdpmc + 1)
+ * parent - fixed parent.  No clk_set_parent support
+ *
+ * Traits of PAD clock:
+ * enable - clk_enable writes divisors and enables PAD output
+ * rate - rate is adjustable.
+ *        clk->rate = parent->rate / (qdaudio * div))
+ * parent - fixed parent.  No clk_set_parent support
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define AUDIO_PLL_DIV_FRAC     BIT(22)
+#define AUDIO_PLL_ND_MAX       (AT91_PMC_AUDIO_PLL_ND_MASK >> \
+                                       AT91_PMC_AUDIO_PLL_ND_OFFSET)
+
+#define AUDIO_PLL_QDPAD(qd, div)       ((AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV(qd) & \
+                                         AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK) | \
+                                        (AT91_PMC_AUDIO_PLL_QDPAD_DIV(div) & \
+                                         AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK))
+
+#define AUDIO_PLL_QDPMC_MAX            (AT91_PMC_AUDIO_PLL_QDPMC_MASK >> \
+                                               AT91_PMC_AUDIO_PLL_QDPMC_OFFSET)
+
+#define AUDIO_PLL_FOUT_MIN     620000000UL
+#define AUDIO_PLL_FOUT_MAX     700000000UL
+
+struct clk_audio_frac {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       u32 fracr;
+       u8 nd;
+};
+
+struct clk_audio_pad {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       u8 qdaudio;
+       u8 div;
+};
+
+struct clk_audio_pmc {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       u8 qdpmc;
+};
+
+#define to_clk_audio_frac(hw) container_of(hw, struct clk_audio_frac, hw)
+#define to_clk_audio_pad(hw) container_of(hw, struct clk_audio_pad, hw)
+#define to_clk_audio_pmc(hw) container_of(hw, struct clk_audio_pmc, hw)
+
+static int clk_audio_pll_frac_enable(struct clk_hw *hw)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_RESETN, 0);
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_RESETN,
+                          AT91_PMC_AUDIO_PLL_RESETN);
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL1,
+                          AT91_PMC_AUDIO_PLL_FRACR_MASK, frac->fracr);
+
+       /*
+        * reset and enable have to be done in 2 separated writes
+        * for AT91_PMC_AUDIO_PLL0
+        */
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PLLEN |
+                          AT91_PMC_AUDIO_PLL_ND_MASK,
+                          AT91_PMC_AUDIO_PLL_PLLEN |
+                          AT91_PMC_AUDIO_PLL_ND(frac->nd));
+
+       return 0;
+}
+
+static int clk_audio_pll_pad_enable(struct clk_hw *hw)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+
+       regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL1,
+                          AT91_PMC_AUDIO_PLL_QDPAD_MASK,
+                          AUDIO_PLL_QDPAD(apad_ck->qdaudio, apad_ck->div));
+       regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PADEN, AT91_PMC_AUDIO_PLL_PADEN);
+
+       return 0;
+}
+
+static int clk_audio_pll_pmc_enable(struct clk_hw *hw)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+
+       regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PMCEN |
+                          AT91_PMC_AUDIO_PLL_QDPMC_MASK,
+                          AT91_PMC_AUDIO_PLL_PMCEN |
+                          AT91_PMC_AUDIO_PLL_QDPMC(apmc_ck->qdpmc));
+       return 0;
+}
+
+static void clk_audio_pll_frac_disable(struct clk_hw *hw)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PLLEN, 0);
+       /* do it in 2 separated writes */
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_RESETN, 0);
+}
+
+static void clk_audio_pll_pad_disable(struct clk_hw *hw)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+
+       regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PADEN, 0);
+}
+
+static void clk_audio_pll_pmc_disable(struct clk_hw *hw)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+
+       regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PMCEN, 0);
+}
+
+static unsigned long clk_audio_pll_fout(unsigned long parent_rate,
+                                       unsigned long nd, unsigned long fracr)
+{
+       unsigned long long fr = (unsigned long long)parent_rate * fracr;
+
+       pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
+
+       fr = DIV_ROUND_CLOSEST_ULL(fr, AUDIO_PLL_DIV_FRAC);
+
+       pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
+
+       return parent_rate * (nd + 1) + fr;
+}
+
+static unsigned long clk_audio_pll_frac_recalc_rate(struct clk_hw *hw,
+                                                   unsigned long parent_rate)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+       unsigned long fout;
+
+       fout = clk_audio_pll_fout(parent_rate, frac->nd, frac->fracr);
+
+       pr_debug("A PLL: %s, fout = %lu (nd = %u, fracr = %lu)\n", __func__,
+                fout, frac->nd, (unsigned long)frac->fracr);
+
+       return fout;
+}
+
+static unsigned long clk_audio_pll_pad_recalc_rate(struct clk_hw *hw,
+                                                  unsigned long parent_rate)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+       unsigned long apad_rate = 0;
+
+       if (apad_ck->qdaudio && apad_ck->div)
+               apad_rate = parent_rate / (apad_ck->qdaudio * apad_ck->div);
+
+       pr_debug("A PLL/PAD: %s, apad_rate = %lu (div = %u, qdaudio = %u)\n",
+                __func__, apad_rate, apad_ck->div, apad_ck->qdaudio);
+
+       return apad_rate;
+}
+
+static unsigned long clk_audio_pll_pmc_recalc_rate(struct clk_hw *hw,
+                                                  unsigned long parent_rate)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+       unsigned long apmc_rate = 0;
+
+       apmc_rate = parent_rate / (apmc_ck->qdpmc + 1);
+
+       pr_debug("A PLL/PMC: %s, apmc_rate = %lu (qdpmc = %u)\n", __func__,
+                apmc_rate, apmc_ck->qdpmc);
+
+       return apmc_rate;
+}
+
+static int clk_audio_pll_frac_compute_frac(unsigned long rate,
+                                          unsigned long parent_rate,
+                                          unsigned long *nd,
+                                          unsigned long *fracr)
+{
+       unsigned long long tmp, rem;
+
+       if (!rate)
+               return -EINVAL;
+
+       tmp = rate;
+       rem = do_div(tmp, parent_rate);
+       if (!tmp || tmp >= AUDIO_PLL_ND_MAX)
+               return -EINVAL;
+
+       *nd = tmp - 1;
+
+       tmp = rem * AUDIO_PLL_DIV_FRAC;
+       tmp = DIV_ROUND_CLOSEST_ULL(tmp, parent_rate);
+       if (tmp > AT91_PMC_AUDIO_PLL_FRACR_MASK)
+               return -EINVAL;
+
+       /* we can cast here as we verified the bounds just above */
+       *fracr = (unsigned long)tmp;
+
+       return 0;
+}
+
+static int clk_audio_pll_frac_determine_rate(struct clk_hw *hw,
+                                            struct clk_rate_request *req)
+{
+       unsigned long fracr, nd;
+       int ret;
+
+       pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                req->rate, req->best_parent_rate);
+
+       req->rate = clamp(req->rate, AUDIO_PLL_FOUT_MIN, AUDIO_PLL_FOUT_MAX);
+
+       req->min_rate = max(req->min_rate, AUDIO_PLL_FOUT_MIN);
+       req->max_rate = min(req->max_rate, AUDIO_PLL_FOUT_MAX);
+
+       ret = clk_audio_pll_frac_compute_frac(req->rate, req->best_parent_rate,
+                                             &nd, &fracr);
+       if (ret)
+               return ret;
+
+       req->rate = clk_audio_pll_fout(req->best_parent_rate, nd, fracr);
+
+       req->best_parent_hw = clk_hw_get_parent(hw);
+
+       pr_debug("A PLL: %s, best_rate = %lu (nd = %lu, fracr = %lu)\n",
+                __func__, req->rate, nd, fracr);
+
+       return 0;
+}
+
+static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *parent_rate)
+{
+       struct clk_hw *pclk = clk_hw_get_parent(hw);
+       long best_rate = -EINVAL;
+       unsigned long best_parent_rate;
+       unsigned long tmp_qd;
+       u32 div;
+       long tmp_rate;
+       int tmp_diff;
+       int best_diff = -1;
+
+       pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, *parent_rate);
+
+       /*
+        * Rate divisor is actually made of two different divisors, multiplied
+        * between themselves before dividing the rate.
+        * tmp_qd goes from 1 to 31 and div is either 2 or 3.
+        * In order to avoid testing twice the rate divisor (e.g. divisor 12 can
+        * be found with (tmp_qd, div) = (2, 6) or (3, 4)), we remove any loop
+        * for a rate divisor when div is 2 and tmp_qd is a multiple of 3.
+        * We cannot inverse it (condition div is 3 and tmp_qd is even) or we
+        * would miss some rate divisor that aren't reachable with div being 2
+        * (e.g. rate divisor 90 is made with div = 3 and tmp_qd = 30, thus
+        * tmp_qd is even so we skip it because we think div 2 could make this
+        * rate divisor which isn't possible since tmp_qd has to be <= 31).
+        */
+       for (tmp_qd = 1; tmp_qd < AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX; tmp_qd++)
+               for (div = 2; div <= 3; div++) {
+                       if (div == 2 && tmp_qd % 3 == 0)
+                               continue;
+
+                       best_parent_rate = clk_hw_round_rate(pclk,
+                                                       rate * tmp_qd * div);
+                       tmp_rate = best_parent_rate / (div * tmp_qd);
+                       tmp_diff = abs(rate - tmp_rate);
+
+                       if (best_diff < 0 || best_diff > tmp_diff) {
+                               *parent_rate = best_parent_rate;
+                               best_rate = tmp_rate;
+                               best_diff = tmp_diff;
+                       }
+               }
+
+       pr_debug("A PLL/PAD: %s, best_rate = %ld, best_parent_rate = %lu\n",
+                __func__, best_rate, best_parent_rate);
+
+       return best_rate;
+}
+
+static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *parent_rate)
+{
+       struct clk_hw *pclk = clk_hw_get_parent(hw);
+       long best_rate = -EINVAL;
+       unsigned long best_parent_rate = 0;
+       u32 tmp_qd = 0, div;
+       long tmp_rate;
+       int tmp_diff;
+       int best_diff = -1;
+
+       pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, *parent_rate);
+
+       for (div = 1; div <= AUDIO_PLL_QDPMC_MAX; div++) {
+               best_parent_rate = clk_round_rate(pclk->clk, rate * div);
+               tmp_rate = best_parent_rate / div;
+               tmp_diff = abs(rate - tmp_rate);
+
+               if (best_diff < 0 || best_diff > tmp_diff) {
+                       *parent_rate = best_parent_rate;
+                       best_rate = tmp_rate;
+                       best_diff = tmp_diff;
+                       tmp_qd = div;
+               }
+       }
+
+       pr_debug("A PLL/PMC: %s, best_rate = %ld, best_parent_rate = %lu (qd = %d)\n",
+                __func__, best_rate, *parent_rate, tmp_qd - 1);
+
+       return best_rate;
+}
+
+static int clk_audio_pll_frac_set_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long parent_rate)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+       unsigned long fracr, nd;
+       int ret;
+
+       pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__, rate,
+                parent_rate);
+
+       if (rate < AUDIO_PLL_FOUT_MIN || rate > AUDIO_PLL_FOUT_MAX)
+               return -EINVAL;
+
+       ret = clk_audio_pll_frac_compute_frac(rate, parent_rate, &nd, &fracr);
+       if (ret)
+               return ret;
+
+       frac->nd = nd;
+       frac->fracr = fracr;
+
+       return 0;
+}
+
+static int clk_audio_pll_pad_set_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long parent_rate)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+       u8 tmp_div;
+
+       pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, parent_rate);
+
+       if (!rate)
+               return -EINVAL;
+
+       tmp_div = parent_rate / rate;
+       if (tmp_div % 3 == 0) {
+               apad_ck->qdaudio = tmp_div / 3;
+               apad_ck->div = 3;
+       } else {
+               apad_ck->qdaudio = tmp_div / 2;
+               apad_ck->div = 2;
+       }
+
+       return 0;
+}
+
+static int clk_audio_pll_pmc_set_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long parent_rate)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+
+       if (!rate)
+               return -EINVAL;
+
+       pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, parent_rate);
+
+       apmc_ck->qdpmc = parent_rate / rate - 1;
+
+       return 0;
+}
+
+static const struct clk_ops audio_pll_frac_ops = {
+       .enable = clk_audio_pll_frac_enable,
+       .disable = clk_audio_pll_frac_disable,
+       .recalc_rate = clk_audio_pll_frac_recalc_rate,
+       .determine_rate = clk_audio_pll_frac_determine_rate,
+       .set_rate = clk_audio_pll_frac_set_rate,
+};
+
+static const struct clk_ops audio_pll_pad_ops = {
+       .enable = clk_audio_pll_pad_enable,
+       .disable = clk_audio_pll_pad_disable,
+       .recalc_rate = clk_audio_pll_pad_recalc_rate,
+       .round_rate = clk_audio_pll_pad_round_rate,
+       .set_rate = clk_audio_pll_pad_set_rate,
+};
+
+static const struct clk_ops audio_pll_pmc_ops = {
+       .enable = clk_audio_pll_pmc_enable,
+       .disable = clk_audio_pll_pmc_disable,
+       .recalc_rate = clk_audio_pll_pmc_recalc_rate,
+       .round_rate = clk_audio_pll_pmc_round_rate,
+       .set_rate = clk_audio_pll_pmc_set_rate,
+};
+
+static int of_sama5d2_clk_audio_pll_setup(struct device_node *np,
+                                         struct clk_init_data *init,
+                                         struct clk_hw *hw,
+                                         struct regmap **clk_audio_regmap)
+{
+       struct regmap *regmap;
+       const char *parent_names[1];
+       int ret;
+
+       regmap = syscon_node_to_regmap(of_get_parent(np));
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       init->name = np->name;
+       of_clk_parent_fill(np, parent_names, 1);
+       init->parent_names = parent_names;
+       init->num_parents = 1;
+
+       hw->init = init;
+       *clk_audio_regmap = regmap;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret)
+               return ret;
+
+       return of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+
+static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
+{
+       struct clk_audio_frac *frac_ck;
+       struct clk_init_data init = {};
+
+       frac_ck = kzalloc(sizeof(*frac_ck), GFP_KERNEL);
+       if (!frac_ck)
+               return;
+
+       init.ops = &audio_pll_frac_ops;
+       init.flags = CLK_SET_RATE_GATE;
+
+       if (of_sama5d2_clk_audio_pll_setup(np, &init, &frac_ck->hw,
+                                          &frac_ck->regmap))
+               kfree(frac_ck);
+}
+
+static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
+{
+       struct clk_audio_pad *apad_ck;
+       struct clk_init_data init = {};
+
+       apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL);
+       if (!apad_ck)
+               return;
+
+       init.ops = &audio_pll_pad_ops;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+               CLK_SET_RATE_PARENT;
+
+       if (of_sama5d2_clk_audio_pll_setup(np, &init, &apad_ck->hw,
+                                          &apad_ck->regmap))
+               kfree(apad_ck);
+}
+
+static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
+{
+       struct clk_audio_pad *apmc_ck;
+       struct clk_init_data init = {};
+
+       apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL);
+       if (!apmc_ck)
+               return;
+
+       init.ops = &audio_pll_pmc_ops;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+               CLK_SET_RATE_PARENT;
+
+       if (of_sama5d2_clk_audio_pll_setup(np, &init, &apmc_ck->hw,
+                                          &apmc_ck->regmap))
+               kfree(apmc_ck);
+}
+
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
+              "atmel,sama5d2-clk-audio-pll-frac",
+              of_sama5d2_clk_audio_pll_frac_setup);
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
+              "atmel,sama5d2-clk-audio-pll-pad",
+              of_sama5d2_clk_audio_pll_pad_setup);
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
+              "atmel,sama5d2-clk-audio-pll-pmc",
+              of_sama5d2_clk_audio_pll_pmc_setup);
index f0b7ae904ce2c991d8a5f998734a77235de194ee..33481368740e7dc038fe1e32065e2659d8cec730 100644 (file)
 #define GENERATED_SOURCE_MAX   6
 #define GENERATED_MAX_DIV      255
 
+#define GCK_ID_SSC0            43
+#define GCK_ID_SSC1            44
+#define GCK_ID_I2S0            54
+#define GCK_ID_I2S1            55
+#define GCK_ID_CLASSD          59
+#define GCK_INDEX_DT_AUDIO_PLL 5
+
 struct clk_generated {
        struct clk_hw hw;
        struct regmap *regmap;
@@ -34,6 +41,7 @@ struct clk_generated {
        u32 id;
        u32 gckdiv;
        u8 parent_id;
+       bool audio_pll_allowed;
 };
 
 #define to_clk_generated(hw) \
@@ -99,21 +107,41 @@ clk_generated_recalc_rate(struct clk_hw *hw,
        return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1);
 }
 
+static void clk_generated_best_diff(struct clk_rate_request *req,
+                                   struct clk_hw *parent,
+                                   unsigned long parent_rate, u32 div,
+                                   int *best_diff, long *best_rate)
+{
+       unsigned long tmp_rate;
+       int tmp_diff;
+
+       if (!div)
+               tmp_rate = parent_rate;
+       else
+               tmp_rate = parent_rate / div;
+       tmp_diff = abs(req->rate - tmp_rate);
+
+       if (*best_diff < 0 || *best_diff > tmp_diff) {
+               *best_rate = tmp_rate;
+               *best_diff = tmp_diff;
+               req->best_parent_rate = parent_rate;
+               req->best_parent_hw = parent;
+       }
+}
+
 static int clk_generated_determine_rate(struct clk_hw *hw,
                                        struct clk_rate_request *req)
 {
        struct clk_generated *gck = to_clk_generated(hw);
        struct clk_hw *parent = NULL;
+       struct clk_rate_request req_parent = *req;
        long best_rate = -EINVAL;
-       unsigned long tmp_rate, min_rate;
+       unsigned long min_rate, parent_rate;
        int best_diff = -1;
-       int tmp_diff;
        int i;
+       u32 div;
 
-       for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
-               u32 div;
-               unsigned long parent_rate;
-
+       for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
                parent = clk_hw_get_parent_by_index(hw, i);
                if (!parent)
                        continue;
@@ -124,25 +152,43 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
                    (gck->range.max && min_rate > gck->range.max))
                        continue;
 
-               for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
-                       tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
-                       tmp_diff = abs(req->rate - tmp_rate);
+               div = DIV_ROUND_CLOSEST(parent_rate, req->rate);
 
-                       if (best_diff < 0 || best_diff > tmp_diff) {
-                               best_rate = tmp_rate;
-                               best_diff = tmp_diff;
-                               req->best_parent_rate = parent_rate;
-                               req->best_parent_hw = parent;
-                       }
+               clk_generated_best_diff(req, parent, parent_rate, div,
+                                       &best_diff, &best_rate);
 
-                       if (!best_diff || tmp_rate < req->rate)
-                               break;
-               }
+               if (!best_diff)
+                       break;
+       }
+
+       /*
+        * The audio_pll rate can be modified, unlike the five others clocks
+        * that should never be altered.
+        * The audio_pll can technically be used by multiple consumers. However,
+        * with the rate locking, the first consumer to enable to clock will be
+        * the one definitely setting the rate of the clock.
+        * Since audio IPs are most likely to request the same rate, we enforce
+        * that the only clks able to modify gck rate are those of audio IPs.
+        */
+
+       if (!gck->audio_pll_allowed)
+               goto end;
+
+       parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
+       if (!parent)
+               goto end;
+
+       for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
+               req_parent.rate = req->rate * div;
+               __clk_determine_rate(parent, &req_parent);
+               clk_generated_best_diff(req, parent, req_parent.rate, div,
+                                       &best_diff, &best_rate);
 
                if (!best_diff)
                        break;
        }
 
+end:
        pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
                 __func__, best_rate,
                 __clk_get_name((req->best_parent_hw)->clk),
@@ -252,7 +298,8 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
        init.ops = &generated_ops;
        init.parent_names = parent_names;
        init.num_parents = num_parents;
-       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+               CLK_SET_RATE_PARENT;
 
        gck->id = id;
        gck->hw.init = &init;
@@ -284,6 +331,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
        struct device_node *gcknp;
        struct clk_range range = CLK_RANGE(0, 0);
        struct regmap *regmap;
+       struct clk_generated *gck;
 
        num_parents = of_clk_get_parent_count(np);
        if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
@@ -315,6 +363,21 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
                hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
                                                  parent_names, num_parents,
                                                  id, &range);
+
+               gck = to_clk_generated(hw);
+
+               if (of_device_is_compatible(np,
+                                           "atmel,sama5d2-clk-generated")) {
+                       if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 ||
+                           gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 ||
+                           gck->id == GCK_ID_CLASSD)
+                               gck->audio_pll_allowed = true;
+                       else
+                               gck->audio_pll_allowed = false;
+               } else {
+                       gck->audio_pll_allowed = false;
+               }
+
                if (IS_ERR(hw))
                        continue;
 
index 01996b871b06ed5a282f3fa65793d0f1804000c0..d747deafbf1e2e2014232c589d7869e4f96fa9b6 100644 (file)
@@ -1 +1,2 @@
 obj-y += i2s_pll_clock.o
+obj-y += pll_clock.o
diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c
new file mode 100644 (file)
index 0000000..25d8c24
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Synopsys AXS10X SDP Generic PLL clock driver
+ *
+ * Copyright (C) 2017 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+/* PLL registers addresses */
+#define PLL_REG_IDIV   0x0
+#define PLL_REG_FBDIV  0x4
+#define PLL_REG_ODIV   0x8
+
+/*
+ * Bit fields of the PLL IDIV/FBDIV/ODIV registers:
+ *  ________________________________________________________________________
+ * |31                15|    14    |   13   |  12  |11         6|5         0|
+ * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--|
+ * |____________________|__________|________|______|____________|___________|
+ *
+ * Following macros determine the way of access to these registers
+ * They should be set up only using the macros.
+ * reg should be an u32 variable.
+ */
+
+#define PLL_REG_GET_LOW(reg)                   \
+       (((reg) & (0x3F << 0)) >> 0)
+#define PLL_REG_GET_HIGH(reg)                  \
+       (((reg) & (0x3F << 6)) >> 6)
+#define PLL_REG_GET_EDGE(reg)                  \
+       (((reg) & (BIT(12))) ? 1 : 0)
+#define PLL_REG_GET_BYPASS(reg)                        \
+       (((reg) & (BIT(13))) ? 1 : 0)
+#define PLL_REG_GET_NOUPD(reg)                 \
+       (((reg) & (BIT(14))) ? 1 : 0)
+#define PLL_REG_GET_PAD(reg)                   \
+       (((reg) & (0x1FFFF << 15)) >> 15)
+
+#define PLL_REG_SET_LOW(reg, value)            \
+       { reg |= (((value) & 0x3F) << 0); }
+#define PLL_REG_SET_HIGH(reg, value)           \
+       { reg |= (((value) & 0x3F) << 6); }
+#define PLL_REG_SET_EDGE(reg, value)           \
+       { reg |= (((value) & 0x01) << 12); }
+#define PLL_REG_SET_BYPASS(reg, value)         \
+       { reg |= (((value) & 0x01) << 13); }
+#define PLL_REG_SET_NOUPD(reg, value)          \
+       { reg |= (((value) & 0x01) << 14); }
+#define PLL_REG_SET_PAD(reg, value)            \
+       { reg |= (((value) & 0x1FFFF) << 15); }
+
+#define PLL_LOCK       BIT(0)
+#define PLL_ERROR      BIT(1)
+#define PLL_MAX_LOCK_TIME 100 /* 100 us */
+
+struct axs10x_pll_cfg {
+       u32 rate;
+       u32 idiv;
+       u32 fbdiv;
+       u32 odiv;
+};
+
+static const struct axs10x_pll_cfg arc_pll_cfg[] = {
+       { 33333333,  1, 1,  1 },
+       { 50000000,  1, 30, 20 },
+       { 75000000,  2, 45, 10 },
+       { 90000000,  2, 54, 10 },
+       { 100000000, 1, 30, 10 },
+       { 125000000, 2, 45, 6 },
+       {}
+};
+
+static const struct axs10x_pll_cfg pgu_pll_cfg[] = {
+       { 25200000, 1, 84, 90 },
+       { 50000000, 1, 100, 54 },
+       { 74250000, 1, 44, 16 },
+       {}
+};
+
+struct axs10x_pll_clk {
+       struct clk_hw hw;
+       void __iomem *base;
+       void __iomem *lock;
+       const struct axs10x_pll_cfg *pll_cfg;
+       struct device *dev;
+};
+
+static inline void axs10x_pll_write(struct axs10x_pll_clk *clk, u32 reg,
+                                   u32 val)
+{
+       iowrite32(val, clk->base + reg);
+}
+
+static inline u32 axs10x_pll_read(struct axs10x_pll_clk *clk, u32 reg)
+{
+       return ioread32(clk->base + reg);
+}
+
+static inline struct axs10x_pll_clk *to_axs10x_pll_clk(struct clk_hw *hw)
+{
+       return container_of(hw, struct axs10x_pll_clk, hw);
+}
+
+static inline u32 axs10x_div_get_value(u32 reg)
+{
+       if (PLL_REG_GET_BYPASS(reg))
+               return 1;
+
+       return PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg);
+}
+
+static inline u32 axs10x_encode_div(unsigned int id, int upd)
+{
+       u32 div = 0;
+
+       PLL_REG_SET_LOW(div, (id % 2 == 0) ? id >> 1 : (id >> 1) + 1);
+       PLL_REG_SET_HIGH(div, id >> 1);
+       PLL_REG_SET_EDGE(div, id % 2);
+       PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0);
+       PLL_REG_SET_NOUPD(div, upd == 0 ? 1 : 0);
+
+       return div;
+}
+
+static unsigned long axs10x_pll_recalc_rate(struct clk_hw *hw,
+                                           unsigned long parent_rate)
+{
+       u64 rate;
+       u32 idiv, fbdiv, odiv;
+       struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
+
+       idiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_IDIV));
+       fbdiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_FBDIV));
+       odiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_ODIV));
+
+       rate = (u64)parent_rate * fbdiv;
+       do_div(rate, idiv * odiv);
+
+       return rate;
+}
+
+static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long *prate)
+{
+       int i;
+       long best_rate;
+       struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
+       const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg;
+
+       if (pll_cfg[0].rate == 0)
+               return -EINVAL;
+
+       best_rate = pll_cfg[0].rate;
+
+       for (i = 1; pll_cfg[i].rate != 0; i++) {
+               if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
+                       best_rate = pll_cfg[i].rate;
+       }
+
+       return best_rate;
+}
+
+static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long parent_rate)
+{
+       int i;
+       struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
+       const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg;
+
+       for (i = 0; pll_cfg[i].rate != 0; i++) {
+               if (pll_cfg[i].rate == rate) {
+                       axs10x_pll_write(clk, PLL_REG_IDIV,
+                                        axs10x_encode_div(pll_cfg[i].idiv, 0));
+                       axs10x_pll_write(clk, PLL_REG_FBDIV,
+                                        axs10x_encode_div(pll_cfg[i].fbdiv, 0));
+                       axs10x_pll_write(clk, PLL_REG_ODIV,
+                                        axs10x_encode_div(pll_cfg[i].odiv, 1));
+
+                       /*
+                        * Wait until CGU relocks and check error status.
+                        * If after timeout CGU is unlocked yet return error
+                        */
+                       udelay(PLL_MAX_LOCK_TIME);
+                       if (!(ioread32(clk->lock) & PLL_LOCK))
+                               return -ETIMEDOUT;
+
+                       if (ioread32(clk->lock) & PLL_ERROR)
+                               return -EINVAL;
+
+                       return 0;
+               }
+       }
+
+       dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
+                       parent_rate);
+       return -EINVAL;
+}
+
+static const struct clk_ops axs10x_pll_ops = {
+       .recalc_rate = axs10x_pll_recalc_rate,
+       .round_rate = axs10x_pll_round_rate,
+       .set_rate = axs10x_pll_set_rate,
+};
+
+static int axs10x_pll_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const char *parent_name;
+       struct axs10x_pll_clk *pll_clk;
+       struct resource *mem;
+       struct clk_init_data init = { };
+       int ret;
+
+       pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return -ENOMEM;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pll_clk->base = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(pll_clk->base))
+               return PTR_ERR(pll_clk->base);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       pll_clk->lock = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(pll_clk->lock))
+               return PTR_ERR(pll_clk->lock);
+
+       init.name = dev->of_node->name;
+       init.ops = &axs10x_pll_ops;
+       parent_name = of_clk_get_parent_name(dev->of_node, 0);
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+       pll_clk->hw.init = &init;
+       pll_clk->dev = dev;
+       pll_clk->pll_cfg = of_device_get_match_data(dev);
+
+       if (!pll_clk->pll_cfg) {
+               dev_err(dev, "No OF match data provided\n");
+               return -EINVAL;
+       }
+
+       ret = devm_clk_hw_register(dev, &pll_clk->hw);
+       if (ret) {
+               dev_err(dev, "failed to register %s clock\n", init.name);
+               return ret;
+       }
+
+       return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
+                       &pll_clk->hw);
+}
+
+static int axs10x_pll_clk_remove(struct platform_device *pdev)
+{
+       of_clk_del_provider(pdev->dev.of_node);
+       return 0;
+}
+
+static void __init of_axs10x_pll_clk_setup(struct device_node *node)
+{
+       const char *parent_name;
+       struct axs10x_pll_clk *pll_clk;
+       struct clk_init_data init = { };
+       int ret;
+
+       pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return;
+
+       pll_clk->base = of_iomap(node, 0);
+       if (!pll_clk->base) {
+               pr_err("failed to map pll div registers\n");
+               goto err_free_pll_clk;
+       }
+
+       pll_clk->lock = of_iomap(node, 1);
+       if (!pll_clk->lock) {
+               pr_err("failed to map pll lock register\n");
+               goto err_unmap_base;
+       }
+
+       init.name = node->name;
+       init.ops = &axs10x_pll_ops;
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.parent_names = &parent_name;
+       init.num_parents = parent_name ? 1 : 0;
+       pll_clk->hw.init = &init;
+       pll_clk->pll_cfg = arc_pll_cfg;
+
+       ret = clk_hw_register(NULL, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to register %s clock\n", node->name);
+               goto err_unmap_lock;
+       }
+
+       ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to add hw provider for %s clock\n", node->name);
+               goto err_unregister_clk;
+       }
+
+       return;
+
+err_unregister_clk:
+       clk_hw_unregister(&pll_clk->hw);
+err_unmap_lock:
+       iounmap(pll_clk->lock);
+err_unmap_base:
+       iounmap(pll_clk->base);
+err_free_pll_clk:
+       kfree(pll_clk);
+}
+CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock",
+              of_axs10x_pll_clk_setup);
+
+static const struct of_device_id axs10x_pll_clk_id[] = {
+       { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_cfg},
+       { }
+};
+MODULE_DEVICE_TABLE(of, axs10x_pll_clk_id);
+
+static struct platform_driver axs10x_pll_clk_driver = {
+       .driver = {
+               .name = "axs10x-pll-clock",
+               .of_match_table = axs10x_pll_clk_id,
+       },
+       .probe = axs10x_pll_clk_probe,
+       .remove = axs10x_pll_clk_remove,
+};
+builtin_platform_driver(axs10x_pll_clk_driver);
+
+MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>");
+MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver");
+MODULE_LICENSE("GPL v2");
index 1d99292e2039ee5ff6e187e4e0cdbddf85d860e1..e7331ace0337cc564bb3b3114d4f21063f8a849f 100644 (file)
@@ -679,8 +679,7 @@ static void __init berlin2_clock_setup(struct device_node *np)
                if (!IS_ERR(hws[n]))
                        continue;
 
-               pr_err("%s: Unable to register leaf clock %d\n",
-                      np->full_name, n);
+               pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
                goto bg2_fail;
        }
 
index 3b784b593afde7fea97650f938b03c55c79d8ac0..67c270b143f7280da78a8524c32619b7fdb1d73d 100644 (file)
@@ -304,14 +304,14 @@ static void __init berlin2q_clock_setup(struct device_node *np)
 
        gbase = of_iomap(parent_np, 0);
        if (!gbase) {
-               pr_err("%s: Unable to map global base\n", np->full_name);
+               pr_err("%pOF: Unable to map global base\n", np);
                return;
        }
 
        /* BG2Q CPU PLL is not part of global registers */
        cpupll_base = of_iomap(parent_np, 1);
        if (!cpupll_base) {
-               pr_err("%s: Unable to map cpupll base\n", np->full_name);
+               pr_err("%pOF: Unable to map cpupll base\n", np);
                iounmap(gbase);
                return;
        }
@@ -376,8 +376,7 @@ static void __init berlin2q_clock_setup(struct device_node *np)
                if (!IS_ERR(hws[n]))
                        continue;
 
-               pr_err("%s: Unable to register leaf clock %d\n",
-                      np->full_name, n);
+               pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
                goto bg2q_fail;
        }
 
index ea8568536193ba3c59db95e904ceb8ad75e034d2..bf0582cbbf38e31aeaa6aca5a466d79db07adce2 100644 (file)
@@ -338,8 +338,8 @@ static void __init asm9260_acc_init(struct device_node *np)
                if (!IS_ERR(hws[n]))
                        continue;
 
-               pr_err("%s: Unable to register leaf clock %d\n",
-                               np->full_name, n);
+               pr_err("%pOF: Unable to register leaf clock %d\n",
+                               np, n);
                goto fail;
        }
 
index 7ec36722f8ab0f4cac82b18a91283696268c781f..49819b546134bfa4794d513ce0d6fb5d2e6e609d 100644 (file)
@@ -23,8 +23,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
        num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
                                                 "#clock-cells");
        if (num_parents == -EINVAL)
-               pr_err("clk: invalid value of clock-parents property at %s\n",
-                      node->full_name);
+               pr_err("clk: invalid value of clock-parents property at %pOF\n",
+                      node);
 
        for (index = 0; index < num_parents; index++) {
                rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
@@ -41,8 +41,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
                pclk = of_clk_get_from_provider(&clkspec);
                if (IS_ERR(pclk)) {
                        if (PTR_ERR(pclk) != -EPROBE_DEFER)
-                               pr_warn("clk: couldn't get parent clock %d for %s\n",
-                                       index, node->full_name);
+                               pr_warn("clk: couldn't get parent clock %d for %pOF\n",
+                                       index, node);
                        return PTR_ERR(pclk);
                }
 
@@ -57,8 +57,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
                clk = of_clk_get_from_provider(&clkspec);
                if (IS_ERR(clk)) {
                        if (PTR_ERR(clk) != -EPROBE_DEFER)
-                               pr_warn("clk: couldn't get assigned clock %d for %s\n",
-                                       index, node->full_name);
+                               pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
+                                       index, node);
                        rc = PTR_ERR(clk);
                        goto err;
                }
@@ -102,8 +102,8 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
                        clk = of_clk_get_from_provider(&clkspec);
                        if (IS_ERR(clk)) {
                                if (PTR_ERR(clk) != -EPROBE_DEFER)
-                                       pr_warn("clk: couldn't get clock %d for %s\n",
-                                               index, node->full_name);
+                                       pr_warn("clk: couldn't get clock %d for %pOF\n",
+                                               index, node);
                                return PTR_ERR(clk);
                        }
 
index c54baede4d68733ad2861b24e24c0f082aa5520e..e8ea81c30f0ccd290ea9fa7b66750b889c23a8df 100644 (file)
@@ -343,6 +343,15 @@ static int cs2000_set_rate(struct clk_hw *hw,
        return __cs2000_set_rate(priv, ch, rate, parent_rate);
 }
 
+static int cs2000_set_saved_rate(struct cs2000_priv *priv)
+{
+       int ch = 0; /* it uses ch0 only at this point */
+
+       return __cs2000_set_rate(priv, ch,
+                                priv->saved_rate,
+                                priv->saved_parent_rate);
+}
+
 static int cs2000_enable(struct clk_hw *hw)
 {
        struct cs2000_priv *priv = hw_to_priv(hw);
@@ -535,11 +544,8 @@ probe_err:
 static int cs2000_resume(struct device *dev)
 {
        struct cs2000_priv *priv = dev_get_drvdata(dev);
-       int ch = 0; /* it uses ch0 only at this point */
 
-       return __cs2000_set_rate(priv, ch,
-                                priv->saved_rate,
-                                priv->saved_parent_rate);
+       return cs2000_set_saved_rate(priv);
 }
 
 static const struct dev_pm_ops cs2000_pm_ops = {
index 9bb472cccca6e044e46bebc0ec57f4c74641b11b..4ed516cb72764a18a29f8cd77efcc81aa7087c47 100644 (file)
@@ -385,12 +385,14 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
                                unsigned long parent_rate)
 {
        struct clk_divider *divider = to_clk_divider(hw);
-       unsigned int value;
+       int value;
        unsigned long flags = 0;
        u32 val;
 
        value = divider_get_val(rate, parent_rate, divider->table,
                                divider->width, divider->flags);
+       if (value < 0)
+               return value;
 
        if (divider->lock)
                spin_lock_irqsave(divider->lock, flags);
@@ -403,7 +405,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
                val = clk_readl(divider->reg);
                val &= ~(div_mask(divider->width) << divider->shift);
        }
-       val |= value << divider->shift;
+       val |= (u32)value << divider->shift;
        clk_writel(val, divider->reg);
 
        if (divider->lock)
index aab904618eb636f9f926a6b7b46d7b03b780b10c..fdf625fb10faa03fc8c394555612fdcdf855ac09 100644 (file)
@@ -49,16 +49,12 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
        return ret;
 }
 
-static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
-                             unsigned long *parent_rate)
+static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *parent_rate,
+                                        unsigned long *m, unsigned long *n)
 {
        struct clk_fractional_divider *fd = to_clk_fd(hw);
        unsigned long scale;
-       unsigned long m, n;
-       u64 ret;
-
-       if (!rate || rate >= *parent_rate)
-               return *parent_rate;
 
        /*
         * Get rate closer to *parent_rate to guarantee there is no overflow
@@ -71,7 +67,23 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
 
        rational_best_approximation(rate, *parent_rate,
                        GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
-                       &m, &n);
+                       m, n);
+}
+
+static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *parent_rate)
+{
+       struct clk_fractional_divider *fd = to_clk_fd(hw);
+       unsigned long m, n;
+       u64 ret;
+
+       if (!rate || rate >= *parent_rate)
+               return *parent_rate;
+
+       if (fd->approximation)
+               fd->approximation(hw, rate, parent_rate, &m, &n);
+       else
+               clk_fd_general_approximation(hw, rate, parent_rate, &m, &n);
 
        ret = (u64)*parent_rate * m;
        do_div(ret, n);
index 4e0c054a787c07f93c287c4d38b306dffd3ee409..dd82485e09a1f9cac9d4652a4def98bb0eaa6110 100644 (file)
@@ -86,7 +86,7 @@ static void clk_gate_disable(struct clk_hw *hw)
        clk_gate_endisable(hw, 0);
 }
 
-static int clk_gate_is_enabled(struct clk_hw *hw)
+int clk_gate_is_enabled(struct clk_hw *hw)
 {
        u32 reg;
        struct clk_gate *gate = to_clk_gate(hw);
@@ -101,6 +101,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 
        return reg ? 1 : 0;
 }
+EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
 
 const struct clk_ops clk_gate_ops = {
        .enable = clk_gate_enable,
index b4cf2f699a21024b727aabcb5a265fb0d613e817..f940e5af845b8d71eabe0bd2e20de20a1cb3f25e 100644 (file)
@@ -37,7 +37,6 @@ static DEFINE_SPINLOCK(gemini_clk_lock);
 
 #define GEMINI_GLOBAL_MISC_CONTROL     0x30
 #define PCI_CLK_66MHZ                  BIT(18)
-#define PCI_CLK_OE                     BIT(17)
 
 #define GEMINI_GLOBAL_CLOCK_CONTROL    0x34
 #define PCI_CLKRUN_EN                  BIT(16)
@@ -159,9 +158,6 @@ static int gemini_pci_enable(struct clk_hw *hw)
 
        regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL,
                           0, PCI_CLKRUN_EN);
-       regmap_update_bits(pciclk->map,
-                          GEMINI_GLOBAL_MISC_CONTROL,
-                          0, PCI_CLK_OE);
        return 0;
 }
 
@@ -169,9 +165,6 @@ static void gemini_pci_disable(struct clk_hw *hw)
 {
        struct clk_gemini_pci *pciclk = to_pciclk(hw);
 
-       regmap_update_bits(pciclk->map,
-                          GEMINI_GLOBAL_MISC_CONTROL,
-                          PCI_CLK_OE, 0);
        regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL,
                           PCI_CLKRUN_EN, 0);
 }
diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c
new file mode 100644 (file)
index 0000000..bbf2371
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Synopsys HSDK SDP Generic PLL clock driver
+ *
+ * Copyright (C) 2017 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define CGU_PLL_CTRL   0x000 /* ARC PLL control register */
+#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */
+#define CGU_PLL_FMEAS  0x008 /* ARC PLL frequency measurement register */
+#define CGU_PLL_MON    0x00C /* ARC PLL monitor register */
+
+#define CGU_PLL_CTRL_ODIV_SHIFT                2
+#define CGU_PLL_CTRL_IDIV_SHIFT                4
+#define CGU_PLL_CTRL_FBDIV_SHIFT       9
+#define CGU_PLL_CTRL_BAND_SHIFT                20
+
+#define CGU_PLL_CTRL_ODIV_MASK         GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT)
+#define CGU_PLL_CTRL_IDIV_MASK         GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT)
+#define CGU_PLL_CTRL_FBDIV_MASK                GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT)
+
+#define CGU_PLL_CTRL_PD                        BIT(0)
+#define CGU_PLL_CTRL_BYPASS            BIT(1)
+
+#define CGU_PLL_STATUS_LOCK            BIT(0)
+#define CGU_PLL_STATUS_ERR             BIT(1)
+
+#define HSDK_PLL_MAX_LOCK_TIME         100 /* 100 us */
+
+#define CGU_PLL_SOURCE_MAX             1
+
+#define CORE_IF_CLK_THRESHOLD_HZ       500000000
+#define CREG_CORE_IF_CLK_DIV_1         0x0
+#define CREG_CORE_IF_CLK_DIV_2         0x1
+
+struct hsdk_pll_cfg {
+       u32 rate;
+       u32 idiv;
+       u32 fbdiv;
+       u32 odiv;
+       u32 band;
+};
+
+static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
+       { 100000000,  0, 11, 3, 0 },
+       { 133000000,  0, 15, 3, 0 },
+       { 200000000,  1, 47, 3, 0 },
+       { 233000000,  1, 27, 2, 0 },
+       { 300000000,  1, 35, 2, 0 },
+       { 333000000,  1, 39, 2, 0 },
+       { 400000000,  1, 47, 2, 0 },
+       { 500000000,  0, 14, 1, 0 },
+       { 600000000,  0, 17, 1, 0 },
+       { 700000000,  0, 20, 1, 0 },
+       { 800000000,  0, 23, 1, 0 },
+       { 900000000,  1, 26, 0, 0 },
+       { 1000000000, 1, 29, 0, 0 },
+       { 1100000000, 1, 32, 0, 0 },
+       { 1200000000, 1, 35, 0, 0 },
+       { 1300000000, 1, 38, 0, 0 },
+       { 1400000000, 1, 41, 0, 0 },
+       { 1500000000, 1, 44, 0, 0 },
+       { 1600000000, 1, 47, 0, 0 },
+       {}
+};
+
+static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
+       { 297000000,  0, 21, 2, 0 },
+       { 540000000,  0, 19, 1, 0 },
+       { 594000000,  0, 21, 1, 0 },
+       {}
+};
+
+struct hsdk_pll_clk {
+       struct clk_hw hw;
+       void __iomem *regs;
+       void __iomem *spec_regs;
+       const struct hsdk_pll_devdata *pll_devdata;
+       struct device *dev;
+};
+
+struct hsdk_pll_devdata {
+       const struct hsdk_pll_cfg *pll_cfg;
+       int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate,
+                          const struct hsdk_pll_cfg *cfg);
+};
+
+static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long,
+                                    const struct hsdk_pll_cfg *);
+static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long,
+                                    const struct hsdk_pll_cfg *);
+
+static const struct hsdk_pll_devdata core_pll_devdata = {
+       .pll_cfg = asdt_pll_cfg,
+       .update_rate = hsdk_pll_core_update_rate,
+};
+
+static const struct hsdk_pll_devdata sdt_pll_devdata = {
+       .pll_cfg = asdt_pll_cfg,
+       .update_rate = hsdk_pll_comm_update_rate,
+};
+
+static const struct hsdk_pll_devdata hdmi_pll_devdata = {
+       .pll_cfg = hdmi_pll_cfg,
+       .update_rate = hsdk_pll_comm_update_rate,
+};
+
+static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val)
+{
+       iowrite32(val, clk->regs + reg);
+}
+
+static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg)
+{
+       return ioread32(clk->regs + reg);
+}
+
+static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk,
+                                   const struct hsdk_pll_cfg *cfg)
+{
+       u32 val = 0;
+
+       /* Powerdown and Bypass bits should be cleared */
+       val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
+       val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
+       val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
+       val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
+
+       dev_dbg(clk->dev, "write configurarion: %#x\n", val);
+
+       hsdk_pll_write(clk, CGU_PLL_CTRL, val);
+}
+
+static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk)
+{
+       return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK);
+}
+
+static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk)
+{
+       return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR);
+}
+
+static inline struct hsdk_pll_clk *to_hsdk_pll_clk(struct clk_hw *hw)
+{
+       return container_of(hw, struct hsdk_pll_clk, hw);
+}
+
+static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw,
+                                         unsigned long parent_rate)
+{
+       u32 val;
+       u64 rate;
+       u32 idiv, fbdiv, odiv;
+       struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
+
+       val = hsdk_pll_read(clk, CGU_PLL_CTRL);
+
+       dev_dbg(clk->dev, "current configurarion: %#x\n", val);
+
+       /* Check if PLL is disabled */
+       if (val & CGU_PLL_CTRL_PD)
+               return 0;
+
+       /* Check if PLL is bypassed */
+       if (val & CGU_PLL_CTRL_BYPASS)
+               return parent_rate;
+
+       /* input divider = reg.idiv + 1 */
+       idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT);
+       /* fb divider = 2*(reg.fbdiv + 1) */
+       fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT));
+       /* output divider = 2^(reg.odiv) */
+       odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT);
+
+       rate = (u64)parent_rate * fbdiv;
+       do_div(rate, idiv * odiv);
+
+       return rate;
+}
+
+static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long *prate)
+{
+       int i;
+       unsigned long best_rate;
+       struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
+       const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+
+       if (pll_cfg[0].rate == 0)
+               return -EINVAL;
+
+       best_rate = pll_cfg[0].rate;
+
+       for (i = 1; pll_cfg[i].rate != 0; i++) {
+               if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
+                       best_rate = pll_cfg[i].rate;
+       }
+
+       dev_dbg(clk->dev, "chosen best rate: %lu\n", best_rate);
+
+       return best_rate;
+}
+
+static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk,
+                                    unsigned long rate,
+                                    const struct hsdk_pll_cfg *cfg)
+{
+       hsdk_pll_set_cfg(clk, cfg);
+
+       /*
+        * Wait until CGU relocks and check error status.
+        * If after timeout CGU is unlocked yet return error.
+        */
+       udelay(HSDK_PLL_MAX_LOCK_TIME);
+       if (!hsdk_pll_is_locked(clk))
+               return -ETIMEDOUT;
+
+       if (hsdk_pll_is_err(clk))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk,
+                                    unsigned long rate,
+                                    const struct hsdk_pll_cfg *cfg)
+{
+       /*
+        * When core clock exceeds 500MHz, the divider for the interface
+        * clock must be programmed to div-by-2.
+        */
+       if (rate > CORE_IF_CLK_THRESHOLD_HZ)
+               iowrite32(CREG_CORE_IF_CLK_DIV_2, clk->spec_regs);
+
+       hsdk_pll_set_cfg(clk, cfg);
+
+       /*
+        * Wait until CGU relocks and check error status.
+        * If after timeout CGU is unlocked yet return error.
+        */
+       udelay(HSDK_PLL_MAX_LOCK_TIME);
+       if (!hsdk_pll_is_locked(clk))
+               return -ETIMEDOUT;
+
+       if (hsdk_pll_is_err(clk))
+               return -EINVAL;
+
+       /*
+        * Program divider to div-by-1 if we succesfuly set core clock below
+        * 500MHz threshold.
+        */
+       if (rate <= CORE_IF_CLK_THRESHOLD_HZ)
+               iowrite32(CREG_CORE_IF_CLK_DIV_1, clk->spec_regs);
+
+       return 0;
+}
+
+static int hsdk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                            unsigned long parent_rate)
+{
+       int i;
+       struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
+       const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+
+       for (i = 0; pll_cfg[i].rate != 0; i++) {
+               if (pll_cfg[i].rate == rate) {
+                       return clk->pll_devdata->update_rate(clk, rate,
+                                                            &pll_cfg[i]);
+               }
+       }
+
+       dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
+                       parent_rate);
+
+       return -EINVAL;
+}
+
+static const struct clk_ops hsdk_pll_ops = {
+       .recalc_rate = hsdk_pll_recalc_rate,
+       .round_rate = hsdk_pll_round_rate,
+       .set_rate = hsdk_pll_set_rate,
+};
+
+static int hsdk_pll_clk_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *mem;
+       const char *parent_name;
+       unsigned int num_parents;
+       struct hsdk_pll_clk *pll_clk;
+       struct clk_init_data init = { };
+       struct device *dev = &pdev->dev;
+
+       pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return -ENOMEM;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pll_clk->regs = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(pll_clk->regs))
+               return PTR_ERR(pll_clk->regs);
+
+       init.name = dev->of_node->name;
+       init.ops = &hsdk_pll_ops;
+       parent_name = of_clk_get_parent_name(dev->of_node, 0);
+       init.parent_names = &parent_name;
+       num_parents = of_clk_get_parent_count(dev->of_node);
+       if (num_parents == 0 || num_parents > CGU_PLL_SOURCE_MAX) {
+               dev_err(dev, "wrong clock parents number: %u\n", num_parents);
+               return -EINVAL;
+       }
+       init.num_parents = num_parents;
+
+       pll_clk->hw.init = &init;
+       pll_clk->dev = dev;
+       pll_clk->pll_devdata = of_device_get_match_data(dev);
+
+       if (!pll_clk->pll_devdata) {
+               dev_err(dev, "No OF match data provided\n");
+               return -EINVAL;
+       }
+
+       ret = devm_clk_hw_register(dev, &pll_clk->hw);
+       if (ret) {
+               dev_err(dev, "failed to register %s clock\n", init.name);
+               return ret;
+       }
+
+       return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
+                       &pll_clk->hw);
+}
+
+static int hsdk_pll_clk_remove(struct platform_device *pdev)
+{
+       of_clk_del_provider(pdev->dev.of_node);
+       return 0;
+}
+
+static void __init of_hsdk_pll_clk_setup(struct device_node *node)
+{
+       int ret;
+       const char *parent_name;
+       unsigned int num_parents;
+       struct hsdk_pll_clk *pll_clk;
+       struct clk_init_data init = { };
+
+       pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return;
+
+       pll_clk->regs = of_iomap(node, 0);
+       if (!pll_clk->regs) {
+               pr_err("failed to map pll registers\n");
+               goto err_free_pll_clk;
+       }
+
+       pll_clk->spec_regs = of_iomap(node, 1);
+       if (!pll_clk->spec_regs) {
+               pr_err("failed to map pll registers\n");
+               goto err_unmap_comm_regs;
+       }
+
+       init.name = node->name;
+       init.ops = &hsdk_pll_ops;
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.parent_names = &parent_name;
+       num_parents = of_clk_get_parent_count(node);
+       if (num_parents > CGU_PLL_SOURCE_MAX) {
+               pr_err("too much clock parents: %u\n", num_parents);
+               goto err_unmap_spec_regs;
+       }
+       init.num_parents = num_parents;
+
+       pll_clk->hw.init = &init;
+       pll_clk->pll_devdata = &core_pll_devdata;
+
+       ret = clk_hw_register(NULL, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to register %s clock\n", node->name);
+               goto err_unmap_spec_regs;
+       }
+
+       ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to add hw provider for %s clock\n", node->name);
+               goto err_unmap_spec_regs;
+       }
+
+       return;
+
+err_unmap_spec_regs:
+       iounmap(pll_clk->spec_regs);
+err_unmap_comm_regs:
+       iounmap(pll_clk->regs);
+err_free_pll_clk:
+       kfree(pll_clk);
+}
+
+/* Core PLL needed early for ARC cpus timers */
+CLK_OF_DECLARE(hsdk_pll_clock, "snps,hsdk-core-pll-clock",
+of_hsdk_pll_clk_setup);
+
+static const struct of_device_id hsdk_pll_clk_id[] = {
+       { .compatible = "snps,hsdk-gp-pll-clock", .data = &sdt_pll_devdata},
+       { .compatible = "snps,hsdk-hdmi-pll-clock", .data = &hdmi_pll_devdata},
+       { }
+};
+
+static struct platform_driver hsdk_pll_clk_driver = {
+       .driver = {
+               .name = "hsdk-gp-pll-clock",
+               .of_match_table = hsdk_pll_clk_id,
+       },
+       .probe = hsdk_pll_clk_probe,
+       .remove = hsdk_pll_clk_remove,
+};
+builtin_platform_driver(hsdk_pll_clk_driver);
diff --git a/drivers/clk/clk-mb86s7x.c b/drivers/clk/clk-mb86s7x.c
deleted file mode 100644 (file)
index 2a83a3f..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (C) 2013-2015 FUJITSU SEMICONDUCTOR LIMITED
- * Copyright (C) 2015 Linaro Ltd.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/clkdev.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/cpu.h>
-#include <linux/clk-provider.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/topology.h>
-#include <linux/mailbox_client.h>
-#include <linux/platform_device.h>
-
-#include <soc/mb86s7x/scb_mhu.h>
-
-#define to_crg_clk(p) container_of(p, struct crg_clk, hw)
-#define to_clc_clk(p) container_of(p, struct cl_clk, hw)
-
-struct mb86s7x_peri_clk {
-       u32 payload_size;
-       u32 cntrlr;
-       u32 domain;
-       u32 port;
-       u32 en;
-       u64 frequency;
-} __packed __aligned(4);
-
-struct hack_rate {
-       unsigned clk_id;
-       unsigned long rate;
-       int gated;
-};
-
-struct crg_clk {
-       struct clk_hw hw;
-       u8 cntrlr, domain, port;
-};
-
-static int crg_gate_control(struct clk_hw *hw, int en)
-{
-       struct crg_clk *crgclk = to_crg_clk(hw);
-       struct mb86s7x_peri_clk cmd;
-       int ret;
-
-       cmd.payload_size = sizeof(cmd);
-       cmd.cntrlr = crgclk->cntrlr;
-       cmd.domain = crgclk->domain;
-       cmd.port = crgclk->port;
-       cmd.en = en;
-
-       /* Port is UngatedCLK */
-       if (cmd.port == 8)
-               return en ? 0 : -EINVAL;
-
-       pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u En-%u}\n",
-                __func__, __LINE__, cmd.cntrlr,
-                cmd.domain, cmd.port, cmd.en);
-
-       ret = mb86s7x_send_packet(CMD_PERI_CLOCK_GATE_SET_REQ,
-                                 &cmd, sizeof(cmd));
-       if (ret < 0) {
-               pr_err("%s:%d failed!\n", __func__, __LINE__);
-               return ret;
-       }
-
-       pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u En-%u}\n",
-                __func__, __LINE__, cmd.cntrlr,
-                cmd.domain, cmd.port, cmd.en);
-
-       /* If the request was rejected */
-       if (cmd.en != en)
-               ret = -EINVAL;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-static int crg_port_prepare(struct clk_hw *hw)
-{
-       return crg_gate_control(hw, 1);
-}
-
-static void crg_port_unprepare(struct clk_hw *hw)
-{
-       crg_gate_control(hw, 0);
-}
-
-static int
-crg_rate_control(struct clk_hw *hw, int set, unsigned long *rate)
-{
-       struct crg_clk *crgclk = to_crg_clk(hw);
-       struct mb86s7x_peri_clk cmd;
-       int code, ret;
-
-       cmd.payload_size = sizeof(cmd);
-       cmd.cntrlr = crgclk->cntrlr;
-       cmd.domain = crgclk->domain;
-       cmd.port = crgclk->port;
-       cmd.frequency = *rate;
-
-       if (set) {
-               code = CMD_PERI_CLOCK_RATE_SET_REQ;
-               pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port, cmd.frequency);
-       } else {
-               code = CMD_PERI_CLOCK_RATE_GET_REQ;
-               pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-GET}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port);
-       }
-
-       ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
-       if (ret < 0) {
-               pr_err("%s:%d failed!\n", __func__, __LINE__);
-               return ret;
-       }
-
-       if (set)
-               pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port, cmd.frequency);
-       else
-               pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-GOT %lluHz}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port, cmd.frequency);
-
-       *rate = cmd.frequency;
-       return 0;
-}
-
-static unsigned long
-crg_port_recalc_rate(struct clk_hw *hw,        unsigned long parent_rate)
-{
-       unsigned long rate;
-
-       crg_rate_control(hw, 0, &rate);
-
-       return rate;
-}
-
-static long
-crg_port_round_rate(struct clk_hw *hw,
-                   unsigned long rate, unsigned long *pr)
-{
-       return rate;
-}
-
-static int
-crg_port_set_rate(struct clk_hw *hw,
-                 unsigned long rate, unsigned long parent_rate)
-{
-       return crg_rate_control(hw, 1, &rate);
-}
-
-const struct clk_ops crg_port_ops = {
-       .prepare = crg_port_prepare,
-       .unprepare = crg_port_unprepare,
-       .recalc_rate = crg_port_recalc_rate,
-       .round_rate = crg_port_round_rate,
-       .set_rate = crg_port_set_rate,
-};
-
-struct mb86s70_crg11 {
-       struct mutex lock; /* protects CLK populating and searching */
-};
-
-static struct clk *crg11_get(struct of_phandle_args *clkspec, void *data)
-{
-       struct mb86s70_crg11 *crg11 = data;
-       struct clk_init_data init;
-       u32 cntrlr, domain, port;
-       struct crg_clk *crgclk;
-       struct clk *clk;
-       char clkp[20];
-
-       if (clkspec->args_count != 3)
-               return ERR_PTR(-EINVAL);
-
-       cntrlr = clkspec->args[0];
-       domain = clkspec->args[1];
-       port = clkspec->args[2];
-
-       if (port > 7)
-               snprintf(clkp, 20, "UngatedCLK%d_%X", cntrlr, domain);
-       else
-               snprintf(clkp, 20, "CLK%d_%X_%d", cntrlr, domain, port);
-
-       mutex_lock(&crg11->lock);
-
-       clk = __clk_lookup(clkp);
-       if (clk) {
-               mutex_unlock(&crg11->lock);
-               return clk;
-       }
-
-       crgclk = kzalloc(sizeof(*crgclk), GFP_KERNEL);
-       if (!crgclk) {
-               mutex_unlock(&crg11->lock);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       init.name = clkp;
-       init.num_parents = 0;
-       init.ops = &crg_port_ops;
-       init.flags = 0;
-       crgclk->hw.init = &init;
-       crgclk->cntrlr = cntrlr;
-       crgclk->domain = domain;
-       crgclk->port = port;
-       clk = clk_register(NULL, &crgclk->hw);
-       if (IS_ERR(clk))
-               pr_err("%s:%d Error!\n", __func__, __LINE__);
-       else
-               pr_debug("Registered %s\n", clkp);
-
-       clk_register_clkdev(clk, clkp, NULL);
-       mutex_unlock(&crg11->lock);
-       return clk;
-}
-
-static void __init crg_port_init(struct device_node *node)
-{
-       struct mb86s70_crg11 *crg11;
-
-       crg11 = kzalloc(sizeof(*crg11), GFP_KERNEL);
-       if (!crg11)
-               return;
-
-       mutex_init(&crg11->lock);
-
-       of_clk_add_provider(node, crg11_get, crg11);
-}
-CLK_OF_DECLARE(crg11_gate, "fujitsu,mb86s70-crg11", crg_port_init);
-
-struct cl_clk {
-       struct clk_hw hw;
-       int cluster;
-};
-
-struct mb86s7x_cpu_freq {
-       u32 payload_size;
-       u32 cluster_class;
-       u32 cluster_id;
-       u32 cpu_id;
-       u64 frequency;
-};
-
-static void mhu_cluster_rate(struct clk_hw *hw, unsigned long *rate, int get)
-{
-       struct cl_clk *clc = to_clc_clk(hw);
-       struct mb86s7x_cpu_freq cmd;
-       int code, ret;
-
-       cmd.payload_size = sizeof(cmd);
-       cmd.cluster_class = 0;
-       cmd.cluster_id = clc->cluster;
-       cmd.cpu_id = 0;
-       cmd.frequency = *rate;
-
-       if (get)
-               code = CMD_CPU_CLOCK_RATE_GET_REQ;
-       else
-               code = CMD_CPU_CLOCK_RATE_SET_REQ;
-
-       pr_debug("%s:%d CMD Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
-                __func__, __LINE__, cmd.cluster_class,
-                cmd.cluster_id, cmd.cpu_id, cmd.frequency);
-
-       ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
-       if (ret < 0) {
-               pr_err("%s:%d failed!\n", __func__, __LINE__);
-               return;
-       }
-
-       pr_debug("%s:%d REP Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
-                __func__, __LINE__, cmd.cluster_class,
-                cmd.cluster_id, cmd.cpu_id, cmd.frequency);
-
-       *rate = cmd.frequency;
-}
-
-static unsigned long
-clc_recalc_rate(struct clk_hw *hw, unsigned long unused)
-{
-       unsigned long rate;
-
-       mhu_cluster_rate(hw, &rate, 1);
-       return rate;
-}
-
-static long
-clc_round_rate(struct clk_hw *hw, unsigned long rate,
-              unsigned long *unused)
-{
-       return rate;
-}
-
-static int
-clc_set_rate(struct clk_hw *hw, unsigned long rate,
-            unsigned long unused)
-{
-       unsigned long res = rate;
-
-       mhu_cluster_rate(hw, &res, 0);
-
-       return (res == rate) ? 0 : -EINVAL;
-}
-
-static struct clk_ops clk_clc_ops = {
-       .recalc_rate = clc_recalc_rate,
-       .round_rate = clc_round_rate,
-       .set_rate = clc_set_rate,
-};
-
-static struct clk_hw *mb86s7x_clclk_register(struct device *cpu_dev)
-{
-       struct clk_init_data init;
-       struct cl_clk *clc;
-       int ret;
-
-       clc = kzalloc(sizeof(*clc), GFP_KERNEL);
-       if (!clc)
-               return ERR_PTR(-ENOMEM);
-
-       clc->hw.init = &init;
-       clc->cluster = topology_physical_package_id(cpu_dev->id);
-
-       init.name = dev_name(cpu_dev);
-       init.ops = &clk_clc_ops;
-       init.flags = CLK_GET_RATE_NOCACHE;
-       init.num_parents = 0;
-
-       ret = devm_clk_hw_register(cpu_dev, &clc->hw);
-       if (ret)
-               return ERR_PTR(ret);
-       return &clc->hw;
-}
-
-static int mb86s7x_clclk_of_init(void)
-{
-       int cpu, ret = -ENODEV;
-       struct device_node *np;
-       struct clk_hw *hw;
-
-       np = of_find_compatible_node(NULL, NULL, "fujitsu,mb86s70-scb-1.0");
-       if (!np || !of_device_is_available(np))
-               goto exit;
-
-       for_each_possible_cpu(cpu) {
-               struct device *cpu_dev = get_cpu_device(cpu);
-
-               if (!cpu_dev) {
-                       pr_err("failed to get cpu%d device\n", cpu);
-                       continue;
-               }
-
-               hw = mb86s7x_clclk_register(cpu_dev);
-               if (IS_ERR(hw)) {
-                       pr_err("failed to register cpu%d clock\n", cpu);
-                       continue;
-               }
-               if (clk_hw_register_clkdev(hw, NULL, dev_name(cpu_dev))) {
-                       pr_err("failed to register cpu%d clock lookup\n", cpu);
-                       continue;
-               }
-               pr_debug("registered clk for %s\n", dev_name(cpu_dev));
-       }
-       ret = 0;
-
-       platform_device_register_simple("arm-bL-cpufreq-dt", -1, NULL, 0);
-exit:
-       of_node_put(np);
-       return ret;
-}
-module_init(mb86s7x_clclk_of_init);
index b86dac851116a72e4b897900f63ce7c1ae960dd6..58428d0043fdc9aa10350ebd30460c2424750aca 100644 (file)
@@ -18,7 +18,7 @@
 
 static void __init moxart_of_pll_clk_init(struct device_node *node)
 {
-       static void __iomem *base;
+       void __iomem *base;
        struct clk_hw *hw;
        struct clk *ref_clk;
        unsigned int mul;
@@ -30,7 +30,7 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
 
        base = of_iomap(node, 0);
        if (!base) {
-               pr_err("%s: of_iomap failed\n", node->full_name);
+               pr_err("%pOF: of_iomap failed\n", node);
                return;
        }
 
@@ -39,13 +39,13 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
 
        ref_clk = of_clk_get(node, 0);
        if (IS_ERR(ref_clk)) {
-               pr_err("%s: of_clk_get failed\n", node->full_name);
+               pr_err("%pOF: of_clk_get failed\n", node);
                return;
        }
 
        hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
        if (IS_ERR(hw)) {
-               pr_err("%s: failed to register clock\n", node->full_name);
+               pr_err("%pOF: failed to register clock\n", node);
                return;
        }
 
@@ -57,7 +57,7 @@ CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
 
 static void __init moxart_of_apb_clk_init(struct device_node *node)
 {
-       static void __iomem *base;
+       void __iomem *base;
        struct clk_hw *hw;
        struct clk *pll_clk;
        unsigned int div, val;
@@ -70,7 +70,7 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
 
        base = of_iomap(node, 0);
        if (!base) {
-               pr_err("%s: of_iomap failed\n", node->full_name);
+               pr_err("%pOF: of_iomap failed\n", node);
                return;
        }
 
@@ -83,13 +83,13 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
 
        pll_clk = of_clk_get(node, 0);
        if (IS_ERR(pll_clk)) {
-               pr_err("%s: of_clk_get failed\n", node->full_name);
+               pr_err("%pOF: of_clk_get failed\n", node);
                return;
        }
 
        hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
        if (IS_ERR(hw)) {
-               pr_err("%s: failed to register clock\n", node->full_name);
+               pr_err("%pOF: failed to register clock\n", node);
                return;
        }
 
index f3931e38fac0fb58a9bb6262e0fe7d9da33a6269..b0ea753b8709dafa7f4fdc886b0765de1ea1c248 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/clkdev.h>
 #include <linux/fsl/guts.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -536,6 +537,17 @@ static const struct clockgen_chipinfo chipinfo[] = {
                .pll_mask = 0x07,
                .flags = CG_PLL_8BIT,
        },
+       {
+               .compat = "fsl,ls1088a-clockgen",
+               .cmux_groups = {
+                       &clockgen2_cmux_cga12
+               },
+               .cmux_to_group = {
+                       0, 0, -1
+               },
+               .pll_mask = 0x07,
+               .flags = CG_VER3 | CG_LITTLE_ENDIAN,
+       },
        {
                .compat = "fsl,ls1012a-clockgen",
                .cmux_groups = {
@@ -1113,6 +1125,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
 
        for (i = 0; i < ARRAY_SIZE(pll->div); i++) {
                struct clk *clk;
+               int ret;
 
                snprintf(pll->div[i].name, sizeof(pll->div[i].name),
                         "cg-pll%d-div%d", idx, i + 1);
@@ -1126,6 +1139,11 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
                }
 
                pll->div[i].clk = clk;
+               ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
+               if (ret != 0)
+                       pr_err("%s: %s: register to lookup table failed %ld\n",
+                              __func__, pll->div[i].name, PTR_ERR(clk));
+
        }
 }
 
@@ -1348,8 +1366,7 @@ static void __init clockgen_init(struct device_node *np)
        }
 
        if (i == ARRAY_SIZE(chipinfo)) {
-               pr_err("%s: unknown clockgen node %s\n", __func__,
-                      np->full_name);
+               pr_err("%s: unknown clockgen node %pOF\n", __func__, np);
                goto err;
        }
        clockgen.info = chipinfo[i];
@@ -1362,8 +1379,8 @@ static void __init clockgen_init(struct device_node *np)
                if (guts) {
                        clockgen.guts = of_iomap(guts, 0);
                        if (!clockgen.guts) {
-                               pr_err("%s: Couldn't map %s regs\n", __func__,
-                                      guts->full_name);
+                               pr_err("%s: Couldn't map %pOF regs\n", __func__,
+                                      guts);
                        }
                }
 
@@ -1398,6 +1415,7 @@ CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
 
 /* Legacy nodes */
index 2492442eea77aa0c5abcf540e9bedb81e36d62d3..20d90769cceda980a0e198919c226e1d86d80c9e 100644 (file)
@@ -519,6 +519,11 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                SI5351_CLK_INTEGER_MODE,
                (hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0);
 
+       /* Do a pll soft reset on the affected pll */
+       si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
+                        hwdata->num == 0 ? SI5351_PLL_RESET_A :
+                                           SI5351_PLL_RESET_B);
+
        dev_dbg(&hwdata->drvdata->client->dev,
                "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
                __func__, clk_hw_get_name(hw),
@@ -1091,13 +1096,6 @@ static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
        si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
                        SI5351_CLK_POWERDOWN, 0);
 
-       /*
-        * Do a pll soft reset on both plls, needed in some cases to get
-        * all outputs running.
-        */
-       si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
-                        SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
-
        dev_dbg(&hwdata->drvdata->client->dev,
                "%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
                __func__, clk_hw_get_name(hw), (1 << rdiv),
index 68e2a4e499f1d31ec490b29cb08eb16dcbf6d418..96c6b6bc8f0e475f9d03de0ffa5210a2f06acae2 100644 (file)
@@ -1541,8 +1541,8 @@ static void __init stm32f4_rcc_init(struct device_node *np)
                    base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
 
                if (IS_ERR(clks[idx])) {
-                       pr_err("%s: Unable to register leaf clock %s\n",
-                              np->full_name, gd->name);
+                       pr_err("%pOF: Unable to register leaf clock %s\n",
+                              np, gd->name);
                        goto fail;
                }
        }
diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c
new file mode 100644 (file)
index 0000000..a94c3f5
--- /dev/null
@@ -0,0 +1,1410 @@
+/*
+ * Copyright (C) Gabriel Fernandez 2017
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com>
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/stm32h7-clks.h>
+
+/* Reset Clock Control Registers */
+#define RCC_CR         0x00
+#define RCC_CFGR       0x10
+#define RCC_D1CFGR     0x18
+#define RCC_D2CFGR     0x1C
+#define RCC_D3CFGR     0x20
+#define RCC_PLLCKSELR  0x28
+#define RCC_PLLCFGR    0x2C
+#define RCC_PLL1DIVR   0x30
+#define RCC_PLL1FRACR  0x34
+#define RCC_PLL2DIVR   0x38
+#define RCC_PLL2FRACR  0x3C
+#define RCC_PLL3DIVR   0x40
+#define RCC_PLL3FRACR  0x44
+#define RCC_D1CCIPR    0x4C
+#define RCC_D2CCIP1R   0x50
+#define RCC_D2CCIP2R   0x54
+#define RCC_D3CCIPR    0x58
+#define RCC_BDCR       0x70
+#define RCC_CSR                0x74
+#define RCC_AHB3ENR    0xD4
+#define RCC_AHB1ENR    0xD8
+#define RCC_AHB2ENR    0xDC
+#define RCC_AHB4ENR    0xE0
+#define RCC_APB3ENR    0xE4
+#define RCC_APB1LENR   0xE8
+#define RCC_APB1HENR   0xEC
+#define RCC_APB2ENR    0xF0
+#define RCC_APB4ENR    0xF4
+
+static DEFINE_SPINLOCK(stm32rcc_lock);
+
+static void __iomem *base;
+static struct clk_hw **hws;
+
+/* System clock parent */
+static const char * const sys_src[] = {
+       "hsi_ck", "csi_ck", "hse_ck", "pll1_p" };
+
+static const char * const tracein_src[] = {
+       "hsi_ck", "csi_ck", "hse_ck", "pll1_r" };
+
+static const char * const per_src[] = {
+       "hsi_ker", "csi_ker", "hse_ck", "disabled" };
+
+static const char * const pll_src[] = {
+       "hsi_ck", "csi_ck", "hse_ck", "no clock" };
+
+static const char * const sdmmc_src[] = { "pll1_q", "pll2_r" };
+
+static const char * const dsi_src[] = { "ck_dsi_phy", "pll2_q" };
+
+static const char * const qspi_src[] = {
+       "hclk", "pll1_q", "pll2_r", "per_ck" };
+
+static const char * const fmc_src[] = {
+       "hclk", "pll1_q", "pll2_r", "per_ck" };
+
+/* Kernel clock parent */
+static const char * const swp_src[] = {        "pclk1", "hsi_ker" };
+
+static const char * const fdcan_src[] = { "hse_ck", "pll1_q", "pll2_q" };
+
+static const char * const dfsdm1_src[] = { "pclk2", "sys_ck" };
+
+static const char * const spdifrx_src[] = {
+       "pll1_q", "pll2_r", "pll3_r", "hsi_ker" };
+
+static const char *spi_src1[5] = {
+       "pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const spi_src2[] = {
+       "pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const spi_src3[] = {
+       "pclk4", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const lptim_src1[] = {
+       "pclk1", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const lptim_src2[] = {
+       "pclk4", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const cec_src[] = {"lse_ck", "lsi_ck", "csi_ker_div122" };
+
+static const char * const usbotg_src[] = {"pll1_q", "pll3_q", "rc48_ck" };
+
+/* i2c 1,2,3 src */
+static const char * const i2c_src1[] = {
+       "pclk1", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const i2c_src2[] = {
+       "pclk4", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const rng_src[] = {
+       "rc48_ck", "pll1_q", "lse_ck", "lsi_ck" };
+
+/* usart 1,6 src */
+static const char * const usart_src1[] = {
+       "pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+/* usart 2,3,4,5,7,8 src */
+static const char * const usart_src2[] = {
+       "pclk1", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+static const char *sai_src[5] = {
+       "pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const adc_src[] = { "pll2_p", "pll3_r", "per_ck" };
+
+/* lptim 2,3,4,5 src */
+static const char * const lpuart1_src[] = {
+       "pclk3", "pll2_q", "pll3_q", "csi_ker", "lse_ck" };
+
+static const char * const hrtim_src[] = { "tim2_ker", "d1cpre" };
+
+/* RTC clock parent */
+static const char * const rtc_src[] = { "off", "lse_ck", "lsi_ck", "hse_1M" };
+
+/* Micro-controller output clock parent */
+static const char * const mco_src1[] = {
+       "hsi_ck", "lse_ck", "hse_ck", "pll1_q", "rc48_ck" };
+
+static const char * const mco_src2[] = {
+       "sys_ck", "pll2_p", "hse_ck", "pll1_p", "csi_ck", "lsi_ck" };
+
+/* LCD clock */
+static const char * const ltdc_src[] = {"pll3_r"};
+
+/* Gate clock with ready bit and backup domain management */
+struct stm32_ready_gate {
+       struct  clk_gate gate;
+       u8      bit_rdy;
+};
+
+#define to_ready_gate_clk(_rgate) container_of(_rgate, struct stm32_ready_gate,\
+               gate)
+
+#define RGATE_TIMEOUT 10000
+
+static int ready_gate_clk_enable(struct clk_hw *hw)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+       struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+       int bit_status;
+       unsigned int timeout = RGATE_TIMEOUT;
+
+       if (clk_gate_ops.is_enabled(hw))
+               return 0;
+
+       clk_gate_ops.enable(hw);
+
+       /* We can't use readl_poll_timeout() because we can blocked if
+        * someone enables this clock before clocksource changes.
+        * Only jiffies counter is available. Jiffies are incremented by
+        * interruptions and enable op does not allow to be interrupted.
+        */
+       do {
+               bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+               if (bit_status)
+                       udelay(100);
+
+       } while (bit_status && --timeout);
+
+       return bit_status;
+}
+
+static void ready_gate_clk_disable(struct clk_hw *hw)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+       struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+       int bit_status;
+       unsigned int timeout = RGATE_TIMEOUT;
+
+       if (!clk_gate_ops.is_enabled(hw))
+               return;
+
+       clk_gate_ops.disable(hw);
+
+       do {
+               bit_status = !!(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+               if (bit_status)
+                       udelay(100);
+
+       } while (bit_status && --timeout);
+}
+
+static const struct clk_ops ready_gate_clk_ops = {
+       .enable         = ready_gate_clk_enable,
+       .disable        = ready_gate_clk_disable,
+       .is_enabled     = clk_gate_is_enabled,
+};
+
+static struct clk_hw *clk_register_ready_gate(struct device *dev,
+               const char *name, const char *parent_name,
+               void __iomem *reg, u8 bit_idx, u8 bit_rdy,
+               unsigned long flags, spinlock_t *lock)
+{
+       struct stm32_ready_gate *rgate;
+       struct clk_init_data init = { NULL };
+       struct clk_hw *hw;
+       int ret;
+
+       rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
+       if (!rgate)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &ready_gate_clk_ops;
+       init.flags = flags;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       rgate->bit_rdy = bit_rdy;
+       rgate->gate.lock = lock;
+       rgate->gate.reg = reg;
+       rgate->gate.bit_idx = bit_idx;
+       rgate->gate.hw.init = &init;
+
+       hw = &rgate->gate.hw;
+       ret = clk_hw_register(dev, hw);
+       if (ret) {
+               kfree(rgate);
+               hw = ERR_PTR(ret);
+       }
+
+       return hw;
+}
+
+struct gate_cfg {
+       u32 offset;
+       u8  bit_idx;
+};
+
+struct muxdiv_cfg {
+       u32 offset;
+       u8 shift;
+       u8 width;
+};
+
+struct composite_clk_cfg {
+       struct gate_cfg *gate;
+       struct muxdiv_cfg *mux;
+       struct muxdiv_cfg *div;
+       const char *name;
+       const char * const *parent_name;
+       int num_parents;
+       u32 flags;
+};
+
+struct composite_clk_gcfg_t {
+       u8 flags;
+       const struct clk_ops *ops;
+};
+
+/*
+ * General config definition of a composite clock (only clock diviser for rate)
+ */
+struct composite_clk_gcfg {
+       struct composite_clk_gcfg_t *mux;
+       struct composite_clk_gcfg_t *div;
+       struct composite_clk_gcfg_t *gate;
+};
+
+#define M_CFG_MUX(_mux_ops, _mux_flags)\
+       .mux = &(struct composite_clk_gcfg_t) { _mux_flags, _mux_ops}
+
+#define M_CFG_DIV(_rate_ops, _rate_flags)\
+       .div = &(struct composite_clk_gcfg_t) {_rate_flags, _rate_ops}
+
+#define M_CFG_GATE(_gate_ops, _gate_flags)\
+       .gate = &(struct composite_clk_gcfg_t) { _gate_flags, _gate_ops}
+
+static struct clk_mux *_get_cmux(void __iomem *reg, u8 shift, u8 width,
+               u32 flags, spinlock_t *lock)
+{
+       struct clk_mux *mux;
+
+       mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+       if (!mux)
+               return ERR_PTR(-ENOMEM);
+
+       mux->reg        = reg;
+       mux->shift      = shift;
+       mux->mask       = (1 << width) - 1;
+       mux->flags      = flags;
+       mux->lock       = lock;
+
+       return mux;
+}
+
+static struct clk_divider *_get_cdiv(void __iomem *reg, u8 shift, u8 width,
+               u32 flags, spinlock_t *lock)
+{
+       struct clk_divider *div;
+
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+
+       if (!div)
+               return ERR_PTR(-ENOMEM);
+
+       div->reg   = reg;
+       div->shift = shift;
+       div->width = width;
+       div->flags = flags;
+       div->lock  = lock;
+
+       return div;
+}
+
+static struct clk_gate *_get_cgate(void __iomem *reg, u8 bit_idx, u32 flags,
+               spinlock_t *lock)
+{
+       struct clk_gate *gate;
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate)
+               return ERR_PTR(-ENOMEM);
+
+       gate->reg       = reg;
+       gate->bit_idx   = bit_idx;
+       gate->flags     = flags;
+       gate->lock      = lock;
+
+       return gate;
+}
+
+struct composite_cfg {
+       struct clk_hw *mux_hw;
+       struct clk_hw *div_hw;
+       struct clk_hw *gate_hw;
+
+       const struct clk_ops *mux_ops;
+       const struct clk_ops *div_ops;
+       const struct clk_ops *gate_ops;
+};
+
+static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg,
+               const struct composite_clk_cfg *cfg,
+               struct composite_cfg *composite, spinlock_t *lock)
+{
+       struct clk_mux     *mux = NULL;
+       struct clk_divider *div = NULL;
+       struct clk_gate    *gate = NULL;
+       const struct clk_ops *mux_ops, *div_ops, *gate_ops;
+       struct clk_hw *mux_hw;
+       struct clk_hw *div_hw;
+       struct clk_hw *gate_hw;
+
+       mux_ops = div_ops = gate_ops = NULL;
+       mux_hw = div_hw = gate_hw = NULL;
+
+       if (gcfg->mux && gcfg->mux) {
+               mux = _get_cmux(base + cfg->mux->offset,
+                               cfg->mux->shift,
+                               cfg->mux->width,
+                               gcfg->mux->flags, lock);
+
+               if (!IS_ERR(mux)) {
+                       mux_hw = &mux->hw;
+                       mux_ops = gcfg->mux->ops ?
+                                 gcfg->mux->ops : &clk_mux_ops;
+               }
+       }
+
+       if (gcfg->div && cfg->div) {
+               div = _get_cdiv(base + cfg->div->offset,
+                               cfg->div->shift,
+                               cfg->div->width,
+                               gcfg->div->flags, lock);
+
+               if (!IS_ERR(div)) {
+                       div_hw = &div->hw;
+                       div_ops = gcfg->div->ops ?
+                                 gcfg->div->ops : &clk_divider_ops;
+               }
+       }
+
+       if (gcfg->gate && gcfg->gate) {
+               gate = _get_cgate(base + cfg->gate->offset,
+                               cfg->gate->bit_idx,
+                               gcfg->gate->flags, lock);
+
+               if (!IS_ERR(gate)) {
+                       gate_hw = &gate->hw;
+                       gate_ops = gcfg->gate->ops ?
+                                  gcfg->gate->ops : &clk_gate_ops;
+               }
+       }
+
+       composite->mux_hw = mux_hw;
+       composite->mux_ops = mux_ops;
+
+       composite->div_hw = div_hw;
+       composite->div_ops = div_ops;
+
+       composite->gate_hw = gate_hw;
+       composite->gate_ops = gate_ops;
+}
+
+/* Kernel Timer */
+struct timer_ker {
+       u8 dppre_shift;
+       struct clk_hw hw;
+       spinlock_t *lock;
+};
+
+#define to_timer_ker(_hw) container_of(_hw, struct timer_ker, hw)
+
+static unsigned long timer_ker_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct timer_ker *clk_elem = to_timer_ker(hw);
+       u32 timpre;
+       u32 dppre_shift = clk_elem->dppre_shift;
+       u32 prescaler;
+       u32 mul;
+
+       timpre = (readl(base + RCC_CFGR) >> 15) & 0x01;
+
+       prescaler = (readl(base + RCC_D2CFGR) >> dppre_shift) & 0x03;
+
+       mul = 2;
+
+       if (prescaler < 4)
+               mul = 1;
+
+       else if (timpre && prescaler > 4)
+               mul = 4;
+
+       return parent_rate * mul;
+}
+
+static const struct clk_ops timer_ker_ops = {
+       .recalc_rate = timer_ker_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_timer_ker(struct device *dev,
+               const char *name, const char *parent_name,
+               unsigned long flags,
+               u8 dppre_shift,
+               spinlock_t *lock)
+{
+       struct timer_ker *element;
+       struct clk_init_data init;
+       struct clk_hw *hw;
+       int err;
+
+       element = kzalloc(sizeof(*element), GFP_KERNEL);
+       if (!element)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &timer_ker_ops;
+       init.flags = flags;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       element->hw.init = &init;
+       element->lock = lock;
+       element->dppre_shift = dppre_shift;
+
+       hw = &element->hw;
+       err = clk_hw_register(dev, hw);
+
+       if (err) {
+               kfree(element);
+               return ERR_PTR(err);
+       }
+
+       return hw;
+}
+
+static const struct clk_div_table d1cpre_div_table[] = {
+       { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+       { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1},
+       { 8, 2 }, { 9, 4 }, { 10, 8 }, { 11, 16 },
+       { 12, 64 }, { 13, 128 }, { 14, 256 },
+       { 15, 512 },
+       { 0 },
+};
+
+static const struct clk_div_table ppre_div_table[] = {
+       { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+       { 4, 2 }, { 5, 4 }, { 6, 8 }, { 7, 16 },
+       { 0 },
+};
+
+static void register_core_and_bus_clocks(void)
+{
+       /* CORE AND BUS */
+       hws[SYS_D1CPRE] = clk_hw_register_divider_table(NULL, "d1cpre",
+                       "sys_ck", CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 8, 4, 0,
+                       d1cpre_div_table, &stm32rcc_lock);
+
+       hws[HCLK] = clk_hw_register_divider_table(NULL, "hclk", "d1cpre",
+                       CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 0, 4, 0,
+                       d1cpre_div_table, &stm32rcc_lock);
+
+       /* D1 DOMAIN */
+       /* * CPU Systick */
+       hws[CPU_SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick",
+                       "d1cpre", 0, 1, 8);
+
+       /* * APB3 peripheral */
+       hws[PCLK3] = clk_hw_register_divider_table(NULL, "pclk3", "hclk", 0,
+                       base + RCC_D1CFGR, 4, 3, 0,
+                       ppre_div_table, &stm32rcc_lock);
+
+       /* D2 DOMAIN */
+       /* * APB1 peripheral */
+       hws[PCLK1] = clk_hw_register_divider_table(NULL, "pclk1", "hclk", 0,
+                       base + RCC_D2CFGR, 4, 3, 0,
+                       ppre_div_table, &stm32rcc_lock);
+
+       /* Timers prescaler clocks */
+       clk_register_stm32_timer_ker(NULL, "tim1_ker", "pclk1", 0,
+                       4, &stm32rcc_lock);
+
+       /* * APB2 peripheral */
+       hws[PCLK2] = clk_hw_register_divider_table(NULL, "pclk2", "hclk", 0,
+                       base + RCC_D2CFGR, 8, 3, 0, ppre_div_table,
+                       &stm32rcc_lock);
+
+       clk_register_stm32_timer_ker(NULL, "tim2_ker", "pclk2", 0, 8,
+                       &stm32rcc_lock);
+
+       /* D3 DOMAIN */
+       /* * APB4 peripheral */
+       hws[PCLK4] = clk_hw_register_divider_table(NULL, "pclk4", "hclk", 0,
+                       base + RCC_D3CFGR, 4, 3, 0,
+                       ppre_div_table, &stm32rcc_lock);
+}
+
+/* MUX clock configuration */
+struct stm32_mux_clk {
+       const char *name;
+       const char * const *parents;
+       u8 num_parents;
+       u32 offset;
+       u8 shift;
+       u8 width;
+       u32 flags;
+};
+
+#define M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, _flags)\
+{\
+       .name           = _name,\
+       .parents        = _parents,\
+       .num_parents    = ARRAY_SIZE(_parents),\
+       .offset         = _mux_offset,\
+       .shift          = _mux_shift,\
+       .width          = _mux_width,\
+       .flags          = _flags,\
+}
+
+#define M_MCLOC(_name, _parents, _mux_offset, _mux_shift, _mux_width)\
+       M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, 0)\
+
+static const struct stm32_mux_clk stm32_mclk[] __initconst = {
+       M_MCLOC("per_ck",       per_src,        RCC_D1CCIPR,    28, 3),
+       M_MCLOC("pllsrc",       pll_src,        RCC_PLLCKSELR,   0, 3),
+       M_MCLOC("sys_ck",       sys_src,        RCC_CFGR,        0, 3),
+       M_MCLOC("tracein_ck",   tracein_src,    RCC_CFGR,        0, 3),
+};
+
+/* Oscillary clock configuration */
+struct stm32_osc_clk {
+       const char *name;
+       const char *parent;
+       u32 gate_offset;
+       u8 bit_idx;
+       u8 bit_rdy;
+       u32 flags;
+};
+
+#define OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, _flags)\
+{\
+       .name           = _name,\
+       .parent         = _parent,\
+       .gate_offset    = _gate_offset,\
+       .bit_idx        = _bit_idx,\
+       .bit_rdy        = _bit_rdy,\
+       .flags          = _flags,\
+}
+
+#define OSC_CLK(_name, _parent, _gate_offset, _bit_idx, _bit_rdy)\
+       OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, 0)
+
+static const struct stm32_osc_clk stm32_oclk[] __initconst = {
+       OSC_CLKF("hsi_ck",  "hsidiv",   RCC_CR,   0,  2, CLK_IGNORE_UNUSED),
+       OSC_CLKF("hsi_ker", "hsidiv",   RCC_CR,   1,  2, CLK_IGNORE_UNUSED),
+       OSC_CLKF("csi_ck",  "clk-csi",  RCC_CR,   7,  8, CLK_IGNORE_UNUSED),
+       OSC_CLKF("csi_ker", "clk-csi",  RCC_CR,   9,  8, CLK_IGNORE_UNUSED),
+       OSC_CLKF("rc48_ck", "clk-rc48", RCC_CR,  12, 13, CLK_IGNORE_UNUSED),
+       OSC_CLKF("lsi_ck",  "clk-lsi",  RCC_CSR,  0,  1, CLK_IGNORE_UNUSED),
+};
+
+/* PLL configuration */
+struct st32h7_pll_cfg {
+       u8 bit_idx;
+       u32 offset_divr;
+       u8 bit_frac_en;
+       u32 offset_frac;
+       u8 divm;
+};
+
+struct stm32_pll_data {
+       const char *name;
+       const char *parent_name;
+       unsigned long flags;
+       const struct st32h7_pll_cfg *cfg;
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll1 = {
+       .bit_idx = 24,
+       .offset_divr = RCC_PLL1DIVR,
+       .bit_frac_en = 0,
+       .offset_frac = RCC_PLL1FRACR,
+       .divm = 4,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll2 = {
+       .bit_idx = 26,
+       .offset_divr = RCC_PLL2DIVR,
+       .bit_frac_en = 4,
+       .offset_frac = RCC_PLL2FRACR,
+       .divm = 12,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll3 = {
+       .bit_idx = 28,
+       .offset_divr = RCC_PLL3DIVR,
+       .bit_frac_en = 8,
+       .offset_frac = RCC_PLL3FRACR,
+       .divm = 20,
+};
+
+static const struct stm32_pll_data stm32_pll[] = {
+       { "vco1", "pllsrc", CLK_IGNORE_UNUSED, &stm32h7_pll1 },
+       { "vco2", "pllsrc", 0, &stm32h7_pll2 },
+       { "vco3", "pllsrc", 0, &stm32h7_pll3 },
+};
+
+struct stm32_fractional_divider {
+       void __iomem    *mreg;
+       u8              mshift;
+       u8              mwidth;
+       u32             mmask;
+
+       void __iomem    *nreg;
+       u8              nshift;
+       u8              nwidth;
+
+       void __iomem    *freg_status;
+       u8              freg_bit;
+       void __iomem    *freg_value;
+       u8              fshift;
+       u8              fwidth;
+
+       u8              flags;
+       struct clk_hw   hw;
+       spinlock_t      *lock;
+};
+
+struct stm32_pll_obj {
+       spinlock_t *lock;
+       struct stm32_fractional_divider div;
+       struct stm32_ready_gate rgate;
+       struct clk_hw hw;
+};
+
+#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw)
+
+static int pll_is_enabled(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+       __clk_hw_set_clk(_hw, hw);
+
+       return ready_gate_clk_ops.is_enabled(_hw);
+}
+
+static int pll_enable(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+       __clk_hw_set_clk(_hw, hw);
+
+       return ready_gate_clk_ops.enable(_hw);
+}
+
+static void pll_disable(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+       __clk_hw_set_clk(_hw, hw);
+
+       ready_gate_clk_ops.disable(_hw);
+}
+
+static int pll_frac_is_enabled(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct stm32_fractional_divider *fd = &clk_elem->div;
+
+       return (readl(fd->freg_status) >> fd->freg_bit) & 0x01;
+}
+
+static unsigned long pll_read_frac(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct stm32_fractional_divider *fd = &clk_elem->div;
+
+       return (readl(fd->freg_value) >> fd->fshift) &
+               GENMASK(fd->fwidth - 1, 0);
+}
+
+static unsigned long pll_fd_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct stm32_fractional_divider *fd = &clk_elem->div;
+       unsigned long m, n;
+       u32 val, mask;
+       u64 rate, rate1 = 0;
+
+       val = readl(fd->mreg);
+       mask = GENMASK(fd->mwidth - 1, 0) << fd->mshift;
+       m = (val & mask) >> fd->mshift;
+
+       val = readl(fd->nreg);
+       mask = GENMASK(fd->nwidth - 1, 0) << fd->nshift;
+       n = ((val & mask) >> fd->nshift) + 1;
+
+       if (!n || !m)
+               return parent_rate;
+
+       rate = (u64)parent_rate * n;
+       do_div(rate, m);
+
+       if (pll_frac_is_enabled(hw)) {
+               val = pll_read_frac(hw);
+               rate1 = (u64)parent_rate * (u64)val;
+               do_div(rate1, (m * 8191));
+       }
+
+       return rate + rate1;
+}
+
+static const struct clk_ops pll_ops = {
+       .enable         = pll_enable,
+       .disable        = pll_disable,
+       .is_enabled     = pll_is_enabled,
+       .recalc_rate    = pll_fd_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_pll(struct device *dev,
+               const char *name,
+               const char *parent,
+               unsigned long flags,
+               const struct st32h7_pll_cfg *cfg,
+               spinlock_t *lock)
+{
+       struct stm32_pll_obj *pll;
+       struct clk_init_data init = { NULL };
+       struct clk_hw *hw;
+       int ret;
+       struct stm32_fractional_divider *div = NULL;
+       struct stm32_ready_gate *rgate;
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &pll_ops;
+       init.flags = flags;
+       init.parent_names = &parent;
+       init.num_parents = 1;
+       pll->hw.init = &init;
+
+       hw = &pll->hw;
+       rgate = &pll->rgate;
+
+       rgate->bit_rdy = cfg->bit_idx + 1;
+       rgate->gate.lock = lock;
+       rgate->gate.reg = base + RCC_CR;
+       rgate->gate.bit_idx = cfg->bit_idx;
+
+       div = &pll->div;
+       div->flags = 0;
+       div->mreg = base + RCC_PLLCKSELR;
+       div->mshift = cfg->divm;
+       div->mwidth = 6;
+       div->nreg = base +  cfg->offset_divr;
+       div->nshift = 0;
+       div->nwidth = 9;
+
+       div->freg_status = base + RCC_PLLCFGR;
+       div->freg_bit = cfg->bit_frac_en;
+       div->freg_value = base +  cfg->offset_frac;
+       div->fshift = 3;
+       div->fwidth = 13;
+
+       div->lock = lock;
+
+       ret = clk_hw_register(dev, hw);
+       if (ret) {
+               kfree(pll);
+               hw = ERR_PTR(ret);
+       }
+
+       return hw;
+}
+
+/* ODF CLOCKS */
+static unsigned long odf_divider_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long odf_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int odf_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_hw *hwp;
+       int pll_status;
+       int ret;
+
+       hwp = clk_hw_get_parent(hw);
+
+       pll_status = pll_is_enabled(hwp);
+
+       if (pll_status)
+               pll_disable(hwp);
+
+       ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+       if (pll_status)
+               pll_enable(hwp);
+
+       return ret;
+}
+
+static const struct clk_ops odf_divider_ops = {
+       .recalc_rate    = odf_divider_recalc_rate,
+       .round_rate     = odf_divider_round_rate,
+       .set_rate       = odf_divider_set_rate,
+};
+
+static int odf_gate_enable(struct clk_hw *hw)
+{
+       struct clk_hw *hwp;
+       int pll_status;
+       int ret;
+
+       if (clk_gate_ops.is_enabled(hw))
+               return 0;
+
+       hwp = clk_hw_get_parent(hw);
+
+       pll_status = pll_is_enabled(hwp);
+
+       if (pll_status)
+               pll_disable(hwp);
+
+       ret = clk_gate_ops.enable(hw);
+
+       if (pll_status)
+               pll_enable(hwp);
+
+       return ret;
+}
+
+static void odf_gate_disable(struct clk_hw *hw)
+{
+       struct clk_hw *hwp;
+       int pll_status;
+
+       if (!clk_gate_ops.is_enabled(hw))
+               return;
+
+       hwp = clk_hw_get_parent(hw);
+
+       pll_status = pll_is_enabled(hwp);
+
+       if (pll_status)
+               pll_disable(hwp);
+
+       clk_gate_ops.disable(hw);
+
+       if (pll_status)
+               pll_enable(hwp);
+}
+
+static const struct clk_ops odf_gate_ops = {
+       .enable         = odf_gate_enable,
+       .disable        = odf_gate_disable,
+       .is_enabled     = clk_gate_is_enabled,
+};
+
+static struct composite_clk_gcfg odf_clk_gcfg = {
+       M_CFG_DIV(&odf_divider_ops, 0),
+       M_CFG_GATE(&odf_gate_ops, 0),
+};
+
+#define M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+               _rate_shift, _rate_width, _flags)\
+{\
+       .mux = NULL,\
+       .div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+       .gate = &(struct gate_cfg) {_gate_offset, _bit_idx },\
+       .name = _name,\
+       .parent_name = &(const char *) {_parent},\
+       .num_parents = 1,\
+       .flags = _flags,\
+}
+
+#define M_ODF(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+               _rate_shift, _rate_width)\
+M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+               _rate_shift, _rate_width, 0)\
+
+static const struct composite_clk_cfg stm32_odf[3][3] = {
+       {
+               M_ODF_F("pll1_p", "vco1", RCC_PLLCFGR, 16, RCC_PLL1DIVR,  9, 7,
+                               CLK_IGNORE_UNUSED),
+               M_ODF_F("pll1_q", "vco1", RCC_PLLCFGR, 17, RCC_PLL1DIVR, 16, 7,
+                               CLK_IGNORE_UNUSED),
+               M_ODF_F("pll1_r", "vco1", RCC_PLLCFGR, 18, RCC_PLL1DIVR, 24, 7,
+                               CLK_IGNORE_UNUSED),
+       },
+
+       {
+               M_ODF("pll2_p", "vco2", RCC_PLLCFGR, 19, RCC_PLL2DIVR,  9, 7),
+               M_ODF("pll2_q", "vco2", RCC_PLLCFGR, 20, RCC_PLL2DIVR, 16, 7),
+               M_ODF("pll2_r", "vco2", RCC_PLLCFGR, 21, RCC_PLL2DIVR, 24, 7),
+       },
+       {
+               M_ODF("pll3_p", "vco3", RCC_PLLCFGR, 22, RCC_PLL3DIVR,  9, 7),
+               M_ODF("pll3_q", "vco3", RCC_PLLCFGR, 23, RCC_PLL3DIVR, 16, 7),
+               M_ODF("pll3_r", "vco3", RCC_PLLCFGR, 24, RCC_PLL3DIVR, 24, 7),
+       }
+};
+
+/* PERIF CLOCKS */
+struct pclk_t {
+       u32 gate_offset;
+       u8 bit_idx;
+       const char *name;
+       const char *parent;
+       u32 flags;
+};
+
+#define PER_CLKF(_gate_offset, _bit_idx, _name, _parent, _flags)\
+{\
+       .gate_offset    = _gate_offset,\
+       .bit_idx        = _bit_idx,\
+       .name           = _name,\
+       .parent         = _parent,\
+       .flags          = _flags,\
+}
+
+#define PER_CLK(_gate_offset, _bit_idx, _name, _parent)\
+       PER_CLKF(_gate_offset, _bit_idx, _name, _parent, 0)
+
+static const struct pclk_t pclk[] = {
+       PER_CLK(RCC_AHB3ENR, 31, "d1sram1", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 30, "itcm", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 29, "dtcm2", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 28, "dtcm1", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 8, "flitf", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 5, "jpgdec", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 4, "dma2d", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 0, "mdma", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 28, "usb2ulpi", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 26, "usb1ulpi", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 17, "eth1rx", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 16, "eth1tx", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 15, "eth1mac", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 14, "art", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 1, "dma2", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 0, "dma1", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 31, "d2sram3", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 30, "d2sram2", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 29, "d2sram1", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 5, "hash", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 4, "crypt", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 0, "camitf", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 28, "bkpram", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 25, "hsem", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 21, "bdma", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 19, "crc", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 10, "gpiok", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 9, "gpioj", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 8, "gpioi", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 7, "gpioh", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 6, "gpiog", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 5, "gpiof", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 4, "gpioe", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 3, "gpiod", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 2, "gpioc", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 1, "gpiob", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 0, "gpioa", "hclk"),
+       PER_CLK(RCC_APB3ENR, 6, "wwdg1", "pclk3"),
+       PER_CLK(RCC_APB1LENR, 29, "dac12", "pclk1"),
+       PER_CLK(RCC_APB1LENR, 11, "wwdg2", "pclk1"),
+       PER_CLK(RCC_APB1LENR, 8, "tim14", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 7, "tim13", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 6, "tim12", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 5, "tim7", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 4, "tim6", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 3, "tim5", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 2, "tim4", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 1, "tim3", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 0, "tim2", "tim1_ker"),
+       PER_CLK(RCC_APB1HENR, 5, "mdios", "pclk1"),
+       PER_CLK(RCC_APB1HENR, 4, "opamp", "pclk1"),
+       PER_CLK(RCC_APB1HENR, 1, "crs", "pclk1"),
+       PER_CLK(RCC_APB2ENR, 18, "tim17", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 17, "tim16", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 16, "tim15", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 1, "tim8", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 0, "tim1", "tim2_ker"),
+       PER_CLK(RCC_APB4ENR, 26, "tmpsens", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 16, "rtcapb", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 15, "vref", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 14, "comp12", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 1, "syscfg", "pclk4"),
+};
+
+/* KERNEL CLOCKS */
+#define KER_CLKF(_gate_offset, _bit_idx,\
+               _mux_offset, _mux_shift, _mux_width,\
+               _name, _parent_name,\
+               _flags) \
+{ \
+       .gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+       .mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+       .name = _name, \
+       .parent_name = _parent_name, \
+       .num_parents = ARRAY_SIZE(_parent_name),\
+       .flags = _flags,\
+}
+
+#define KER_CLK(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+               _name, _parent_name) \
+KER_CLKF(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+               _name, _parent_name, 0)\
+
+#define KER_CLKF_NOMUX(_gate_offset, _bit_idx,\
+               _name, _parent_name,\
+               _flags) \
+{ \
+       .gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+       .mux = NULL,\
+       .name = _name, \
+       .parent_name = _parent_name, \
+       .num_parents = 1,\
+       .flags = _flags,\
+}
+
+static const struct composite_clk_cfg kclk[] = {
+       KER_CLK(RCC_AHB3ENR,  16, RCC_D1CCIPR,  16, 1, "sdmmc1", sdmmc_src),
+       KER_CLKF(RCC_AHB3ENR, 14, RCC_D1CCIPR,   4, 2, "quadspi", qspi_src,
+                       CLK_IGNORE_UNUSED),
+       KER_CLKF(RCC_AHB3ENR, 12, RCC_D1CCIPR,   0, 2, "fmc", fmc_src,
+                       CLK_IGNORE_UNUSED),
+       KER_CLK(RCC_AHB1ENR,  27, RCC_D2CCIP2R, 20, 2, "usb2otg", usbotg_src),
+       KER_CLK(RCC_AHB1ENR,  25, RCC_D2CCIP2R, 20, 2, "usb1otg", usbotg_src),
+       KER_CLK(RCC_AHB1ENR,   5, RCC_D3CCIPR,  16, 2, "adc12", adc_src),
+       KER_CLK(RCC_AHB2ENR,   9, RCC_D1CCIPR,  16, 1, "sdmmc2", sdmmc_src),
+       KER_CLK(RCC_AHB2ENR,   6, RCC_D2CCIP2R,  8, 2, "rng", rng_src),
+       KER_CLK(RCC_AHB4ENR,  24, RCC_D3CCIPR,  16, 2, "adc3", adc_src),
+       KER_CLKF(RCC_APB3ENR,   4, RCC_D1CCIPR,  8, 1, "dsi", dsi_src,
+                       CLK_SET_RATE_PARENT),
+       KER_CLKF_NOMUX(RCC_APB3ENR, 3, "ltdc", ltdc_src, CLK_SET_RATE_PARENT),
+       KER_CLK(RCC_APB1LENR, 31, RCC_D2CCIP2R,  0, 3, "usart8", usart_src2),
+       KER_CLK(RCC_APB1LENR, 30, RCC_D2CCIP2R,  0, 3, "usart7", usart_src2),
+       KER_CLK(RCC_APB1LENR, 27, RCC_D2CCIP2R, 22, 2, "hdmicec", cec_src),
+       KER_CLK(RCC_APB1LENR, 23, RCC_D2CCIP2R, 12, 2, "i2c3", i2c_src1),
+       KER_CLK(RCC_APB1LENR, 22, RCC_D2CCIP2R, 12, 2, "i2c2", i2c_src1),
+       KER_CLK(RCC_APB1LENR, 21, RCC_D2CCIP2R, 12, 2, "i2c1", i2c_src1),
+       KER_CLK(RCC_APB1LENR, 20, RCC_D2CCIP2R,  0, 3, "uart5", usart_src2),
+       KER_CLK(RCC_APB1LENR, 19, RCC_D2CCIP2R,  0, 3, "uart4", usart_src2),
+       KER_CLK(RCC_APB1LENR, 18, RCC_D2CCIP2R,  0, 3, "usart3", usart_src2),
+       KER_CLK(RCC_APB1LENR, 17, RCC_D2CCIP2R,  0, 3, "usart2", usart_src2),
+       KER_CLK(RCC_APB1LENR, 16, RCC_D2CCIP1R, 20, 2, "spdifrx", spdifrx_src),
+       KER_CLK(RCC_APB1LENR, 15, RCC_D2CCIP1R, 16, 3, "spi3", spi_src1),
+       KER_CLK(RCC_APB1LENR, 14, RCC_D2CCIP1R, 16, 3, "spi2", spi_src1),
+       KER_CLK(RCC_APB1LENR,  9, RCC_D2CCIP2R, 28, 3, "lptim1", lptim_src1),
+       KER_CLK(RCC_APB1HENR,  8, RCC_D2CCIP1R, 28, 2, "fdcan", fdcan_src),
+       KER_CLK(RCC_APB1HENR,  2, RCC_D2CCIP1R, 31, 1, "swp", swp_src),
+       KER_CLK(RCC_APB2ENR,  29, RCC_CFGR,     14, 1, "hrtim", hrtim_src),
+       KER_CLK(RCC_APB2ENR,  28, RCC_D2CCIP1R, 24, 1, "dfsdm1", dfsdm1_src),
+       KER_CLKF(RCC_APB2ENR,  24, RCC_D2CCIP1R,  6, 3, "sai3", sai_src,
+                CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
+       KER_CLKF(RCC_APB2ENR,  23, RCC_D2CCIP1R,  6, 3, "sai2", sai_src,
+                CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
+       KER_CLKF(RCC_APB2ENR,  22, RCC_D2CCIP1R,  0, 3, "sai1", sai_src,
+                CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
+       KER_CLK(RCC_APB2ENR,  20, RCC_D2CCIP1R, 16, 3, "spi5", spi_src2),
+       KER_CLK(RCC_APB2ENR,  13, RCC_D2CCIP1R, 16, 3, "spi4", spi_src2),
+       KER_CLK(RCC_APB2ENR,  12, RCC_D2CCIP1R, 16, 3, "spi1", spi_src1),
+       KER_CLK(RCC_APB2ENR,   5, RCC_D2CCIP2R,  3, 3, "usart6", usart_src1),
+       KER_CLK(RCC_APB2ENR,   4, RCC_D2CCIP2R,  3, 3, "usart1", usart_src1),
+       KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,  24, 3, "sai4b", sai_src),
+       KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,  21, 3, "sai4a", sai_src),
+       KER_CLK(RCC_APB4ENR,  12, RCC_D3CCIPR,  13, 3, "lptim5", lptim_src2),
+       KER_CLK(RCC_APB4ENR,  11, RCC_D3CCIPR,  13, 3, "lptim4", lptim_src2),
+       KER_CLK(RCC_APB4ENR,  10, RCC_D3CCIPR,  13, 3, "lptim3", lptim_src2),
+       KER_CLK(RCC_APB4ENR,   9, RCC_D3CCIPR,  10, 3, "lptim2", lptim_src2),
+       KER_CLK(RCC_APB4ENR,   7, RCC_D3CCIPR,   8, 2, "i2c4", i2c_src2),
+       KER_CLK(RCC_APB4ENR,   5, RCC_D3CCIPR,  28, 3, "spi6", spi_src3),
+       KER_CLK(RCC_APB4ENR,   3, RCC_D3CCIPR,   0, 3, "lpuart1", lpuart1_src),
+};
+
+static struct composite_clk_gcfg kernel_clk_cfg = {
+       M_CFG_MUX(NULL, 0),
+       M_CFG_GATE(NULL, 0),
+};
+
+/* RTC clock */
+/*
+ * RTC & LSE registers are protected against parasitic write access.
+ * PWR_CR_DBP bit must be set to enable write access to RTC registers.
+ */
+/* STM32_PWR_CR */
+#define PWR_CR                         0x00
+/* STM32_PWR_CR bit field */
+#define PWR_CR_DBP                     BIT(8)
+
+static struct composite_clk_gcfg rtc_clk_cfg = {
+       M_CFG_MUX(NULL, 0),
+       M_CFG_GATE(NULL, 0),
+};
+
+static const struct composite_clk_cfg rtc_clk =
+       KER_CLK(RCC_BDCR, 15, RCC_BDCR, 8, 2, "rtc_ck", rtc_src);
+
+/* Micro-controller output clock */
+static struct composite_clk_gcfg mco_clk_cfg = {
+       M_CFG_MUX(NULL, 0),
+       M_CFG_DIV(NULL, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+};
+
+#define M_MCO_F(_name, _parents, _mux_offset,  _mux_shift, _mux_width,\
+               _rate_offset, _rate_shift, _rate_width,\
+               _flags)\
+{\
+       .mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+       .div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+       .gate = NULL,\
+       .name = _name,\
+       .parent_name = _parents,\
+       .num_parents = ARRAY_SIZE(_parents),\
+       .flags = _flags,\
+}
+
+static const struct composite_clk_cfg mco_clk[] = {
+       M_MCO_F("mco1", mco_src1, RCC_CFGR, 22, 4, RCC_CFGR, 18, 4, 0),
+       M_MCO_F("mco2", mco_src2, RCC_CFGR, 29, 3, RCC_CFGR, 25, 4, 0),
+};
+
+static void __init stm32h7_rcc_init(struct device_node *np)
+{
+       struct clk_hw_onecell_data *clk_data;
+       struct composite_cfg c_cfg;
+       int n;
+       const char *hse_clk, *lse_clk, *i2s_clk;
+       struct regmap *pdrm;
+
+       clk_data = kzalloc(sizeof(*clk_data) +
+                       sizeof(*clk_data->hws) * STM32H7_MAX_CLKS,
+                       GFP_KERNEL);
+       if (!clk_data)
+               return;
+
+       clk_data->num = STM32H7_MAX_CLKS;
+
+       hws = clk_data->hws;
+
+       for (n = 0; n < STM32H7_MAX_CLKS; n++)
+               hws[n] = ERR_PTR(-ENOENT);
+
+       /* get RCC base @ from DT */
+       base = of_iomap(np, 0);
+       if (!base) {
+               pr_err("%s: unable to map resource", np->name);
+               goto err_free_clks;
+       }
+
+       pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+       if (IS_ERR(pdrm))
+               pr_warn("%s: Unable to get syscfg\n", __func__);
+       else
+               /* In any case disable backup domain write protection
+                * and will never be enabled.
+                * Needed by LSE & RTC clocks.
+                */
+               regmap_update_bits(pdrm, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+       /* Put parent names from DT */
+       hse_clk = of_clk_get_parent_name(np, 0);
+       lse_clk = of_clk_get_parent_name(np, 1);
+       i2s_clk = of_clk_get_parent_name(np, 2);
+
+       sai_src[3] = i2s_clk;
+       spi_src1[3] = i2s_clk;
+
+       /* Register Internal oscillators */
+       clk_hw_register_fixed_rate(NULL, "clk-hsi", NULL, 0, 64000000);
+       clk_hw_register_fixed_rate(NULL, "clk-csi", NULL, 0, 4000000);
+       clk_hw_register_fixed_rate(NULL, "clk-lsi", NULL, 0, 32000);
+       clk_hw_register_fixed_rate(NULL, "clk-rc48", NULL, 0, 48000);
+
+       /* This clock is coming from outside. Frequencies unknown */
+       hws[CK_DSI_PHY] = clk_hw_register_fixed_rate(NULL, "ck_dsi_phy", NULL,
+                       0, 0);
+
+       hws[HSI_DIV] = clk_hw_register_divider(NULL, "hsidiv", "clk-hsi", 0,
+                       base + RCC_CR, 3, 2, CLK_DIVIDER_POWER_OF_TWO,
+                       &stm32rcc_lock);
+
+       hws[HSE_1M] = clk_hw_register_divider(NULL, "hse_1M", "hse_ck", 0,
+                       base + RCC_CFGR, 8, 6, CLK_DIVIDER_ONE_BASED |
+                       CLK_DIVIDER_ALLOW_ZERO,
+                       &stm32rcc_lock);
+
+       /* Mux system clocks */
+       for (n = 0; n < ARRAY_SIZE(stm32_mclk); n++)
+               hws[MCLK_BANK + n] = clk_hw_register_mux(NULL,
+                               stm32_mclk[n].name,
+                               stm32_mclk[n].parents,
+                               stm32_mclk[n].num_parents,
+                               stm32_mclk[n].flags,
+                               stm32_mclk[n].offset + base,
+                               stm32_mclk[n].shift,
+                               stm32_mclk[n].width,
+                               0,
+                               &stm32rcc_lock);
+
+       register_core_and_bus_clocks();
+
+       /* Oscillary clocks */
+       for (n = 0; n < ARRAY_SIZE(stm32_oclk); n++)
+               hws[OSC_BANK + n] = clk_register_ready_gate(NULL,
+                               stm32_oclk[n].name,
+                               stm32_oclk[n].parent,
+                               stm32_oclk[n].gate_offset + base,
+                               stm32_oclk[n].bit_idx,
+                               stm32_oclk[n].bit_rdy,
+                               stm32_oclk[n].flags,
+                               &stm32rcc_lock);
+
+       hws[HSE_CK] = clk_register_ready_gate(NULL,
+                               "hse_ck",
+                               hse_clk,
+                               RCC_CR + base,
+                               16, 17,
+                               0,
+                               &stm32rcc_lock);
+
+       hws[LSE_CK] = clk_register_ready_gate(NULL,
+                               "lse_ck",
+                               lse_clk,
+                               RCC_BDCR + base,
+                               0, 1,
+                               0,
+                               &stm32rcc_lock);
+
+       hws[CSI_KER_DIV122 + n] = clk_hw_register_fixed_factor(NULL,
+                       "csi_ker_div122", "csi_ker", 0, 1, 122);
+
+       /* PLLs */
+       for (n = 0; n < ARRAY_SIZE(stm32_pll); n++) {
+               int odf;
+
+               /* Register the VCO */
+               clk_register_stm32_pll(NULL, stm32_pll[n].name,
+                               stm32_pll[n].parent_name, stm32_pll[n].flags,
+                               stm32_pll[n].cfg,
+                               &stm32rcc_lock);
+
+               /* Register the 3 output dividers */
+               for (odf = 0; odf < 3; odf++) {
+                       int idx = n * 3 + odf;
+
+                       get_cfg_composite_div(&odf_clk_gcfg, &stm32_odf[n][odf],
+                                       &c_cfg, &stm32rcc_lock);
+
+                       hws[ODF_BANK + idx] = clk_hw_register_composite(NULL,
+                                       stm32_odf[n][odf].name,
+                                       stm32_odf[n][odf].parent_name,
+                                       stm32_odf[n][odf].num_parents,
+                                       c_cfg.mux_hw, c_cfg.mux_ops,
+                                       c_cfg.div_hw, c_cfg.div_ops,
+                                       c_cfg.gate_hw, c_cfg.gate_ops,
+                                       stm32_odf[n][odf].flags);
+               }
+       }
+
+       /* Peripheral clocks */
+       for (n = 0; n < ARRAY_SIZE(pclk); n++)
+               hws[PERIF_BANK + n] = clk_hw_register_gate(NULL, pclk[n].name,
+                               pclk[n].parent,
+                               pclk[n].flags, base + pclk[n].gate_offset,
+                               pclk[n].bit_idx, pclk[n].flags, &stm32rcc_lock);
+
+       /* Kernel clocks */
+       for (n = 0; n < ARRAY_SIZE(kclk); n++) {
+               get_cfg_composite_div(&kernel_clk_cfg, &kclk[n], &c_cfg,
+                               &stm32rcc_lock);
+
+               hws[KERN_BANK + n] = clk_hw_register_composite(NULL,
+                               kclk[n].name,
+                               kclk[n].parent_name,
+                               kclk[n].num_parents,
+                               c_cfg.mux_hw, c_cfg.mux_ops,
+                               c_cfg.div_hw, c_cfg.div_ops,
+                               c_cfg.gate_hw, c_cfg.gate_ops,
+                               kclk[n].flags);
+       }
+
+       /* RTC clock (default state is off) */
+       clk_hw_register_fixed_rate(NULL, "off", NULL, 0, 0);
+
+       get_cfg_composite_div(&rtc_clk_cfg, &rtc_clk, &c_cfg, &stm32rcc_lock);
+
+       hws[RTC_CK] = clk_hw_register_composite(NULL,
+                       rtc_clk.name,
+                       rtc_clk.parent_name,
+                       rtc_clk.num_parents,
+                       c_cfg.mux_hw, c_cfg.mux_ops,
+                       c_cfg.div_hw, c_cfg.div_ops,
+                       c_cfg.gate_hw, c_cfg.gate_ops,
+                       rtc_clk.flags);
+
+       /* Micro-controller clocks */
+       for (n = 0; n < ARRAY_SIZE(mco_clk); n++) {
+               get_cfg_composite_div(&mco_clk_cfg, &mco_clk[n], &c_cfg,
+                               &stm32rcc_lock);
+
+               hws[MCO_BANK + n] = clk_hw_register_composite(NULL,
+                               mco_clk[n].name,
+                               mco_clk[n].parent_name,
+                               mco_clk[n].num_parents,
+                               c_cfg.mux_hw, c_cfg.mux_ops,
+                               c_cfg.div_hw, c_cfg.div_ops,
+                               c_cfg.gate_hw, c_cfg.gate_ops,
+                               mco_clk[n].flags);
+       }
+
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+
+       return;
+
+err_free_clks:
+       kfree(clk_data);
+}
+
+/* The RCC node is a clock and reset controller, and these
+ * functionalities are supported by different drivers that
+ * matches the same compatible strings.
+ */
+CLK_OF_DECLARE_DRIVER(stm32h7_rcc, "st,stm32h743-rcc", stm32h7_rcc_init);
index ea7d552a2f2b11be9429574597ea3d7cf76249b0..decffb3826ece8be3206c8c9da2d535ddcbf5be1 100644 (file)
@@ -57,6 +57,7 @@
 #define VC5_PRIM_SRC_SHDN                      0x10
 #define VC5_PRIM_SRC_SHDN_EN_XTAL              BIT(7)
 #define VC5_PRIM_SRC_SHDN_EN_CLKIN             BIT(6)
+#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ  BIT(3)
 #define VC5_PRIM_SRC_SHDN_SP                   BIT(1)
 #define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN          BIT(0)
 
 /* flags to describe chip features */
 /* chip has built-in oscilator */
 #define VC5_HAS_INTERNAL_XTAL  BIT(0)
+/* chip has PFD requency doubler */
+#define VC5_HAS_PFD_FREQ_DBL   BIT(1)
 
 /* Supported IDT VC5 models. */
 enum vc5_model {
        IDT_VC5_5P49V5923,
+       IDT_VC5_5P49V5925,
        IDT_VC5_5P49V5933,
        IDT_VC5_5P49V5935,
+       IDT_VC6_5P49V6901,
 };
 
 /* Structure to describe features of a particular VC5 model */
@@ -157,6 +162,8 @@ struct vc5_driver_data {
        struct clk              *pin_clkin;
        unsigned char           clk_mux_ins;
        struct clk_hw           clk_mux;
+       struct clk_hw           clk_mul;
+       struct clk_hw           clk_pfd;
        struct vc5_hw_data      clk_pll;
        struct vc5_hw_data      clk_fod[VC5_MAX_FOD_NUM];
        struct vc5_hw_data      clk_out[VC5_MAX_CLK_OUT_NUM];
@@ -166,6 +173,14 @@ static const char * const vc5_mux_names[] = {
        "mux"
 };
 
+static const char * const vc5_dbl_names[] = {
+       "dbl"
+};
+
+static const char * const vc5_pfd_names[] = {
+       "pfd"
+};
+
 static const char * const vc5_pll_names[] = {
        "pll"
 };
@@ -254,11 +269,64 @@ static int vc5_mux_set_parent(struct clk_hw *hw, u8 index)
        return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src);
 }
 
-static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
+static const struct clk_ops vc5_mux_ops = {
+       .set_parent     = vc5_mux_set_parent,
+       .get_parent     = vc5_mux_get_parent,
+};
+
+static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
                                         unsigned long parent_rate)
 {
        struct vc5_driver_data *vc5 =
-               container_of(hw, struct vc5_driver_data, clk_mux);
+               container_of(hw, struct vc5_driver_data, clk_mul);
+       unsigned int premul;
+
+       regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
+       if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
+               parent_rate *= 2;
+
+       return parent_rate;
+}
+
+static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long *parent_rate)
+{
+       if ((*parent_rate == rate) || ((*parent_rate * 2) == rate))
+               return rate;
+       else
+               return -EINVAL;
+}
+
+static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
+                           unsigned long parent_rate)
+{
+       struct vc5_driver_data *vc5 =
+               container_of(hw, struct vc5_driver_data, clk_mul);
+       u32 mask;
+
+       if ((parent_rate * 2) == rate)
+               mask = VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ;
+       else
+               mask = 0;
+
+       regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
+                          VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
+                          mask);
+
+       return 0;
+}
+
+static const struct clk_ops vc5_dbl_ops = {
+       .recalc_rate    = vc5_dbl_recalc_rate,
+       .round_rate     = vc5_dbl_round_rate,
+       .set_rate       = vc5_dbl_set_rate,
+};
+
+static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
+                                        unsigned long parent_rate)
+{
+       struct vc5_driver_data *vc5 =
+               container_of(hw, struct vc5_driver_data, clk_pfd);
        unsigned int prediv, div;
 
        regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
@@ -276,7 +344,7 @@ static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
                return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
 }
 
-static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
+static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
                               unsigned long *parent_rate)
 {
        unsigned long idiv;
@@ -296,11 +364,11 @@ static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
        return *parent_rate / idiv;
 }
 
-static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
+static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
                            unsigned long parent_rate)
 {
        struct vc5_driver_data *vc5 =
-               container_of(hw, struct vc5_driver_data, clk_mux);
+               container_of(hw, struct vc5_driver_data, clk_pfd);
        unsigned long idiv;
        u8 div;
 
@@ -328,12 +396,10 @@ static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
        return 0;
 }
 
-static const struct clk_ops vc5_mux_ops = {
-       .set_parent     = vc5_mux_set_parent,
-       .get_parent     = vc5_mux_get_parent,
-       .recalc_rate    = vc5_mux_recalc_rate,
-       .round_rate     = vc5_mux_round_rate,
-       .set_rate       = vc5_mux_set_rate,
+static const struct clk_ops vc5_pfd_ops = {
+       .recalc_rate    = vc5_pfd_recalc_rate,
+       .round_rate     = vc5_pfd_round_rate,
+       .set_rate       = vc5_pfd_set_rate,
 };
 
 /*
@@ -426,6 +492,10 @@ static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw,
        div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) |
                  (od_frc[2] << 6) | (od_frc[3] >> 2);
 
+       /* Avoid division by zero if the output is not configured. */
+       if (div_int == 0 && div_frc == 0)
+               return 0;
+
        /* The PLL divider has 12 integer bits and 30 fractional bits */
        return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
 }
@@ -503,6 +573,25 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
 {
        struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
+       const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
+                       VC5_OUT_DIV_CONTROL_SEL_EXT |
+                       VC5_OUT_DIV_CONTROL_EN_FOD;
+       unsigned int src;
+       int ret;
+
+       /*
+        * If the input mux is disabled, enable it first and
+        * select source from matching FOD.
+        */
+       regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
+       if ((src & mask) == 0) {
+               src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
+               ret = regmap_update_bits(vc5->regmap,
+                                        VC5_OUT_DIV_CONTROL(hwdata->num),
+                                        mask | VC5_OUT_DIV_CONTROL_RESET, src);
+               if (ret)
+                       return ret;
+       }
 
        /* Enable the clock buffer */
        regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
@@ -516,7 +605,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw)
        struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
 
-       /* Enable the clock buffer */
+       /* Disable the clock buffer */
        regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
                           VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
 }
@@ -537,6 +626,9 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
        regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
        src &= mask;
 
+       if (src == 0)   /* Input mux set to DISABLED */
+               return 0;
+
        if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD)
                return 0;
 
@@ -595,7 +687,9 @@ static int vc5_map_index_to_output(const enum vc5_model model,
        case IDT_VC5_5P49V5933:
                return (n == 0) ? 0 : 3;
        case IDT_VC5_5P49V5923:
+       case IDT_VC5_5P49V5925:
        case IDT_VC5_5P49V5935:
+       case IDT_VC6_5P49V6901:
        default:
                return n;
        }
@@ -672,12 +766,46 @@ static int vc5_probe(struct i2c_client *client,
                goto err_clk;
        }
 
+       if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
+               /* Register frequency doubler */
+               memset(&init, 0, sizeof(init));
+               init.name = vc5_dbl_names[0];
+               init.ops = &vc5_dbl_ops;
+               init.flags = CLK_SET_RATE_PARENT;
+               init.parent_names = vc5_mux_names;
+               init.num_parents = 1;
+               vc5->clk_mul.init = &init;
+               ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
+               if (ret) {
+                       dev_err(&client->dev, "unable to register %s\n",
+                               init.name);
+                       goto err_clk;
+               }
+       }
+
+       /* Register PFD */
+       memset(&init, 0, sizeof(init));
+       init.name = vc5_pfd_names[0];
+       init.ops = &vc5_pfd_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
+               init.parent_names = vc5_dbl_names;
+       else
+               init.parent_names = vc5_mux_names;
+       init.num_parents = 1;
+       vc5->clk_pfd.init = &init;
+       ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
+       if (ret) {
+               dev_err(&client->dev, "unable to register %s\n", init.name);
+               goto err_clk;
+       }
+
        /* Register PLL */
        memset(&init, 0, sizeof(init));
        init.name = vc5_pll_names[0];
        init.ops = &vc5_pll_ops;
        init.flags = CLK_SET_RATE_PARENT;
-       init.parent_names = vc5_mux_names;
+       init.parent_names = vc5_pfd_names;
        init.num_parents = 1;
        vc5->clk_pll.num = 0;
        vc5->clk_pll.vc5 = vc5;
@@ -785,6 +913,13 @@ static const struct vc5_chip_info idt_5p49v5923_info = {
        .flags = 0,
 };
 
+static const struct vc5_chip_info idt_5p49v5925_info = {
+       .model = IDT_VC5_5P49V5925,
+       .clk_fod_cnt = 4,
+       .clk_out_cnt = 5,
+       .flags = 0,
+};
+
 static const struct vc5_chip_info idt_5p49v5933_info = {
        .model = IDT_VC5_5P49V5933,
        .clk_fod_cnt = 2,
@@ -799,18 +934,29 @@ static const struct vc5_chip_info idt_5p49v5935_info = {
        .flags = VC5_HAS_INTERNAL_XTAL,
 };
 
+static const struct vc5_chip_info idt_5p49v6901_info = {
+       .model = IDT_VC6_5P49V6901,
+       .clk_fod_cnt = 4,
+       .clk_out_cnt = 5,
+       .flags = VC5_HAS_PFD_FREQ_DBL,
+};
+
 static const struct i2c_device_id vc5_id[] = {
        { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
+       { "5p49v5925", .driver_data = IDT_VC5_5P49V5925 },
        { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
        { "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
+       { "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, vc5_id);
 
 static const struct of_device_id clk_vc5_of_match[] = {
        { .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info },
+       { .compatible = "idt,5p49v5925", .data = &idt_5p49v5925_info },
        { .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
        { .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
+       { .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
        { },
 };
 MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
index bc37030e38ba62833316302a383d86cdfd671921..4c75821a3933c26cd1c0582ce7ae13b145836f40 100644 (file)
@@ -192,7 +192,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty
 
        reg = of_iomap(np, 0);
        if (reg == NULL) {
-               pr_err("Unable to map CSR register for %s\n", np->full_name);
+               pr_err("Unable to map CSR register for %pOF\n", np);
                return;
        }
        of_property_read_string(np, "clock-output-names", &clk_name);
@@ -409,12 +409,12 @@ static void xgene_pmdclk_init(struct device_node *np)
        /* Parse the DTS register for resource */
        rc = of_address_to_resource(np, 0, &res);
        if (rc != 0) {
-               pr_err("no DTS register for %s\n", np->full_name);
+               pr_err("no DTS register for %pOF\n", np);
                return;
        }
        csr_reg = of_iomap(np, 0);
        if (!csr_reg) {
-               pr_err("Unable to map resource for %s\n", np->full_name);
+               pr_err("Unable to map resource for %pOF\n", np);
                return;
        }
        of_property_read_string(np, "clock-output-names", &clk_name);
@@ -703,16 +703,14 @@ static void __init xgene_devclk_init(struct device_node *np)
                rc = of_address_to_resource(np, i, &res);
                if (rc != 0) {
                        if (i == 0) {
-                               pr_err("no DTS register for %s\n",
-                                       np->full_name);
+                               pr_err("no DTS register for %pOF\n", np);
                                return;
                        }
                        break;
                }
                map_res = of_iomap(np, i);
                if (map_res == NULL) {
-                       pr_err("Unable to map resource %d for %s\n",
-                               i, np->full_name);
+                       pr_err("Unable to map resource %d for %pOF\n", i, np);
                        goto err;
                }
                if (strcmp(res.name, "div-reg") == 0)
@@ -747,8 +745,7 @@ static void __init xgene_devclk_init(struct device_node *np)
        pr_debug("Add %s clock\n", clk_name);
        rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
        if (rc != 0)
-               pr_err("%s: could register provider clk %s\n", __func__,
-                       np->full_name);
+               pr_err("%s: could register provider clk %pOF\n", __func__, np);
 
        return;
 
index fc58c52a26b4d1de4802be06950f45469d5b807d..c8d83acda0061977218d1fd084bc6faddff4091c 100644 (file)
@@ -3132,7 +3132,7 @@ int of_clk_add_provider(struct device_node *np,
        mutex_lock(&of_clk_mutex);
        list_add(&cp->link, &of_clk_providers);
        mutex_unlock(&of_clk_mutex);
-       pr_debug("Added clock from %s\n", np->full_name);
+       pr_debug("Added clock from %pOF\n", np);
 
        ret = of_clk_set_defaults(np, true);
        if (ret < 0)
@@ -3167,7 +3167,7 @@ int of_clk_add_hw_provider(struct device_node *np,
        mutex_lock(&of_clk_mutex);
        list_add(&cp->link, &of_clk_providers);
        mutex_unlock(&of_clk_mutex);
-       pr_debug("Added clk_hw provider from %s\n", np->full_name);
+       pr_debug("Added clk_hw provider from %pOF\n", np);
 
        ret = of_clk_set_defaults(np, true);
        if (ret < 0)
index bb8a77a5985f8627e6ea396298745c9b6c7eaf77..6b2f29df3f709feda0dd2dce53f1430152734d2c 100644 (file)
@@ -77,8 +77,8 @@ static struct clk *__of_clk_get_by_name(struct device_node *np,
                        break;
                } else if (name && index >= 0) {
                        if (PTR_ERR(clk) != -EPROBE_DEFER)
-                               pr_err("ERROR: could not get clock %s:%s(%i)\n",
-                                       np->full_name, name ? name : "", index);
+                               pr_err("ERROR: could not get clock %pOF:%s(%i)\n",
+                                       np, name ? name : "", index);
                        return clk;
                }
 
index 4181b68085456d9cc8f9f0ff0b8bbca5eb3fa7f5..e786d717f75dcf51383627988e22f5956fe74d6c 100644 (file)
@@ -55,9 +55,9 @@ static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
 };
 
 static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
-       { HI6220_WDT0_PCLK,   "wdt0_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
-       { HI6220_WDT1_PCLK,   "wdt1_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
-       { HI6220_WDT2_PCLK,   "wdt2_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
+       { HI6220_WDT0_PCLK,   "wdt0_pclk",   "ref32k",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
+       { HI6220_WDT1_PCLK,   "wdt1_pclk",   "ref32k",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
+       { HI6220_WDT2_PCLK,   "wdt2_pclk",   "ref32k",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
        { HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
        { HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
        { HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
index 1e3c9ea5f9dcf9e909e4412eaf5a2185659d9c84..7bcaf270db1175860832f3269cc7c03d1abdc68a 100644 (file)
@@ -416,10 +416,10 @@ static void __init mx51_clocks_init(struct device_node *np)
 
        clk[IMX5_CLK_LP_APM]            = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1,
                                                lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
-       clk[IMX5_CLK_IPU_DI0_SEL]       = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
-                                               mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel));
-       clk[IMX5_CLK_IPU_DI1_SEL]       = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
-                                               mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel));
+       clk[IMX5_CLK_IPU_DI0_SEL]       = imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
+                                               mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel), CLK_SET_RATE_PARENT);
+       clk[IMX5_CLK_IPU_DI1_SEL]       = imx_clk_mux_flags("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
+                                               mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel), CLK_SET_RATE_PARENT);
        clk[IMX5_CLK_TVE_EXT_SEL]       = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1,
                                                mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel), CLK_SET_RATE_PARENT);
        clk[IMX5_CLK_TVE_SEL]           = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1,
index 5fd4ddac1bf19cba71f16d95911e1a2e54218f0f..9642cdf0fb88e0e717e4cb7fdf9986f88fa02fd8 100644 (file)
@@ -71,7 +71,7 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
 static const char *pll6_bypass_sels[]  = { "pll6", "pll6_bypass_src", };
 static const char *pll7_bypass_sels[]  = { "pll7", "pll7_bypass_src", };
 
-static struct clk_div_table clk_enet_ref_table[] = {
+static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
        { .val = 1, .div = 10, },
        { .val = 2, .div = 5, },
@@ -79,14 +79,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 0, .div = 4, },
        { }
 };
 
-static struct clk_div_table video_div_table[] = {
+static const struct clk_div_table video_div_table[] = {
        { .val = 0, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 2, .div = 1, },
index b5c96de41ccf957b5f556794756545714d0a3528..e6d389e333d7d15bdb30cde8d2db45abc1706f3b 100644 (file)
@@ -105,7 +105,7 @@ static int const clks_init_on[] __initconst = {
        IMX6SX_CLK_EPIT2,
 };
 
-static struct clk_div_table clk_enet_ref_table[] = {
+static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
        { .val = 1, .div = 10, },
        { .val = 2, .div = 5, },
@@ -113,14 +113,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 0, .div = 4, },
        { }
 };
 
-static struct clk_div_table video_div_table[] = {
+static const struct clk_div_table video_div_table[] = {
        { .val = 0, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 2, .div = 1, },
index b4e0dff3c8c26b9c2a7eac10702b222e486bad96..5e8c18afce9ad35742dd378cded8042abe80c922 100644 (file)
@@ -78,7 +78,7 @@ static int const clks_init_on[] __initconst = {
        IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG,
 };
 
-static struct clk_div_table clk_enet_ref_table[] = {
+static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
        { .val = 1, .div = 10, },
        { .val = 2, .div = 5, },
@@ -86,14 +86,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 0, .div = 4, },
        { }
 };
 
-static struct clk_div_table video_div_table[] = {
+static const struct clk_div_table video_div_table[] = {
        { .val = 0, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 2, .div = 1, },
index 3da121826b1baba4667858e01579dfb7d1acab12..2305699db46798441c7c32ef8910b5fe3354c64a 100644 (file)
@@ -27,7 +27,7 @@ static u32 share_count_sai2;
 static u32 share_count_sai3;
 static u32 share_count_nand;
 
-static struct clk_div_table test_div_table[] = {
+static const struct clk_div_table test_div_table[] = {
        { .val = 3, .div = 1, },
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
@@ -35,7 +35,7 @@ static struct clk_div_table test_div_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 3, .div = 4, },
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
index 59b1863deb88863fcf9e1b113ea14303dfcb5f04..6dae54325a91ddb32bb733b9d7d5cf48d0ecc023 100644 (file)
+++ b/dr