From: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [RFC PATCH v2 12/18] arm: socfpga: gen5: add readonly clk driver
Date: Tue, 15 Oct 2019 22:10:25 +0200 [thread overview]
Message-ID: <20191015201032.20156-13-simon.k.r.goldschmidt@gmail.com> (raw)
In-Reply-To: <20191015201032.20156-1-simon.k.r.goldschmidt@gmail.com>
This adds clk-gen5 as a readonly DM_CLK driver that can return clocks for
the peripherals.
Signed-off-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
---
Changes in v2: None
MAINTAINERS | 1 +
drivers/clk/altera/Makefile | 1 +
drivers/clk/altera/clk-gen5.c | 338 ++++++++++++++++++++++++++++++++++
3 files changed, 340 insertions(+)
create mode 100644 drivers/clk/altera/clk-gen5.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 74a1423f50..be8a38ea07 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -114,6 +114,7 @@ M: Simon Goldschmidt <simon.k.r.goldschmidt@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
F: drivers/sysreset/sysreset_socfpga*
ARM AMLOGIC SOC SUPPORT
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 <marex@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
next prev parent reply other threads:[~2019-10-15 20:10 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-15 20:10 [U-Boot] [RFC PATCH v2 00/18] arm: socfpga: gen5: move to DM Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 01/18] ddr: socfpga: gen5: constify altera_gen5_sdram_ops Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 02/18] dts: arm: socfpga: add label for clkmgr Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 03/18] arm: socfpga: gen5: increase SPL_SYS_MALLOC_F_LEN Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 04/18] timer: dw-apb: add reset handling Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 05/18] arm: socfpga: gen5: move initial reset handling to reset driver Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 06/18] arm: dts: socfpga: add settings for gen5 clk driver Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 07/18] arm: dts: socfpga: make clock nodes available in SPL Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 08/18] socfpga: gen5: add new tool to create handoff dtsi files Simon Goldschmidt
2019-10-22 17:10 ` Dalon L Westergreen
2019-10-22 17:13 ` Simon Goldschmidt
2019-10-23 16:03 ` Dalon L Westergreen
2019-10-23 19:22 ` Simon Goldschmidt
2019-10-24 14:25 ` Dalon L Westergreen
2019-10-24 14:29 ` Simon Goldschmidt
2019-10-24 17:29 ` Dalon L Westergreen
2019-10-24 18:00 ` Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 09/18] sdram: socfpga: gen5: make config structs dts compatible Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 10/18] ddr: socfpga: gen5: fetch handoff information from 'of_to_platdata' Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 11/18] ddr: socfpga: gen5: read handoff information from devicetree Simon Goldschmidt
2019-10-15 20:10 ` Simon Goldschmidt [this message]
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 13/18] arm: socfpga: gen5: enable DM CLK Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 14/18] arm: socfpga: gen5: move clock initialization to CLK driver Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 15/18] arm: socfpga: gen5: load CLK config from devicetree Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 16/18] spi: cadence_qspi: support DM_CLK Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 17/18] arm: socfpga: gen5: parse qspi clock from devictree Simon Goldschmidt
2019-10-15 20:10 ` [U-Boot] [RFC PATCH v2 18/18] socfpga: gen5: move CLK and SDRAM to DM Simon Goldschmidt
2019-10-23 20:36 ` [U-Boot] [RFC PATCH v2 00/18] arm: socfpga: gen5: move " Simon Goldschmidt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191015201032.20156-13-simon.k.r.goldschmidt@gmail.com \
--to=simon.k.r.goldschmidt@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.