Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/drivers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ rsource "phye/Kconfig"
rsource "block/Kconfig"
rsource "nvme/Kconfig"
rsource "scsi/Kconfig"
rsource "reset/Kconfig"
rsource "virtio/Kconfig"
rsource "dma/Kconfig"
rsource "mfd/Kconfig"
Expand Down
82 changes: 82 additions & 0 deletions components/drivers/include/drivers/reset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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
*/

#ifndef __RESET_H__
#define __RESET_H__

#include <rthw.h>
#include <rtthread.h>
#include <drivers/ofw.h>

#define RT_RESET_CONTROLLER_OBJ_NAME "RSTC"

struct rt_reset_control_ops;

struct rt_reset_controller
{
struct rt_object parent;

rt_list_t rstc_nodes;

const char *name;
const struct rt_reset_control_ops *ops;

struct rt_ofw_node *ofw_node;
void *priv;

struct rt_spinlock spinlock;
};

struct rt_reset_control
{
rt_list_t list;

struct rt_reset_controller *rstcer;

int id;
const char *con_id;
rt_bool_t is_array;

void *priv;
};

struct rt_reset_control_ops
{
/*
* rt_ofw_cell_args return:
* args[0] = rstc.id
*/
rt_err_t (*ofw_parse)(struct rt_reset_control *rstc, struct rt_ofw_cell_args *args);
/* API */
rt_err_t (*reset)(struct rt_reset_control *rstc);
rt_err_t (*assert)(struct rt_reset_control *rstc);
rt_err_t (*deassert)(struct rt_reset_control *rstc);
int (*status)(struct rt_reset_control *rstc);
};

rt_err_t rt_reset_controller_register(struct rt_reset_controller *rstcer);
rt_err_t rt_reset_controller_unregister(struct rt_reset_controller *rstcer);

rt_err_t rt_reset_control_reset(struct rt_reset_control *rstc);
rt_err_t rt_reset_control_assert(struct rt_reset_control *rstc);
rt_err_t rt_reset_control_deassert(struct rt_reset_control *rstc);
int rt_reset_control_status(struct rt_reset_control *rstc);

rt_ssize_t rt_reset_control_get_count(struct rt_device *dev);
struct rt_reset_control *rt_reset_control_get_array(struct rt_device *dev);
struct rt_reset_control *rt_reset_control_get_by_index(struct rt_device *dev, int index);
struct rt_reset_control *rt_reset_control_get_by_name(struct rt_device *dev, const char *name);
void rt_reset_control_put(struct rt_reset_control *rstc);

struct rt_reset_control *rt_ofw_get_reset_control_array(struct rt_ofw_node *np);
struct rt_reset_control *rt_ofw_get_reset_control_by_index(struct rt_ofw_node *np, int index);
struct rt_reset_control *rt_ofw_get_reset_control_by_name(struct rt_ofw_node *np, const char *name);

#endif /* __RESET_H__ */
4 changes: 4 additions & 0 deletions components/drivers/include/rtdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ extern "C" {
#include "drivers/pic.h"
#endif /* RT_USING_PIC */

#ifdef RT_USING_RESET
#include "drivers/reset.h"
#endif /* RT_USING_RESET */

#ifdef RT_USING_SCSI
#include "drivers/scsi.h"
#endif /* RT_USING_SCSI */
Expand Down
3 changes: 3 additions & 0 deletions components/drivers/ofw/ofw.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ static const struct ofw_obj_cmp_list ofw_obj_cmp_list[] =
{
#ifdef RT_USING_CLK
{ "#clock-cells", RT_CLK_NODE_OBJ_NAME, sizeof(struct rt_clk_node) },
#endif
#ifdef RT_USING_RESET
{ "#reset-cells", RT_RESET_CONTROLLER_OBJ_NAME, sizeof(struct rt_reset_controller) },
#endif
{ "#power-domain-cells", RT_POWER_DOMAIN_PROXY_OBJ_NAME, sizeof(struct rt_dm_power_domain_proxy) },
{ "#power-domain-cells", RT_POWER_DOMAIN_OBJ_NAME, sizeof(struct rt_dm_power_domain) },
Expand Down
14 changes: 14 additions & 0 deletions components/drivers/reset/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
menuconfig RT_USING_RESET
bool "Using Reset Controller support"
depends on RT_USING_DM
depends on RT_USING_OFW
default n

config RT_RESET_SIMPLE
bool "Simple Reset Controller Driver"
depends on RT_USING_RESET
default n

if RT_USING_RESET
osource "$(SOC_DM_RESET_DIR)/Kconfig"
endif
18 changes: 18 additions & 0 deletions components/drivers/reset/SConscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from building import *

group = []

if not GetDepend(['RT_USING_RESET']):
Return('group')

cwd = GetCurrentDir()
CPPPATH = [cwd + '/../include']

src = ['reset.c']

if GetDepend(['RT_RESET_SIMPLE']):
src += ['reset-simple.c']

group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)

Return('group')
202 changes: 202 additions & 0 deletions components/drivers/reset/reset-simple.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* 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 "reset-simple.h"

struct reset_simple_data
{
rt_uint32_t reg_offset;
rt_bool_t active_low;
rt_bool_t status_active_low;
};

#define raw_to_reset_simple(raw) rt_container_of(raw, struct reset_simple, parent)

static rt_err_t reset_simple_update(struct reset_simple *rsts, int id, rt_bool_t assert)
{
rt_uint32_t reg;
rt_ubase_t level;
int reg_width = sizeof(rt_uint32_t);
int bank = id / (reg_width * 8);
int offset = id % (reg_width * 8);

level = rt_spin_lock_irqsave(&rsts->lock);

reg = HWREG32(rsts->mmio_base + (bank * reg_width));

if (assert ^ rsts->active_low)
{
reg |= RT_BIT(offset);
}
else
{
reg &= ~RT_BIT(offset);
}

HWREG32(rsts->mmio_base + (bank * reg_width)) = reg;

rt_spin_unlock_irqrestore(&rsts->lock, level);

return RT_EOK;
}

static rt_err_t reset_simple_assert(struct rt_reset_control *rstc)
{
struct reset_simple *rsts = raw_to_reset_simple(rstc);

return reset_simple_update(rsts, rstc->id, RT_TRUE);
}

static rt_err_t reset_simple_deassert(struct rt_reset_control *rstc)
{
struct reset_simple *rsts = raw_to_reset_simple(rstc);

return reset_simple_update(rsts, rstc->id, RT_FALSE);
}

static rt_err_t reset_simple_reset(struct rt_reset_control *rstc)
{
rt_err_t err;
struct reset_simple *rsts = raw_to_reset_simple(rstc);

if (!rsts->reset_us)
{
return -RT_ENOSYS;
}

if ((err = reset_simple_assert(rstc)))
{
return err;
}

rt_hw_us_delay(rsts->reset_us + (rsts->reset_us >> 1));

return reset_simple_deassert(rstc);
}

static int reset_simple_status(struct rt_reset_control *rstc)
{
rt_uint32_t value;
int reg_width = sizeof(rt_uint32_t);
int bank = rstc->id / (reg_width * 8);
int offset = rstc->id % (reg_width * 8);
struct reset_simple *rsts = raw_to_reset_simple(rstc);

value = HWREG32(rsts->mmio_base + (bank * reg_width));

return !(value & RT_BIT(offset)) ^ !rsts->status_active_low;
}

const struct rt_reset_control_ops reset_simple_ops =
{
.reset = reset_simple_reset,
.assert = reset_simple_assert,
.deassert = reset_simple_deassert,
.status = reset_simple_status,
};

static rt_err_t reset_simple_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
struct rt_reset_controller *rstcer;
struct rt_device *dev = &pdev->parent;
const struct reset_simple_data *rsts_data = pdev->id->data;
struct reset_simple *rsts = rt_calloc(1, sizeof(*rsts));

if (!rsts)
{
return -RT_ENOMEM;
}

rsts->mmio_base = rt_dm_dev_iomap(dev, 0);

if (!rsts->mmio_base)
{
err = -RT_EIO;
goto _fail;
}

rt_spin_lock_init(&rsts->lock);

rstcer = &rsts->parent;

rstcer->priv = rsts;
rstcer->ofw_node = dev->ofw_node;
rstcer->ops = &reset_simple_ops;

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

if (rsts_data)
{
rsts->mmio_base += rsts_data->reg_offset;
rsts->active_low = rsts_data->active_low;
rsts->status_active_low = rsts_data->status_active_low;
}

return RT_EOK;

_fail:
if (rsts->mmio_base)
{
rt_iounmap(rsts->mmio_base);
}

rt_free(rsts);

return err;
}

static const struct reset_simple_data reset_simple_socfpga =
{
.reg_offset = 0x20,
.status_active_low = RT_TRUE,
};

static const struct reset_simple_data reset_simple_active_low =
{
.active_low = RT_TRUE,
.status_active_low = RT_TRUE,
};

static const struct rt_ofw_node_id reset_simple_ofw_ids[] =
{
{ .compatible = "altr,stratix10-rst-mgr", .data = &reset_simple_socfpga },
{ .compatible = "st,stm32-rcc", },
{ .compatible = "allwinner,sun6i-a31-clock-reset", .data = &reset_simple_active_low },
{ .compatible = "zte,zx296718-reset", .data = &reset_simple_active_low },
{ .compatible = "aspeed,ast2400-lpc-reset" },
{ .compatible = "aspeed,ast2500-lpc-reset" },
{ .compatible = "aspeed,ast2600-lpc-reset" },
{ .compatible = "bitmain,bm1880-reset", .data = &reset_simple_active_low },
{ .compatible = "brcm,bcm4908-misc-pcie-reset", .data = &reset_simple_active_low },
{ .compatible = "snps,dw-high-reset" },
{ .compatible = "snps,dw-low-reset", .data = &reset_simple_active_low },
{ .compatible = "sophgo,sg2042-reset", .data = &reset_simple_active_low },
{ /* sentinel */ }
};

static struct rt_platform_driver reset_simple_driver =
{
.name = "reset-simple",
.ids = reset_simple_ofw_ids,

.probe = reset_simple_probe,
};

static int reset_simple_register(void)
{
rt_platform_driver_register(&reset_simple_driver);

return 0;
}
INIT_SUBSYS_EXPORT(reset_simple_register);
50 changes: 50 additions & 0 deletions components/drivers/reset/reset-simple.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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
*/

#ifndef __RESET_SIMPLE_H__
#define __RESET_SIMPLE_H__

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

struct reset_simple
{
struct rt_reset_controller parent;

void *mmio_base;

/*
* If true, bits are cleared to assert the reset.
* Otherwise, bits are set to assert the reset.
*/
rt_bool_t active_low;
/*
* If true, bits read back as cleared while the reset is asserted.
* Otherwise, bits read back as set while the reset is asserted.
*/
rt_bool_t status_active_low;

/*
* Minimum delay in microseconds needed that needs to be
* waited for between an assert and a deassert to reset the device.
* If multiple consumers with different delay
* requirements are connected to this controller, it must
* be the largest minimum delay. 0 means that such a delay is
* unknown and the reset operation is unsupported.
*/
rt_uint32_t reset_us;

/* protect registers during read-modify-write cycles */
struct rt_spinlock lock;
};

extern const struct rt_reset_control_ops reset_simple_ops;

#endif /* __RESET_SIMPLE_H__ */
Loading