1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Amlogic Meson Reset Controller driver 4 * 5 * Copyright (c) 2018 BayLibre, SAS. 6 * Author: Neil Armstrong <narmstrong@baylibre.com> 7 */ 8 9#include <common.h> 10#include <dm.h> 11#include <log.h> 12#include <malloc.h> 13#include <reset-uclass.h> 14#include <regmap.h> 15#include <linux/bitops.h> 16#include <linux/delay.h> 17 18#define BITS_PER_REG 32 19 20struct meson_reset_drvdata { 21 unsigned int reg_count; 22 unsigned int level_offset; 23}; 24 25struct meson_reset_priv { 26 struct regmap *regmap; 27 struct meson_reset_drvdata *drvdata; 28}; 29 30static int meson_reset_request(struct reset_ctl *reset_ctl) 31{ 32 struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); 33 struct meson_reset_drvdata *data = priv->drvdata; 34 35 if (reset_ctl->id > (data->reg_count * BITS_PER_REG)) 36 return -EINVAL; 37 38 return 0; 39} 40 41static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) 42{ 43 struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); 44 struct meson_reset_drvdata *data = priv->drvdata; 45 uint bank = reset_ctl->id / BITS_PER_REG; 46 uint offset = reset_ctl->id % BITS_PER_REG; 47 uint reg_offset = data->level_offset + (bank << 2); 48 uint val; 49 50 regmap_read(priv->regmap, reg_offset, &val); 51 if (assert) 52 val &= ~BIT(offset); 53 else 54 val |= BIT(offset); 55 regmap_write(priv->regmap, reg_offset, val); 56 57 return 0; 58} 59 60static int meson_reset_assert(struct reset_ctl *reset_ctl) 61{ 62 return meson_reset_level(reset_ctl, true); 63} 64 65static int meson_reset_deassert(struct reset_ctl *reset_ctl) 66{ 67 return meson_reset_level(reset_ctl, false); 68} 69 70struct reset_ops meson_reset_ops = { 71 .request = meson_reset_request, 72 .rst_assert = meson_reset_assert, 73 .rst_deassert = meson_reset_deassert, 74}; 75 76static const struct meson_reset_drvdata meson_gxbb_data = { 77 .reg_count = 8, 78 .level_offset = 0x7c, 79}; 80 81static const struct meson_reset_drvdata meson_a1_data = { 82 .reg_count = 3, 83 .level_offset = 0x40, 84}; 85 86static const struct udevice_id meson_reset_ids[] = { 87 { 88 .compatible = "amlogic,meson-gxbb-reset", 89 .data = (ulong)&meson_gxbb_data, 90 }, 91 { 92 .compatible = "amlogic,meson-axg-reset", 93 .data = (ulong)&meson_gxbb_data, 94 }, 95 { 96 .compatible = "amlogic,meson-a1-reset", 97 .data = (ulong)&meson_a1_data, 98 }, 99 { } 100}; 101 102static int meson_reset_probe(struct udevice *dev) 103{ 104 struct meson_reset_priv *priv = dev_get_priv(dev); 105 priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev); 106 107 return regmap_init_mem(dev_ofnode(dev), &priv->regmap); 108} 109 110U_BOOT_DRIVER(meson_reset) = { 111 .name = "meson_reset", 112 .id = UCLASS_RESET, 113 .of_match = meson_reset_ids, 114 .probe = meson_reset_probe, 115 .ops = &meson_reset_ops, 116 .priv_auto = sizeof(struct meson_reset_priv), 117}; 118