summaryrefslogtreecommitdiff
path: root/bsp/raspberry-pi/dm/reset/reset-brcmstb-rescal.c
blob: 9a2e8cb25494e99a42fa688015979dbf9de2b1d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-11-26     GuEe-GUI     first version
 */

#include <rtthread.h>
#include <rtdevice.h>

#define DBG_TAG "reset.brcmstb-rescal"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#include <cpuport.h>

#define BRCM_RESCAL_START           0x0
#define   BRCM_RESCAL_START_BIT     RT_BIT(0)
#define BRCM_RESCAL_CTRL            0x4
#define BRCM_RESCAL_STATUS          0x8
#define   BRCM_RESCAL_STATUS_BIT    RT_BIT(0)

struct brcm_rescal_reset
{
    struct rt_reset_controller parent;

    void *regs;
};

static rt_err_t brcm_rescal_reset_ofw_parse(struct rt_reset_control *rstc, struct rt_ofw_cell_args *args)
{
    args->args[0] = 0;

    return RT_EOK;
}

static rt_err_t brcm_rescal_reset_reset(struct rt_reset_control *rstc)
{
    rt_uint32_t reg;
    struct brcm_rescal_reset *brrst = rstc->rstcer->priv;

    reg = HWREG32(brrst->regs + BRCM_RESCAL_START);
    HWREG32(brrst->regs + BRCM_RESCAL_START) = reg | BRCM_RESCAL_START_BIT;
    reg = HWREG32(brrst->regs + BRCM_RESCAL_START);

    if (!(reg & BRCM_RESCAL_START_BIT))
    {
        LOG_E("Failed to start SATA/PCIe rescal");

        return -RT_EIO;
    }

    for (rt_uint32_t time = 0; time < 1000; time += 100)
    {
        reg = HWREG32(brrst->regs + BRCM_RESCAL_STATUS);

        if (reg & BRCM_RESCAL_STATUS_BIT)
        {
            goto _status_ok;
        }

        rt_hw_us_delay(100);

        rt_hw_cpu_relax();
    }

    LOG_E("Time out on SATA/PCIe rescal");

    return -RT_ETIMEOUT;

_status_ok:
    reg = HWREG32(brrst->regs + BRCM_RESCAL_START);
    HWREG32(brrst->regs + BRCM_RESCAL_START) = reg & ~BRCM_RESCAL_START_BIT;

    LOG_D("SATA/PCIe rescal success");

    return RT_EOK;
}

static rt_err_t brcm_rescal_reset_assert(struct rt_reset_control *rstc)
{
    return RT_EOK;
}

static rt_err_t brcm_rescal_reset_deassert(struct rt_reset_control *rstc)
{
    return brcm_rescal_reset_reset(rstc);
}

const static struct rt_reset_control_ops brcm_rescal_reset_ops =
{
    .ofw_parse = brcm_rescal_reset_ofw_parse,
    .reset = brcm_rescal_reset_reset,
    .assert = brcm_rescal_reset_assert,
    .deassert = brcm_rescal_reset_deassert,
};

static rt_err_t brcm_rescal_reset_probe(struct rt_platform_device *pdev)
{
    rt_err_t err;
    struct rt_reset_controller *rstcer;
    struct rt_device *dev = &pdev->parent;
    struct brcm_rescal_reset *brrst = rt_calloc(1, sizeof(*brrst));

    if (!brrst)
    {
        return -RT_ENOMEM;
    }

    brrst->regs = rt_dm_dev_iomap(dev, 0);

    if (!brrst->regs)
    {
        err = -RT_EIO;
        goto _fail;
    }

    rstcer = &brrst->parent;

    rstcer->priv = brrst;
    rstcer->ofw_node = dev->ofw_node;
    rstcer->ops = &brcm_rescal_reset_ops;

    if ((err = rt_reset_controller_register(rstcer)))
    {
        goto _fail;
    }

    return RT_EOK;

_fail:
    if (brrst->regs)
    {
        rt_iounmap(brrst->regs);
    }

    rt_free(brrst);

    return err;
}

static const struct rt_ofw_node_id brcm_rescal_reset_ofw_ids[] =
{
    { .compatible = "brcm,bcm7216-pcie-sata-rescal" },
    { /* sentinel */ }
};

static struct rt_platform_driver brcm_rescal_reset_driver =
{
    .name = "reset-brcm-rescal",
    .ids = brcm_rescal_reset_ofw_ids,

    .probe = brcm_rescal_reset_probe,
};

static int brcm_rescal_reset_register(void)
{
    rt_platform_driver_register(&brcm_rescal_reset_driver);

    return 0;
}
INIT_SUBSYS_EXPORT(brcm_rescal_reset_register);