* [PATCH v6 1/5] clk: Add clock driver for ASPEED BMC SoCs
2017-11-28 7:19 [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
@ 2017-11-28 7:19 ` Joel Stanley
2017-12-20 3:42 ` Joel Stanley
2017-11-28 7:19 ` [PATCH v6 2/5] clk: aspeed: Register core clocks Joel Stanley
` (4 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Joel Stanley @ 2017-11-28 7:19 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>
---
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 | 139 +++++++++++++++++++++++++++++++
include/dt-bindings/clock/aspeed-clock.h | 44 ++++++++++
4 files changed, 196 insertions(+)
create mode 100644 drivers/clk/clk-aspeed.c
create mode 100644 include/dt-bindings/clock/aspeed-clock.h
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..381be5547178
--- /dev/null
+++ b/drivers/clk/clk-aspeed.c
@@ -0,0 +1,139 @@
+// 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_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);
diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h
new file mode 100644
index 000000000000..9e170fb9a0da
--- /dev/null
+++ b/include/dt-bindings/clock/aspeed-clock.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+
+#ifndef DT_BINDINGS_ASPEED_CLOCK_H
+#define DT_BINDINGS_ASPEED_CLOCK_H
+
+#define ASPEED_CLK_GATE_ECLK 0
+#define ASPEED_CLK_GATE_GCLK 1
+#define ASPEED_CLK_GATE_MCLK 2
+#define ASPEED_CLK_GATE_VCLK 3
+#define ASPEED_CLK_GATE_BCLK 4
+#define ASPEED_CLK_GATE_DCLK 5
+#define ASPEED_CLK_GATE_REFCLK 6
+#define ASPEED_CLK_GATE_USBPORT2CLK 7
+#define ASPEED_CLK_GATE_LCLK 8
+#define ASPEED_CLK_GATE_USBUHCICLK 9
+#define ASPEED_CLK_GATE_D1CLK 10
+#define ASPEED_CLK_GATE_YCLK 11
+#define ASPEED_CLK_GATE_USBPORT1CLK 12
+#define ASPEED_CLK_GATE_UART1CLK 13
+#define ASPEED_CLK_GATE_UART2CLK 14
+#define ASPEED_CLK_GATE_UART5CLK 15
+#define ASPEED_CLK_GATE_ESPICLK 16
+#define ASPEED_CLK_GATE_MAC1CLK 17
+#define ASPEED_CLK_GATE_MAC2CLK 18
+#define ASPEED_CLK_GATE_RSACLK 19
+#define ASPEED_CLK_GATE_UART3CLK 20
+#define ASPEED_CLK_GATE_UART4CLK 21
+#define ASPEED_CLK_GATE_SDCLKCLK 22
+#define ASPEED_CLK_GATE_LHCCLK 23
+#define ASPEED_CLK_HPLL 24
+#define ASPEED_CLK_AHB 25
+#define ASPEED_CLK_APB 26
+#define ASPEED_CLK_UART 27
+#define ASPEED_CLK_SDIO 28
+#define ASPEED_CLK_ECLK 29
+#define ASPEED_CLK_ECLK_MUX 30
+#define ASPEED_CLK_LHCLK 31
+#define ASPEED_CLK_MAC 32
+#define ASPEED_CLK_BCLK 33
+#define ASPEED_CLK_MPLL 34
+
+#define ASPEED_NUM_CLKS 35
+
+#endif
--
2.14.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v6 1/5] clk: Add clock driver for ASPEED BMC SoCs
2017-11-28 7:19 ` [PATCH v6 1/5] clk: Add clock driver for ASPEED BMC SoCs Joel Stanley
@ 2017-12-20 3:42 ` Joel Stanley
0 siblings, 0 replies; 17+ messages in thread
From: Joel Stanley @ 2017-12-20 3:42 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Nov 28, 2017 at 5:49 PM, Joel Stanley <joel@jms.id.au> 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>
> ---
> 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 | 139 +++++++++++++++++++++++++++++++
> include/dt-bindings/clock/aspeed-clock.h | 44 ++++++++++
> 4 files changed, 196 insertions(+)
> create mode 100644 drivers/clk/clk-aspeed.c
> create mode 100644 include/dt-bindings/clock/aspeed-clock.h
> diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h
> new file mode 100644
> index 000000000000..9e170fb9a0da
> --- /dev/null
> +++ b/include/dt-bindings/clock/aspeed-clock.h
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +
> +#ifndef DT_BINDINGS_ASPEED_CLOCK_H
> +#define DT_BINDINGS_ASPEED_CLOCK_H
> +
> +#define ASPEED_CLK_GATE_ECLK 0
> +#define ASPEED_CLK_GATE_GCLK 1
> +#define ASPEED_CLK_GATE_MCLK 2
> +#define ASPEED_CLK_GATE_VCLK 3
> +#define ASPEED_CLK_GATE_BCLK 4
> +#define ASPEED_CLK_GATE_DCLK 5
> +#define ASPEED_CLK_GATE_REFCLK 6
> +#define ASPEED_CLK_GATE_USBPORT2CLK 7
> +#define ASPEED_CLK_GATE_LCLK 8
> +#define ASPEED_CLK_GATE_USBUHCICLK 9
> +#define ASPEED_CLK_GATE_D1CLK 10
> +#define ASPEED_CLK_GATE_YCLK 11
> +#define ASPEED_CLK_GATE_USBPORT1CLK 12
> +#define ASPEED_CLK_GATE_UART1CLK 13
> +#define ASPEED_CLK_GATE_UART2CLK 14
> +#define ASPEED_CLK_GATE_UART5CLK 15
> +#define ASPEED_CLK_GATE_ESPICLK 16
> +#define ASPEED_CLK_GATE_MAC1CLK 17
> +#define ASPEED_CLK_GATE_MAC2CLK 18
> +#define ASPEED_CLK_GATE_RSACLK 19
> +#define ASPEED_CLK_GATE_UART3CLK 20
> +#define ASPEED_CLK_GATE_UART4CLK 21
> +#define ASPEED_CLK_GATE_SDCLKCLK 22
> +#define ASPEED_CLK_GATE_LHCCLK 23
> +#define ASPEED_CLK_HPLL 24
> +#define ASPEED_CLK_AHB 25
> +#define ASPEED_CLK_APB 26
> +#define ASPEED_CLK_UART 27
> +#define ASPEED_CLK_SDIO 28
> +#define ASPEED_CLK_ECLK 29
> +#define ASPEED_CLK_ECLK_MUX 30
> +#define ASPEED_CLK_LHCLK 31
> +#define ASPEED_CLK_MAC 32
> +#define ASPEED_CLK_BCLK 33
> +#define ASPEED_CLK_MPLL 34
> +
> +#define ASPEED_NUM_CLKS 35
In reviewing this change as part of some ASPEED device tree changes,
we moved the define out of this header (as we do not want it to be
part of the ABI) and into the c file where it is used.
I have a v7 ready to send out with this change. Are there any other
issues with this before I send that version out?
Cheers,
Joel
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 2/5] clk: aspeed: Register core clocks
2017-11-28 7:19 [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
2017-11-28 7:19 ` [PATCH v6 1/5] clk: Add clock driver for ASPEED BMC SoCs Joel Stanley
@ 2017-11-28 7:19 ` Joel Stanley
2017-11-28 7:19 ` [PATCH v6 3/5] clk: aspeed: Add platform driver and register PLLs Joel Stanley
` (3 subsequent siblings)
5 siblings, 0 replies; 17+ messages in thread
From: Joel Stanley @ 2017-11-28 7:19 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 381be5547178..9742f1d0977f 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -11,7 +11,23 @@
#include <dt-bindings/clock/aspeed-clock.h>
+#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;
@@ -89,6 +105,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;
@@ -130,6 +300,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.14.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v6 3/5] clk: aspeed: Add platform driver and register PLLs
2017-11-28 7:19 [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
2017-11-28 7:19 ` [PATCH v6 1/5] clk: Add clock driver for ASPEED BMC SoCs Joel Stanley
2017-11-28 7:19 ` [PATCH v6 2/5] clk: aspeed: Register core clocks Joel Stanley
@ 2017-11-28 7:19 ` Joel Stanley
2017-11-28 7:19 ` [PATCH v6 4/5] clk: aspeed: Register gated clocks Joel Stanley
` (2 subsequent siblings)
5 siblings, 0 replies; 17+ messages in thread
From: Joel Stanley @ 2017-11-28 7:19 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 9742f1d0977f..839243691b26 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>
@@ -105,6 +107,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 },
@@ -170,6 +184,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.14.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-11-28 7:19 [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
` (2 preceding siblings ...)
2017-11-28 7:19 ` [PATCH v6 3/5] clk: aspeed: Add platform driver and register PLLs Joel Stanley
@ 2017-11-28 7:19 ` Joel Stanley
2017-12-21 23:39 ` Stephen Boyd
2017-11-28 7:19 ` [PATCH v6 5/5] clk: aspeed: Add reset controller Joel Stanley
2017-12-06 7:56 ` [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
5 siblings, 1 reply; 17+ messages in thread
From: Joel Stanley @ 2017-11-28 7:19 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>
---
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
---
drivers/clk/clk-aspeed.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index 839243691b26..b5dc3e298693 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -202,6 +202,107 @@ 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) {
+ /* Delay 10ms */
+ /* TODO: can we sleep here? */
+ msleep(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;
@@ -209,6 +310,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)) {
@@ -281,6 +383,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.14.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-11-28 7:19 ` [PATCH v6 4/5] clk: aspeed: Register gated clocks Joel Stanley
@ 2017-12-21 23:39 ` Stephen Boyd
2017-12-22 2:36 ` Benjamin Herrenschmidt
0 siblings, 1 reply; 17+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:39 UTC (permalink / raw)
To: linux-arm-kernel
On 11/28, Joel Stanley wrote:
> diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
> index 839243691b26..b5dc3e298693 100644
> --- a/drivers/clk/clk-aspeed.c
> +++ b/drivers/clk/clk-aspeed.c
> @@ -202,6 +202,107 @@ 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) {
> + /* Delay 10ms */
> + /* TODO: can we sleep here? */
> + msleep(10);
No you can't sleep here. It needs to delay because this is inside
spinlock_irqsave.
> +
> + /* Take IP out of reset */
> + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0);
> + }
> +
> + spin_unlock_irqrestore(gate->lock, flags);
> +
> + return 0;
> +}
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-12-21 23:39 ` Stephen Boyd
@ 2017-12-22 2:36 ` Benjamin Herrenschmidt
2017-12-22 2:43 ` Benjamin Herrenschmidt
0 siblings, 1 reply; 17+ messages in thread
From: Benjamin Herrenschmidt @ 2017-12-22 2:36 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, 2017-12-21 at 15:39 -0800, Stephen Boyd wrote:
> On 11/28, Joel Stanley wrote:
> > diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
> > index 839243691b26..b5dc3e298693 100644
> > --- a/drivers/clk/clk-aspeed.c
> > +++ b/drivers/clk/clk-aspeed.c
> > @@ -202,6 +202,107 @@ 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) {
> > + /* Delay 10ms */
> > + /* TODO: can we sleep here? */
> > + msleep(10);
>
> No you can't sleep here. It needs to delay because this is inside
> spinlock_irqsave.
Additionally you really don't want to delay for 10ms with interrupts
off :-(
Sadly, it looks like the clk framework already calls you with spinlock
irqsafe, which is a rather major suckage.
Stephen, why is that so ? That pretty much makes it impossible to
do sleeping things, which prevents things like i2c based clock
controllers etc...
I think the clk framework needs to be overhauled to use sleeping
mutexes instead. Doing clock enable/disable at interrupt time is
a bad idea anyway.
In the meantime, Joel, you have little choice but do an mdelay
though that really sucks.
> > + /* Take IP out of reset */
> > + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0);
> > + }
> > +
> > + spin_unlock_irqrestore(gate->lock, flags);
> > +
> > + return 0;
> > +}
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-12-22 2:36 ` Benjamin Herrenschmidt
@ 2017-12-22 2:43 ` Benjamin Herrenschmidt
2017-12-27 1:32 ` Stephen Boyd
0 siblings, 1 reply; 17+ messages in thread
From: Benjamin Herrenschmidt @ 2017-12-22 2:43 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 2017-12-22 at 13:36 +1100, Benjamin Herrenschmidt wrote:
>
> > No you can't sleep here. It needs to delay because this is inside
> > spinlock_irqsave.
>
> Additionally you really don't want to delay for 10ms with interrupts
> off :-(
>
> Sadly, it looks like the clk framework already calls you with spinlock
> irqsafe, which is a rather major suckage.
>
> Stephen, why is that so ? That pretty much makes it impossible to
> do sleeping things, which prevents things like i2c based clock
> controllers etc...
I noticed we do have a few i2c based clock drivers... how are they ever
supposed to work ? i2c bus controllers are allowed to sleep and the i2c
core takes mutexes...
> I think the clk framework needs to be overhauled to use sleeping
> mutexes instead. Doing clock enable/disable at interrupt time is
> a bad idea anyway.
>
>
> In the meantime, Joel, you have little choice but do an mdelay
> though that really sucks.
>
> > > + /* Take IP out of reset */
> > > + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0);
> > > + }
> > > +
> > > + spin_unlock_irqrestore(gate->lock, flags);
> > > +
> > > + return 0;
> > > +}
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-12-22 2:43 ` Benjamin Herrenschmidt
@ 2017-12-27 1:32 ` Stephen Boyd
2017-12-29 22:03 ` Benjamin Herrenschmidt
0 siblings, 1 reply; 17+ messages in thread
From: Stephen Boyd @ 2017-12-27 1:32 UTC (permalink / raw)
To: linux-arm-kernel
On 12/22, Benjamin Herrenschmidt wrote:
> On Fri, 2017-12-22 at 13:36 +1100, Benjamin Herrenschmidt wrote:
> >
> > > No you can't sleep here. It needs to delay because this is inside
> > > spinlock_irqsave.
> >
> > Additionally you really don't want to delay for 10ms with interrupts
> > off :-(
> >
> > Sadly, it looks like the clk framework already calls you with spinlock
> > irqsafe, which is a rather major suckage.
> >
> > Stephen, why is that so ? That pretty much makes it impossible to
> > do sleeping things, which prevents things like i2c based clock
> > controllers etc...
>
> I noticed we do have a few i2c based clock drivers... how are they ever
> supposed to work ? i2c bus controllers are allowed to sleep and the i2c
> core takes mutexes...
We have clk_prepare()/clk_unprepare() for sleeping suckage. You
can use that, and i2c based clk drivers do that today.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-12-27 1:32 ` Stephen Boyd
@ 2017-12-29 22:03 ` Benjamin Herrenschmidt
2018-01-02 5:46 ` Benjamin Herrenschmidt
2018-01-02 18:16 ` Stephen Boyd
0 siblings, 2 replies; 17+ messages in thread
From: Benjamin Herrenschmidt @ 2017-12-29 22:03 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 2017-12-26 at 17:32 -0800, Stephen Boyd wrote:
> > I noticed we do have a few i2c based clock drivers... how are they ever
> > supposed to work ? i2c bus controllers are allowed to sleep and the i2c
> > core takes mutexes...
>
> We have clk_prepare()/clk_unprepare() for sleeping suckage. You
> can use that, and i2c based clk drivers do that today.
"suckage" ? Hehe ... the suckage should rather be stuff that cannot
sleep. Arbitrary latencies and jitter caused by too much code wanting
to be "atomic" when unnecessary are a bad thing.
In the case of clocks like the aspeed where we have to wait for a
rather long stabilization delay, way too long to legitimately do a non-
sleepable delay with a lock held, do we need to do everything in
prepare() then ?
Ben.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-12-29 22:03 ` Benjamin Herrenschmidt
@ 2018-01-02 5:46 ` Benjamin Herrenschmidt
2018-01-02 18:16 ` Stephen Boyd
1 sibling, 0 replies; 17+ messages in thread
From: Benjamin Herrenschmidt @ 2018-01-02 5:46 UTC (permalink / raw)
To: linux-arm-kernel
On Sat, 2017-12-30 at 09:03 +1100, Benjamin Herrenschmidt wrote:
> On Tue, 2017-12-26 at 17:32 -0800, Stephen Boyd wrote:
> > > I noticed we do have a few i2c based clock drivers... how are they ever
> > > supposed to work ? i2c bus controllers are allowed to sleep and the i2c
> > > core takes mutexes...
> >
> > We have clk_prepare()/clk_unprepare() for sleeping suckage. You
> > can use that, and i2c based clk drivers do that today.
>
> "suckage" ? Hehe ... the suckage should rather be stuff that cannot
> sleep. Arbitrary latencies and jitter caused by too much code wanting
> to be "atomic" when unnecessary are a bad thing.
>
> In the case of clocks like the aspeed where we have to wait for a
> rather long stabilization delay, way too long to legitimately do a non-
> sleepable delay with a lock held, do we need to do everything in
> prepare() then ?
BTW. Pls don't hold Joel's patches for this. Without that clk framework
a lot of the aspeed stuff already upstream doesn't actually work
without additional out-of-tree hacks or uboot black magic.
We can sort out the sleeping issues (and possibly move to using prepare
for the clocks that have that delay requirement) via subsequent
improvements.
Cheers,
Ben.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 4/5] clk: aspeed: Register gated clocks
2017-12-29 22:03 ` Benjamin Herrenschmidt
2018-01-02 5:46 ` Benjamin Herrenschmidt
@ 2018-01-02 18:16 ` Stephen Boyd
1 sibling, 0 replies; 17+ messages in thread
From: Stephen Boyd @ 2018-01-02 18:16 UTC (permalink / raw)
To: linux-arm-kernel
On 12/30, Benjamin Herrenschmidt wrote:
> On Tue, 2017-12-26 at 17:32 -0800, Stephen Boyd wrote:
> > > I noticed we do have a few i2c based clock drivers... how are they ever
> > > supposed to work ? i2c bus controllers are allowed to sleep and the i2c
> > > core takes mutexes...
> >
> > We have clk_prepare()/clk_unprepare() for sleeping suckage. You
> > can use that, and i2c based clk drivers do that today.
>
> "suckage" ? Hehe ... the suckage should rather be stuff that cannot
> sleep. Arbitrary latencies and jitter caused by too much code wanting
> to be "atomic" when unnecessary are a bad thing.
Heh. Of course.
>
> In the case of clocks like the aspeed where we have to wait for a
> rather long stabilization delay, way too long to legitimately do a non-
> sleepable delay with a lock held, do we need to do everything in
> prepare() then ?
>
Yes. If we have to wait a long time in the enable path it makes
sense to move it to the prepare path instead, if possible. That
way we avoid holding a spinlock for a long time.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 5/5] clk: aspeed: Add reset controller
2017-11-28 7:19 [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
` (3 preceding siblings ...)
2017-11-28 7:19 ` [PATCH v6 4/5] clk: aspeed: Register gated clocks Joel Stanley
@ 2017-11-28 7:19 ` Joel Stanley
2017-12-06 7:56 ` [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
5 siblings, 0 replies; 17+ messages in thread
From: Joel Stanley @ 2017-11-28 7:19 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>
---
v5:
- Add Andrew's Reviewed-by
v3:
- Add named initalisers for the reset defines
- Add define for ADC
---
drivers/clk/clk-aspeed.c | 82 +++++++++++++++++++++++++++++++-
include/dt-bindings/clock/aspeed-clock.h | 10 ++++
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index b5dc3e298693..f2722be17ede 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>
@@ -266,6 +267,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,
@@ -307,10 +370,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)) {
@@ -318,6 +382,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) {
diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h
index 9e170fb9a0da..fe46ab69da5c 100644
--- a/include/dt-bindings/clock/aspeed-clock.h
+++ b/include/dt-bindings/clock/aspeed-clock.h
@@ -41,4 +41,14 @@
#define ASPEED_NUM_CLKS 35
+#define ASPEED_RESET_XDMA 0
+#define ASPEED_RESET_MCTP 1
+#define ASPEED_RESET_ADC 2
+#define ASPEED_RESET_JTAG_MASTER 3
+#define ASPEED_RESET_MIC 4
+#define ASPEED_RESET_PWM 5
+#define ASPEED_RESET_PCIVGA 6
+#define ASPEED_RESET_I2C 7
+#define ASPEED_RESET_AHB 8
+
#endif
--
2.14.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v6 0/5] clk: Add Aspeed clock driver
2017-11-28 7:19 [PATCH v6 0/5] clk: Add Aspeed clock driver Joel Stanley
` (4 preceding siblings ...)
2017-11-28 7:19 ` [PATCH v6 5/5] clk: aspeed: Add reset controller Joel Stanley
@ 2017-12-06 7:56 ` Joel Stanley
2017-12-21 23:40 ` Stephen Boyd
5 siblings, 1 reply; 17+ messages in thread
From: Joel Stanley @ 2017-12-06 7:56 UTC (permalink / raw)
To: linux-arm-kernel
Hello clk maintainers,
Has anyone had a chance to review these patches?
On Tue, Nov 28, 2017 at 5:49 PM, Joel Stanley <joel@jms.id.au> wrote:
> This driver supports the ast2500, ast2400 (and derivative) BMC SoCs from
> Aspeed.
>
> This is v6. See patches for detailed changelogs.
>
> v6: Added reviewed-bys
> v5: Address review from Andrew
> v4: Address review from Andrew and Stephen.
> v3: Address review from Andrew and has seen more testing on hardware
> v2: split the driver out into a series of patches to make them easier to
> review.
>
> All of the important clocks are supported, with most non-essential ones
> also implemented where information is available. I am working with
> Aspeed to clear up some of the missing information, including the
> missing parent-sibling relationships.
>
> We need to know the rate of the apb clock in order to correctly program
> the clocksource driver, so the apb and it's parents are created in the
> CLK_OF_DECLARE_DRIVER callback.
>
> The rest of the clocks are created at normal driver probe time. I
> followed the Gemini driver's lead with using the regmap where I could,
> but also having a pointer to the base address for use with the common
> clock callbacks.
>
> The driver borrows from the clk_gate common clock infrastructure, but modifies
> it in order to support the clock gate and reset pair that most of the clocks
> have. This pair must be reset-ungated-released, with appropriate delays,
> according to the datasheet.
>
> The first patch introduces the core clock registration parts, and describes
> the clocks. The second creates the core clocks, giving the system enough to
> boot (but without uart). Next come the non-core clocks, and finally the reset
> controller that is used for the few cocks that don't have a gate to go with their
> reset pair.
>
> Please review!
>
> Cheers,
>
> Joel
>
> Joel Stanley (5):
> clk: Add clock driver for ASPEED BMC SoCs
> clk: aspeed: Register core clocks
> clk: aspeed: Add platform driver and register PLLs
> clk: aspeed: Register gated clocks
> clk: aspeed: Add reset controller
>
> drivers/clk/Kconfig | 12 +
> drivers/clk/Makefile | 1 +
> drivers/clk/clk-aspeed.c | 657 +++++++++++++++++++++++++++++++
> include/dt-bindings/clock/aspeed-clock.h | 54 +++
> 4 files changed, 724 insertions(+)
> create mode 100644 drivers/clk/clk-aspeed.c
> create mode 100644 include/dt-bindings/clock/aspeed-clock.h
>
> --
> 2.14.1
>
^ permalink raw reply [flat|nested] 17+ messages in thread