* [PATCH v7 1/5] clk: Add clock driver for ASPEED BMC SoCs
2017-12-22 2:45 [PATCH v7 0/5] clk: Add Aspeed clock driver Joel Stanley
@ 2017-12-22 2:45 ` Joel Stanley
2018-01-02 5:48 ` Benjamin Herrenschmidt
2018-01-03 1:46 ` Stephen Boyd
2017-12-22 2:45 ` [PATCH v7 2/5] clk: aspeed: Register core clocks Joel Stanley
` (3 subsequent siblings)
4 siblings, 2 replies; 16+ messages in thread
From: Joel Stanley @ 2017-12-22 2:45 UTC (permalink / raw)
To: linux-arm-kernel
This adds the stub of a driver for the ASPEED SoCs. The clocks are
defined and the static registration is set up.
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
v7:
- Rebase on dt-bindings patch
- Add ASPEED_NUM_CLKS as it no longer lives in the header
v6:
- Add SPDX copyright notices
v5:
- Add Andrew's reviewed-by
- Make aspeed_gates not initconst to avoid section mismatch warning
v3:
- use named initlisers for aspeed_gates table
- fix clocks typo
- Move ASPEED_NUM_CLKS to the bottom of the list
- Put gates at the start of the list, so we can use them to initalise
the aspeed_gates table
- Add ASPEED_CLK_SELECTION_2
- Set parent of network MAC gates
---
drivers/clk/Kconfig | 12 ++++
drivers/clk/Makefile | 1 +
drivers/clk/clk-aspeed.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 154 insertions(+)
create mode 100644 drivers/clk/clk-aspeed.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1c4e1aa6767e..9abe063ef8d2 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -142,6 +142,18 @@ config COMMON_CLK_GEMINI
This driver supports the SoC clocks on the Cortina Systems Gemini
platform, also known as SL3516 or CS3516.
+config COMMON_CLK_ASPEED
+ bool "Clock driver for Aspeed BMC SoCs"
+ depends on ARCH_ASPEED || COMPILE_TEST
+ default ARCH_ASPEED
+ select MFD_SYSCON
+ select RESET_CONTROLLER
+ ---help---
+ This driver supports the SoC clocks on the Aspeed BMC platforms.
+
+ The G4 and G5 series, including the ast2400 and ast2500, are supported
+ by this driver.
+
config COMMON_CLK_S2MPS11
tristate "Clock driver for S2MPS1X/S5M8767 MFD"
depends on MFD_SEC_CORE || COMPILE_TEST
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f7f761b02bed..d260da4809f8 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
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_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
new file mode 100644
index 000000000000..7a86ee08ea4f
--- /dev/null
+++ b/drivers/clk/clk-aspeed.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#define pr_fmt(fmt) "clk-aspeed: " fmt
+
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/aspeed-clock.h>
+
+#define ASPEED_NUM_CLKS 35
+
+#define ASPEED_STRAP 0x70
+
+/* Keeps track of all clocks */
+static struct clk_hw_onecell_data *aspeed_clk_data;
+
+static void __iomem *scu_base;
+
+/**
+ * struct aspeed_gate_data - Aspeed gated clocks
+ * @clock_idx: bit used to gate this clock in the clock register
+ * @reset_idx: bit used to reset this IP in the reset register. -1 if no
+ * reset is required when enabling the clock
+ * @name: the clock name
+ * @parent_name: the name of the parent clock
+ * @flags: standard clock framework flags
+ */
+struct aspeed_gate_data {
+ u8 clock_idx;
+ s8 reset_idx;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+};
+
+/**
+ * struct aspeed_clk_gate - Aspeed specific clk_gate structure
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: register controlling gate
+ * @clock_idx: bit used to gate this clock in the clock register
+ * @reset_idx: bit used to reset this IP in the reset register. -1 if no
+ * reset is required when enabling the clock
+ * @flags: hardware-specific flags
+ * @lock: register lock
+ *
+ * Some of the clocks in the Aspeed SoC must be put in reset before enabling.
+ * This modified version of clk_gate allows an optional reset bit to be
+ * specified.
+ */
+struct aspeed_clk_gate {
+ struct clk_hw hw;
+ struct regmap *map;
+ u8 clock_idx;
+ s8 reset_idx;
+ u8 flags;
+ spinlock_t *lock;
+};
+
+#define to_aspeed_clk_gate(_hw) container_of(_hw, struct aspeed_clk_gate, hw)
+
+/* TODO: ask Aspeed about the actual parent data */
+static const struct aspeed_gate_data aspeed_gates[] = {
+ /* clk rst name parent flags */
+ [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */
+ [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */
+ [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */
+ [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */
+ [ASPEED_CLK_GATE_BCLK] = { 4, 10, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */
+ [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, 0 }, /* DAC */
+ [ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL },
+ [ASPEED_CLK_GATE_USBPORT2CLK] = { 7, 3, "usb-port2-gate", NULL, 0 }, /* USB2.0 Host port 2 */
+ [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, 0 }, /* LPC */
+ [ASPEED_CLK_GATE_USBUHCICLK] = { 9, 15, "usb-uhci-gate", NULL, 0 }, /* USB1.1 (requires port 2 enabled) */
+ [ASPEED_CLK_GATE_D1CLK] = { 10, 13, "d1clk-gate", NULL, 0 }, /* GFX CRT */
+ [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */
+ [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */
+ [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */
+ [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */
+ [ASPEED_CLK_GATE_UART5CLK] = { 17, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */
+ [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, 0 }, /* eSPI */
+ [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac", 0 }, /* MAC1 */
+ [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac", 0 }, /* MAC2 */
+ [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */
+ [ASPEED_CLK_GATE_UART3CLK] = { 25, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */
+ [ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */
+ [ASPEED_CLK_GATE_SDCLKCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */
+ [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
+};
+
+static void __init aspeed_cc_init(struct device_node *np)
+{
+ struct regmap *map;
+ u32 val;
+ int ret;
+ int i;
+
+ scu_base = of_iomap(np, 0);
+ if (IS_ERR(scu_base))
+ return;
+
+ aspeed_clk_data = kzalloc(sizeof(*aspeed_clk_data) +
+ sizeof(*aspeed_clk_data->hws) * ASPEED_NUM_CLKS,
+ GFP_KERNEL);
+ if (!aspeed_clk_data)
+ return;
+
+ /*
+ * This way all clocks fetched before the platform device probes,
+ * except those we assign here for early use, will be deferred.
+ */
+ for (i = 0; i < ASPEED_NUM_CLKS; i++)
+ aspeed_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
+
+ map = syscon_node_to_regmap(np);
+ if (IS_ERR(map)) {
+ pr_err("no syscon regmap\n");
+ return;
+ }
+ /*
+ * We check that the regmap works on this very first access,
+ * but as this is an MMIO-backed regmap, subsequent regmap
+ * access is not going to fail and we skip error checks from
+ * this point.
+ */
+ ret = regmap_read(map, ASPEED_STRAP, &val);
+ if (ret) {
+ pr_err("failed to read strapping register\n");
+ return;
+ }
+
+ aspeed_clk_data->num = ASPEED_NUM_CLKS;
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data);
+ if (ret)
+ pr_err("failed to add DT provider: %d\n", ret);
+};
+CLK_OF_DECLARE_DRIVER(aspeed_cc_g5, "aspeed,ast2500-scu", aspeed_cc_init);
+CLK_OF_DECLARE_DRIVER(aspeed_cc_g4, "aspeed,ast2400-scu", aspeed_cc_init);
--
2.15.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 1/5] clk: Add clock driver for ASPEED BMC SoCs
2017-12-22 2:45 ` [PATCH v7 1/5] clk: Add clock driver for ASPEED BMC SoCs Joel Stanley
@ 2018-01-02 5:48 ` Benjamin Herrenschmidt
2018-01-03 1:46 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Benjamin Herrenschmidt @ 2018-01-02 5:48 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 2017-12-22 at 13:15 +1030, Joel Stanley wrote:
> This adds the stub of a driver for the ASPEED SoCs. The clocks are
> defined and the static registration is set up.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> v7:
> - Rebase on dt-bindings patch
> - Add ASPEED_NUM_CLKS as it no longer lives in the header
> v6:
> - Add SPDX copyright notices
> v5:
> - Add Andrew's reviewed-by
> - Make aspeed_gates not initconst to avoid section mismatch warning
> v3:
> - use named initlisers for aspeed_gates table
> - fix clocks typo
> - Move ASPEED_NUM_CLKS to the bottom of the list
> - Put gates at the start of the list, so we can use them to initalise
> the aspeed_gates table
> - Add ASPEED_CLK_SELECTION_2
> - Set parent of network MAC gates
> ---
> drivers/clk/Kconfig | 12 ++++
> drivers/clk/Makefile | 1 +
> drivers/clk/clk-aspeed.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 154 insertions(+)
> create mode 100644 drivers/clk/clk-aspeed.c
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 1c4e1aa6767e..9abe063ef8d2 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -142,6 +142,18 @@ config COMMON_CLK_GEMINI
> This driver supports the SoC clocks on the Cortina Systems Gemini
> platform, also known as SL3516 or CS3516.
>
> +config COMMON_CLK_ASPEED
> + bool "Clock driver for Aspeed BMC SoCs"
> + depends on ARCH_ASPEED || COMPILE_TEST
> + default ARCH_ASPEED
> + select MFD_SYSCON
> + select RESET_CONTROLLER
> + ---help---
> + This driver supports the SoC clocks on the Aspeed BMC platforms.
> +
> + The G4 and G5 series, including the ast2400 and ast2500, are supported
> + by this driver.
> +
> config COMMON_CLK_S2MPS11
> tristate "Clock driver for S2MPS1X/S5M8767 MFD"
> depends on MFD_SEC_CORE || COMPILE_TEST
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index f7f761b02bed..d260da4809f8 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
> 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_COMMON_CLK_ASPEED) += clk-aspeed.o
> obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
> obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
> obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
> diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
> new file mode 100644
> index 000000000000..7a86ee08ea4f
> --- /dev/null
> +++ b/drivers/clk/clk-aspeed.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#define pr_fmt(fmt) "clk-aspeed: " fmt
> +
> +#include <linux/clk-provider.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_address.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#include <dt-bindings/clock/aspeed-clock.h>
> +
> +#define ASPEED_NUM_CLKS 35
> +
> +#define ASPEED_STRAP 0x70
> +
> +/* Keeps track of all clocks */
> +static struct clk_hw_onecell_data *aspeed_clk_data;
> +
> +static void __iomem *scu_base;
> +
> +/**
> + * struct aspeed_gate_data - Aspeed gated clocks
> + * @clock_idx: bit used to gate this clock in the clock register
> + * @reset_idx: bit used to reset this IP in the reset register. -1 if no
> + * reset is required when enabling the clock
> + * @name: the clock name
> + * @parent_name: the name of the parent clock
> + * @flags: standard clock framework flags
> + */
> +struct aspeed_gate_data {
> + u8 clock_idx;
> + s8 reset_idx;
> + const char *name;
> + const char *parent_name;
> + unsigned long flags;
> +};
> +
> +/**
> + * struct aspeed_clk_gate - Aspeed specific clk_gate structure
> + * @hw: handle between common and hardware-specific interfaces
> + * @reg: register controlling gate
> + * @clock_idx: bit used to gate this clock in the clock register
> + * @reset_idx: bit used to reset this IP in the reset register. -1 if no
> + * reset is required when enabling the clock
> + * @flags: hardware-specific flags
> + * @lock: register lock
> + *
> + * Some of the clocks in the Aspeed SoC must be put in reset before enabling.
> + * This modified version of clk_gate allows an optional reset bit to be
> + * specified.
> + */
> +struct aspeed_clk_gate {
> + struct clk_hw hw;
> + struct regmap *map;
> + u8 clock_idx;
> + s8 reset_idx;
> + u8 flags;
> + spinlock_t *lock;
> +};
> +
> +#define to_aspeed_clk_gate(_hw) container_of(_hw, struct aspeed_clk_gate, hw)
> +
> +/* TODO: ask Aspeed about the actual parent data */
> +static const struct aspeed_gate_data aspeed_gates[] = {
> + /* clk rst name parent flags */
> + [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */
> + [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */
> + [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */
> + [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */
> + [ASPEED_CLK_GATE_BCLK] = { 4, 10, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */
> + [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, 0 }, /* DAC */
> + [ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL },
> + [ASPEED_CLK_GATE_USBPORT2CLK] = { 7, 3, "usb-port2-gate", NULL, 0 }, /* USB2.0 Host port 2 */
> + [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, 0 }, /* LPC */
> + [ASPEED_CLK_GATE_USBUHCICLK] = { 9, 15, "usb-uhci-gate", NULL, 0 }, /* USB1.1 (requires port 2 enabled) */
> + [ASPEED_CLK_GATE_D1CLK] = { 10, 13, "d1clk-gate", NULL, 0 }, /* GFX CRT */
> + [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */
> + [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */
> + [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */
> + [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */
> + [ASPEED_CLK_GATE_UART5CLK] = { 17, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */
> + [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, 0 }, /* eSPI */
> + [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac", 0 }, /* MAC1 */
> + [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac", 0 }, /* MAC2 */
> + [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */
> + [ASPEED_CLK_GATE_UART3CLK] = { 25, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */
> + [ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */
> + [ASPEED_CLK_GATE_SDCLKCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */
> + [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
> +};
> +
> +static void __init aspeed_cc_init(struct device_node *np)
> +{
> + struct regmap *map;
> + u32 val;
> + int ret;
> + int i;
> +
> + scu_base = of_iomap(np, 0);
> + if (IS_ERR(scu_base))
> + return;
> +
> + aspeed_clk_data = kzalloc(sizeof(*aspeed_clk_data) +
> + sizeof(*aspeed_clk_data->hws) * ASPEED_NUM_CLKS,
> + GFP_KERNEL);
> + if (!aspeed_clk_data)
> + return;
> +
> + /*
> + * This way all clocks fetched before the platform device probes,
> + * except those we assign here for early use, will be deferred.
> + */
> + for (i = 0; i < ASPEED_NUM_CLKS; i++)
> + aspeed_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
> +
> + map = syscon_node_to_regmap(np);
> + if (IS_ERR(map)) {
> + pr_err("no syscon regmap\n");
> + return;
> + }
> + /*
> + * We check that the regmap works on this very first access,
> + * but as this is an MMIO-backed regmap, subsequent regmap
> + * access is not going to fail and we skip error checks from
> + * this point.
> + */
> + ret = regmap_read(map, ASPEED_STRAP, &val);
> + if (ret) {
> + pr_err("failed to read strapping register\n");
> + return;
> + }
> +
> + aspeed_clk_data->num = ASPEED_NUM_CLKS;
> + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data);
> + if (ret)
> + pr_err("failed to add DT provider: %d\n", ret);
> +};
> +CLK_OF_DECLARE_DRIVER(aspeed_cc_g5, "aspeed,ast2500-scu", aspeed_cc_init);
> +CLK_OF_DECLARE_DRIVER(aspeed_cc_g4, "aspeed,ast2400-scu", aspeed_cc_init);
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 1/5] clk: Add clock driver for ASPEED BMC SoCs
2017-12-22 2:45 ` [PATCH v7 1/5] clk: Add clock driver for ASPEED BMC SoCs Joel Stanley
2018-01-02 5:48 ` Benjamin Herrenschmidt
@ 2018-01-03 1:46 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Stephen Boyd @ 2018-01-03 1:46 UTC (permalink / raw)
To: linux-arm-kernel
On 12/22, Joel Stanley wrote:
> This adds the stub of a driver for the ASPEED SoCs. The clocks are
> defined and the static registration is set up.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 2/5] clk: aspeed: Register core clocks
2017-12-22 2:45 [PATCH v7 0/5] clk: Add Aspeed clock driver Joel Stanley
2017-12-22 2:45 ` [PATCH v7 1/5] clk: Add clock driver for ASPEED BMC SoCs Joel Stanley
@ 2017-12-22 2:45 ` Joel Stanley
2018-01-02 5:49 ` Benjamin Herrenschmidt
2018-01-03 1:46 ` Stephen Boyd
2017-12-22 2:45 ` [PATCH v7 3/5] clk: aspeed: Add platform driver and register PLLs Joel Stanley
` (2 subsequent siblings)
4 siblings, 2 replies; 16+ messages in thread
From: Joel Stanley @ 2017-12-22 2:45 UTC (permalink / raw)
To: linux-arm-kernel
This registers the core clocks; those which are required to calculate
the rate of the timer peripheral so the system can load a clocksource
driver.
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
v5:
- Add Andrew's Reviewed-by
v4:
- Add defines to document the BIT() macros
v3:
- Fix ast2400 ahb calculation
- Remove incorrect 'this is wrong' comment
- Separate out clkin calc to be per platform
- Support 48MHz clkin on ast2400
---
drivers/clk/clk-aspeed.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 177 insertions(+)
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index 7a86ee08ea4f..5adedda82d26 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -13,7 +13,23 @@
#define ASPEED_NUM_CLKS 35
+#define ASPEED_RESET_CTRL 0x04
+#define ASPEED_CLK_SELECTION 0x08
+#define ASPEED_CLK_STOP_CTRL 0x0c
+#define ASPEED_MPLL_PARAM 0x20
+#define ASPEED_HPLL_PARAM 0x24
+#define AST2500_HPLL_BYPASS_EN BIT(20)
+#define AST2400_HPLL_STRAPPED BIT(18)
+#define AST2400_HPLL_BYPASS_EN BIT(17)
+#define ASPEED_MISC_CTRL 0x2c
+#define UART_DIV13_EN BIT(12)
#define ASPEED_STRAP 0x70
+#define CLKIN_25MHZ_EN BIT(23)
+#define AST2400_CLK_SOURCE_SEL BIT(18)
+#define ASPEED_CLK_SELECTION_2 0xd8
+
+/* Globally visible clocks */
+static DEFINE_SPINLOCK(aspeed_clk_lock);
/* Keeps track of all clocks */
static struct clk_hw_onecell_data *aspeed_clk_data;
@@ -91,6 +107,160 @@ static const struct aspeed_gate_data aspeed_gates[] = {
[ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
};
+static const struct clk_div_table ast2400_div_table[] = {
+ { 0x0, 2 },
+ { 0x1, 4 },
+ { 0x2, 6 },
+ { 0x3, 8 },
+ { 0x4, 10 },
+ { 0x5, 12 },
+ { 0x6, 14 },
+ { 0x7, 16 },
+ { 0 }
+};
+
+static const struct clk_div_table ast2500_div_table[] = {
+ { 0x0, 4 },
+ { 0x1, 8 },
+ { 0x2, 12 },
+ { 0x3, 16 },
+ { 0x4, 20 },
+ { 0x5, 24 },
+ { 0x6, 28 },
+ { 0x7, 32 },
+ { 0 }
+};
+
+static struct clk_hw *aspeed_ast2400_calc_pll(const char *name, u32 val)
+{
+ unsigned int mult, div;
+
+ if (val & AST2400_HPLL_BYPASS_EN) {
+ /* Pass through mode */
+ mult = div = 1;
+ } else {
+ /* F = 24Mhz * (2-OD) * [(N + 2) / (D + 1)] */
+ u32 n = (val >> 5) & 0x3f;
+ u32 od = (val >> 4) & 0x1;
+ u32 d = val & 0xf;
+
+ mult = (2 - od) * (n + 2);
+ div = d + 1;
+ }
+ return clk_hw_register_fixed_factor(NULL, name, "clkin", 0,
+ mult, div);
+};
+
+static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val)
+{
+ unsigned int mult, div;
+
+ if (val & AST2500_HPLL_BYPASS_EN) {
+ /* Pass through mode */
+ mult = div = 1;
+ } else {
+ /* F = clkin * [(M+1) / (N+1)] / (P + 1) */
+ u32 p = (val >> 13) & 0x3f;
+ u32 m = (val >> 5) & 0xff;
+ u32 n = val & 0x1f;
+
+ mult = (m + 1) / (n + 1);
+ div = p + 1;
+ }
+
+ return clk_hw_register_fixed_factor(NULL, name, "clkin", 0,
+ mult, div);
+}
+
+static void __init aspeed_ast2400_cc(struct regmap *map)
+{
+ struct clk_hw *hw;
+ u32 val, freq, div;
+
+ /*
+ * CLKIN is the crystal oscillator, 24, 48 or 25MHz selected by
+ * strapping
+ */
+ regmap_read(map, ASPEED_STRAP, &val);
+ if (val & CLKIN_25MHZ_EN)
+ freq = 25000000;
+ else if (val & AST2400_CLK_SOURCE_SEL)
+ freq = 48000000;
+ else
+ freq = 24000000;
+ hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq);
+ pr_debug("clkin @%u MHz\n", freq / 1000000);
+
+ /*
+ * High-speed PLL clock derived from the crystal. This the CPU clock,
+ * and we assume that it is enabled
+ */
+ regmap_read(map, ASPEED_HPLL_PARAM, &val);
+ WARN(val & AST2400_HPLL_STRAPPED, "hpll is strapped not configured");
+ aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2400_calc_pll("hpll", val);
+
+ /*
+ * Strap bits 11:10 define the CPU/AHB clock frequency ratio (aka HCLK)
+ * 00: Select CPU:AHB = 1:1
+ * 01: Select CPU:AHB = 2:1
+ * 10: Select CPU:AHB = 4:1
+ * 11: Select CPU:AHB = 3:1
+ */
+ regmap_read(map, ASPEED_STRAP, &val);
+ val = (val >> 10) & 0x3;
+ div = val + 1;
+ if (div == 3)
+ div = 4;
+ else if (div == 4)
+ div = 3;
+ hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div);
+ aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw;
+
+ /* APB clock clock selection register SCU08 (aka PCLK) */
+ hw = clk_hw_register_divider_table(NULL, "apb", "hpll", 0,
+ scu_base + ASPEED_CLK_SELECTION, 23, 3, 0,
+ ast2400_div_table,
+ &aspeed_clk_lock);
+ aspeed_clk_data->hws[ASPEED_CLK_APB] = hw;
+}
+
+static void __init aspeed_ast2500_cc(struct regmap *map)
+{
+ struct clk_hw *hw;
+ u32 val, freq, div;
+
+ /* CLKIN is the crystal oscillator, 24 or 25MHz selected by strapping */
+ regmap_read(map, ASPEED_STRAP, &val);
+ if (val & CLKIN_25MHZ_EN)
+ freq = 25000000;
+ else
+ freq = 24000000;
+ hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq);
+ pr_debug("clkin @%u MHz\n", freq / 1000000);
+
+ /*
+ * High-speed PLL clock derived from the crystal. This the CPU clock,
+ * and we assume that it is enabled
+ */
+ regmap_read(map, ASPEED_HPLL_PARAM, &val);
+ aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2500_calc_pll("hpll", val);
+
+ /* Strap bits 11:9 define the AXI/AHB clock frequency ratio (aka HCLK)*/
+ regmap_read(map, ASPEED_STRAP, &val);
+ val = (val >> 9) & 0x7;
+ WARN(val == 0, "strapping is zero: cannot determine ahb clock");
+ div = 2 * (val + 1);
+ hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div);
+ aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw;
+
+ /* APB clock clock selection register SCU08 (aka PCLK) */
+ regmap_read(map, ASPEED_CLK_SELECTION, &val);
+ val = (val >> 23) & 0x7;
+ div = 4 * (val + 1);
+ hw = clk_hw_register_fixed_factor(NULL, "apb", "hpll", 0, 1, div);
+ aspeed_clk_data->hws[ASPEED_CLK_APB] = hw;
+};
+
static void __init aspeed_cc_init(struct device_node *np)
{
struct regmap *map;
@@ -132,6 +302,13 @@ static void __init aspeed_cc_init(struct device_node *np)
return;
}
+ if (of_device_is_compatible(np, "aspeed,ast2400-scu"))
+ aspeed_ast2400_cc(map);
+ else if (of_device_is_compatible(np, "aspeed,ast2500-scu"))
+ aspeed_ast2500_cc(map);
+ else
+ pr_err("unknown platform, failed to add clocks\n");
+
aspeed_clk_data->num = ASPEED_NUM_CLKS;
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data);
if (ret)
--
2.15.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 2/5] clk: aspeed: Register core clocks
2017-12-22 2:45 ` [PATCH v7 2/5] clk: aspeed: Register core clocks Joel Stanley
@ 2018-01-02 5:49 ` Benjamin Herrenschmidt
2018-01-03 1:46 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Benjamin Herrenschmidt @ 2018-01-02 5:49 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 2017-12-22 at 13:15 +1030, Joel Stanley wrote:
> This registers the core clocks; those which are required to calculate
> the rate of the timer peripheral so the system can load a clocksource
> driver.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> v5:
> - Add Andrew's Reviewed-by
> v4:
> - Add defines to document the BIT() macros
> v3:
> - Fix ast2400 ahb calculation
> - Remove incorrect 'this is wrong' comment
> - Separate out clkin calc to be per platform
> - Support 48MHz clkin on ast2400
> ---
> drivers/clk/clk-aspeed.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 177 insertions(+)
>
> diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
> index 7a86ee08ea4f..5adedda82d26 100644
> --- a/drivers/clk/clk-aspeed.c
> +++ b/drivers/clk/clk-aspeed.c
> @@ -13,7 +13,23 @@
>
> #define ASPEED_NUM_CLKS 35
>
> +#define ASPEED_RESET_CTRL 0x04
> +#define ASPEED_CLK_SELECTION 0x08
> +#define ASPEED_CLK_STOP_CTRL 0x0c
> +#define ASPEED_MPLL_PARAM 0x20
> +#define ASPEED_HPLL_PARAM 0x24
> +#define AST2500_HPLL_BYPASS_EN BIT(20)
> +#define AST2400_HPLL_STRAPPED BIT(18)
> +#define AST2400_HPLL_BYPASS_EN BIT(17)
> +#define ASPEED_MISC_CTRL 0x2c
> +#define UART_DIV13_EN BIT(12)
> #define ASPEED_STRAP 0x70
> +#define CLKIN_25MHZ_EN BIT(23)
> +#define AST2400_CLK_SOURCE_SEL BIT(18)
> +#define ASPEED_CLK_SELECTION_2 0xd8
> +
> +/* Globally visible clocks */
> +static DEFINE_SPINLOCK(aspeed_clk_lock);
>
> /* Keeps track of all clocks */
> static struct clk_hw_onecell_data *aspeed_clk_data;
> @@ -91,6 +107,160 @@ static const struct aspeed_gate_data aspeed_gates[] = {
> [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
> };
>
> +static const struct clk_div_table ast2400_div_table[] = {
> + { 0x0, 2 },
> + { 0x1, 4 },
> + { 0x2, 6 },
> + { 0x3, 8 },
> + { 0x4, 10 },
> + { 0x5, 12 },
> + { 0x6, 14 },
> + { 0x7, 16 },
> + { 0 }
> +};
> +
> +static const struct clk_div_table ast2500_div_table[] = {
> + { 0x0, 4 },
> + { 0x1, 8 },
> + { 0x2, 12 },
> + { 0x3, 16 },
> + { 0x4, 20 },
> + { 0x5, 24 },
> + { 0x6, 28 },
> + { 0x7, 32 },
> + { 0 }
> +};
> +
> +static struct clk_hw *aspeed_ast2400_calc_pll(const char *name, u32 val)
> +{
> + unsigned int mult, div;
> +
> + if (val & AST2400_HPLL_BYPASS_EN) {
> + /* Pass through mode */
> + mult = div = 1;
> + } else {
> + /* F = 24Mhz * (2-OD) * [(N + 2) / (D + 1)] */
> + u32 n = (val >> 5) & 0x3f;
> + u32 od = (val >> 4) & 0x1;
> + u32 d = val & 0xf;
> +
> + mult = (2 - od) * (n + 2);
> + div = d + 1;
> + }
> + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0,
> + mult, div);
> +};
> +
> +static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val)
> +{
> + unsigned int mult, div;
> +
> + if (val & AST2500_HPLL_BYPASS_EN) {
> + /* Pass through mode */
> + mult = div = 1;
> + } else {
> + /* F = clkin * [(M+1) / (N+1)] / (P + 1) */
> + u32 p = (val >> 13) & 0x3f;
> + u32 m = (val >> 5) & 0xff;
> + u32 n = val & 0x1f;
> +
> + mult = (m + 1) / (n + 1);
> + div = p + 1;
> + }
> +
> + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0,
> + mult, div);
> +}
> +
> +static void __init aspeed_ast2400_cc(struct regmap *map)
> +{
> + struct clk_hw *hw;
> + u32 val, freq, div;
> +
> + /*
> + * CLKIN is the crystal oscillator, 24, 48 or 25MHz selected by
> + * strapping
> + */
> + regmap_read(map, ASPEED_STRAP, &val);
> + if (val & CLKIN_25MHZ_EN)
> + freq = 25000000;
> + else if (val & AST2400_CLK_SOURCE_SEL)
> + freq = 48000000;
> + else
> + freq = 24000000;
> + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq);
> + pr_debug("clkin @%u MHz\n", freq / 1000000);
> +
> + /*
> + * High-speed PLL clock derived from the crystal. This the CPU clock,
> + * and we assume that it is enabled
> + */
> + regmap_read(map, ASPEED_HPLL_PARAM, &val);
> + WARN(val & AST2400_HPLL_STRAPPED, "hpll is strapped not configured");
> + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2400_calc_pll("hpll", val);
> +
> + /*
> + * Strap bits 11:10 define the CPU/AHB clock frequency ratio (aka HCLK)
> + * 00: Select CPU:AHB = 1:1
> + * 01: Select CPU:AHB = 2:1
> + * 10: Select CPU:AHB = 4:1
> + * 11: Select CPU:AHB = 3:1
> + */
> + regmap_read(map, ASPEED_STRAP, &val);
> + val = (val >> 10) & 0x3;
> + div = val + 1;
> + if (div == 3)
> + div = 4;
> + else if (div == 4)
> + div = 3;
> + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div);
> + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw;
> +
> + /* APB clock clock selection register SCU08 (aka PCLK) */
> + hw = clk_hw_register_divider_table(NULL, "apb", "hpll", 0,
> + scu_base + ASPEED_CLK_SELECTION, 23, 3, 0,
> + ast2400_div_table,
> + &aspeed_clk_lock);
> + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw;
> +}
> +
> +static void __init aspeed_ast2500_cc(struct regmap *map)
> +{
> + struct clk_hw *hw;
> + u32 val, freq, div;
> +
> + /* CLKIN is the crystal oscillator, 24 or 25MHz selected by strapping */
> + regmap_read(map, ASPEED_STRAP, &val);
> + if (val & CLKIN_25MHZ_EN)
> + freq = 25000000;
> + else
> + freq = 24000000;
> + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq);
> + pr_debug("clkin @%u MHz\n", freq / 1000000);
> +
> + /*
> + * High-speed PLL clock derived from the crystal. This the CPU clock,
> + * and we assume that it is enabled
> + */
> + regmap_read(map, ASPEED_HPLL_PARAM, &val);
> + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2500_calc_pll("hpll", val);
> +
> + /* Strap bits 11:9 define the AXI/AHB clock frequency ratio (aka HCLK)*/
> + regmap_read(map, ASPEED_STRAP, &val);
> + val = (val >> 9) & 0x7;
> + WARN(val == 0, "strapping is zero: cannot determine ahb clock");
> + div = 2 * (val + 1);
> + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div);
> + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw;
> +
> + /* APB clock clock selection register SCU08 (aka PCLK) */
> + regmap_read(map, ASPEED_CLK_SELECTION, &val);
> + val = (val >> 23) & 0x7;
> + div = 4 * (val + 1);
> + hw = clk_hw_register_fixed_factor(NULL, "apb", "hpll", 0, 1, div);
> + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw;
> +};
> +
> static void __init aspeed_cc_init(struct device_node *np)
> {
> struct regmap *map;
> @@ -132,6 +302,13 @@ static void __init aspeed_cc_init(struct device_node *np)
> return;
> }
>
> + if (of_device_is_compatible(np, "aspeed,ast2400-scu"))
> + aspeed_ast2400_cc(map);
> + else if (of_device_is_compatible(np, "aspeed,ast2500-scu"))
> + aspeed_ast2500_cc(map);
> + else
> + pr_err("unknown platform, failed to add clocks\n");
> +
> aspeed_clk_data->num = ASPEED_NUM_CLKS;
> ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data);
> if (ret)
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 2/5] clk: aspeed: Register core clocks
2017-12-22 2:45 ` [PATCH v7 2/5] clk: aspeed: Register core clocks Joel Stanley
2018-01-02 5:49 ` Benjamin Herrenschmidt
@ 2018-01-03 1:46 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Stephen Boyd @ 2018-01-03 1:46 UTC (permalink / raw)
To: linux-arm-kernel
On 12/22, Joel Stanley wrote:
> This registers the core clocks; those which are required to calculate
> the rate of the timer peripheral so the system can load a clocksource
> driver.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 3/5] clk: aspeed: Add platform driver and register PLLs
2017-12-22 2:45 [PATCH v7 0/5] clk: Add Aspeed clock driver Joel Stanley
2017-12-22 2:45 ` [PATCH v7 1/5] clk: Add clock driver for ASPEED BMC SoCs Joel Stanley
2017-12-22 2:45 ` [PATCH v7 2/5] clk: aspeed: Register core clocks Joel Stanley
@ 2017-12-22 2:45 ` Joel Stanley
2018-01-02 5:49 ` Benjamin Herrenschmidt
2018-01-03 1:47 ` Stephen Boyd
2017-12-22 2:45 ` [PATCH v7 4/5] clk: aspeed: Register gated clocks Joel Stanley
2017-12-22 2:45 ` [PATCH v7 5/5] clk: aspeed: Add reset controller Joel Stanley
4 siblings, 2 replies; 16+ messages in thread
From: Joel Stanley @ 2017-12-22 2:45 UTC (permalink / raw)
To: linux-arm-kernel
This registers a platform driver to set up all of the non-core clocks.
The clocks that have configurable rates are now registered.
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Joel Stanley <joel@jms.id.au>
--
v6:
- Add Andrew's reviewed-by
v5:
- Remove eclk configuration. We do not have enough information to
correctly implement the mux and divisor, so it will have to be
implemented in the future
v4:
- Add eclk div table to fix ast2500 calculation
- Add defines to document the BIT() macros
- Pass dev where we can when registering clocks
- Check for errors when registering clk_hws
v3:
- Fix bclk and eclk calculation
- Separate out ast2400 and ast25000 for pll calculation
---
drivers/clk/clk-aspeed.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index 5adedda82d26..cf5ea63feb31 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -5,6 +5,8 @@
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -107,6 +109,18 @@ static const struct aspeed_gate_data aspeed_gates[] = {
[ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
};
+static const struct clk_div_table ast2500_mac_div_table[] = {
+ { 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */
+ { 0x1, 4 },
+ { 0x2, 6 },
+ { 0x3, 8 },
+ { 0x4, 10 },
+ { 0x5, 12 },
+ { 0x6, 14 },
+ { 0x7, 16 },
+ { 0 }
+};
+
static const struct clk_div_table ast2400_div_table[] = {
{ 0x0, 2 },
{ 0x1, 4 },
@@ -172,6 +186,122 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val)
mult, div);
}
+struct aspeed_clk_soc_data {
+ const struct clk_div_table *div_table;
+ const struct clk_div_table *mac_div_table;
+ struct clk_hw *(*calc_pll)(const char *name, u32 val);
+};
+
+static const struct aspeed_clk_soc_data ast2500_data = {
+ .div_table = ast2500_div_table,
+ .mac_div_table = ast2500_mac_div_table,
+ .calc_pll = aspeed_ast2500_calc_pll,
+};
+
+static const struct aspeed_clk_soc_data ast2400_data = {
+ .div_table = ast2400_div_table,
+ .mac_div_table = ast2400_div_table,
+ .calc_pll = aspeed_ast2400_calc_pll,
+};
+
+static int aspeed_clk_probe(struct platform_device *pdev)
+{
+ const struct aspeed_clk_soc_data *soc_data;
+ struct device *dev = &pdev->dev;
+ struct regmap *map;
+ struct clk_hw *hw;
+ u32 val, rate;
+
+ map = syscon_node_to_regmap(dev->of_node);
+ if (IS_ERR(map)) {
+ dev_err(dev, "no syscon regmap\n");
+ return PTR_ERR(map);
+ }
+
+ /* SoC generations share common layouts but have different divisors */
+ soc_data = of_device_get_match_data(dev);
+ if (!soc_data) {
+ dev_err(dev, "no match data for platform\n");
+ return -EINVAL;
+ }
+
+ /* UART clock div13 setting */
+ regmap_read(map, ASPEED_MISC_CTRL, &val);
+ if (val & UART_DIV13_EN)
+ rate = 24000000 / 13;
+ else
+ rate = 24000000;
+ /* TODO: Find the parent data for the uart clock */
+ hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_UART] = hw;
+
+ /*
+ * Memory controller (M-PLL) PLL. This clock is configured by the
+ * bootloader, and is exposed to Linux as a read-only clock rate.
+ */
+ regmap_read(map, ASPEED_MPLL_PARAM, &val);
+ hw = soc_data->calc_pll("mpll", val);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_MPLL] = hw;
+
+ /* SD/SDIO clock divider (TODO: There's a gate too) */
+ hw = clk_hw_register_divider_table(dev, "sdio", "hpll", 0,
+ scu_base + ASPEED_CLK_SELECTION, 12, 3, 0,
+ soc_data->div_table,
+ &aspeed_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_SDIO] = hw;
+
+ /* MAC AHB bus clock divider */
+ hw = clk_hw_register_divider_table(dev, "mac", "hpll", 0,
+ scu_base + ASPEED_CLK_SELECTION, 16, 3, 0,
+ soc_data->mac_div_table,
+ &aspeed_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_MAC] = hw;
+
+ /* LPC Host (LHCLK) clock divider */
+ hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0,
+ scu_base + ASPEED_CLK_SELECTION, 20, 3, 0,
+ soc_data->div_table,
+ &aspeed_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_LHCLK] = hw;
+
+ /* P-Bus (BCLK) clock divider */
+ hw = clk_hw_register_divider_table(dev, "bclk", "hpll", 0,
+ scu_base + ASPEED_CLK_SELECTION_2, 0, 2, 0,
+ soc_data->div_table,
+ &aspeed_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw;
+
+ return 0;
+};
+
+static const struct of_device_id aspeed_clk_dt_ids[] = {
+ { .compatible = "aspeed,ast2400-scu", .data = &ast2400_data },
+ { .compatible = "aspeed,ast2500-scu", .data = &ast2500_data },
+ { }
+};
+
+static struct platform_driver aspeed_clk_driver = {
+ .probe = aspeed_clk_probe,
+ .driver = {
+ .name = "aspeed-clk",
+ .of_match_table = aspeed_clk_dt_ids,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver(aspeed_clk_driver);
+
static void __init aspeed_ast2400_cc(struct regmap *map)
{
struct clk_hw *hw;
--
2.15.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 3/5] clk: aspeed: Add platform driver and register PLLs
2017-12-22 2:45 ` [PATCH v7 3/5] clk: aspeed: Add platform driver and register PLLs Joel Stanley
@ 2018-01-02 5:49 ` Benjamin Herrenschmidt
2018-01-03 1:47 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Benjamin Herrenschmidt @ 2018-01-02 5:49 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 2017-12-22 at 13:15 +1030, Joel Stanley wrote:
> This registers a platform driver to set up all of the non-core clocks.
>
> The clocks that have configurable rates are now registered.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> --
> v6:
> - Add Andrew's reviewed-by
> v5:
> - Remove eclk configuration. We do not have enough information to
> correctly implement the mux and divisor, so it will have to be
> implemented in the future
> v4:
> - Add eclk div table to fix ast2500 calculation
> - Add defines to document the BIT() macros
> - Pass dev where we can when registering clocks
> - Check for errors when registering clk_hws
> v3:
> - Fix bclk and eclk calculation
> - Separate out ast2400 and ast25000 for pll calculation
> ---
> drivers/clk/clk-aspeed.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 130 insertions(+)
>
> diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
> index 5adedda82d26..cf5ea63feb31 100644
> --- a/drivers/clk/clk-aspeed.c
> +++ b/drivers/clk/clk-aspeed.c
> @@ -5,6 +5,8 @@
> #include <linux/clk-provider.h>
> #include <linux/mfd/syscon.h>
> #include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> #include <linux/regmap.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
> @@ -107,6 +109,18 @@ static const struct aspeed_gate_data aspeed_gates[] = {
> [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
> };
>
> +static const struct clk_div_table ast2500_mac_div_table[] = {
> + { 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */
> + { 0x1, 4 },
> + { 0x2, 6 },
> + { 0x3, 8 },
> + { 0x4, 10 },
> + { 0x5, 12 },
> + { 0x6, 14 },
> + { 0x7, 16 },
> + { 0 }
> +};
> +
> static const struct clk_div_table ast2400_div_table[] = {
> { 0x0, 2 },
> { 0x1, 4 },
> @@ -172,6 +186,122 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val)
> mult, div);
> }
>
> +struct aspeed_clk_soc_data {
> + const struct clk_div_table *div_table;
> + const struct clk_div_table *mac_div_table;
> + struct clk_hw *(*calc_pll)(const char *name, u32 val);
> +};
> +
> +static const struct aspeed_clk_soc_data ast2500_data = {
> + .div_table = ast2500_div_table,
> + .mac_div_table = ast2500_mac_div_table,
> + .calc_pll = aspeed_ast2500_calc_pll,
> +};
> +
> +static const struct aspeed_clk_soc_data ast2400_data = {
> + .div_table = ast2400_div_table,
> + .mac_div_table = ast2400_div_table,
> + .calc_pll = aspeed_ast2400_calc_pll,
> +};
> +
> +static int aspeed_clk_probe(struct platform_device *pdev)
> +{
> + const struct aspeed_clk_soc_data *soc_data;
> + struct device *dev = &pdev->dev;
> + struct regmap *map;
> + struct clk_hw *hw;
> + u32 val, rate;
> +
> + map = syscon_node_to_regmap(dev->of_node);
> + if (IS_ERR(map)) {
> + dev_err(dev, "no syscon regmap\n");
> + return PTR_ERR(map);
> + }
> +
> + /* SoC generations share common layouts but have different divisors */
> + soc_data = of_device_get_match_data(dev);
> + if (!soc_data) {
> + dev_err(dev, "no match data for platform\n");
> + return -EINVAL;
> + }
> +
> + /* UART clock div13 setting */
> + regmap_read(map, ASPEED_MISC_CTRL, &val);
> + if (val & UART_DIV13_EN)
> + rate = 24000000 / 13;
> + else
> + rate = 24000000;
> + /* TODO: Find the parent data for the uart clock */
> + hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate);
> + if (IS_ERR(hw))
> + return PTR_ERR(hw);
> + aspeed_clk_data->hws[ASPEED_CLK_UART] = hw;
> +
> + /*
> + * Memory controller (M-PLL) PLL. This clock is configured by the
> + * bootloader, and is exposed to Linux as a read-only clock rate.
> + */
> + regmap_read(map, ASPEED_MPLL_PARAM, &val);
> + hw = soc_data->calc_pll("mpll", val);
> + if (IS_ERR(hw))
> + return PTR_ERR(hw);
> + aspeed_clk_data->hws[ASPEED_CLK_MPLL] = hw;
> +
> + /* SD/SDIO clock divider (TODO: There's a gate too) */
> + hw = clk_hw_register_divider_table(dev, "sdio", "hpll", 0,
> + scu_base + ASPEED_CLK_SELECTION, 12, 3, 0,
> + soc_data->div_table,
> + &aspeed_clk_lock);
> + if (IS_ERR(hw))
> + return PTR_ERR(hw);
> + aspeed_clk_data->hws[ASPEED_CLK_SDIO] = hw;
> +
> + /* MAC AHB bus clock divider */
> + hw = clk_hw_register_divider_table(dev, "mac", "hpll", 0,
> + scu_base + ASPEED_CLK_SELECTION, 16, 3, 0,
> + soc_data->mac_div_table,
> + &aspeed_clk_lock);
> + if (IS_ERR(hw))
> + return PTR_ERR(hw);
> + aspeed_clk_data->hws[ASPEED_CLK_MAC] = hw;
> +
> + /* LPC Host (LHCLK) clock divider */
> + hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0,
> + scu_base + ASPEED_CLK_SELECTION, 20, 3, 0,
> + soc_data->div_table,
> + &aspeed_clk_lock);
> + if (IS_ERR(hw))
> + return PTR_ERR(hw);
> + aspeed_clk_data->hws[ASPEED_CLK_LHCLK] = hw;
> +
> + /* P-Bus (BCLK) clock divider */
> + hw = clk_hw_register_divider_table(dev, "bclk", "hpll", 0,
> + scu_base + ASPEED_CLK_SELECTION_2, 0, 2, 0,
> + soc_data->div_table,
> + &aspeed_clk_lock);
> + if (IS_ERR(hw))
> + return PTR_ERR(hw);
> + aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw;
> +
> + return 0;
> +};
> +
> +static const struct of_device_id aspeed_clk_dt_ids[] = {
> + { .compatible = "aspeed,ast2400-scu", .data = &ast2400_data },
> + { .compatible = "aspeed,ast2500-scu", .data = &ast2500_data },
> + { }
> +};
> +
> +static struct platform_driver aspeed_clk_driver = {
> + .probe = aspeed_clk_probe,
> + .driver = {
> + .name = "aspeed-clk",
> + .of_match_table = aspeed_clk_dt_ids,
> + .suppress_bind_attrs = true,
> + },
> +};
> +builtin_platform_driver(aspeed_clk_driver);
> +
> static void __init aspeed_ast2400_cc(struct regmap *map)
> {
> struct clk_hw *hw;
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 3/5] clk: aspeed: Add platform driver and register PLLs
2017-12-22 2:45 ` [PATCH v7 3/5] clk: aspeed: Add platform driver and register PLLs Joel Stanley
2018-01-02 5:49 ` Benjamin Herrenschmidt
@ 2018-01-03 1:47 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Stephen Boyd @ 2018-01-03 1:47 UTC (permalink / raw)
To: linux-arm-kernel
On 12/22, Joel Stanley wrote:
> This registers a platform driver to set up all of the non-core clocks.
>
> The clocks that have configurable rates are now registered.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> --
> v6:
> - Add Andrew's reviewed-by
> v5:
> - Remove eclk configuration. We do not have enough information to
> correctly implement the mux and divisor, so it will have to be
> implemented in the future
> v4:
> - Add eclk div table to fix ast2500 calculation
> - Add defines to document the BIT() macros
> - Pass dev where we can when registering clocks
> - Check for errors when registering clk_hws
> v3:
> - Fix bclk and eclk calculation
> - Separate out ast2400 and ast25000 for pll calculation
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 4/5] clk: aspeed: Register gated clocks
2017-12-22 2:45 [PATCH v7 0/5] clk: Add Aspeed clock driver Joel Stanley
` (2 preceding siblings ...)
2017-12-22 2:45 ` [PATCH v7 3/5] clk: aspeed: Add platform driver and register PLLs Joel Stanley
@ 2017-12-22 2:45 ` Joel Stanley
2018-01-02 5:50 ` Benjamin Herrenschmidt
2018-01-03 1:47 ` Stephen Boyd
2017-12-22 2:45 ` [PATCH v7 5/5] clk: aspeed: Add reset controller Joel Stanley
4 siblings, 2 replies; 16+ messages in thread
From: Joel Stanley @ 2017-12-22 2:45 UTC (permalink / raw)
To: linux-arm-kernel
The majority of the clocks in the system are gates paired with a reset
controller that holds the IP in reset.
This borrows from clk_hw_register_gate, but registers two 'gates', one
to control the clock enable register and the other to control the reset
IP. This allows us to enforce the ordering:
1. Place IP in reset
2. Enable clock
3. Delay
4. Release reset
There are some gates that do not have an associated reset; these are
handled by using -1 as the index for the reset.
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
v7:
- Use mdelay instead of msleep and remove the todo. Stephen points out:
> No you can't sleep here. It needs to delay because this is inside
> spinlock_irqsave.
v5:
- Add Andrew's Reviewed-by
v4:
- Drop useless 'disable clock' comment
- Drop CLK_IS_BASIC flag
- Fix 'there are a number of clocks...' comment
- Pass device to clk registration functions
- Check for errors when registering clk_hws
v3:
- Remove gates offset as gates are now at the start of the list
mdelay
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
drivers/clk/clk-aspeed.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index cf5ea63feb31..dbd3c7774831 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -204,6 +204,106 @@ static const struct aspeed_clk_soc_data ast2400_data = {
.calc_pll = aspeed_ast2400_calc_pll,
};
+static int aspeed_clk_enable(struct clk_hw *hw)
+{
+ struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
+ unsigned long flags;
+ u32 clk = BIT(gate->clock_idx);
+ u32 rst = BIT(gate->reset_idx);
+
+ spin_lock_irqsave(gate->lock, flags);
+
+ if (gate->reset_idx >= 0) {
+ /* Put IP in reset */
+ regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst);
+
+ /* Delay 100us */
+ udelay(100);
+ }
+
+ /* Enable clock */
+ regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, 0);
+
+ if (gate->reset_idx >= 0) {
+ /* A delay of 10ms is specified by the ASPEED docs */
+ mdelay(10);
+
+ /* Take IP out of reset */
+ regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0);
+ }
+
+ spin_unlock_irqrestore(gate->lock, flags);
+
+ return 0;
+}
+
+static void aspeed_clk_disable(struct clk_hw *hw)
+{
+ struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
+ unsigned long flags;
+ u32 clk = BIT(gate->clock_idx);
+
+ spin_lock_irqsave(gate->lock, flags);
+
+ regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, clk);
+
+ spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static int aspeed_clk_is_enabled(struct clk_hw *hw)
+{
+ struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
+ u32 clk = BIT(gate->clock_idx);
+ u32 reg;
+
+ regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, ®);
+
+ return (reg & clk) ? 0 : 1;
+}
+
+static const struct clk_ops aspeed_clk_gate_ops = {
+ .enable = aspeed_clk_enable,
+ .disable = aspeed_clk_disable,
+ .is_enabled = aspeed_clk_is_enabled,
+};
+
+static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev,
+ const char *name, const char *parent_name, unsigned long flags,
+ struct regmap *map, u8 clock_idx, u8 reset_idx,
+ u8 clk_gate_flags, spinlock_t *lock)
+{
+ struct aspeed_clk_gate *gate;
+ struct clk_init_data init;
+ struct clk_hw *hw;
+ int ret;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &aspeed_clk_gate_ops;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ gate->map = map;
+ gate->clock_idx = clock_idx;
+ gate->reset_idx = reset_idx;
+ gate->flags = clk_gate_flags;
+ gate->lock = lock;
+ gate->hw.init = &init;
+
+ hw = &gate->hw;
+ ret = clk_hw_register(dev, hw);
+ if (ret) {
+ kfree(gate);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
+
static int aspeed_clk_probe(struct platform_device *pdev)
{
const struct aspeed_clk_soc_data *soc_data;
@@ -211,6 +311,7 @@ static int aspeed_clk_probe(struct platform_device *pdev)
struct regmap *map;
struct clk_hw *hw;
u32 val, rate;
+ int i;
map = syscon_node_to_regmap(dev->of_node);
if (IS_ERR(map)) {
@@ -283,6 +384,35 @@ static int aspeed_clk_probe(struct platform_device *pdev)
return PTR_ERR(hw);
aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw;
+ /*
+ * TODO: There are a number of clocks that not included in this driver
+ * as more information is required:
+ * D2-PLL
+ * D-PLL
+ * YCLK
+ * RGMII
+ * RMII
+ * UART[1..5] clock source mux
+ * Video Engine (ECLK) mux and clock divider
+ */
+
+ for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) {
+ const struct aspeed_gate_data *gd = &aspeed_gates[i];
+
+ hw = aspeed_clk_hw_register_gate(dev,
+ gd->name,
+ gd->parent_name,
+ gd->flags,
+ map,
+ gd->clock_idx,
+ gd->reset_idx,
+ CLK_GATE_SET_TO_DISABLE,
+ &aspeed_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[i] = hw;
+ }
+
return 0;
};
--
2.15.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 4/5] clk: aspeed: Register gated clocks
2017-12-22 2:45 ` [PATCH v7 4/5] clk: aspeed: Register gated clocks Joel Stanley
@ 2018-01-02 5:50 ` Benjamin Herrenschmidt
2018-01-03 1:47 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Benjamin Herrenschmidt @ 2018-01-02 5:50 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 2017-12-22 at 13:15 +1030, Joel Stanley wrote:
> The majority of the clocks in the system are gates paired with a reset
> controller that holds the IP in reset.
>
> This borrows from clk_hw_register_gate, but registers two 'gates', one
> to control the clock enable register and the other to control the reset
> IP. This allows us to enforce the ordering:
>
> 1. Place IP in reset
> 2. Enable clock
> 3. Delay
> 4. Release reset
>
> There are some gates that do not have an associated reset; these are
> handled by using -1 as the index for the reset.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> v7:
> - Use mdelay instead of msleep and remove the todo. Stephen points out:
> > No you can't sleep here. It needs to delay because this is inside
> > spinlock_irqsave.
> v5:
> - Add Andrew's Reviewed-by
> v4:
> - Drop useless 'disable clock' comment
> - Drop CLK_IS_BASIC flag
> - Fix 'there are a number of clocks...' comment
> - Pass device to clk registration functions
> - Check for errors when registering clk_hws
> v3:
> - Remove gates offset as gates are now at the start of the list
>
> mdelay
>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> ---
> drivers/clk/clk-aspeed.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 130 insertions(+)
>
> diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
> index cf5ea63feb31..dbd3c7774831 100644
> --- a/drivers/clk/clk-aspeed.c
> +++ b/drivers/clk/clk-aspeed.c
> @@ -204,6 +204,106 @@ static const struct aspeed_clk_soc_data ast2400_data = {
> .calc_pll = aspeed_ast2400_calc_pll,
> };
>
> +static int aspeed_clk_enable(struct clk_hw *hw)
> +{
> + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
> + unsigned long flags;
> + u32 clk = BIT(gate->clock_idx);
> + u32 rst = BIT(gate->reset_idx);
> +
> + spin_lock_irqsave(gate->lock, flags);
> +
> + if (gate->reset_idx >= 0) {
> + /* Put IP in reset */
> + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst);
> +
> + /* Delay 100us */
> + udelay(100);
> + }
> +
> + /* Enable clock */
> + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, 0);
> +
> + if (gate->reset_idx >= 0) {
> + /* A delay of 10ms is specified by the ASPEED docs */
> + mdelay(10);
> +
> + /* Take IP out of reset */
> + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0);
> + }
> +
> + spin_unlock_irqrestore(gate->lock, flags);
> +
> + return 0;
> +}
> +
> +static void aspeed_clk_disable(struct clk_hw *hw)
> +{
> + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
> + unsigned long flags;
> + u32 clk = BIT(gate->clock_idx);
> +
> + spin_lock_irqsave(gate->lock, flags);
> +
> + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, clk);
> +
> + spin_unlock_irqrestore(gate->lock, flags);
> +}
> +
> +static int aspeed_clk_is_enabled(struct clk_hw *hw)
> +{
> + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
> + u32 clk = BIT(gate->clock_idx);
> + u32 reg;
> +
> + regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, ®);
> +
> + return (reg & clk) ? 0 : 1;
> +}
> +
> +static const struct clk_ops aspeed_clk_gate_ops = {
> + .enable = aspeed_clk_enable,
> + .disable = aspeed_clk_disable,
> + .is_enabled = aspeed_clk_is_enabled,
> +};
> +
> +static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev,
> + const char *name, const char *parent_name, unsigned long flags,
> + struct regmap *map, u8 clock_idx, u8 reset_idx,
> + u8 clk_gate_flags, spinlock_t *lock)
> +{
> + struct aspeed_clk_gate *gate;
> + struct clk_init_data init;
> + struct clk_hw *hw;
> + int ret;
> +
> + gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> + if (!gate)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &aspeed_clk_gate_ops;
> + init.flags = flags;
> + init.parent_names = parent_name ? &parent_name : NULL;
> + init.num_parents = parent_name ? 1 : 0;
> +
> + gate->map = map;
> + gate->clock_idx = clock_idx;
> + gate->reset_idx = reset_idx;
> + gate->flags = clk_gate_flags;
> + gate->lock = lock;
> + gate->hw.init = &init;
> +
> + hw = &gate->hw;
> + ret = clk_hw_register(dev, hw);
> + if (ret) {
> + kfree(gate);
> + hw = ERR_PTR(ret);
> + }
> +
> + return hw;
> +}
> +
> static int aspeed_clk_probe(struct platform_device *pdev)
> {
> const struct aspeed_clk_soc_data *soc_data;
> @@ -211,6 +311,7 @@ static int aspeed_clk_probe(struct platform_device *pdev)
> struct regmap *map;
> struct clk_hw *hw;
> u32 val, rate;
> + int i;
>
> map = syscon_node_to_regmap(dev->of_node);
> if (IS_ERR(map)) {
> @@ -283,6 +384,35 @@ static int aspeed_clk_probe(struct platform_device *pdev)
> return PTR_ERR(hw);
> aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw;
>
> + /*
> + * TODO: There are a number of clocks that not included in this driver
> + * as more information is required:
> + * D2-PLL
> + * D-PLL
> + * YCLK
> + * RGMII
> + * RMII
> + * UART[1..5] clock source mux
> + * Video Engine (ECLK) mux and clock divider
> + */
> +
> + for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) {
> + const struct aspeed_gate_data *gd = &aspeed_gates[i];
> +
> + hw = aspeed_clk_hw_register_gate(dev,
> + gd->name,
> + gd->parent_name,
> + gd->flags,
> + map,
> + gd->clock_idx,
> + gd->reset_idx,
> + CLK_GATE_SET_TO_DISABLE,
> + &aspeed_clk_lock);
> + if (IS_ERR(hw))
> + return PTR_ERR(hw);
> + aspeed_clk_data->hws[i] = hw;
> + }
> +
> return 0;
> };
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 4/5] clk: aspeed: Register gated clocks
2017-12-22 2:45 ` [PATCH v7 4/5] clk: aspeed: Register gated clocks Joel Stanley
2018-01-02 5:50 ` Benjamin Herrenschmidt
@ 2018-01-03 1:47 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Stephen Boyd @ 2018-01-03 1:47 UTC (permalink / raw)
To: linux-arm-kernel
On 12/22, Joel Stanley wrote:
> The majority of the clocks in the system are gates paired with a reset
> controller that holds the IP in reset.
>
> This borrows from clk_hw_register_gate, but registers two 'gates', one
> to control the clock enable register and the other to control the reset
> IP. This allows us to enforce the ordering:
>
> 1. Place IP in reset
> 2. Enable clock
> 3. Delay
> 4. Release reset
>
> There are some gates that do not have an associated reset; these are
> handled by using -1 as the index for the reset.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 5/5] clk: aspeed: Add reset controller
2017-12-22 2:45 [PATCH v7 0/5] clk: Add Aspeed clock driver Joel Stanley
` (3 preceding siblings ...)
2017-12-22 2:45 ` [PATCH v7 4/5] clk: aspeed: Register gated clocks Joel Stanley
@ 2017-12-22 2:45 ` Joel Stanley
2018-01-02 5:50 ` Benjamin Herrenschmidt
2018-01-03 1:47 ` Stephen Boyd
4 siblings, 2 replies; 16+ messages in thread
From: Joel Stanley @ 2017-12-22 2:45 UTC (permalink / raw)
To: linux-arm-kernel
There are some resets that are not associated with gates. These are
represented by a reset controller.
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
v7:
- Rebase on dt-bindings patch
v5:
- Add Andrew's Reviewed-by
v3:
- Add named initalisers for the reset defines
- Add define for ADC
---
drivers/clk/clk-aspeed.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 81 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index dbd3c7774831..6fb344730cea 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -8,6 +8,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -267,6 +268,68 @@ static const struct clk_ops aspeed_clk_gate_ops = {
.is_enabled = aspeed_clk_is_enabled,
};
+/**
+ * struct aspeed_reset - Aspeed reset controller
+ * @map: regmap to access the containing system controller
+ * @rcdev: reset controller device
+ */
+struct aspeed_reset {
+ struct regmap *map;
+ struct reset_controller_dev rcdev;
+};
+
+#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev)
+
+static const u8 aspeed_resets[] = {
+ [ASPEED_RESET_XDMA] = 25,
+ [ASPEED_RESET_MCTP] = 24,
+ [ASPEED_RESET_ADC] = 23,
+ [ASPEED_RESET_JTAG_MASTER] = 22,
+ [ASPEED_RESET_MIC] = 18,
+ [ASPEED_RESET_PWM] = 9,
+ [ASPEED_RESET_PCIVGA] = 8,
+ [ASPEED_RESET_I2C] = 2,
+ [ASPEED_RESET_AHB] = 1,
+};
+
+static int aspeed_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct aspeed_reset *ar = to_aspeed_reset(rcdev);
+ u32 rst = BIT(aspeed_resets[id]);
+
+ return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, 0);
+}
+
+static int aspeed_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct aspeed_reset *ar = to_aspeed_reset(rcdev);
+ u32 rst = BIT(aspeed_resets[id]);
+
+ return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, rst);
+}
+
+static int aspeed_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct aspeed_reset *ar = to_aspeed_reset(rcdev);
+ u32 val, rst = BIT(aspeed_resets[id]);
+ int ret;
+
+ ret = regmap_read(ar->map, ASPEED_RESET_CTRL, &val);
+ if (ret)
+ return ret;
+
+ return !!(val & rst);
+}
+
+static const struct reset_control_ops aspeed_reset_ops = {
+ .assert = aspeed_reset_assert,
+ .deassert = aspeed_reset_deassert,
+ .status = aspeed_reset_status,
+};
+
static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
struct regmap *map, u8 clock_idx, u8 reset_idx,
@@ -308,10 +371,11 @@ static int aspeed_clk_probe(struct platform_device *pdev)
{
const struct aspeed_clk_soc_data *soc_data;
struct device *dev = &pdev->dev;
+ struct aspeed_reset *ar;
struct regmap *map;
struct clk_hw *hw;
u32 val, rate;
- int i;
+ int i, ret;
map = syscon_node_to_regmap(dev->of_node);
if (IS_ERR(map)) {
@@ -319,6 +383,22 @@ static int aspeed_clk_probe(struct platform_device *pdev)
return PTR_ERR(map);
}
+ ar = devm_kzalloc(dev, sizeof(*ar), GFP_KERNEL);
+ if (!ar)
+ return -ENOMEM;
+
+ ar->map = map;
+ ar->rcdev.owner = THIS_MODULE;
+ ar->rcdev.nr_resets = ARRAY_SIZE(aspeed_resets);
+ ar->rcdev.ops = &aspeed_reset_ops;
+ ar->rcdev.of_node = dev->of_node;
+
+ ret = devm_reset_controller_register(dev, &ar->rcdev);
+ if (ret) {
+ dev_err(dev, "could not register reset controller\n");
+ return ret;
+ }
+
/* SoC generations share common layouts but have different divisors */
soc_data = of_device_get_match_data(dev);
if (!soc_data) {
--
2.15.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 5/5] clk: aspeed: Add reset controller
2017-12-22 2:45 ` [PATCH v7 5/5] clk: aspeed: Add reset controller Joel Stanley
@ 2018-01-02 5:50 ` Benjamin Herrenschmidt
2018-01-03 1:47 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Benjamin Herrenschmidt @ 2018-01-02 5:50 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 2017-12-22 at 13:15 +1030, Joel Stanley wrote:
> There are some resets that are not associated with gates. These are
> represented by a reset controller.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> v7:
> - Rebase on dt-bindings patch
> v5:
> - Add Andrew's Reviewed-by
> v3:
> - Add named initalisers for the reset defines
> - Add define for ADC
> ---
> drivers/clk/clk-aspeed.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 81 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
> index dbd3c7774831..6fb344730cea 100644
> --- a/drivers/clk/clk-aspeed.c
> +++ b/drivers/clk/clk-aspeed.c
> @@ -8,6 +8,7 @@
> #include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> +#include <linux/reset-controller.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
>
> @@ -267,6 +268,68 @@ static const struct clk_ops aspeed_clk_gate_ops = {
> .is_enabled = aspeed_clk_is_enabled,
> };
>
> +/**
> + * struct aspeed_reset - Aspeed reset controller
> + * @map: regmap to access the containing system controller
> + * @rcdev: reset controller device
> + */
> +struct aspeed_reset {
> + struct regmap *map;
> + struct reset_controller_dev rcdev;
> +};
> +
> +#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev)
> +
> +static const u8 aspeed_resets[] = {
> + [ASPEED_RESET_XDMA] = 25,
> + [ASPEED_RESET_MCTP] = 24,
> + [ASPEED_RESET_ADC] = 23,
> + [ASPEED_RESET_JTAG_MASTER] = 22,
> + [ASPEED_RESET_MIC] = 18,
> + [ASPEED_RESET_PWM] = 9,
> + [ASPEED_RESET_PCIVGA] = 8,
> + [ASPEED_RESET_I2C] = 2,
> + [ASPEED_RESET_AHB] = 1,
> +};
> +
> +static int aspeed_reset_deassert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct aspeed_reset *ar = to_aspeed_reset(rcdev);
> + u32 rst = BIT(aspeed_resets[id]);
> +
> + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, 0);
> +}
> +
> +static int aspeed_reset_assert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct aspeed_reset *ar = to_aspeed_reset(rcdev);
> + u32 rst = BIT(aspeed_resets[id]);
> +
> + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, rst);
> +}
> +
> +static int aspeed_reset_status(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct aspeed_reset *ar = to_aspeed_reset(rcdev);
> + u32 val, rst = BIT(aspeed_resets[id]);
> + int ret;
> +
> + ret = regmap_read(ar->map, ASPEED_RESET_CTRL, &val);
> + if (ret)
> + return ret;
> +
> + return !!(val & rst);
> +}
> +
> +static const struct reset_control_ops aspeed_reset_ops = {
> + .assert = aspeed_reset_assert,
> + .deassert = aspeed_reset_deassert,
> + .status = aspeed_reset_status,
> +};
> +
> static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev,
> const char *name, const char *parent_name, unsigned long flags,
> struct regmap *map, u8 clock_idx, u8 reset_idx,
> @@ -308,10 +371,11 @@ static int aspeed_clk_probe(struct platform_device *pdev)
> {
> const struct aspeed_clk_soc_data *soc_data;
> struct device *dev = &pdev->dev;
> + struct aspeed_reset *ar;
> struct regmap *map;
> struct clk_hw *hw;
> u32 val, rate;
> - int i;
> + int i, ret;
>
> map = syscon_node_to_regmap(dev->of_node);
> if (IS_ERR(map)) {
> @@ -319,6 +383,22 @@ static int aspeed_clk_probe(struct platform_device *pdev)
> return PTR_ERR(map);
> }
>
> + ar = devm_kzalloc(dev, sizeof(*ar), GFP_KERNEL);
> + if (!ar)
> + return -ENOMEM;
> +
> + ar->map = map;
> + ar->rcdev.owner = THIS_MODULE;
> + ar->rcdev.nr_resets = ARRAY_SIZE(aspeed_resets);
> + ar->rcdev.ops = &aspeed_reset_ops;
> + ar->rcdev.of_node = dev->of_node;
> +
> + ret = devm_reset_controller_register(dev, &ar->rcdev);
> + if (ret) {
> + dev_err(dev, "could not register reset controller\n");
> + return ret;
> + }
> +
> /* SoC generations share common layouts but have different divisors */
> soc_data = of_device_get_match_data(dev);
> if (!soc_data) {
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 5/5] clk: aspeed: Add reset controller
2017-12-22 2:45 ` [PATCH v7 5/5] clk: aspeed: Add reset controller Joel Stanley
2018-01-02 5:50 ` Benjamin Herrenschmidt
@ 2018-01-03 1:47 ` Stephen Boyd
1 sibling, 0 replies; 16+ messages in thread
From: Stephen Boyd @ 2018-01-03 1:47 UTC (permalink / raw)
To: linux-arm-kernel
On 12/22, Joel Stanley wrote:
> There are some resets that are not associated with gates. These are
> represented by a reset controller.
>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 16+ messages in thread