This adds clk-gen5 as a readonly DM_CLK driver that can return clocks for
the peripherals.

Further changes are:
- select DM_CLK for gen5 U-Boot and SPL
- add SPL tags to clock nodes in socfpga-common-u-boot.dtsi
- adjust socfpga.dtsi to provide missing src selection registers
- start 'handoff.dtsi' file for socrates (conatains clock speeds for now)

Signed-off-by: Simon Goldschmidt <simon.k.r.goldschm...@gmail.com>
---

 MAINTAINERS                                   |   1 +
 arch/arm/dts/socfpga-common-u-boot.dtsi       |  70 ++++
 arch/arm/dts/socfpga.dtsi                     |   5 +
 .../dts/socfpga_cyclone5_socrates-u-boot.dtsi |   1 +
 .../socfpga_cyclone5_socrates_handoff.dtsi    |  26 ++
 arch/arm/mach-socfpga/Kconfig                 |   2 +
 drivers/clk/altera/Makefile                   |   1 +
 drivers/clk/altera/clk-gen5.c                 | 338 ++++++++++++++++++
 8 files changed, 444 insertions(+)
 create mode 100644 arch/arm/dts/socfpga_cyclone5_socrates_handoff.dtsi
 create mode 100644 drivers/clk/altera/clk-gen5.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a7d626ffff..b7a9a2671f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -94,6 +94,7 @@ M:    Simon Goldschmidt <simon.k.r.goldschm...@gmail.com>
 S:     Maintainted
 T:     git https://gitlab.denx.de/u-boot/custodians/u-boot-socfpga.git
 F:     arch/arm/mach-socfpga/
+F:     drivers/clk/altera/clk-gen5.c
 
 ARM AMLOGIC SOC SUPPORT
 M:     Neil Armstrong <narmstr...@baylibre.com>
diff --git a/arch/arm/dts/socfpga-common-u-boot.dtsi 
b/arch/arm/dts/socfpga-common-u-boot.dtsi
index 322c858c4b..270ba99a63 100644
--- a/arch/arm/dts/socfpga-common-u-boot.dtsi
+++ b/arch/arm/dts/socfpga-common-u-boot.dtsi
@@ -7,6 +7,12 @@
 /{
        soc {
                u-boot,dm-pre-reloc;
+               clkmgr@ffd04000 {
+                       u-boot,dm-pre-reloc;
+                       clocks {
+                               u-boot,dm-pre-reloc;
+                       };
+               };
        };
 };
 
@@ -17,3 +23,67 @@
 &sdr {
        u-boot,dm-pre-reloc;
 };
+
+&osc1 {
+       u-boot,dm-pre-reloc;
+};
+
+&osc2 {
+       u-boot,dm-pre-reloc;
+};
+
+&f2s_periph_ref_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&main_pll {
+       u-boot,dm-pre-reloc;
+};
+
+&mainclk {
+       u-boot,dm-pre-reloc;
+};
+
+&main_qspi_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&main_nand_sdmmc_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&periph_pll {
+       u-boot,dm-pre-reloc;
+};
+
+&per_qspi_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&per_nand_mmc_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&per_base_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&l4_mp_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&l4_sp_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&sdmmc_clk {
+       u-boot,dm-pre-reloc;
+};
+
+&sdmmc_clk_divided {
+       u-boot,dm-pre-reloc;
+};
+
+&qspi_clk {
+       u-boot,dm-pre-reloc;
+};
diff --git a/arch/arm/dts/socfpga.dtsi b/arch/arm/dts/socfpga.dtsi
index 51a6a51b53..319334899b 100644
--- a/arch/arm/dts/socfpga.dtsi
+++ b/arch/arm/dts/socfpga.dtsi
@@ -332,6 +332,7 @@
                                                compatible = 
"altr,socfpga-gate-clk";
                                                clocks = <&mainclk>, 
<&per_base_clk>;
                                                div-reg = <0x64 4 3>;
+                                               src-reg = <0x70 0 1>;
                                                clk-gate = <0x60 2>;
                                        };
 
@@ -340,6 +341,7 @@
                                                compatible = 
"altr,socfpga-gate-clk";
                                                clocks = <&mainclk>, 
<&per_base_clk>;
                                                div-reg = <0x64 7 3>;
+                                               src-reg = <0x70 1 1>;
                                                clk-gate = <0x60 3>;
                                        };
 
@@ -453,6 +455,7 @@
                                                #clock-cells = <0>;
                                                compatible = 
"altr,socfpga-gate-clk";
                                                clocks = <&f2s_periph_ref_clk>, 
<&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
+                                               src-reg = <0xac 0 2>;
                                                clk-gate = <0xa0 8>;
                                                clk-phase = <0 135>;
                                        };
@@ -469,6 +472,7 @@
                                                #clock-cells = <0>;
                                                compatible = 
"altr,socfpga-gate-clk";
                                                clocks = <&f2s_periph_ref_clk>, 
<&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
+                                               src-reg = <0xac 2 2>;
                                                clk-gate = <0xa0 9>;
                                        };
 
@@ -491,6 +495,7 @@
                                                #clock-cells = <0>;
                                                compatible = 
"altr,socfpga-gate-clk";
                                                clocks = <&f2s_periph_ref_clk>, 
<&main_qspi_clk>, <&per_qspi_clk>;
+                                               src-reg = <0xac 4 2>;
                                                clk-gate = <0xa0 11>;
                                        };
 
diff --git a/arch/arm/dts/socfpga_cyclone5_socrates-u-boot.dtsi 
b/arch/arm/dts/socfpga_cyclone5_socrates-u-boot.dtsi
index 0a4d54e304..36ae10ab28 100644
--- a/arch/arm/dts/socfpga_cyclone5_socrates-u-boot.dtsi
+++ b/arch/arm/dts/socfpga_cyclone5_socrates-u-boot.dtsi
@@ -7,6 +7,7 @@
  */
 
 #include "socfpga-common-u-boot.dtsi"
+#include "socfpga_cyclone5_socrates_handoff.dtsi"
 
 /{
        aliases {
diff --git a/arch/arm/dts/socfpga_cyclone5_socrates_handoff.dtsi 
b/arch/arm/dts/socfpga_cyclone5_socrates_handoff.dtsi
new file mode 100644
index 0000000000..e6f19f2653
--- /dev/null
+++ b/arch/arm/dts/socfpga_cyclone5_socrates_handoff.dtsi
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *<auto-generated>
+ *     This code was generated by a tool based on
+ *     handoffs from both Qsys and Quartus.
+ *
+ *     Changes to this file may be lost if
+ *     the code is regenerated.
+ *</auto-generated>
+ */
+
+&osc1 {
+       clock-frequency = <25000000>;
+};
+
+&osc2 {
+       clock-frequency = <25000000>;
+};
+
+&f2s_periph_ref_clk {
+       clock-frequency = <0>;
+};
+
+&f2s_sdram_ref_clk {
+       clock-frequency = <0>;
+};
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index 9efdcd6f10..81052f27d5 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -53,7 +53,9 @@ config TARGET_SOCFPGA_CYCLONE5
 
 config TARGET_SOCFPGA_GEN5
        bool
+       select CLK
        select SPL_ALTERA_SDRAM
+       select SPL_CLK if SPL
        imply FPGA_SOCFPGA
        imply SPL_SIZE_LIMIT_SUBTRACT_GD
        imply SPL_SIZE_LIMIT_SUBTRACT_MALLOC
diff --git a/drivers/clk/altera/Makefile b/drivers/clk/altera/Makefile
index a3ae8b24b0..d0664c6ad5 100644
--- a/drivers/clk/altera/Makefile
+++ b/drivers/clk/altera/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += clk-arria10.o
+obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += clk-gen5.o
diff --git a/drivers/clk/altera/clk-gen5.c b/drivers/clk/altera/clk-gen5.c
new file mode 100644
index 0000000000..4c197b81b0
--- /dev/null
+++ b/drivers/clk/altera/clk-gen5.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Marek Vasut <ma...@denx.de>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/util.h>
+
+#include <asm/arch/clock_manager.h>
+
+enum socfpga_gen5_clk_type {
+       SOCFPGA_GEN5_CLK_MAIN_PLL,
+       SOCFPGA_GEN5_CLK_PER_PLL,
+       SOCFPGA_GEN5_CLK_PERIP_CLK,
+       SOCFPGA_GEN5_CLK_GATE_CLK,
+       SOCFPGA_GEN5_CLK_UNKNOWN_CLK,
+};
+
+struct socfpga_gen5_clk_platdata {
+       enum socfpga_gen5_clk_type type;
+       struct clk_bulk clks;
+       u32             regs;
+       /* Fixed divider */
+       u16             fix_div;
+       /* Control register */
+       u16             ctl_reg;
+       /* Divider register */
+       u16             div_reg;
+       u8              div_len;
+       u8              div_off;
+       /* Clock gating register */
+       u16             gate_reg;
+       u8              gate_bit;
+       /* Clock source register */
+       u16             src_reg;
+       u8              src_len;
+       u8              src_off;
+};
+
+static int socfpga_gen5_clk_get_upstream(struct clk *clk, struct clk **upclk)
+{
+       struct socfpga_gen5_clk_platdata *plat = dev_get_platdata(clk->dev);
+       u32 reg, maxval;
+
+       if (plat->clks.count == 0)
+               return 0;
+
+       if (plat->src_reg && plat->src_len) {
+               maxval = 1 << plat->src_len;
+               if (plat->clks.count <= maxval) {
+                       reg = readl(plat->regs + plat->src_reg);
+                       reg >>= plat->src_off;
+                       reg &= (maxval - 1);
+                       *upclk = &plat->clks.clks[reg];
+                       return 0;
+               }
+       }
+
+       if (plat->clks.count == 1) {
+               *upclk = &plat->clks.clks[0];
+               return 0;
+       }
+
+       if (!plat->ctl_reg)
+               return -EINVAL;
+
+       reg = readl(plat->regs + plat->ctl_reg);
+
+       /* Assume PLLs are ON for now */
+       if (plat->type == SOCFPGA_GEN5_CLK_MAIN_PLL) {
+               reg = (reg >> 8) & 0x3;
+               maxval = 2;
+       } else if (plat->type == SOCFPGA_GEN5_CLK_PER_PLL) {
+               reg = (reg >> 8) & 0x3;
+               maxval = 3;
+       } else {
+               reg = (reg >> 16) & 0x7;
+               maxval = 4;
+       }
+
+       if (reg > maxval) {
+               dev_err(clk->dev, "Invalid clock source\n");
+               return -EINVAL;
+       }
+
+       *upclk = &plat->clks.clks[reg];
+       return 0;
+}
+
+static int socfpga_gen5_clk_endisable(struct clk *clk, bool enable)
+{
+       struct socfpga_gen5_clk_platdata *plat = dev_get_platdata(clk->dev);
+       struct clk *upclk = NULL;
+       int ret;
+
+       if (!enable && plat->gate_reg)
+               clrbits_le32(plat->regs + plat->gate_reg, BIT(plat->gate_bit));
+
+       ret = socfpga_gen5_clk_get_upstream(clk, &upclk);
+       if (ret)
+               return ret;
+
+       if (upclk) {
+               if (enable)
+                       clk_enable(upclk);
+               else
+                       clk_disable(upclk);
+       }
+
+       if (enable && plat->gate_reg)
+               setbits_le32(plat->regs + plat->gate_reg, BIT(plat->gate_bit));
+
+       return 0;
+}
+
+static int socfpga_gen5_clk_enable(struct clk *clk)
+{
+       return socfpga_gen5_clk_endisable(clk, true);
+}
+
+static int socfpga_gen5_clk_disable(struct clk *clk)
+{
+       return socfpga_gen5_clk_endisable(clk, false);
+}
+
+static ulong socfpga_gen5_clk_get_rate(struct clk *clk)
+{
+       struct socfpga_gen5_clk_platdata *plat = dev_get_platdata(clk->dev);
+       struct clk *upclk = NULL;
+       ulong rate, uprate, reg, numer, denom;
+       int ret;
+
+       ret = socfpga_gen5_clk_get_upstream(clk, &upclk);
+       if (ret || !upclk)
+               return 0;
+
+       uprate = clk_get_rate(upclk);
+       rate = uprate;
+
+       if (plat->type == SOCFPGA_GEN5_CLK_MAIN_PLL) {
+               reg = readl(plat->regs + plat->ctl_reg);        /* VCO */
+               numer = (reg & CLKMGR_MAINPLLGRP_VCO_NUMER_MASK) >>
+                       CLKMGR_MAINPLLGRP_VCO_NUMER_OFFSET;
+               denom = (reg & CLKMGR_MAINPLLGRP_VCO_DENOM_MASK) >>
+                       CLKMGR_MAINPLLGRP_VCO_DENOM_OFFSET;
+               rate /= denom + 1;
+               rate *= numer + 1;
+       } else if (plat->type == SOCFPGA_GEN5_CLK_PER_PLL) {
+               reg = readl(plat->regs + plat->ctl_reg);        /* VCO */
+               numer = (reg & CLKMGR_PERPLLGRP_VCO_NUMER_MASK) >>
+                       CLKMGR_PERPLLGRP_VCO_NUMER_OFFSET;
+               denom = (reg & CLKMGR_PERPLLGRP_VCO_DENOM_MASK) >>
+                       CLKMGR_PERPLLGRP_VCO_DENOM_OFFSET;
+               rate /= denom + 1;
+               rate *= numer + 1;
+       } else {
+               rate /= plat->fix_div;
+
+               if (plat->fix_div == 1 && plat->ctl_reg) {
+                       reg = readl(plat->regs + plat->ctl_reg);
+                       reg &= 0x1ff;
+                       rate /= reg + 1;
+               }
+
+               if (plat->div_reg) {
+                       reg = readl(plat->regs + plat->div_reg);
+                       reg >>= plat->div_off;
+                       reg &= (1 << plat->div_len) - 1;
+                       if (plat->type == SOCFPGA_GEN5_CLK_PERIP_CLK)
+                               rate /= reg + 1;
+                       if (plat->type == SOCFPGA_GEN5_CLK_GATE_CLK)
+                               rate /= 1 << reg;
+               }
+       }
+
+       return rate;
+}
+
+static const struct clk_ops socfpga_gen5_clk_ops = {
+       .enable         = socfpga_gen5_clk_enable,
+       .disable        = socfpga_gen5_clk_disable,
+       .get_rate       = socfpga_gen5_clk_get_rate,
+};
+
+static int socfpga_gen5_clk_bind(struct udevice *dev)
+{
+       const void *fdt = gd->fdt_blob;
+       int offset = dev_of_offset(dev);
+       bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+       const char *name;
+       int ret;
+       const char *drv_name;
+
+       for (offset = fdt_first_subnode(fdt, offset);
+            offset > 0;
+            offset = fdt_next_subnode(fdt, offset)) {
+               name = fdt_get_name(fdt, offset, NULL);
+               if (!name)
+                       return -EINVAL;
+
+               if (!strcmp(name, "clocks")) {
+                       offset = fdt_first_subnode(fdt, offset);
+                       name = fdt_get_name(fdt, offset, NULL);
+                       if (!name)
+                               return -EINVAL;
+               }
+
+               /* Filter out supported sub-clock */
+               if (fdt_node_check_compatible(fdt, offset,
+                                             "altr,socfpga-pll-clock") &&
+                   fdt_node_check_compatible(fdt, offset,
+                                             "altr,socfpga-perip-clk") &&
+                   fdt_node_check_compatible(fdt, offset,
+                                             "altr,socfpga-gate-clk") &&
+                   fdt_node_check_compatible(fdt, offset, "fixed-clock"))
+                       continue;
+
+               if (pre_reloc_only &&
+                   !dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
+                       continue;
+
+               if (fdt_node_check_compatible(fdt, offset, "fixed-clock"))
+                       drv_name = "clk-gen5";
+               else
+                       drv_name = "fixed_rate_clock";
+
+               ret = device_bind_driver_to_node(dev, drv_name, name,
+                                                offset_to_ofnode(offset),
+                                                NULL);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int socfpga_gen5_clk_probe(struct udevice *dev)
+{
+       struct socfpga_gen5_clk_platdata *plat = dev_get_platdata(dev);
+       const void *fdt = gd->fdt_blob;
+       int offset = dev_of_offset(dev);
+
+       clk_get_bulk(dev, &plat->clks);
+
+       if (!fdt_node_check_compatible(fdt, offset,
+                                      "altr,socfpga-pll-clock")) {
+               /* Main PLL has 3 upstream clock */
+               if (plat->clks.count == 1)
+                       plat->type = SOCFPGA_GEN5_CLK_MAIN_PLL;
+               else
+                       plat->type = SOCFPGA_GEN5_CLK_PER_PLL;
+       } else if (!fdt_node_check_compatible(fdt, offset,
+                                             "altr,socfpga-perip-clk")) {
+               plat->type = SOCFPGA_GEN5_CLK_PERIP_CLK;
+       } else if (!fdt_node_check_compatible(fdt, offset,
+                                             "altr,socfpga-gate-clk")) {
+               plat->type = SOCFPGA_GEN5_CLK_GATE_CLK;
+       } else {
+               plat->type = SOCFPGA_GEN5_CLK_UNKNOWN_CLK;
+       }
+
+       return 0;
+}
+
+static int socfpga_gen5_ofdata_to_platdata(struct udevice *dev)
+{
+       struct socfpga_gen5_clk_platdata *plat = dev_get_platdata(dev);
+       struct socfpga_gen5_clk_platdata *pplat;
+       struct udevice *pdev;
+       const void *fdt = gd->fdt_blob;
+       unsigned int divreg[3], gatereg[2], srcreg[3];
+       int ret, offset = dev_of_offset(dev);
+       u32 regs;
+
+       regs = dev_read_u32_default(dev, "reg", 0x0);
+
+       if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
+               plat->regs = devfdt_get_addr(dev);
+       } else {
+               pdev = dev_get_parent(dev);
+               if (!pdev)
+                       return -ENODEV;
+
+               pplat = dev_get_platdata(pdev);
+               if (!pplat)
+                       return -EINVAL;
+
+               plat->ctl_reg = regs;
+               plat->regs = pplat->regs;
+       }
+
+       plat->type = SOCFPGA_GEN5_CLK_UNKNOWN_CLK;
+
+       plat->fix_div = dev_read_u32_default(dev, "fixed-divider", 1);
+
+       ret = dev_read_u32_array(dev, "src-reg", srcreg, ARRAY_SIZE(srcreg));
+       if (!ret) {
+               plat->src_reg = srcreg[0];
+               plat->src_len = srcreg[2];
+               plat->src_off = srcreg[1];
+       }
+
+       ret = dev_read_u32_array(dev, "div-reg", divreg, ARRAY_SIZE(divreg));
+       if (!ret) {
+               plat->div_reg = divreg[0];
+               plat->div_len = divreg[2];
+               plat->div_off = divreg[1];
+       }
+
+       ret = dev_read_u32_array(dev, "clk-gate", gatereg, ARRAY_SIZE(gatereg));
+       if (!ret) {
+               plat->gate_reg = gatereg[0];
+               plat->gate_bit = gatereg[1];
+       }
+
+       return 0;
+}
+
+static const struct udevice_id socfpga_gen5_clk_match[] = {
+       { .compatible = "altr,clk-mgr" },
+       {}
+};
+
+U_BOOT_DRIVER(socfpga_gen5_clk) = {
+       .name           = "clk-gen5",
+       .id             = UCLASS_CLK,
+       .of_match       = socfpga_gen5_clk_match,
+       .ops            = &socfpga_gen5_clk_ops,
+       .bind           = socfpga_gen5_clk_bind,
+       .probe          = socfpga_gen5_clk_probe,
+       .ofdata_to_platdata = socfpga_gen5_ofdata_to_platdata,
+
+       .platdata_auto_alloc_size = sizeof(struct socfpga_gen5_clk_platdata),
+};
-- 
2.20.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to