162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 1999 ARM Limited 462306a36Sopenharmony_ci * Copyright (C) 2000 Deep Blue Solutions Ltd 562306a36Sopenharmony_ci * Copyright 2006-2007,2010 Freescale Semiconductor, Inc. All Rights Reserved. 662306a36Sopenharmony_ci * Copyright 2008 Juergen Beisert, kernel@pengutronix.de 762306a36Sopenharmony_ci * Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com 862306a36Sopenharmony_ci * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/compiler.h> 1562306a36Sopenharmony_ci#include <linux/export.h> 1662306a36Sopenharmony_ci#include <linux/stmp_device.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define STMP_MODULE_CLKGATE (1 << 30) 1962306a36Sopenharmony_ci#define STMP_MODULE_SFTRST (1 << 31) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * Clear the bit and poll it cleared. This is usually called with 2362306a36Sopenharmony_ci * a reset address and mask being either SFTRST(bit 31) or CLKGATE 2462306a36Sopenharmony_ci * (bit 30). 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistatic int stmp_clear_poll_bit(void __iomem *addr, u32 mask) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci int timeout = 0x400; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci writel(mask, addr + STMP_OFFSET_REG_CLR); 3162306a36Sopenharmony_ci udelay(1); 3262306a36Sopenharmony_ci while ((readl(addr) & mask) && --timeout) 3362306a36Sopenharmony_ci /* nothing */; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return !timeout; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciint stmp_reset_block(void __iomem *reset_addr) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci int ret; 4162306a36Sopenharmony_ci int timeout = 0x400; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* clear and poll SFTRST */ 4462306a36Sopenharmony_ci ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_SFTRST); 4562306a36Sopenharmony_ci if (unlikely(ret)) 4662306a36Sopenharmony_ci goto error; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* clear CLKGATE */ 4962306a36Sopenharmony_ci writel(STMP_MODULE_CLKGATE, reset_addr + STMP_OFFSET_REG_CLR); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* set SFTRST to reset the block */ 5262306a36Sopenharmony_ci writel(STMP_MODULE_SFTRST, reset_addr + STMP_OFFSET_REG_SET); 5362306a36Sopenharmony_ci udelay(1); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* poll CLKGATE becoming set */ 5662306a36Sopenharmony_ci while ((!(readl(reset_addr) & STMP_MODULE_CLKGATE)) && --timeout) 5762306a36Sopenharmony_ci /* nothing */; 5862306a36Sopenharmony_ci if (unlikely(!timeout)) 5962306a36Sopenharmony_ci goto error; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* clear and poll SFTRST */ 6262306a36Sopenharmony_ci ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_SFTRST); 6362306a36Sopenharmony_ci if (unlikely(ret)) 6462306a36Sopenharmony_ci goto error; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* clear and poll CLKGATE */ 6762306a36Sopenharmony_ci ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_CLKGATE); 6862306a36Sopenharmony_ci if (unlikely(ret)) 6962306a36Sopenharmony_ci goto error; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cierror: 7462306a36Sopenharmony_ci pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); 7562306a36Sopenharmony_ci return -ETIMEDOUT; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ciEXPORT_SYMBOL(stmp_reset_block); 78