blob: 7dd92e07e1af1c36a8a344106e7dcde2e8df85a5 [file] [log] [blame]
Gabriel Fernandezafdc1ae2025-05-27 15:27:53 +02001// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
2/*
3 * Copyright (C) 2024, STMicroelectronics - All Rights Reserved
4 * Author(s): Gabriel Fernandez, <gabriel.fernandez@foss.st.com> for STMicroelectronics.
5 */
6
7#include <dm.h>
8#include <reset-uclass.h>
9#include <stm32-reset-core.h>
10#include <stm32_rcc.h>
11#include <dm/device_compat.h>
12#include <linux/iopoll.h>
13
14static int stm32_reset_update(struct reset_ctl *reset_ctl, bool status)
15{
16 struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev);
17 const struct stm32_reset_data *data = priv->data;
18 const struct stm32_reset_cfg *ptr_line;
19 fdt_addr_t addr;
20
21 assert(priv->data->get_reset_line);
22
23 ptr_line = priv->data->get_reset_line(reset_ctl);
24 if (!ptr_line)
25 return -EPERM;
26
27 addr = priv->base + ptr_line->offset;
28
29 dev_dbg(reset_ctl->dev, "reset id=%ld offset=0x%x bit=%d status=%d\n",
30 reset_ctl->id, ptr_line->offset, ptr_line->bit_idx, status);
31
32 status = ptr_line->inverted ^ status;
33
34 if (ptr_line->set_clr) {
35 if (!status)
36 addr += data->clear_offset;
37
38 writel(BIT(ptr_line->bit_idx), addr);
39
40 } else {
41 if (status)
42 setbits_le32(addr, BIT(ptr_line->bit_idx));
43 else
44 clrbits_le32(addr, BIT(ptr_line->bit_idx));
45 }
46
47 /* Check deassert */
48 if (!status) {
49 u32 reg;
50
51 return readl_poll_timeout(addr, reg,
52 !(reg & BIT(ptr_line->bit_idx)),
53 data->reset_us);
54 }
55
56 return 0;
57}
58
59static int stm32_reset_assert(struct reset_ctl *reset_ctl)
60{
61 return stm32_reset_update(reset_ctl, true);
62}
63
64static int stm32_reset_deassert(struct reset_ctl *reset_ctl)
65{
66 return stm32_reset_update(reset_ctl, false);
67}
68
69const struct reset_ops stm32_reset_ops = {
70 .rst_assert = stm32_reset_assert,
71 .rst_deassert = stm32_reset_deassert,
72};
73
74int stm32_reset_core_probe(struct udevice *dev,
75 const struct stm32_reset_data *data)
76{
77 struct stm32_reset_priv *priv = dev_get_priv(dev);
78
79 priv->base = dev_read_addr(dev);
80 if (priv->base == FDT_ADDR_T_NONE) {
81 /* for MFD, get address of parent */
82 priv->base = dev_read_addr(dev->parent);
83 if (priv->base == FDT_ADDR_T_NONE)
84 return -EINVAL;
85 }
86
87 priv->data = data;
88
89 assert(priv->data);
90
91 return 0;
92}