
Subject: [PATCH 1/5] imx8: Add lpcg driver for iMX8QM/QXP
[...]
diff --git a/arch/arm/include/asm/arch-imx8/imx8qm_lpcg.h b/arch/arm/include/asm/arch-imx8/imx8qm_lpcg.h new file mode 100644 index 0000000..692c27f --- /dev/null +++ b/arch/arm/include/asm/arch-imx8/imx8qm_lpcg.h @@ -0,0 +1,200 @@ +/*
- Copyright 2018 NXP
- SPDX-License-Identifier: GPL-2.0+
Please fix license and time.
- */
+#ifndef _SC_LPCG_H +#define _SC_LPCG_H
[...]
+#endif diff --git a/arch/arm/include/asm/arch-imx8/imx8qxp_lpcg.h b/arch/arm/include/asm/arch-imx8/imx8qxp_lpcg.h new file mode 100644 index 0000000..5fed514 --- /dev/null +++ b/arch/arm/include/asm/arch-imx8/imx8qxp_lpcg.h @@ -0,0 +1,195 @@ +/*
- Copyright 2018 NXP
- SPDX-License-Identifier: GPL-2.0+
Ditto
- */
+#ifndef _SC_LPCG_H +#define _SC_LPCG_H
[...]
+#define AUD_EDMA_1_LPCG 0x59df0000
Blank line.
+/* Connectivity SS */ +#define USDHC_0_LPCG 0x5B200000 +#define USDHC_1_LPCG 0x5B210000 +#define USDHC_2_LPCG 0x5B220000 +#define ENET_0_LPCG 0x5B230000 +#define ENET_1_LPCG 0x5B240000 +#define DTCP_LPCG 0x5B250000 +#define MLB_LPCG 0x5B260000 +#define USB_2_LPCG 0x5B270000 +#define USB_3_LPCG 0x5B280000 +#define NAND_LPCG 0x5B290000 +#define EDMA_LPCG 0x5B2A0000
+/* CM40 SS */ +#define CM40_I2C_LPCG 0x37630000
Ditto
+#endif diff --git a/arch/arm/include/asm/arch-imx8/lpcg.h b/arch/arm/include/asm/arch-imx8/lpcg.h new file mode 100644 index 0000000..b3a4545 --- /dev/null +++ b/arch/arm/include/asm/arch-imx8/lpcg.h @@ -0,0 +1,26 @@ +/*
- Copyright 2018 NXP
- SPDX-License-Identifier: GPL-2.0+
Please fix copyright and license.
- */
+#ifndef __ASM_ARCH_IMX8_LPCG_H__ +#define __ASM_ARCH_IMX8_LPCG_H__
+#if defined(CONFIG_IMX8QM) +#include "imx8qm_lpcg.h" +#elif defined(CONFIG_IMX8QXP) +#include "imx8qxp_lpcg.h" +#else +#error "No lpcg header" +#endif
+void lpcg_clock_off(u32 lpcg_addr, u8 clk); void lpcg_clock_on(u32 +lpcg_addr, u8 clk); void lpcg_clock_autogate(u32 lpcg_addr, u8 clk); +bool lpcg_is_clock_on(u32 lpcg_addr, u8 clk); void +lpcg_all_clock_off(u32 lpcg_addr); void lpcg_all_clock_on(u32 +lpcg_addr); void lpcg_all_clock_autogate(u32 lpcg_addr);
+#endif /* __ASM_ARCH_IMX8_LPCG_H__ */ diff --git a/arch/arm/mach-imx/imx8/Makefile b/arch/arm/mach-imx/imx8/Makefile index 31ad169..e23f84f 100644 --- a/arch/arm/mach-imx/imx8/Makefile +++ b/arch/arm/mach-imx/imx8/Makefile @@ -4,4 +4,4 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += cpu.o iomux.o +obj-y += cpu.o iomux.o lpcg.o diff --git a/arch/arm/mach-imx/imx8/lpcg.c b/arch/arm/mach-imx/imx8/lpcg.c new file mode 100644 index 0000000..5f5d770 --- /dev/null +++ b/arch/arm/mach-imx/imx8/lpcg.c @@ -0,0 +1,115 @@ +/*
- Copyright 2017-2019 NXP
- SPDX-License-Identifier: GPL-2.0+
Ditto.
Regards, Peng.
- */
+#include <common.h> +#include <asm/io.h> +#include <linux/errno.h> +#include <asm/arch/lpcg.h>
+#define LPCG_CLOCK_MASK 0x3U +#define LPCG_CLOCK_OFF 0x0U +#define LPCG_CLOCK_ON 0x2U +#define LPCG_CLOCK_AUTO 0x3U +#define LPCG_CLOCK_STOP 0x8U
+#define LPCG_ALL_CLOCK_OFF 0x00000000U +#define LPCG_ALL_CLOCK_ON 0x22222222U +#define LPCG_ALL_CLOCK_AUTO 0x33333333U +#define LPCG_ALL_CLOCK_STOP 0x88888888U
+static inline void lpcg_write(u32 lpcgVal, ulong lpcg_addr) {
- /*
- Write twice with 4x DSC clock cycles (40x IPS clock cycles) interval
- to work around LPCG issue
- */
- writel(lpcgVal, lpcg_addr);
- udelay(10); /* 10us is enough. Worst case is 40x IPS cycle (200Mhz) */
- writel(lpcgVal, lpcg_addr);
- udelay(10);
+}
+void lpcg_clock_off(u32 lpcg_addr, u8 clk) {
- u32 lpcgVal;
- /* Read from LPCG */
- lpcgVal = readl((ulong)lpcg_addr);
- /* Modify */
- lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U));
- lpcgVal |= ((u32)(LPCG_CLOCK_OFF) << (clk * 4U));
- /* Write to LPCG */
- lpcg_write(lpcgVal, (ulong)lpcg_addr); }
+void lpcg_clock_on(u32 lpcg_addr, u8 clk) {
- u32 lpcgVal;
- /* Read from LPCG */
- lpcgVal = readl((ulong)lpcg_addr);
- /* Modify */
- lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U));
- lpcgVal |= ((u32)(LPCG_CLOCK_ON) << (clk * 4U));
- /* Write to LPCG */
- lpcg_write(lpcgVal, (ulong)lpcg_addr); }
+bool lpcg_is_clock_on(u32 lpcg_addr, u8 clk) {
- u32 lpcgVal;
- /* Read from LPCG */
- lpcgVal = readl((ulong)lpcg_addr);
- lpcgVal = (lpcgVal >> (clk * 4U)) & (u32)(LPCG_CLOCK_MASK);
- if (lpcgVal == LPCG_CLOCK_ON)
return true;
- return false;
+}
+void lpcg_clock_autogate(u32 lpcg_addr, u8 clk) {
- u32 lpcgVal;
- /* Read from LPCG */
- lpcgVal = readl((ulong)lpcg_addr);
- /* Modify */
- lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U));
- lpcgVal |= ((u32)(LPCG_CLOCK_AUTO) << (clk * 4U));
- /* Write to LPCG */
- lpcg_write(lpcgVal, (ulong)lpcg_addr); }
+void lpcg_all_clock_off(u32 lpcg_addr) +{
- /* Write to LPCG */
- lpcg_write(LPCG_ALL_CLOCK_OFF, (ulong)lpcg_addr); }
+void lpcg_all_clock_on(u32 lpcg_addr) +{
- /* Write to LPCG */
- lpcg_write(LPCG_ALL_CLOCK_ON, (ulong)lpcg_addr);
- /* Wait for clocks to start */
- while ((readl((ulong)lpcg_addr) & LPCG_ALL_CLOCK_STOP) != 0U)
- {
- }
+}
+void lpcg_all_clock_autogate(u32 lpcg_addr) {
- /* Write to LPCG */
- lpcg_write(LPCG_ALL_CLOCK_AUTO, (ulong)lpcg_addr); }
-- 2.7.4