Эх сурвалжийг харах

Merge branches 'clk-aspeed', 'clk-lock-UP', 'clk-mediatek' and 'clk-allwinner' into clk-next

* clk-aspeed:
  clk: aspeed: Handle inverse polarity of USB port 1 clock gate
  clk: aspeed: Fix return value check in aspeed_cc_init()
  clk: aspeed: Add reset controller
  clk: aspeed: Register gated clocks
  clk: aspeed: Add platform driver and register PLLs
  clk: aspeed: Register core clocks
  clk: Add clock driver for ASPEED BMC SoCs
  dt-bindings: clock: Add ASPEED constants

* clk-lock-UP:
  clk: fix reentrancy of clk_enable() on UP systems

* clk-mediatek:
  clk: mediatek: adjust dependency of reset.c to avoid unexpectedly being built
  clk: mediatek: Fix all warnings for missing struct clk_onecell_data
  clk: mediatek: fixup test-building of MediaTek clock drivers
  clk: mediatek: group drivers under indpendent menu

* clk-allwinner:
  clk: sunxi-ng: a83t: Add M divider to TCON1 clock
  clk: sunxi-ng: fix the A64/H5 clock description of DE2 CCU
  clk: sunxi-ng: add support for Allwinner H3 DE2 CCU
  dt-bindings: fix the binding of Allwinner DE2 CCU of A83T and H3
  clk: sunxi-ng: sun8i: a83t: Use sigma-delta modulation for audio PLL
  clk: sunxi-ng: sun8i: a83t: Add /2 fixed post divider to audio PLL
  clk: sunxi-ng: Support fixed post-dividers on NM style clocks
  clk: sunxi-ng: sun50i: a64: Add 2x fixed post-divider to MMC module clocks
  clk: sunxi-ng: Support fixed post-dividers on MP style clocks
  clk: sunxi: Use PTR_ERR_OR_ZERO()
Stephen Boyd 7 жил өмнө

+ 3 - 2
Documentation/devicetree/bindings/clock/sun8i-de2.txt

@@ -4,13 +4,14 @@ Allwinner Display Engine 2.0 Clock Control Binding
 Required properties :
 Required properties :
 - compatible: must contain one of the following compatibles:
 - compatible: must contain one of the following compatibles:
 		- "allwinner,sun8i-a83t-de2-clk"
 		- "allwinner,sun8i-a83t-de2-clk"
+		- "allwinner,sun8i-h3-de2-clk"
 		- "allwinner,sun8i-v3s-de2-clk"
 		- "allwinner,sun8i-v3s-de2-clk"
 		- "allwinner,sun50i-h5-de2-clk"
 		- "allwinner,sun50i-h5-de2-clk"
 
 
 - reg: Must contain the registers base address and length
 - reg: Must contain the registers base address and length
 - clocks: phandle to the clocks feeding the display engine subsystem.
 - clocks: phandle to the clocks feeding the display engine subsystem.
 	  Three are needed:
 	  Three are needed:
-  - "mod": the display engine module clock
+  - "mod": the display engine module clock (on A83T it's the DE PLL)
   - "bus": the bus clock for the whole display engine subsystem
   - "bus": the bus clock for the whole display engine subsystem
 - clock-names: Must contain the clock names described just above
 - clock-names: Must contain the clock names described just above
 - resets: phandle to the reset control for the display engine subsystem.
 - resets: phandle to the reset control for the display engine subsystem.
@@ -19,7 +20,7 @@ Required properties :
 
 
 Example:
 Example:
 de2_clocks: clock@1000000 {
 de2_clocks: clock@1000000 {
-	compatible = "allwinner,sun8i-a83t-de2-clk";
+	compatible = "allwinner,sun8i-h3-de2-clk";
 	reg = <0x01000000 0x100000>;
 	reg = <0x01000000 0x100000>;
 	clocks = <&ccu CLK_BUS_DE>,
 	clocks = <&ccu CLK_BUS_DE>,
 		 <&ccu CLK_DE>;
 		 <&ccu CLK_DE>;

+ 12 - 0
drivers/clk/Kconfig

@@ -142,6 +142,18 @@ config COMMON_CLK_GEMINI
 	  This driver supports the SoC clocks on the Cortina Systems Gemini
 	  This driver supports the SoC clocks on the Cortina Systems Gemini
 	  platform, also known as SL3516 or CS3516.
 	  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
 config COMMON_CLK_S2MPS11
 	tristate "Clock driver for S2MPS1X/S5M8767 MFD"
 	tristate "Clock driver for S2MPS1X/S5M8767 MFD"
 	depends on MFD_SEC_CORE || COMPILE_TEST
 	depends on MFD_SEC_CORE || COMPILE_TEST

+ 2 - 1
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_COMMON_CLK_CS2000_CP)	+= clk-cs2000-cp.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_COMMON_CLK_GEMINI)		+= clk-gemini.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_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
 obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
@@ -67,7 +68,7 @@ obj-$(CONFIG_ARCH_MXC)			+= imx/
 obj-$(CONFIG_MACH_INGENIC)		+= ingenic/
 obj-$(CONFIG_MACH_INGENIC)		+= ingenic/
 obj-$(CONFIG_ARCH_KEYSTONE)		+= keystone/
 obj-$(CONFIG_ARCH_KEYSTONE)		+= keystone/
 obj-$(CONFIG_MACH_LOONGSON32)		+= loongson1/
 obj-$(CONFIG_MACH_LOONGSON32)		+= loongson1/
-obj-$(CONFIG_ARCH_MEDIATEK)		+= mediatek/
+obj-y					+= mediatek/
 obj-$(CONFIG_COMMON_CLK_AMLOGIC)	+= meson/
 obj-$(CONFIG_COMMON_CLK_AMLOGIC)	+= meson/
 obj-$(CONFIG_MACH_PIC32)		+= microchip/
 obj-$(CONFIG_MACH_PIC32)		+= microchip/
 ifeq ($(CONFIG_COMMON_CLK), y)
 ifeq ($(CONFIG_COMMON_CLK), y)

+ 667 - 0
drivers/clk/clk-aspeed.c

@@ -0,0 +1,667 @@
+// 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/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>
+
+#include <dt-bindings/clock/aspeed-clock.h>
+
+#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;
+
+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 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 },
+	{ 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);
+}
+
+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_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);
+	u32 enval;
+
+	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 */
+	enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk;
+	regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, enval);
+
+	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);
+	u32 enval;
+
+	spin_lock_irqsave(gate->lock, flags);
+
+	enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? clk : 0;
+	regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, enval);
+
+	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, &reg);
+
+	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,
+};
+
+/**
+ * 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,
+		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;
+	struct device *dev = &pdev->dev;
+	struct aspeed_reset *ar;
+	struct regmap *map;
+	struct clk_hw *hw;
+	u32 val, rate;
+	int i, ret;
+
+	map = syscon_node_to_regmap(dev->of_node);
+	if (IS_ERR(map)) {
+		dev_err(dev, "no syscon regmap\n");
+		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) {
+		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;
+
+	/*
+	 * 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];
+		u32 gate_flags;
+
+		/* Special case: the USB port 1 clock (bit 14) is always
+		 * working the opposite way from the other ones.
+		 */
+		gate_flags = (gd->clock_idx == 14) ? 0 : CLK_GATE_SET_TO_DISABLE;
+		hw = aspeed_clk_hw_register_gate(dev,
+				gd->name,
+				gd->parent_name,
+				gd->flags,
+				map,
+				gd->clock_idx,
+				gd->reset_idx,
+				gate_flags,
+				&aspeed_clk_lock);
+		if (IS_ERR(hw))
+			return PTR_ERR(hw);
+		aspeed_clk_data->hws[i] = 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;
+	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;
+	u32 val;
+	int ret;
+	int i;
+
+	scu_base = of_iomap(np, 0);
+	if (!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;
+	}
+
+	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)
+		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);

+ 9 - 1
drivers/clk/clk.c

@@ -144,10 +144,18 @@ static unsigned long clk_enable_lock(void)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!spin_trylock_irqsave(&enable_lock, flags)) {
+	/*
+	 * On UP systems, spin_trylock_irqsave() always returns true, even if
+	 * we already hold the lock. So, in that case, we rely only on
+	 * reference counting.
+	 */
+	if (!IS_ENABLED(CONFIG_SMP) ||
+	    !spin_trylock_irqsave(&enable_lock, flags)) {
 		if (enable_owner == current) {
 		if (enable_owner == current) {
 			enable_refcnt++;
 			enable_refcnt++;
 			__acquire(enable_lock);
 			__acquire(enable_lock);
+			if (!IS_ENABLED(CONFIG_SMP))
+				local_save_flags(flags);
 			return flags;
 			return flags;
 		}
 		}
 		spin_lock_irqsave(&enable_lock, flags);
 		spin_lock_irqsave(&enable_lock, flags);

+ 51 - 46
drivers/clk/mediatek/Kconfig

@@ -1,136 +1,140 @@
 #
 #
-# MediaTek SoC drivers
+# MediaTek Clock Drivers
 #
 #
+menu "Clock driver for MediaTek SoC"
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+
 config COMMON_CLK_MEDIATEK
 config COMMON_CLK_MEDIATEK
 	bool
 	bool
+	select RESET_CONTROLLER
 	---help---
 	---help---
-	  Mediatek SoCs' clock support.
+	  MediaTek SoCs' clock support.
 
 
 config COMMON_CLK_MT2701
 config COMMON_CLK_MT2701
-	bool "Clock driver for Mediatek MT2701"
+	bool "Clock driver for MediaTek MT2701"
 	depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
 	depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
 	select COMMON_CLK_MEDIATEK
 	select COMMON_CLK_MEDIATEK
 	default ARCH_MEDIATEK && ARM
 	default ARCH_MEDIATEK && ARM
 	---help---
 	---help---
-	  This driver supports Mediatek MT2701 basic clocks.
+	  This driver supports MediaTek MT2701 basic clocks.
 
 
 config COMMON_CLK_MT2701_MMSYS
 config COMMON_CLK_MT2701_MMSYS
-	bool "Clock driver for Mediatek MT2701 mmsys"
+	bool "Clock driver for MediaTek MT2701 mmsys"
 	depends on COMMON_CLK_MT2701
 	depends on COMMON_CLK_MT2701
 	---help---
 	---help---
-	  This driver supports Mediatek MT2701 mmsys clocks.
+	  This driver supports MediaTek MT2701 mmsys clocks.
 
 
 config COMMON_CLK_MT2701_IMGSYS
 config COMMON_CLK_MT2701_IMGSYS
-	bool "Clock driver for Mediatek MT2701 imgsys"
+	bool "Clock driver for MediaTek MT2701 imgsys"
 	depends on COMMON_CLK_MT2701
 	depends on COMMON_CLK_MT2701
 	---help---
 	---help---
-	  This driver supports Mediatek MT2701 imgsys clocks.
+	  This driver supports MediaTek MT2701 imgsys clocks.
 
 
 config COMMON_CLK_MT2701_VDECSYS
 config COMMON_CLK_MT2701_VDECSYS
-	bool "Clock driver for Mediatek MT2701 vdecsys"
+	bool "Clock driver for MediaTek MT2701 vdecsys"
 	depends on COMMON_CLK_MT2701
 	depends on COMMON_CLK_MT2701
 	---help---
 	---help---
-	  This driver supports Mediatek MT2701 vdecsys clocks.
+	  This driver supports MediaTek MT2701 vdecsys clocks.
 
 
 config COMMON_CLK_MT2701_HIFSYS
 config COMMON_CLK_MT2701_HIFSYS
-	bool "Clock driver for Mediatek MT2701 hifsys"
+	bool "Clock driver for MediaTek MT2701 hifsys"
 	depends on COMMON_CLK_MT2701
 	depends on COMMON_CLK_MT2701
 	---help---
 	---help---
-	  This driver supports Mediatek MT2701 hifsys clocks.
+	  This driver supports MediaTek MT2701 hifsys clocks.
 
 
 config COMMON_CLK_MT2701_ETHSYS
 config COMMON_CLK_MT2701_ETHSYS
-	bool "Clock driver for Mediatek MT2701 ethsys"
+	bool "Clock driver for MediaTek MT2701 ethsys"
 	depends on COMMON_CLK_MT2701
 	depends on COMMON_CLK_MT2701
 	---help---
 	---help---
-	  This driver supports Mediatek MT2701 ethsys clocks.
+	  This driver supports MediaTek MT2701 ethsys clocks.
 
 
 config COMMON_CLK_MT2701_BDPSYS
 config COMMON_CLK_MT2701_BDPSYS
-	bool "Clock driver for Mediatek MT2701 bdpsys"
+	bool "Clock driver for MediaTek MT2701 bdpsys"
 	depends on COMMON_CLK_MT2701
 	depends on COMMON_CLK_MT2701
 	---help---
 	---help---
-	  This driver supports Mediatek MT2701 bdpsys clocks.
+	  This driver supports MediaTek MT2701 bdpsys clocks.
 
 
 config COMMON_CLK_MT2712
 config COMMON_CLK_MT2712
-	bool "Clock driver for Mediatek MT2712"
+	bool "Clock driver for MediaTek MT2712"
 	depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
 	depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
 	select COMMON_CLK_MEDIATEK
 	select COMMON_CLK_MEDIATEK
 	default ARCH_MEDIATEK && ARM64
 	default ARCH_MEDIATEK && ARM64
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 basic clocks.
+	  This driver supports MediaTek MT2712 basic clocks.
 
 
 config COMMON_CLK_MT2712_BDPSYS
 config COMMON_CLK_MT2712_BDPSYS
-	bool "Clock driver for Mediatek MT2712 bdpsys"
+	bool "Clock driver for MediaTek MT2712 bdpsys"
 	depends on COMMON_CLK_MT2712
 	depends on COMMON_CLK_MT2712
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 bdpsys clocks.
+	  This driver supports MediaTek MT2712 bdpsys clocks.
 
 
 config COMMON_CLK_MT2712_IMGSYS
 config COMMON_CLK_MT2712_IMGSYS
-	bool "Clock driver for Mediatek MT2712 imgsys"
+	bool "Clock driver for MediaTek MT2712 imgsys"
 	depends on COMMON_CLK_MT2712
 	depends on COMMON_CLK_MT2712
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 imgsys clocks.
+	  This driver supports MediaTek MT2712 imgsys clocks.
 
 
 config COMMON_CLK_MT2712_JPGDECSYS
 config COMMON_CLK_MT2712_JPGDECSYS
-	bool "Clock driver for Mediatek MT2712 jpgdecsys"
+	bool "Clock driver for MediaTek MT2712 jpgdecsys"
 	depends on COMMON_CLK_MT2712
 	depends on COMMON_CLK_MT2712
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 jpgdecsys clocks.
+	  This driver supports MediaTek MT2712 jpgdecsys clocks.
 
 
 config COMMON_CLK_MT2712_MFGCFG
 config COMMON_CLK_MT2712_MFGCFG
-	bool "Clock driver for Mediatek MT2712 mfgcfg"
+	bool "Clock driver for MediaTek MT2712 mfgcfg"
 	depends on COMMON_CLK_MT2712
 	depends on COMMON_CLK_MT2712
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 mfgcfg clocks.
+	  This driver supports MediaTek MT2712 mfgcfg clocks.
 
 
 config COMMON_CLK_MT2712_MMSYS
 config COMMON_CLK_MT2712_MMSYS
-	bool "Clock driver for Mediatek MT2712 mmsys"
+	bool "Clock driver for MediaTek MT2712 mmsys"
 	depends on COMMON_CLK_MT2712
 	depends on COMMON_CLK_MT2712
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 mmsys clocks.
+	  This driver supports MediaTek MT2712 mmsys clocks.
 
 
 config COMMON_CLK_MT2712_VDECSYS
 config COMMON_CLK_MT2712_VDECSYS
-	bool "Clock driver for Mediatek MT2712 vdecsys"
+	bool "Clock driver for MediaTek MT2712 vdecsys"
 	depends on COMMON_CLK_MT2712
 	depends on COMMON_CLK_MT2712
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 vdecsys clocks.
+	  This driver supports MediaTek MT2712 vdecsys clocks.
 
 
 config COMMON_CLK_MT2712_VENCSYS
 config COMMON_CLK_MT2712_VENCSYS
-	bool "Clock driver for Mediatek MT2712 vencsys"
+	bool "Clock driver for MediaTek MT2712 vencsys"
 	depends on COMMON_CLK_MT2712
 	depends on COMMON_CLK_MT2712
 	---help---
 	---help---
-	  This driver supports Mediatek MT2712 vencsys clocks.
+	  This driver supports MediaTek MT2712 vencsys clocks.
 
 
 config COMMON_CLK_MT6797
 config COMMON_CLK_MT6797
-       bool "Clock driver for Mediatek MT6797"
+       bool "Clock driver for MediaTek MT6797"
        depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
        depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
        select COMMON_CLK_MEDIATEK
        select COMMON_CLK_MEDIATEK
        default ARCH_MEDIATEK && ARM64
        default ARCH_MEDIATEK && ARM64
        ---help---
        ---help---
-         This driver supports Mediatek MT6797 basic clocks.
+         This driver supports MediaTek MT6797 basic clocks.
 
 
 config COMMON_CLK_MT6797_MMSYS
 config COMMON_CLK_MT6797_MMSYS
-       bool "Clock driver for Mediatek MT6797 mmsys"
+       bool "Clock driver for MediaTek MT6797 mmsys"
        depends on COMMON_CLK_MT6797
        depends on COMMON_CLK_MT6797
        ---help---
        ---help---
-         This driver supports Mediatek MT6797 mmsys clocks.
+         This driver supports MediaTek MT6797 mmsys clocks.
 
 
 config COMMON_CLK_MT6797_IMGSYS
 config COMMON_CLK_MT6797_IMGSYS
-       bool "Clock driver for Mediatek MT6797 imgsys"
+       bool "Clock driver for MediaTek MT6797 imgsys"
        depends on COMMON_CLK_MT6797
        depends on COMMON_CLK_MT6797
        ---help---
        ---help---
-         This driver supports Mediatek MT6797 imgsys clocks.
+         This driver supports MediaTek MT6797 imgsys clocks.
 
 
 config COMMON_CLK_MT6797_VDECSYS
 config COMMON_CLK_MT6797_VDECSYS
-       bool "Clock driver for Mediatek MT6797 vdecsys"
+       bool "Clock driver for MediaTek MT6797 vdecsys"
        depends on COMMON_CLK_MT6797
        depends on COMMON_CLK_MT6797
        ---help---
        ---help---
-         This driver supports Mediatek MT6797 vdecsys clocks.
+         This driver supports MediaTek MT6797 vdecsys clocks.
 
 
 config COMMON_CLK_MT6797_VENCSYS
 config COMMON_CLK_MT6797_VENCSYS
-       bool "Clock driver for Mediatek MT6797 vencsys"
+       bool "Clock driver for MediaTek MT6797 vencsys"
        depends on COMMON_CLK_MT6797
        depends on COMMON_CLK_MT6797
        ---help---
        ---help---
-         This driver supports Mediatek MT6797 vencsys clocks.
+         This driver supports MediaTek MT6797 vencsys clocks.
 
 
 config COMMON_CLK_MT7622
 config COMMON_CLK_MT7622
 	bool "Clock driver for MediaTek MT7622"
 	bool "Clock driver for MediaTek MT7622"
@@ -163,17 +167,18 @@ config COMMON_CLK_MT7622_AUDSYS
 	  to audio consumers such as I2S and TDM.
 	  to audio consumers such as I2S and TDM.
 
 
 config COMMON_CLK_MT8135
 config COMMON_CLK_MT8135
-	bool "Clock driver for Mediatek MT8135"
+	bool "Clock driver for MediaTek MT8135"
 	depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
 	depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
 	select COMMON_CLK_MEDIATEK
 	select COMMON_CLK_MEDIATEK
 	default ARCH_MEDIATEK && ARM
 	default ARCH_MEDIATEK && ARM
 	---help---
 	---help---
-	  This driver supports Mediatek MT8135 clocks.
+	  This driver supports MediaTek MT8135 clocks.
 
 
 config COMMON_CLK_MT8173
 config COMMON_CLK_MT8173
-	bool "Clock driver for Mediatek MT8173"
+	bool "Clock driver for MediaTek MT8173"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
 	depends on ARCH_MEDIATEK || COMPILE_TEST
 	select COMMON_CLK_MEDIATEK
 	select COMMON_CLK_MEDIATEK
 	default ARCH_MEDIATEK
 	default ARCH_MEDIATEK
 	---help---
 	---help---
-	  This driver supports Mediatek MT8173 clocks.
+	  This driver supports MediaTek MT8173 clocks.
+endmenu

+ 1 - 2
drivers/clk/mediatek/Makefile

@@ -1,6 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o
-obj-$(CONFIG_RESET_CONTROLLER) += reset.o
+obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o
 obj-$(CONFIG_COMMON_CLK_MT6797) += clk-mt6797.o
 obj-$(CONFIG_COMMON_CLK_MT6797) += clk-mt6797.o
 obj-$(CONFIG_COMMON_CLK_MT6797_IMGSYS) += clk-mt6797-img.o
 obj-$(CONFIG_COMMON_CLK_MT6797_IMGSYS) += clk-mt6797-img.o
 obj-$(CONFIG_COMMON_CLK_MT6797_MMSYS) += clk-mt6797-mm.o
 obj-$(CONFIG_COMMON_CLK_MT6797_MMSYS) += clk-mt6797-mm.o

+ 1 - 7
drivers/clk/mediatek/clk-mtk.h

@@ -20,6 +20,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clk-provider.h>
 
 
 struct clk;
 struct clk;
+struct clk_onecell_data;
 
 
 #define MAX_MUX_GATE_BIT	31
 #define MAX_MUX_GATE_BIT	31
 #define INVALID_MUX_GATE_BIT	(MAX_MUX_GATE_BIT + 1)
 #define INVALID_MUX_GATE_BIT	(MAX_MUX_GATE_BIT + 1)
@@ -228,14 +229,7 @@ void mtk_clk_register_plls(struct device_node *node,
 struct clk *mtk_clk_register_ref2usb_tx(const char *name,
 struct clk *mtk_clk_register_ref2usb_tx(const char *name,
 			const char *parent_name, void __iomem *reg);
 			const char *parent_name, void __iomem *reg);
 
 
-#ifdef CONFIG_RESET_CONTROLLER
 void mtk_register_reset_controller(struct device_node *np,
 void mtk_register_reset_controller(struct device_node *np,
 			unsigned int num_regs, int regofs);
 			unsigned int num_regs, int regofs);
-#else
-static inline void mtk_register_reset_controller(struct device_node *np,
-			unsigned int num_regs, int regofs)
-{
-}
-#endif
 
 
 #endif /* __DRV_CLK_MTK_H */
 #endif /* __DRV_CLK_MTK_H */

+ 37 - 20
drivers/clk/sunxi-ng/ccu-sun50i-a64.c

@@ -400,28 +400,45 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080,
 				  BIT(31),	/* gate */
 				  BIT(31),	/* gate */
 				  0);
 				  0);
 
 
+/*
+ * MMC clocks are the new timing mode (see A83T & H3) variety, but without
+ * the mode switch. This means they have a 2x post divider between the clock
+ * and the MMC module. This is not documented in the manual, but is taken
+ * into consideration when setting the mmc module clocks in the BSP kernel.
+ * Without it, MMC performance is degraded.
+ *
+ * We model it here to be consistent with other SoCs supporting this mode.
+ * The alternative would be to add the 2x multiplier when setting the MMC
+ * module clock in the MMC driver, just for the A64.
+ */
 static const char * const mmc_default_parents[] = { "osc24M", "pll-periph0-2x",
 static const char * const mmc_default_parents[] = { "osc24M", "pll-periph0-2x",
 						    "pll-periph1-2x" };
 						    "pll-periph1-2x" };
-static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_default_parents, 0x088,
-				  0, 4,		/* M */
-				  16, 2,	/* P */
-				  24, 2,	/* mux */
-				  BIT(31),	/* gate */
-				  0);
-
-static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_default_parents, 0x08c,
-				  0, 4,		/* M */
-				  16, 2,	/* P */
-				  24, 2,	/* mux */
-				  BIT(31),	/* gate */
-				  0);
-
-static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_default_parents, 0x090,
-				  0, 4,		/* M */
-				  16, 2,	/* P */
-				  24, 2,	/* mux */
-				  BIT(31),	/* gate */
-				  0);
+static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0",
+					  mmc_default_parents, 0x088,
+					  0, 4,		/* M */
+					  16, 2,	/* P */
+					  24, 2,	/* mux */
+					  BIT(31),	/* gate */
+					  2,		/* post-div */
+					  0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1",
+					  mmc_default_parents, 0x08c,
+					  0, 4,		/* M */
+					  16, 2,	/* P */
+					  24, 2,	/* mux */
+					  BIT(31),	/* gate */
+					  2,		/* post-div */
+					  0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2",
+					  mmc_default_parents, 0x090,
+					  0, 4,		/* M */
+					  16, 2,	/* P */
+					  24, 2,	/* mux */
+					  BIT(31),	/* gate */
+					  2,		/* post-div */
+					  0);
 
 
 static const char * const ts_parents[] = { "osc24M", "pll-periph0", };
 static const char * const ts_parents[] = { "osc24M", "pll-periph0", };
 static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098,
 static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098,

+ 17 - 5
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c

@@ -76,15 +76,26 @@ static struct ccu_mult pll_c1cpux_clk = {
  */
  */
 #define SUN8I_A83T_PLL_AUDIO_REG	0x008
 #define SUN8I_A83T_PLL_AUDIO_REG	0x008
 
 
+/* clock rates doubled for post divider */
+static struct ccu_sdm_setting pll_audio_sdm_table[] = {
+	{ .rate = 45158400, .pattern = 0xc00121ff, .m = 29, .n = 54 },
+	{ .rate = 49152000, .pattern = 0xc000e147, .m = 30, .n = 61 },
+};
+
 static struct ccu_nm pll_audio_clk = {
 static struct ccu_nm pll_audio_clk = {
 	.enable		= BIT(31),
 	.enable		= BIT(31),
 	.lock		= BIT(2),
 	.lock		= BIT(2),
 	.n		= _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
 	.n		= _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
 	.m		= _SUNXI_CCU_DIV(0, 6),
 	.m		= _SUNXI_CCU_DIV(0, 6),
+	.fixed_post_div	= 2,
+	.sdm		= _SUNXI_CCU_SDM(pll_audio_sdm_table, BIT(24),
+					 0x284, BIT(31)),
 	.common		= {
 	.common		= {
 		.reg		= SUN8I_A83T_PLL_AUDIO_REG,
 		.reg		= SUN8I_A83T_PLL_AUDIO_REG,
 		.lock_reg	= CCU_SUN8I_A83T_LOCK_REG,
 		.lock_reg	= CCU_SUN8I_A83T_LOCK_REG,
-		.features	= CCU_FEATURE_LOCK_REG,
+		.features	= CCU_FEATURE_LOCK_REG |
+				  CCU_FEATURE_FIXED_POSTDIV |
+				  CCU_FEATURE_SIGMA_DELTA_MOD,
 		.hw.init	= CLK_HW_INIT("pll-audio", "osc24M",
 		.hw.init	= CLK_HW_INIT("pll-audio", "osc24M",
 					      &ccu_nm_ops, CLK_SET_RATE_UNGATE),
 					      &ccu_nm_ops, CLK_SET_RATE_UNGATE),
 	},
 	},
@@ -493,8 +504,8 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents,
 				 0x118, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
 				 0x118, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
 
 
 static const char * const tcon1_parents[] = { "pll-video1" };
 static const char * const tcon1_parents[] = { "pll-video1" };
-static SUNXI_CCU_MUX_WITH_GATE(tcon1_clk, "tcon1", tcon1_parents,
-				 0x11c, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_MUX_GATE(tcon1_clk, "tcon1", tcon1_parents,
+				 0x11c, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT);
 
 
 static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0);
 static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0);
 
 
@@ -889,9 +900,10 @@ static int sun8i_a83t_ccu_probe(struct platform_device *pdev)
 	if (IS_ERR(reg))
 	if (IS_ERR(reg))
 		return PTR_ERR(reg);
 		return PTR_ERR(reg);
 
 
-	/* Enforce d1 = 0, d2 = 0 for Audio PLL */
+	/* Enforce d1 = 0, d2 = 1 for Audio PLL */
 	val = readl(reg + SUN8I_A83T_PLL_AUDIO_REG);
 	val = readl(reg + SUN8I_A83T_PLL_AUDIO_REG);
-	val &= ~(BIT(16) | BIT(18));
+	val &= ~BIT(16);
+	val |= BIT(18);
 	writel(val, reg + SUN8I_A83T_PLL_AUDIO_REG);
 	writel(val, reg + SUN8I_A83T_PLL_AUDIO_REG);
 
 
 	/* Enforce P = 1 for both CPU cluster PLLs */
 	/* Enforce P = 1 for both CPU cluster PLLs */

+ 50 - 3
drivers/clk/sunxi-ng/ccu-sun8i-de2.c

@@ -41,6 +41,8 @@ static SUNXI_CCU_GATE(wb_clk,		"wb",		"wb-div",
 
 
 static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4,
 static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4,
 		   CLK_SET_RATE_PARENT);
 		   CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4,
+		   CLK_SET_RATE_PARENT);
 static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4,
 static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4,
 		   CLK_SET_RATE_PARENT);
 		   CLK_SET_RATE_PARENT);
 
 
@@ -65,6 +67,20 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = {
 	&wb_div_a83_clk.common,
 	&wb_div_a83_clk.common,
 };
 };
 
 
+static struct ccu_common *sun8i_h3_de2_clks[] = {
+	&mixer0_clk.common,
+	&mixer1_clk.common,
+	&wb_clk.common,
+
+	&bus_mixer0_clk.common,
+	&bus_mixer1_clk.common,
+	&bus_wb_clk.common,
+
+	&mixer0_div_clk.common,
+	&mixer1_div_clk.common,
+	&wb_div_clk.common,
+};
+
 static struct ccu_common *sun8i_v3s_de2_clks[] = {
 static struct ccu_common *sun8i_v3s_de2_clks[] = {
 	&mixer0_clk.common,
 	&mixer0_clk.common,
 	&wb_clk.common,
 	&wb_clk.common,
@@ -93,6 +109,23 @@ static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = {
 	.num	= CLK_NUMBER,
 	.num	= CLK_NUMBER,
 };
 };
 
 
+static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = {
+	.hws	= {
+		[CLK_MIXER0]		= &mixer0_clk.common.hw,
+		[CLK_MIXER1]		= &mixer1_clk.common.hw,
+		[CLK_WB]		= &wb_clk.common.hw,
+
+		[CLK_BUS_MIXER0]	= &bus_mixer0_clk.common.hw,
+		[CLK_BUS_MIXER1]	= &bus_mixer1_clk.common.hw,
+		[CLK_BUS_WB]		= &bus_wb_clk.common.hw,
+
+		[CLK_MIXER0_DIV]	= &mixer0_div_clk.common.hw,
+		[CLK_MIXER1_DIV]	= &mixer1_div_clk.common.hw,
+		[CLK_WB_DIV]		= &wb_div_clk.common.hw,
+	},
+	.num	= CLK_NUMBER,
+};
+
 static struct clk_hw_onecell_data sun8i_v3s_de2_hw_clks = {
 static struct clk_hw_onecell_data sun8i_v3s_de2_hw_clks = {
 	.hws	= {
 	.hws	= {
 		[CLK_MIXER0]		= &mixer0_clk.common.hw,
 		[CLK_MIXER0]		= &mixer0_clk.common.hw,
@@ -133,11 +166,21 @@ static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = {
 	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
 	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
 };
 };
 
 
+static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = {
+	.ccu_clks	= sun8i_h3_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun8i_h3_de2_clks),
+
+	.hw_clks	= &sun8i_h3_de2_hw_clks,
+
+	.resets		= sun8i_a83t_de2_resets,
+	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
+};
+
 static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
 static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
-	.ccu_clks	= sun8i_a83t_de2_clks,
-	.num_ccu_clks	= ARRAY_SIZE(sun8i_a83t_de2_clks),
+	.ccu_clks	= sun8i_h3_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun8i_h3_de2_clks),
 
 
-	.hw_clks	= &sun8i_a83t_de2_hw_clks,
+	.hw_clks	= &sun8i_h3_de2_hw_clks,
 
 
 	.resets		= sun50i_a64_de2_resets,
 	.resets		= sun50i_a64_de2_resets,
 	.num_resets	= ARRAY_SIZE(sun50i_a64_de2_resets),
 	.num_resets	= ARRAY_SIZE(sun50i_a64_de2_resets),
@@ -237,6 +280,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
 		.compatible = "allwinner,sun8i-a83t-de2-clk",
 		.compatible = "allwinner,sun8i-a83t-de2-clk",
 		.data = &sun8i_a83t_de2_clk_desc,
 		.data = &sun8i_a83t_de2_clk_desc,
 	},
 	},
+	{
+		.compatible = "allwinner,sun8i-h3-de2-clk",
+		.data = &sun8i_h3_de2_clk_desc,
+	},
 	{
 	{
 		.compatible = "allwinner,sun8i-v3s-de2-clk",
 		.compatible = "allwinner,sun8i-v3s-de2-clk",
 		.data = &sun8i_v3s_de2_clk_desc,
 		.data = &sun8i_v3s_de2_clk_desc,

+ 18 - 2
drivers/clk/sunxi-ng/ccu_mp.c

@@ -50,12 +50,19 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux,
 	unsigned int max_m, max_p;
 	unsigned int max_m, max_p;
 	unsigned int m, p;
 	unsigned int m, p;
 
 
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate *= cmp->fixed_post_div;
+
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 
 
 	ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p);
 	ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p);
+	rate = *parent_rate / p / m;
+
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate /= cmp->fixed_post_div;
 
 
-	return *parent_rate / p / m;
+	return rate;
 }
 }
 
 
 static void ccu_mp_disable(struct clk_hw *hw)
 static void ccu_mp_disable(struct clk_hw *hw)
@@ -83,6 +90,7 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
 					unsigned long parent_rate)
 					unsigned long parent_rate)
 {
 {
 	struct ccu_mp *cmp = hw_to_ccu_mp(hw);
 	struct ccu_mp *cmp = hw_to_ccu_mp(hw);
+	unsigned long rate;
 	unsigned int m, p;
 	unsigned int m, p;
 	u32 reg;
 	u32 reg;
 
 
@@ -101,7 +109,11 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
 	p = reg >> cmp->p.shift;
 	p = reg >> cmp->p.shift;
 	p &= (1 << cmp->p.width) - 1;
 	p &= (1 << cmp->p.width) - 1;
 
 
-	return (parent_rate >> p) / m;
+	rate = (parent_rate >> p) / m;
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate /= cmp->fixed_post_div;
+
+	return rate;
 }
 }
 
 
 static int ccu_mp_determine_rate(struct clk_hw *hw,
 static int ccu_mp_determine_rate(struct clk_hw *hw,
@@ -129,6 +141,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 
 
+	/* Adjust target rate according to post-dividers */
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate = rate * cmp->fixed_post_div;
+
 	ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p);
 	ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p);
 
 
 	spin_lock_irqsave(cmp->common.lock, flags);
 	spin_lock_irqsave(cmp->common.lock, flags);

+ 24 - 0
drivers/clk/sunxi-ng/ccu_mp.h

@@ -33,9 +33,33 @@ struct ccu_mp {
 	struct ccu_div_internal		m;
 	struct ccu_div_internal		m;
 	struct ccu_div_internal		p;
 	struct ccu_div_internal		p;
 	struct ccu_mux_internal	mux;
 	struct ccu_mux_internal	mux;
+
+	unsigned int		fixed_post_div;
+
 	struct ccu_common	common;
 	struct ccu_common	common;
 };
 };
 
 
+#define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
+					   _mshift, _mwidth,		\
+					   _pshift, _pwidth,		\
+					   _muxshift, _muxwidth,	\
+					   _gate, _postdiv, _flags)	\
+	struct ccu_mp _struct = {					\
+		.enable	= _gate,					\
+		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
+		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
+		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
+		.fixed_post_div	= _postdiv,				\
+		.common	= {						\
+			.reg		= _reg,				\
+			.features	= CCU_FEATURE_FIXED_POSTDIV,	\
+			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
+							      _parents, \
+							      &ccu_mp_ops, \
+							      _flags),	\
+		}							\
+	}
+
 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
 				   _mshift, _mwidth,			\
 				   _mshift, _mwidth,			\
 				   _pshift, _pwidth,			\
 				   _pshift, _pwidth,			\

+ 37 - 13
drivers/clk/sunxi-ng/ccu_nm.c

@@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
 					unsigned long parent_rate)
 					unsigned long parent_rate)
 {
 {
 	struct ccu_nm *nm = hw_to_ccu_nm(hw);
 	struct ccu_nm *nm = hw_to_ccu_nm(hw);
+	unsigned long rate;
 	unsigned long n, m;
 	unsigned long n, m;
 	u32 reg;
 	u32 reg;
 
 
-	if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac))
-		return ccu_frac_helper_read_rate(&nm->common, &nm->frac);
+	if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) {
+		rate = ccu_frac_helper_read_rate(&nm->common, &nm->frac);
+
+		if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+			rate /= nm->fixed_post_div;
+
+		return rate;
+	}
 
 
 	reg = readl(nm->common.base + nm->common.reg);
 	reg = readl(nm->common.base + nm->common.reg);
 
 
@@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
 	if (!m)
 	if (!m)
 		m++;
 		m++;
 
 
-	if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) {
-		unsigned long rate =
-			ccu_sdm_helper_read_rate(&nm->common, &nm->sdm,
-						 m, n);
-		if (rate)
-			return rate;
-	}
+	if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm))
+		rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n);
+	else
+		rate = parent_rate * n / m;
+
+	if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate /= nm->fixed_post_div;
 
 
-	return parent_rate * n / m;
+	return rate;
 }
 }
 
 
 static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
 static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -107,11 +114,20 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
 	struct ccu_nm *nm = hw_to_ccu_nm(hw);
 	struct ccu_nm *nm = hw_to_ccu_nm(hw);
 	struct _ccu_nm _nm;
 	struct _ccu_nm _nm;
 
 
-	if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate))
+	if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate *= nm->fixed_post_div;
+
+	if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
+		if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+			rate /= nm->fixed_post_div;
 		return rate;
 		return rate;
+	}
 
 
-	if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate))
+	if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) {
+		if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+			rate /= nm->fixed_post_div;
 		return rate;
 		return rate;
+	}
 
 
 	_nm.min_n = nm->n.min ?: 1;
 	_nm.min_n = nm->n.min ?: 1;
 	_nm.max_n = nm->n.max ?: 1 << nm->n.width;
 	_nm.max_n = nm->n.max ?: 1 << nm->n.width;
@@ -119,8 +135,12 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
 	_nm.max_m = nm->m.max ?: 1 << nm->m.width;
 	_nm.max_m = nm->m.max ?: 1 << nm->m.width;
 
 
 	ccu_nm_find_best(*parent_rate, rate, &_nm);
 	ccu_nm_find_best(*parent_rate, rate, &_nm);
+	rate = *parent_rate * _nm.n / _nm.m;
+
+	if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate /= nm->fixed_post_div;
 
 
-	return *parent_rate * _nm.n / _nm.m;
+	return rate;
 }
 }
 
 
 static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
 static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -131,6 +151,10 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
 	unsigned long flags;
 	unsigned long flags;
 	u32 reg;
 	u32 reg;
 
 
+	/* Adjust target rate according to post-dividers */
+	if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate = rate * nm->fixed_post_div;
+
 	if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
 	if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
 		spin_lock_irqsave(nm->common.lock, flags);
 		spin_lock_irqsave(nm->common.lock, flags);
 
 

+ 2 - 0
drivers/clk/sunxi-ng/ccu_nm.h

@@ -36,6 +36,8 @@ struct ccu_nm {
 	struct ccu_frac_internal	frac;
 	struct ccu_frac_internal	frac;
 	struct ccu_sdm_internal		sdm;
 	struct ccu_sdm_internal		sdm;
 
 
+	unsigned int		fixed_post_div;
+
 	struct ccu_common	common;
 	struct ccu_common	common;
 };
 };
 
 

+ 1 - 4
drivers/clk/sunxi/clk-sun8i-apb0.c

@@ -98,10 +98,7 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
 		return PTR_ERR(reg);
 		return PTR_ERR(reg);
 
 
 	clk = sun8i_a23_apb0_register(np, reg);
 	clk = sun8i_a23_apb0_register(np, reg);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	return 0;
+	return PTR_ERR_OR_ZERO(clk);
 }
 }
 
 
 static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {
 static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {

+ 52 - 0
include/dt-bindings/clock/aspeed-clock.h

@@ -0,0 +1,52 @@
+/* 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_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