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