> 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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot