mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00:00 
			
		
		
		
	This patch adds reset support for the Amlogic A1 family. We add the structure meson_reset_drvdata, which in the future will allow this driver to be used for other families by declaring only the correct parameters reg_count and level_offset. Signed-off-by: Alexey Romanov <avromanov@salutedevices.com> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> Link: https://lore.kernel.org/r/20231005085434.74755-3-avromanov@salutedevices.com Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
		
			
				
	
	
		
			118 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * Amlogic Meson Reset Controller driver
 | 
						|
 *
 | 
						|
 * Copyright (c) 2018 BayLibre, SAS.
 | 
						|
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
						|
 */
 | 
						|
 | 
						|
#include <common.h>
 | 
						|
#include <dm.h>
 | 
						|
#include <log.h>
 | 
						|
#include <malloc.h>
 | 
						|
#include <reset-uclass.h>
 | 
						|
#include <regmap.h>
 | 
						|
#include <linux/bitops.h>
 | 
						|
#include <linux/delay.h>
 | 
						|
 | 
						|
#define BITS_PER_REG	32
 | 
						|
 | 
						|
struct meson_reset_drvdata {
 | 
						|
	unsigned int reg_count;
 | 
						|
	unsigned int level_offset;
 | 
						|
};
 | 
						|
 | 
						|
struct meson_reset_priv {
 | 
						|
	struct regmap *regmap;
 | 
						|
	struct meson_reset_drvdata *drvdata;
 | 
						|
};
 | 
						|
 | 
						|
static int meson_reset_request(struct reset_ctl *reset_ctl)
 | 
						|
{
 | 
						|
	struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
 | 
						|
	struct meson_reset_drvdata *data = priv->drvdata;
 | 
						|
 | 
						|
	if (reset_ctl->id > (data->reg_count * BITS_PER_REG))
 | 
						|
		return -EINVAL;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert)
 | 
						|
{
 | 
						|
	struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
 | 
						|
	struct meson_reset_drvdata *data = priv->drvdata;
 | 
						|
	uint bank = reset_ctl->id / BITS_PER_REG;
 | 
						|
	uint offset = reset_ctl->id % BITS_PER_REG;
 | 
						|
	uint reg_offset = data->level_offset + (bank << 2);
 | 
						|
	uint val;
 | 
						|
 | 
						|
	regmap_read(priv->regmap, reg_offset, &val);
 | 
						|
	if (assert)
 | 
						|
		val &= ~BIT(offset);
 | 
						|
	else
 | 
						|
		val |= BIT(offset);
 | 
						|
	regmap_write(priv->regmap, reg_offset, val);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int meson_reset_assert(struct reset_ctl *reset_ctl)
 | 
						|
{
 | 
						|
	return meson_reset_level(reset_ctl, true);
 | 
						|
}
 | 
						|
 | 
						|
static int meson_reset_deassert(struct reset_ctl *reset_ctl)
 | 
						|
{
 | 
						|
	return meson_reset_level(reset_ctl, false);
 | 
						|
}
 | 
						|
 | 
						|
struct reset_ops meson_reset_ops = {
 | 
						|
	.request = meson_reset_request,
 | 
						|
	.rst_assert = meson_reset_assert,
 | 
						|
	.rst_deassert = meson_reset_deassert,
 | 
						|
};
 | 
						|
 | 
						|
static const struct meson_reset_drvdata meson_gxbb_data = {
 | 
						|
	.reg_count = 8,
 | 
						|
	.level_offset = 0x7c,
 | 
						|
};
 | 
						|
 | 
						|
static const struct meson_reset_drvdata meson_a1_data = {
 | 
						|
	.reg_count = 3,
 | 
						|
	.level_offset = 0x40,
 | 
						|
};
 | 
						|
 | 
						|
static const struct udevice_id meson_reset_ids[] = {
 | 
						|
	{
 | 
						|
		.compatible = "amlogic,meson-gxbb-reset",
 | 
						|
		.data = (ulong)&meson_gxbb_data,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		.compatible = "amlogic,meson-axg-reset",
 | 
						|
		.data = (ulong)&meson_gxbb_data,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		.compatible = "amlogic,meson-a1-reset",
 | 
						|
		.data = (ulong)&meson_a1_data,
 | 
						|
	},
 | 
						|
	{ }
 | 
						|
};
 | 
						|
 | 
						|
static int meson_reset_probe(struct udevice *dev)
 | 
						|
{
 | 
						|
	struct meson_reset_priv *priv = dev_get_priv(dev);
 | 
						|
	priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev);
 | 
						|
 | 
						|
	return regmap_init_mem(dev_ofnode(dev), &priv->regmap);
 | 
						|
}
 | 
						|
 | 
						|
U_BOOT_DRIVER(meson_reset) = {
 | 
						|
	.name = "meson_reset",
 | 
						|
	.id = UCLASS_RESET,
 | 
						|
	.of_match = meson_reset_ids,
 | 
						|
	.probe = meson_reset_probe,
 | 
						|
	.ops = &meson_reset_ops,
 | 
						|
	.priv_auto	= sizeof(struct meson_reset_priv),
 | 
						|
};
 |