Commit c43a52cf authored by Stephen Boyd's avatar Stephen Boyd

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()
...@@ -4,13 +4,14 @@ Allwinner Display Engine 2.0 Clock Control Binding ...@@ -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 : ...@@ -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>;
......
...@@ -142,6 +142,18 @@ config COMMON_CLK_GEMINI ...@@ -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
......
...@@ -27,6 +27,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o ...@@ -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/ ...@@ -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)
......
This diff is collapsed.
...@@ -144,10 +144,18 @@ static unsigned long clk_enable_lock(void) ...@@ -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);
......
# #
# 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 ...@@ -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
# 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_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o
obj-$(CONFIG_RESET_CONTROLLER) += 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
......
...@@ -20,6 +20,7 @@ ...@@ -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, ...@@ -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 */
...@@ -400,28 +400,45 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080, ...@@ -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, static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0",
0, 4, /* M */ mmc_default_parents, 0x088,
16, 2, /* P */ 0, 4, /* M */
24, 2, /* mux */ 16, 2, /* P */
BIT(31), /* gate */ 24, 2, /* mux */
0); BIT(31), /* gate */
2, /* post-div */
static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_default_parents, 0x08c, 0);
0, 4, /* M */
16, 2, /* P */ static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1",
24, 2, /* mux */ mmc_default_parents, 0x08c,
BIT(31), /* gate */ 0, 4, /* M */
0); 16, 2, /* P */
24, 2, /* mux */
static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_default_parents, 0x090, BIT(31), /* gate */
0, 4, /* M */ 2, /* post-div */
16, 2, /* P */ 0);
24, 2, /* mux */
BIT(31), /* gate */ static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2",
0); 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,
......
...@@ -76,15 +76,26 @@ static struct ccu_mult pll_c1cpux_clk = { ...@@ -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, ...@@ -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, static SUNXI_CCU_M_WITH_MUX_GATE(tcon1_clk, "tcon1", tcon1_parents,
0x11c, 24, 3, BIT(31), CLK_SET_RATE_PARENT); 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) ...@@ -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 */
......
...@@ -41,6 +41,8 @@ static SUNXI_CCU_GATE(wb_clk, "wb", "wb-div", ...@@ -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[] = { ...@@ -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 = { ...@@ -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 = { ...@@ -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, .ccu_clks = sun8i_h3_de2_clks,
.num_ccu_clks = ARRAY_SIZE(sun8i_a83t_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[] = { ...@@ -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,
......
...@@ -50,12 +50,19 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
......
...@@ -33,9 +33,33 @@ struct ccu_mp { ...@@ -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, \
......
...@@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, ...@@ -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)) if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) {
return ccu_frac_helper_read_rate(&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, ...@@ -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)) { if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm))
unsigned long rate = rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n);
ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, else
m, n); rate = parent_rate * n / m;
if (rate)
return rate; 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, ...@@ -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, ...@@ -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, ...@@ -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);
......
...@@ -36,6 +36,8 @@ struct ccu_nm { ...@@ -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;
}; };
......
...@@ -98,10 +98,7 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) ...@@ -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_OR_ZERO(clk);
return PTR_ERR(clk);
return 0;
} }
static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {
......
/* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment