From patchwork Thu Nov 25 11:07:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felix Fietkau X-Patchwork-Id: 12693631 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 613E8C433F5 for ; Thu, 25 Nov 2021 11:10:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=gBRfLofbjcOqEJbToe0TF4xzKeAf96rWYQE0NsMYmT8=; b=ue/+TG7BJcjjSx HsJrkEABhkgio9tvvMGycYlUmK9rcJB9BFmJQLu/NbBKTz2uSNQgIJ8mjLOpJpP+8X4mv5AzlF8wy eFxJqR47WRkZJERoTlyJhlfjX8Y3emu6xacfPtcoMwu5Uyax569LoLTpd0vt9KY+/BxkvAZDSjpkU gVCpbzf7+a+5WYlWWNyoQLqrVIyIxS4WYrvalGILJDuGoBbagETkJI9Abcm9cXyrP89lzOj1H7Cam 8RHCiUUeeJLP5bJ5/TPtAYTgLqMlFwA8hoLGVsajaoLHHPPANWYFXdlzoUso30xyfcfAtpBQYLWHi JR7JoBIAc/mO7JYBcVrQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mqCbw-007A9P-9l; Thu, 25 Nov 2021 11:08:16 +0000 Received: from nbd.name ([2a01:4f8:221:3d45::2]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mqCbX-007A22-2g for linux-arm-kernel@lists.infradead.org; Thu, 25 Nov 2021 11:07:53 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=nbd.name; s=20160729; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=cdL8iDKNQfS92432+K6BYpbXGpakRqp7LbIWlITnHf0=; b=YnYg2IZ8KhvG70oLmkCgqfhesE +VpYD69Bd/Z6VZBIIgFtUZtHIYvsunvAUf0RAzhPeDgv2jdbRSTiAtTJdo/X+KacPtf90QNZzDrwR qar13qVFSn4A07kbbKdFRZRv/ypnaf13ocaVCtzKGQvgsigF9lFFfqwRzzLXQagihvb4=; Received: from p54ae9f3f.dip0.t-ipconnect.de ([84.174.159.63] helo=localhost.localdomain) by ds12 with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1mqCbU-0002ws-1g; Thu, 25 Nov 2021 12:07:48 +0100 From: Felix Fietkau To: linux-arm-kernel@lists.infradead.org, Rob Herring , Michael Turquette , Stephen Boyd Cc: john@phrozen.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-clk@vger.kernel.org Subject: [PATCH v4 07/12] clk: en7523: Add clock driver for Airoha EN7523 SoC Date: Thu, 25 Nov 2021 12:07:33 +0100 Message-Id: <20211125110738.41028-8-nbd@nbd.name> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20211125110738.41028-1-nbd@nbd.name> References: <20211125110738.41028-1-nbd@nbd.name> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211125_030751_401661_5AD4ACDD X-CRM114-Status: GOOD ( 27.08 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org This driver only registers fixed rate clocks, since the clocks are fully initialized by the boot loader and should not be changed later, according to Airoha. Signed-off-by: Felix Fietkau Reported-by: kernel test robot --- arch/arm/boot/dts/en7523.dtsi | 8 + drivers/clk/Kconfig | 9 + drivers/clk/Makefile | 1 + drivers/clk/clk-en7523.c | 356 ++++++++++++++++++++++++++++++++++ 4 files changed, 374 insertions(+) create mode 100644 drivers/clk/clk-en7523.c diff --git a/arch/arm/boot/dts/en7523.dtsi b/arch/arm/boot/dts/en7523.dtsi index de9e5f3ff155..eabf3fdb3d52 100644 --- a/arch/arm/boot/dts/en7523.dtsi +++ b/arch/arm/boot/dts/en7523.dtsi @@ -2,6 +2,7 @@ #include #include +#include / { interrupt-parent = <&gic>; @@ -82,6 +83,13 @@ L2_0: l2-cache0 { }; }; + scu: scu@1fa20000 { + compatible = "airoha,en7523-scu"; + reg = <0x1fa20000 0x400>, + <0x1fb00000 0x1000>; + #clock-cells = <1>; + }; + gic: interrupt-controller@9000000 { compatible = "arm,gic-v3"; interrupt-controller; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c5b3dc97396a..b542f58c58d2 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -192,6 +192,15 @@ config COMMON_CLK_CS2000_CP help If you say yes here you get support for the CS2000 clock multiplier. +config COMMON_CLK_EN7523 + bool "Clock driver for Airoha EN7523 SoC system clocks" + depends on OF + depends on ARCH_AIROHA || ARM || COMPILE_TEST + default ARCH_AIROHA + help + This driver provides the fixed clocks and gates present on Airoha + ARM silicon. + config COMMON_CLK_FSL_FLEXSPI tristate "Clock driver for FlexSPI on Layerscape SoCs" depends on ARCH_LAYERSCAPE || COMPILE_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e42312121e51..be11d88c1603 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o +obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c new file mode 100644 index 000000000000..f1774a5bf537 --- /dev/null +++ b/drivers/clk/clk-en7523.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_PCI_CONTROL 0x88 +#define REG_PCI_CONTROL_PERSTOUT BIT(29) +#define REG_PCI_CONTROL_PERSTOUT1 BIT(26) +#define REG_PCI_CONTROL_REFCLK_EN1 BIT(22) +#define REG_GSW_CLK_DIV_SEL 0x1b4 +#define REG_EMI_CLK_DIV_SEL 0x1b8 +#define REG_BUS_CLK_DIV_SEL 0x1bc +#define REG_SPI_CLK_DIV_SEL 0x1c4 +#define REG_SPI_CLK_FREQ_SEL 0x1c8 +#define REG_NPU_CLK_DIV_SEL 0x1fc +#define REG_CRYPTO_CLKSRC 0x200 +#define REG_RESET_CONTROL 0x834 +#define REG_RESET_CONTROL_PCIEHB BIT(29) +#define REG_RESET_CONTROL_PCIE1 BIT(27) +#define REG_RESET_CONTROL_PCIE2 BIT(26) + +struct en_clk_desc { + int id; + const char *name; + u32 base_reg; + u32 base_bits; + u32 base_shift; + union { + const u32 *base_values; + u32 base_value; + }; + int n_base_values; + + u32 div_reg; + u32 div_bits; + u32 div_shift; + u32 div_val0; + u32 div_step; +}; + +struct en_clk_gate { + void __iomem *base; + struct clk_hw hw; +}; + +static const u32 gsw_base[] = { 400000000, 500000000 }; +static const u32 emi_base[] = { 333000000, 400000000 }; +static const u32 bus_base[] = { 500000000, 540000000 }; +static const u32 slic_base[] = { 100000000, 3125000 }; +static const u32 npu_base[] = { 333000000, 400000000, 500000000 }; + +static const struct en_clk_desc en7523_base_clks[] = { + { + .id = EN7523_CLK_GSW, + .name = "gsw", + + .base_reg = REG_GSW_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = gsw_base, + .n_base_values = ARRAY_SIZE(gsw_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + }, { + .id = EN7523_CLK_EMI, + .name = "emi", + + .base_reg = REG_EMI_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = emi_base, + .n_base_values = ARRAY_SIZE(emi_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + }, { + .id = EN7523_CLK_BUS, + .name = "bus", + + .base_reg = REG_BUS_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = bus_base, + .n_base_values = ARRAY_SIZE(bus_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + }, { + .id = EN7523_CLK_SLIC, + .name = "slic", + + .base_reg = REG_SPI_CLK_FREQ_SEL, + .base_bits = 1, + .base_shift = 0, + .base_values = slic_base, + .n_base_values = ARRAY_SIZE(slic_base), + + .div_reg = REG_SPI_CLK_DIV_SEL, + .div_bits = 5, + .div_shift = 24, + .div_val0 = 20, + .div_step = 2, + }, { + .id = EN7523_CLK_SPI, + .name = "spi", + + .base_reg = REG_SPI_CLK_DIV_SEL, + + .base_value = 400000000, + + .div_bits = 5, + .div_shift = 8, + .div_val0 = 40, + .div_step = 2, + }, { + .id = EN7523_CLK_NPU, + .name = "npu", + + .base_reg = REG_NPU_CLK_DIV_SEL, + .base_bits = 2, + .base_shift = 8, + .base_values = npu_base, + .n_base_values = ARRAY_SIZE(npu_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + }, { + .id = EN7523_CLK_CRYPTO, + .name = "crypto", + + .base_reg = REG_CRYPTO_CLKSRC, + .base_bits = 1, + .base_shift = 8, + .base_values = emi_base, + .n_base_values = ARRAY_SIZE(emi_base), + } +}; + +static const struct of_device_id of_match_clk_en7523[] = { + { .compatible = "airoha,en7523-scu", }, + { /* sentinel */ } +}; + +static u32 en7523_get_base_rate(void __iomem *base, int i) +{ + const struct en_clk_desc *desc = &en7523_base_clks[i]; + u32 val; + + if (!desc->base_bits) + return desc->base_value; + + val = readl(base + desc->base_reg); + val >>= desc->base_shift; + val &= (1 << desc->base_bits) - 1; + + if (val >= desc->n_base_values) + return 0; + + return desc->base_values[val]; +} + +static u32 en7523_get_div(void __iomem *base, int i) +{ + const struct en_clk_desc *desc = &en7523_base_clks[i]; + u32 reg, val; + + if (!desc->div_bits) + return 1; + + reg = desc->div_reg ? desc->div_reg : desc->base_reg; + val = readl(base + reg); + val >>= desc->div_shift; + val &= (1 << desc->div_bits) - 1; + + if (!val && desc->div_val0) + return desc->div_val0; + + return (val + 1) * desc->div_step; +} + +static int en7523_pci_is_enabled(struct clk_hw *hw) +{ + struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw); + + return !!(readl(cg->base + REG_PCI_CONTROL) & REG_PCI_CONTROL_REFCLK_EN1); +} + +static int en7523_pci_enable(struct clk_hw *hw) +{ + struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw); + void *np_base = cg->base; + u32 val, mask; + + /* Need to pull device low before reset */ + val = readl(np_base + REG_PCI_CONTROL); + val &= ~(REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT); + writel(val, np_base + REG_PCI_CONTROL); + usleep_range(1000, 2000); + + /* Enable PCIe port 1 */ + val |= REG_PCI_CONTROL_REFCLK_EN1; + writel(val, np_base + REG_PCI_CONTROL); + usleep_range(1000, 2000); + + /* Reset to default */ + val = readl(np_base + REG_RESET_CONTROL); + mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 | + REG_RESET_CONTROL_PCIEHB; + writel(val & ~mask, np_base + REG_RESET_CONTROL); + usleep_range(1000, 2000); + writel(val | mask, np_base + REG_RESET_CONTROL); + msleep(100); + writel(val & ~mask, np_base + REG_RESET_CONTROL); + usleep_range(5000, 10000); + + /* Release device */ + mask = REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT; + val = readl(np_base + REG_PCI_CONTROL); + writel(val & ~mask, np_base + REG_PCI_CONTROL); + usleep_range(1000, 2000); + writel(val | mask, np_base + REG_PCI_CONTROL); + msleep(250); + + return 0; +} + +static void en7523_pci_disable(struct clk_hw *hw) +{ + struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw); + void *np_base = cg->base; + u32 val; + + val = readl(np_base + REG_PCI_CONTROL); + val &= ~REG_PCI_CONTROL_REFCLK_EN1; + writel(val, np_base + REG_PCI_CONTROL); +} + +static struct clk *en7523_register_pcie_clk(struct device *dev, + void __iomem *np_base) +{ + static const struct clk_ops pcie_gate_ops = { + .is_enabled = en7523_pci_is_enabled, + .enable = en7523_pci_enable, + .disable = en7523_pci_disable, + }; + struct clk_init_data init = { + .name = "pcie", + .ops = &pcie_gate_ops, + }; + struct en_clk_gate *cg; + struct clk *clk; + + cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL); + if (!cg) + return NULL; + + cg->base = np_base; + cg->hw.init = &init; + en7523_pci_disable(&cg->hw); + + clk = clk_register(NULL, &cg->hw); + if (IS_ERR(clk)) + clk = NULL; + + return clk; +} + +static void en7523_register_clocks(struct device *dev, struct clk_onecell_data *clk_data, + void __iomem *base, void __iomem *np_base) +{ + struct clk *clk; + u32 rate; + int i; + + for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) { + const struct en_clk_desc *desc = &en7523_base_clks[i]; + + rate = en7523_get_base_rate(base, i); + rate /= en7523_get_div(base, i); + + clk = clk_register_fixed_rate(NULL, desc->name, NULL, 0, rate); + if (IS_ERR(clk)) { + pr_err("Failed to register clk %s: %ld\n", + desc->name, PTR_ERR(clk)); + continue; + } + + clk_data->clks[desc->id] = clk; + } + + clk = en7523_register_pcie_clk(dev, np_base); + clk_data->clks[EN7523_CLK_PCIE] = clk; + + clk_data->clk_num = EN7523_NUM_CLOCKS; +} + +static int en7523_clk_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_onecell_data *clk_data; + void __iomem *base, *np_base; + int r; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + np_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(base)) + return PTR_ERR(np_base); + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kcalloc(&pdev->dev, EN7523_NUM_CLOCKS, + sizeof(*clk_data->clks), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + en7523_register_clocks(&pdev->dev, clk_data, base, np_base); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_en7523_drv = { + .probe = en7523_clk_probe, + .driver = { + .name = "clk-en7523", + .of_match_table = of_match_clk_en7523, + }, +}; + +static int clk_en7523_init(void) +{ + return platform_driver_register(&clk_en7523_drv); +} + +arch_initcall(clk_en7523_init);