/* * Copyright 2017-2019 NXP * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #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); }