18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1999 ARM Limited 48c2ecf20Sopenharmony_ci * Copyright (C) 2000 Deep Blue Solutions Ltd 58c2ecf20Sopenharmony_ci * Copyright 2006-2007,2010 Freescale Semiconductor, Inc. All Rights Reserved. 68c2ecf20Sopenharmony_ci * Copyright 2008 Juergen Beisert, kernel@pengutronix.de 78c2ecf20Sopenharmony_ci * Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com 88c2ecf20Sopenharmony_ci * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/compiler.h> 158c2ecf20Sopenharmony_ci#include <linux/export.h> 168c2ecf20Sopenharmony_ci#include <linux/stmp_device.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define STMP_MODULE_CLKGATE (1 << 30) 198c2ecf20Sopenharmony_ci#define STMP_MODULE_SFTRST (1 << 31) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * Clear the bit and poll it cleared. This is usually called with 238c2ecf20Sopenharmony_ci * a reset address and mask being either SFTRST(bit 31) or CLKGATE 248c2ecf20Sopenharmony_ci * (bit 30). 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_cistatic int stmp_clear_poll_bit(void __iomem *addr, u32 mask) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci int timeout = 0x400; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci writel(mask, addr + STMP_OFFSET_REG_CLR); 318c2ecf20Sopenharmony_ci udelay(1); 328c2ecf20Sopenharmony_ci while ((readl(addr) & mask) && --timeout) 338c2ecf20Sopenharmony_ci /* nothing */; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return !timeout; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint stmp_reset_block(void __iomem *reset_addr) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int ret; 418c2ecf20Sopenharmony_ci int timeout = 0x400; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* clear and poll SFTRST */ 448c2ecf20Sopenharmony_ci ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_SFTRST); 458c2ecf20Sopenharmony_ci if (unlikely(ret)) 468c2ecf20Sopenharmony_ci goto error; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* clear CLKGATE */ 498c2ecf20Sopenharmony_ci writel(STMP_MODULE_CLKGATE, reset_addr + STMP_OFFSET_REG_CLR); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* set SFTRST to reset the block */ 528c2ecf20Sopenharmony_ci writel(STMP_MODULE_SFTRST, reset_addr + STMP_OFFSET_REG_SET); 538c2ecf20Sopenharmony_ci udelay(1); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* poll CLKGATE becoming set */ 568c2ecf20Sopenharmony_ci while ((!(readl(reset_addr) & STMP_MODULE_CLKGATE)) && --timeout) 578c2ecf20Sopenharmony_ci /* nothing */; 588c2ecf20Sopenharmony_ci if (unlikely(!timeout)) 598c2ecf20Sopenharmony_ci goto error; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* clear and poll SFTRST */ 628c2ecf20Sopenharmony_ci ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_SFTRST); 638c2ecf20Sopenharmony_ci if (unlikely(ret)) 648c2ecf20Sopenharmony_ci goto error; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* clear and poll CLKGATE */ 678c2ecf20Sopenharmony_ci ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_CLKGATE); 688c2ecf20Sopenharmony_ci if (unlikely(ret)) 698c2ecf20Sopenharmony_ci goto error; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cierror: 748c2ecf20Sopenharmony_ci pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); 758c2ecf20Sopenharmony_ci return -ETIMEDOUT; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(stmp_reset_block); 78