cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

reset-meson.c (4050B)


      1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
      2/*
      3 * Amlogic Meson Reset Controller driver
      4 *
      5 * Copyright (c) 2016 BayLibre, SAS.
      6 * Author: Neil Armstrong <narmstrong@baylibre.com>
      7 */
      8#include <linux/err.h>
      9#include <linux/init.h>
     10#include <linux/io.h>
     11#include <linux/of.h>
     12#include <linux/module.h>
     13#include <linux/platform_device.h>
     14#include <linux/reset-controller.h>
     15#include <linux/slab.h>
     16#include <linux/types.h>
     17#include <linux/of_device.h>
     18
     19#define BITS_PER_REG	32
     20
     21struct meson_reset_param {
     22	int reg_count;
     23	int level_offset;
     24};
     25
     26struct meson_reset {
     27	void __iomem *reg_base;
     28	const struct meson_reset_param *param;
     29	struct reset_controller_dev rcdev;
     30	spinlock_t lock;
     31};
     32
     33static int meson_reset_reset(struct reset_controller_dev *rcdev,
     34			      unsigned long id)
     35{
     36	struct meson_reset *data =
     37		container_of(rcdev, struct meson_reset, rcdev);
     38	unsigned int bank = id / BITS_PER_REG;
     39	unsigned int offset = id % BITS_PER_REG;
     40	void __iomem *reg_addr = data->reg_base + (bank << 2);
     41
     42	writel(BIT(offset), reg_addr);
     43
     44	return 0;
     45}
     46
     47static int meson_reset_level(struct reset_controller_dev *rcdev,
     48			    unsigned long id, bool assert)
     49{
     50	struct meson_reset *data =
     51		container_of(rcdev, struct meson_reset, rcdev);
     52	unsigned int bank = id / BITS_PER_REG;
     53	unsigned int offset = id % BITS_PER_REG;
     54	void __iomem *reg_addr;
     55	unsigned long flags;
     56	u32 reg;
     57
     58	reg_addr = data->reg_base + data->param->level_offset + (bank << 2);
     59
     60	spin_lock_irqsave(&data->lock, flags);
     61
     62	reg = readl(reg_addr);
     63	if (assert)
     64		writel(reg & ~BIT(offset), reg_addr);
     65	else
     66		writel(reg | BIT(offset), reg_addr);
     67
     68	spin_unlock_irqrestore(&data->lock, flags);
     69
     70	return 0;
     71}
     72
     73static int meson_reset_assert(struct reset_controller_dev *rcdev,
     74			      unsigned long id)
     75{
     76	return meson_reset_level(rcdev, id, true);
     77}
     78
     79static int meson_reset_deassert(struct reset_controller_dev *rcdev,
     80				unsigned long id)
     81{
     82	return meson_reset_level(rcdev, id, false);
     83}
     84
     85static const struct reset_control_ops meson_reset_ops = {
     86	.reset		= meson_reset_reset,
     87	.assert		= meson_reset_assert,
     88	.deassert	= meson_reset_deassert,
     89};
     90
     91static const struct meson_reset_param meson8b_param = {
     92	.reg_count	= 8,
     93	.level_offset	= 0x7c,
     94};
     95
     96static const struct meson_reset_param meson_a1_param = {
     97	.reg_count	= 3,
     98	.level_offset	= 0x40,
     99};
    100
    101static const struct meson_reset_param meson_s4_param = {
    102	.reg_count	= 6,
    103	.level_offset	= 0x40,
    104};
    105
    106static const struct of_device_id meson_reset_dt_ids[] = {
    107	 { .compatible = "amlogic,meson8b-reset",    .data = &meson8b_param},
    108	 { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param},
    109	 { .compatible = "amlogic,meson-axg-reset",  .data = &meson8b_param},
    110	 { .compatible = "amlogic,meson-a1-reset",   .data = &meson_a1_param},
    111	 { .compatible = "amlogic,meson-s4-reset",   .data = &meson_s4_param},
    112	 { /* sentinel */ },
    113};
    114MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
    115
    116static int meson_reset_probe(struct platform_device *pdev)
    117{
    118	struct meson_reset *data;
    119	struct resource *res;
    120
    121	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    122	if (!data)
    123		return -ENOMEM;
    124
    125	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    126	data->reg_base = devm_ioremap_resource(&pdev->dev, res);
    127	if (IS_ERR(data->reg_base))
    128		return PTR_ERR(data->reg_base);
    129
    130	data->param = of_device_get_match_data(&pdev->dev);
    131	if (!data->param)
    132		return -ENODEV;
    133
    134	platform_set_drvdata(pdev, data);
    135
    136	spin_lock_init(&data->lock);
    137
    138	data->rcdev.owner = THIS_MODULE;
    139	data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG;
    140	data->rcdev.ops = &meson_reset_ops;
    141	data->rcdev.of_node = pdev->dev.of_node;
    142
    143	return devm_reset_controller_register(&pdev->dev, &data->rcdev);
    144}
    145
    146static struct platform_driver meson_reset_driver = {
    147	.probe	= meson_reset_probe,
    148	.driver = {
    149		.name		= "meson_reset",
    150		.of_match_table	= meson_reset_dt_ids,
    151	},
    152};
    153module_platform_driver(meson_reset_driver);
    154
    155MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
    156MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
    157MODULE_LICENSE("Dual BSD/GPL");