[U-Boot] [PATCH 1/5] imx8: Add lpcg driver for iMX8QM/QXP

Peng Fan
2019-07-03T06:02:13Z

> 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