Reset controller changes for v4.9

- add reset controller driver Kconfig options,
   allow building drivers with COMPILE_TEST
 - add reset controller driver for UniPhier SoCs
 - add reset controller driver for STM32 MCUs
 - simplify SoCFPGA reset controller driver a bit
 -----BEGIN PGP SIGNATURE-----
 
 iQI0BAABCAAeBQJXxf2tFxxwLnphYmVsQHBlbmd1dHJvbml4LmRlAAoJEFDCiBxw
 nmDrOAEP/RN9LSv7zeCeVEBNJZp699sHRTW8wyJAhtF9u20Ab4+UZzM1hD/Wm8mF
 cK5bo/q68veKgQucRwIV9S/rid8+xqHBVxlke7YAe9TcZ8jypVM/JJTJcf8v/Wfy
 RhpcAw+qicviSovh/BtHn+jbhk3TMiLq0LRvjALa1HSqz1WMquT6g0Avc7LFGXei
 qFnClT5w0PPi2/vc/mrd++NG8tUwsQA9Lh4nmRDZprX6HvKPGk2RlW11KHpSJI/F
 yVh2JF0zKq2xVadqhIwToRb00N+TonuIxNl/+zM6NQMWOr2arxJSSPSNnB6pA3j5
 R5kXq9DFIh3bcFHz6hNNXiiCKHjdPdP88foR48Bj5gK4jhUHQcOWWGzKwc7Vtc9V
 gaRy50AMX1NZwigh1an6u2CjaRrwmHnO0qoYcNuSxh8Pl6yxmmM9cZEvGqsQXWYN
 pWibfbEWbGsKdy4APW6RUQDxQGcJwHRtLvJmwQCg5b4kZyhvhuRAA4LpA/Vkodwv
 dZI7xyVqsDyL7BsGus3EkaOKpX0hvHuvMJdlc13Gba5KFoUOXxN9FeRuySchx7ES
 6eJI/5S0z/zEbk4wHesUudLvgrhCOD2Z1pd+76ZNPLUS0YXdi5q3tAIUNf2JWUdb
 pnNZQRHDbxJjHW5mUY2RL0iDD1rtb2GgIZ+bUkNvuRoGmFiNMlH/
 =GUEB
 -----END PGP SIGNATURE-----

Merge tag 'reset-for-4.9' of git://git.pengutronix.de/git/pza/linux into next/drivers

Merge "Reset controller changes for v4.9" from Philipp Zabel:

- add reset controller driver Kconfig options,
  allow building drivers with COMPILE_TEST
- add reset controller driver for UniPhier SoCs
- add reset controller driver for STM32 MCUs
- simplify SoCFPGA reset controller driver a bit

* tag 'reset-for-4.9' of git://git.pengutronix.de/git/pza/linux:
  reset: hi6220: allow to compile test driver on other architectures
  reset: zynq: add driver Kconfig option
  reset: sunxi: add driver Kconfig option
  reset: stm32: add driver Kconfig option
  reset: socfpga: add driver Kconfig option
  reset: pistachio: add driver Kconfig option
  reset: meson: add driver Kconfig option
  reset: lpc18xx: add driver Kconfig option
  reset: berlin: add driver Kconfig option
  reset: ath79: add driver Kconfig option
  reset: ath79: add missing include
  reset: warn on invalid input to reset_control_reset/assert/deassert/status
  reset: uniphier: add reset controller driver for UniPhier SoCs
  ARM: dts: stm32f429: add missing #reset-cells of rcc
  drivers: reset: Add STM32 reset driver
  dt-bindings: Document the STM32 reset bindings
  dt-bindings: mfd: Add STM32F4 RCC numeric constants into DT include file
  reset: socfpga: no need to store modrst_offset
This commit is contained in:
Arnd Bergmann 2016-09-02 18:29:04 +02:00
commit 7d3ef43f1f
14 changed files with 881 additions and 28 deletions

View file

@ -1,16 +1,16 @@
STMicroelectronics STM32 Reset and Clock Controller
===================================================
The RCC IP is both a reset and a clock controller. This documentation only
describes the clock part.
The RCC IP is both a reset and a clock controller.
Please also refer to clock-bindings.txt in this directory for common clock
controller binding usage.
Please refer to clock-bindings.txt for common clock controller binding usage.
Please also refer to reset.txt for common reset controller binding usage.
Required properties:
- compatible: Should be "st,stm32f42xx-rcc"
- reg: should be register base and length as documented in the
datasheet
- #reset-cells: 1, see below
- #clock-cells: 2, device nodes should specify the clock in their "clocks"
property, containing a phandle to the clock device node, an index selecting
between gated clocks and other clocks and an index specifying the clock to
@ -19,6 +19,7 @@ Required properties:
Example:
rcc: rcc@40023800 {
#reset-cells = <1>;
#clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
@ -35,16 +36,23 @@ from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
To simplify the usage and to share bit definition with the reset and clock
drivers of the RCC IP, macros are available to generate the index in
human-readble format.
For STM32F4 series, the macro are available here:
- include/dt-bindings/mfd/stm32f4-rcc.h
Example:
/* Gated clock, AHB1 bit 0 (GPIOA) */
... {
clocks = <&rcc 0 0>
clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)>
};
/* Gated clock, AHB2 bit 4 (CRYP) */
... {
clocks = <&rcc 0 36>
clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)>
};
Specifying other clocks
@ -61,5 +69,25 @@ Example:
/* Misc clock, FCLK */
... {
clocks = <&rcc 1 1>
clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)>
};
Specifying softreset control of devices
=======================================
Device nodes should specify the reset channel required in their "resets"
property, containing a phandle to the reset device node and an index specifying
which channel to use.
The index is the bit number within the RCC registers bank, starting from RCC
base address.
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
Where bit_offset is the bit offset within the register.
For example, for CRC reset:
crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140
example:
timer2 {
resets = <&rcc STM32F4_APB1_RESET(TIM2)>;
};

View file

@ -0,0 +1,6 @@
STMicroelectronics STM32 Peripheral Reset Controller
====================================================
The RCC IP is both a reset and a clock controller.
Please see Documentation/devicetree/bindings/clock/st,stm32-rcc.txt

View file

@ -0,0 +1,93 @@
UniPhier reset controller
System reset
------------
Required properties:
- compatible: should be one of the following:
"socionext,uniphier-sld3-reset" - for PH1-sLD3 SoC.
"socionext,uniphier-ld4-reset" - for PH1-LD4 SoC.
"socionext,uniphier-pro4-reset" - for PH1-Pro4 SoC.
"socionext,uniphier-sld8-reset" - for PH1-sLD8 SoC.
"socionext,uniphier-pro5-reset" - for PH1-Pro5 SoC.
"socionext,uniphier-pxs2-reset" - for ProXstream2/PH1-LD6b SoC.
"socionext,uniphier-ld11-reset" - for PH1-LD11 SoC.
"socionext,uniphier-ld20-reset" - for PH1-LD20 SoC.
- #reset-cells: should be 1.
Example:
sysctrl@61840000 {
compatible = "socionext,uniphier-ld20-sysctrl",
"simple-mfd", "syscon";
reg = <0x61840000 0x4000>;
reset {
compatible = "socionext,uniphier-ld20-reset";
#reset-cells = <1>;
};
other nodes ...
};
Media I/O (MIO) reset
---------------------
Required properties:
- compatible: should be one of the following:
"socionext,uniphier-sld3-mio-reset" - for PH1-sLD3 SoC.
"socionext,uniphier-ld4-mio-reset" - for PH1-LD4 SoC.
"socionext,uniphier-pro4-mio-reset" - for PH1-Pro4 SoC.
"socionext,uniphier-sld8-mio-reset" - for PH1-sLD8 SoC.
"socionext,uniphier-pro5-mio-reset" - for PH1-Pro5 SoC.
"socionext,uniphier-pxs2-mio-reset" - for ProXstream2/PH1-LD6b SoC.
"socionext,uniphier-ld11-mio-reset" - for PH1-LD11 SoC.
"socionext,uniphier-ld20-mio-reset" - for PH1-LD20 SoC.
- #reset-cells: should be 1.
Example:
mioctrl@59810000 {
compatible = "socionext,uniphier-ld20-mioctrl",
"simple-mfd", "syscon";
reg = <0x59810000 0x800>;
reset {
compatible = "socionext,uniphier-ld20-mio-reset";
#reset-cells = <1>;
};
other nodes ...
};
Peripheral reset
----------------
Required properties:
- compatible: should be one of the following:
"socionext,uniphier-ld4-peri-reset" - for PH1-LD4 SoC.
"socionext,uniphier-pro4-peri-reset" - for PH1-Pro4 SoC.
"socionext,uniphier-sld8-peri-reset" - for PH1-sLD8 SoC.
"socionext,uniphier-pro5-peri-reset" - for PH1-Pro5 SoC.
"socionext,uniphier-pxs2-peri-reset" - for ProXstream2/PH1-LD6b SoC.
"socionext,uniphier-ld11-peri-reset" - for PH1-LD11 SoC.
"socionext,uniphier-ld20-peri-reset" - for PH1-LD20 SoC.
- #reset-cells: should be 1.
Example:
perictrl@59820000 {
compatible = "socionext,uniphier-ld20-perictrl",
"simple-mfd", "syscon";
reg = <0x59820000 0x200>;
reset {
compatible = "socionext,uniphier-ld20-peri-reset";
#reset-cells = <1>;
};
other nodes ...
};

View file

@ -1840,6 +1840,7 @@ F: arch/arm64/boot/dts/socionext/
F: drivers/bus/uniphier-system-bus.c
F: drivers/i2c/busses/i2c-uniphier*
F: drivers/pinctrl/uniphier/
F: drivers/reset/reset-uniphier.c
F: drivers/tty/serial/8250/8250_uniphier.c
N: uniphier

View file

@ -326,6 +326,7 @@ pins {
};
rcc: rcc@40023810 {
#reset-cells = <1>;
#clock-cells = <2>;
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;

View file

@ -14,9 +14,58 @@ menuconfig RESET_CONTROLLER
if RESET_CONTROLLER
config RESET_ATH79
bool "AR71xx Reset Driver" if COMPILE_TEST
default ATH79
help
This enables the ATH79 reset controller driver that supports the
AR71xx SoC reset controller.
config RESET_BERLIN
bool "Berlin Reset Driver" if COMPILE_TEST
default ARCH_BERLIN
help
This enables the reset controller driver for Marvell Berlin SoCs.
config RESET_LPC18XX
bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST
default ARCH_LPC18XX
help
This enables the reset controller driver for NXP LPC18xx/43xx SoCs.
config RESET_MESON
bool "Meson Reset Driver" if COMPILE_TEST
default ARCH_MESON
help
This enables the reset driver for Amlogic Meson SoCs.
config RESET_OXNAS
bool
config RESET_PISTACHIO
bool "Pistachio Reset Driver" if COMPILE_TEST
default MACH_PISTACHIO
help
This enables the reset driver for ImgTec Pistachio SoCs.
config RESET_SOCFPGA
bool "SoCFPGA Reset Driver" if COMPILE_TEST
default ARCH_SOCFPGA
help
This enables the reset controller driver for Altera SoCFPGAs.
config RESET_STM32
bool "STM32 Reset Driver" if COMPILE_TEST
default ARCH_STM32
help
This enables the RCC reset controller driver for STM32 MCUs.
config RESET_SUNXI
bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
default ARCH_SUNXI
help
This enables the reset driver for Allwinner SoCs.
config TI_SYSCON_RESET
tristate "TI SYSCON Reset Driver"
depends on HAS_IOMEM
@ -27,6 +76,22 @@ config TI_SYSCON_RESET
you wish to use the reset framework for such memory-mapped devices,
say Y here. Otherwise, say N.
config RESET_UNIPHIER
tristate "Reset controller driver for UniPhier SoCs"
depends on ARCH_UNIPHIER || COMPILE_TEST
depends on OF && MFD_SYSCON
default ARCH_UNIPHIER
help
Support for reset controllers on UniPhier SoCs.
Say Y if you want to control reset signals provided by System Control
block, Media I/O block, Peripheral Block.
config RESET_ZYNQ
bool "ZYNQ Reset Driver" if COMPILE_TEST
default ARCH_ZYNQ
help
This enables the reset controller driver for Xilinx Zynq SoCs.
source "drivers/reset/sti/Kconfig"
source "drivers/reset/hisilicon/Kconfig"

View file

@ -1,13 +1,15 @@
obj-y += core.o
obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_ARCH_MESON) += reset-meson.o
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
obj-y += hisilicon/
obj-$(CONFIG_ARCH_STI) += sti/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o
obj-$(CONFIG_ATH79) += reset-ath79.o
obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_STM32) += reset-stm32.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o

View file

@ -138,7 +138,8 @@ EXPORT_SYMBOL_GPL(devm_reset_controller_register);
*/
int reset_control_reset(struct reset_control *rstc)
{
if (WARN_ON(rstc->shared))
if (WARN_ON(IS_ERR_OR_NULL(rstc)) ||
WARN_ON(rstc->shared))
return -EINVAL;
if (rstc->rcdev->ops->reset)
@ -161,6 +162,9 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
*/
int reset_control_assert(struct reset_control *rstc)
{
if (WARN_ON(IS_ERR_OR_NULL(rstc)))
return -EINVAL;
if (!rstc->rcdev->ops->assert)
return -ENOTSUPP;
@ -184,6 +188,9 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
*/
int reset_control_deassert(struct reset_control *rstc)
{
if (WARN_ON(IS_ERR_OR_NULL(rstc)))
return -EINVAL;
if (!rstc->rcdev->ops->deassert)
return -ENOTSUPP;
@ -204,6 +211,9 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
*/
int reset_control_status(struct reset_control *rstc)
{
if (WARN_ON(IS_ERR_OR_NULL(rstc)))
return -EINVAL;
if (rstc->rcdev->ops->status)
return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);

View file

@ -1,5 +1,6 @@
config COMMON_RESET_HI6220
tristate "Hi6220 Reset Driver"
depends on (ARCH_HISI && RESET_CONTROLLER)
depends on ARCH_HISI || COMPILE_TEST
default ARCH_HISI
help
Build the Hisilicon Hi6220 reset driver.

View file

@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>

View file

@ -28,7 +28,6 @@
struct socfpga_reset_data {
spinlock_t lock;
void __iomem *membase;
u32 modrst_offset;
struct reset_controller_dev rcdev;
};
@ -45,9 +44,8 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev,
spin_lock_irqsave(&data->lock, flags);
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
writel(reg | BIT(offset), data->membase + data->modrst_offset +
(bank * NR_BANKS));
reg = readl(data->membase + (bank * NR_BANKS));
writel(reg | BIT(offset), data->membase + (bank * NR_BANKS));
spin_unlock_irqrestore(&data->lock, flags);
return 0;
@ -67,9 +65,8 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
spin_lock_irqsave(&data->lock, flags);
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
writel(reg & ~BIT(offset), data->membase + data->modrst_offset +
(bank * NR_BANKS));
reg = readl(data->membase + (bank * NR_BANKS));
writel(reg & ~BIT(offset), data->membase + (bank * NR_BANKS));
spin_unlock_irqrestore(&data->lock, flags);
@ -85,7 +82,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev,
int offset = id % BITS_PER_LONG;
u32 reg;
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
reg = readl(data->membase + (bank * NR_BANKS));
return !(reg & BIT(offset));
}
@ -102,6 +99,7 @@ static int socfpga_reset_probe(struct platform_device *pdev)
struct resource *res;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
u32 modrst_offset;
/*
* The binding was mainlined without the required property.
@ -122,10 +120,11 @@ static int socfpga_reset_probe(struct platform_device *pdev)
if (IS_ERR(data->membase))
return PTR_ERR(data->membase);
if (of_property_read_u32(np, "altr,modrst-offset", &data->modrst_offset)) {
if (of_property_read_u32(np, "altr,modrst-offset", &modrst_offset)) {
dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
data->modrst_offset = 0x10;
modrst_offset = 0x10;
}
data->membase += modrst_offset;
spin_lock_init(&data->lock);

108
drivers/reset/reset-stm32.c Normal file
View file

@ -0,0 +1,108 @@
/*
* Copyright (C) Maxime Coquelin 2015
* Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
* License terms: GNU General Public License (GPL), version 2
*
* Heavily based on sunxi driver from Maxime Ripard.
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
struct stm32_reset_data {
spinlock_t lock;
void __iomem *membase;
struct reset_controller_dev rcdev;
};
static int stm32_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct stm32_reset_data *data = container_of(rcdev,
struct stm32_reset_data,
rcdev);
int bank = id / BITS_PER_LONG;
int offset = id % BITS_PER_LONG;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&data->lock, flags);
reg = readl(data->membase + (bank * 4));
writel(reg | BIT(offset), data->membase + (bank * 4));
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}
static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct stm32_reset_data *data = container_of(rcdev,
struct stm32_reset_data,
rcdev);
int bank = id / BITS_PER_LONG;
int offset = id % BITS_PER_LONG;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&data->lock, flags);
reg = readl(data->membase + (bank * 4));
writel(reg & ~BIT(offset), data->membase + (bank * 4));
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}
static const struct reset_control_ops stm32_reset_ops = {
.assert = stm32_reset_assert,
.deassert = stm32_reset_deassert,
};
static const struct of_device_id stm32_reset_dt_ids[] = {
{ .compatible = "st,stm32-rcc", },
{ /* sentinel */ },
};
static int stm32_reset_probe(struct platform_device *pdev)
{
struct stm32_reset_data *data;
struct resource *res;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->membase))
return PTR_ERR(data->membase);
spin_lock_init(&data->lock);
data->rcdev.owner = THIS_MODULE;
data->rcdev.nr_resets = resource_size(res) * 8;
data->rcdev.ops = &stm32_reset_ops;
data->rcdev.of_node = pdev->dev.of_node;
return devm_reset_controller_register(&pdev->dev, &data->rcdev);
}
static struct platform_driver stm32_reset_driver = {
.probe = stm32_reset_probe,
.driver = {
.name = "stm32-rcc-reset",
.of_match_table = stm32_reset_dt_ids,
},
};
builtin_platform_driver(stm32_reset_driver);

View file

@ -0,0 +1,440 @@
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
struct uniphier_reset_data {
unsigned int id;
unsigned int reg;
unsigned int bit;
unsigned int flags;
#define UNIPHIER_RESET_ACTIVE_LOW BIT(0)
};
#define UNIPHIER_RESET_ID_END (unsigned int)(-1)
#define UNIPHIER_RESET_END \
{ .id = UNIPHIER_RESET_ID_END }
#define UNIPHIER_RESET(_id, _reg, _bit) \
{ \
.id = (_id), \
.reg = (_reg), \
.bit = (_bit), \
}
#define UNIPHIER_RESETX(_id, _reg, _bit) \
{ \
.id = (_id), \
.reg = (_reg), \
.bit = (_bit), \
.flags = UNIPHIER_RESET_ACTIVE_LOW, \
}
/* System reset data */
#define UNIPHIER_SLD3_SYS_RESET_STDMAC(id) \
UNIPHIER_RESETX((id), 0x2000, 10)
#define UNIPHIER_LD11_SYS_RESET_STDMAC(id) \
UNIPHIER_RESETX((id), 0x200c, 8)
#define UNIPHIER_PRO4_SYS_RESET_GIO(id) \
UNIPHIER_RESETX((id), 0x2000, 6)
#define UNIPHIER_LD20_SYS_RESET_GIO(id) \
UNIPHIER_RESETX((id), 0x200c, 5)
#define UNIPHIER_PRO4_SYS_RESET_USB3(id, ch) \
UNIPHIER_RESETX((id), 0x2000 + 0x4 * (ch), 17)
const struct uniphier_reset_data uniphier_sld3_sys_reset_data[] = {
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* Ether, HSC, MIO */
UNIPHIER_RESET_END,
};
const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, MIO, RLE */
UNIPHIER_PRO4_SYS_RESET_GIO(12), /* Ether, SATA, USB3 */
UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
UNIPHIER_RESET_END,
};
const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = {
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC */
UNIPHIER_PRO4_SYS_RESET_GIO(12), /* PCIe, USB3 */
UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
UNIPHIER_RESET_END,
};
const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = {
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, RLE */
UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
UNIPHIER_RESETX(16, 0x2014, 4), /* USB30-PHY0 */
UNIPHIER_RESETX(17, 0x2014, 0), /* USB30-PHY1 */
UNIPHIER_RESETX(18, 0x2014, 2), /* USB30-PHY2 */
UNIPHIER_RESETX(20, 0x2014, 5), /* USB31-PHY0 */
UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */
UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */
UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */
UNIPHIER_RESET_END,
};
const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = {
UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC, MIO */
UNIPHIER_RESET_END,
};
const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC */
UNIPHIER_LD20_SYS_RESET_GIO(12), /* PCIe, USB3 */
UNIPHIER_RESETX(16, 0x200c, 12), /* USB30-PHY0 */
UNIPHIER_RESETX(17, 0x200c, 13), /* USB30-PHY1 */
UNIPHIER_RESETX(18, 0x200c, 14), /* USB30-PHY2 */
UNIPHIER_RESETX(19, 0x200c, 15), /* USB30-PHY3 */
UNIPHIER_RESET_END,
};
/* Media I/O reset data */
#define UNIPHIER_MIO_RESET_SD(id, ch) \
UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 0)
#define UNIPHIER_MIO_RESET_SD_BRIDGE(id, ch) \
UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 26)
#define UNIPHIER_MIO_RESET_EMMC_HW_RESET(id, ch) \
UNIPHIER_RESETX((id), 0x80 + 0x200 * (ch), 0)
#define UNIPHIER_MIO_RESET_USB2(id, ch) \
UNIPHIER_RESETX((id), 0x114 + 0x200 * (ch), 0)
#define UNIPHIER_MIO_RESET_USB2_BRIDGE(id, ch) \
UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 24)
#define UNIPHIER_MIO_RESET_DMAC(id) \
UNIPHIER_RESETX((id), 0x110, 17)
const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = {
UNIPHIER_MIO_RESET_SD(0, 0),
UNIPHIER_MIO_RESET_SD(1, 1),
UNIPHIER_MIO_RESET_SD(2, 2),
UNIPHIER_MIO_RESET_SD_BRIDGE(3, 0),
UNIPHIER_MIO_RESET_SD_BRIDGE(4, 1),
UNIPHIER_MIO_RESET_SD_BRIDGE(5, 2),
UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
UNIPHIER_MIO_RESET_DMAC(7),
UNIPHIER_MIO_RESET_USB2(8, 0),
UNIPHIER_MIO_RESET_USB2(9, 1),
UNIPHIER_MIO_RESET_USB2(10, 2),
UNIPHIER_MIO_RESET_USB2(11, 3),
UNIPHIER_MIO_RESET_USB2_BRIDGE(12, 0),
UNIPHIER_MIO_RESET_USB2_BRIDGE(13, 1),
UNIPHIER_MIO_RESET_USB2_BRIDGE(14, 2),
UNIPHIER_MIO_RESET_USB2_BRIDGE(15, 3),
UNIPHIER_RESET_END,
};
const struct uniphier_reset_data uniphier_pro5_mio_reset_data[] = {
UNIPHIER_MIO_RESET_SD(0, 0),
UNIPHIER_MIO_RESET_SD(1, 1),
UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
UNIPHIER_RESET_END,
};
/* Peripheral reset data */
#define UNIPHIER_PERI_RESET_UART(id, ch) \
UNIPHIER_RESETX((id), 0x114, 19 + (ch))
#define UNIPHIER_PERI_RESET_I2C(id, ch) \
UNIPHIER_RESETX((id), 0x114, 5 + (ch))
#define UNIPHIER_PERI_RESET_FI2C(id, ch) \
UNIPHIER_RESETX((id), 0x114, 24 + (ch))
const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
UNIPHIER_PERI_RESET_UART(0, 0),
UNIPHIER_PERI_RESET_UART(1, 1),
UNIPHIER_PERI_RESET_UART(2, 2),
UNIPHIER_PERI_RESET_UART(3, 3),
UNIPHIER_PERI_RESET_I2C(4, 0),
UNIPHIER_PERI_RESET_I2C(5, 1),
UNIPHIER_PERI_RESET_I2C(6, 2),
UNIPHIER_PERI_RESET_I2C(7, 3),
UNIPHIER_PERI_RESET_I2C(8, 4),
UNIPHIER_RESET_END,
};
const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
UNIPHIER_PERI_RESET_UART(0, 0),
UNIPHIER_PERI_RESET_UART(1, 1),
UNIPHIER_PERI_RESET_UART(2, 2),
UNIPHIER_PERI_RESET_UART(3, 3),
UNIPHIER_PERI_RESET_FI2C(4, 0),
UNIPHIER_PERI_RESET_FI2C(5, 1),
UNIPHIER_PERI_RESET_FI2C(6, 2),
UNIPHIER_PERI_RESET_FI2C(7, 3),
UNIPHIER_PERI_RESET_FI2C(8, 4),
UNIPHIER_PERI_RESET_FI2C(9, 5),
UNIPHIER_PERI_RESET_FI2C(10, 6),
UNIPHIER_RESET_END,
};
/* core implementaton */
struct uniphier_reset_priv {
struct reset_controller_dev rcdev;
struct device *dev;
struct regmap *regmap;
const struct uniphier_reset_data *data;
};
#define to_uniphier_reset_priv(_rcdev) \
container_of(_rcdev, struct uniphier_reset_priv, rcdev)
static int uniphier_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, int assert)
{
struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
const struct uniphier_reset_data *p;
for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
unsigned int mask, val;
if (p->id != id)
continue;
mask = BIT(p->bit);
if (assert)
val = mask;
else
val = ~mask;
if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
val = ~val;
return regmap_write_bits(priv->regmap, p->reg, mask, val);
}
dev_err(priv->dev, "reset_id=%lu was not handled\n", id);
return -EINVAL;
}
static int uniphier_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return uniphier_reset_update(rcdev, id, 1);
}
static int uniphier_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return uniphier_reset_update(rcdev, id, 0);
}
static int uniphier_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
const struct uniphier_reset_data *p;
for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
unsigned int val;
int ret, asserted;
if (p->id != id)
continue;
ret = regmap_read(priv->regmap, p->reg, &val);
if (ret)
return ret;
asserted = !!(val & BIT(p->bit));
if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
asserted = !asserted;
return asserted;
}
dev_err(priv->dev, "reset_id=%lu was not found\n", id);
return -EINVAL;
}
static const struct reset_control_ops uniphier_reset_ops = {
.assert = uniphier_reset_assert,
.deassert = uniphier_reset_deassert,
.status = uniphier_reset_status,
};
static int uniphier_reset_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct uniphier_reset_priv *priv;
const struct uniphier_reset_data *p, *data;
struct regmap *regmap;
struct device_node *parent;
unsigned int nr_resets = 0;
data = of_device_get_match_data(dev);
if (WARN_ON(!data))
return -EINVAL;
parent = of_get_parent(dev->of_node); /* parent should be syscon node */
regmap = syscon_node_to_regmap(parent);
of_node_put(parent);
if (IS_ERR(regmap)) {
dev_err(dev, "failed to get regmap (error %ld)\n",
PTR_ERR(regmap));
return PTR_ERR(regmap);
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
for (p = data; p->id != UNIPHIER_RESET_ID_END; p++)
nr_resets = max(nr_resets, p->id + 1);
priv->rcdev.ops = &uniphier_reset_ops;
priv->rcdev.owner = dev->driver->owner;
priv->rcdev.of_node = dev->of_node;
priv->rcdev.nr_resets = nr_resets;
priv->dev = dev;
priv->regmap = regmap;
priv->data = data;
return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
}
static const struct of_device_id uniphier_reset_match[] = {
/* System reset */
{
.compatible = "socionext,uniphier-sld3-reset",
.data = uniphier_sld3_sys_reset_data,
},
{
.compatible = "socionext,uniphier-ld4-reset",
.data = uniphier_sld3_sys_reset_data,
},
{
.compatible = "socionext,uniphier-pro4-reset",
.data = uniphier_pro4_sys_reset_data,
},
{
.compatible = "socionext,uniphier-sld8-reset",
.data = uniphier_sld3_sys_reset_data,
},
{
.compatible = "socionext,uniphier-pro5-reset",
.data = uniphier_pro5_sys_reset_data,
},
{
.compatible = "socionext,uniphier-pxs2-reset",
.data = uniphier_pxs2_sys_reset_data,
},
{
.compatible = "socionext,uniphier-ld11-reset",
.data = uniphier_ld11_sys_reset_data,
},
{
.compatible = "socionext,uniphier-ld20-reset",
.data = uniphier_ld20_sys_reset_data,
},
/* Media I/O reset */
{
.compatible = "socionext,uniphier-sld3-mio-reset",
.data = uniphier_sld3_mio_reset_data,
},
{
.compatible = "socionext,uniphier-ld4-mio-reset",
.data = uniphier_sld3_mio_reset_data,
},
{
.compatible = "socionext,uniphier-pro4-mio-reset",
.data = uniphier_sld3_mio_reset_data,
},
{
.compatible = "socionext,uniphier-sld8-mio-reset",
.data = uniphier_sld3_mio_reset_data,
},
{
.compatible = "socionext,uniphier-pro5-mio-reset",
.data = uniphier_pro5_mio_reset_data,
},
{
.compatible = "socionext,uniphier-pxs2-mio-reset",
.data = uniphier_pro5_mio_reset_data,
},
{
.compatible = "socionext,uniphier-ld11-mio-reset",
.data = uniphier_sld3_mio_reset_data,
},
{
.compatible = "socionext,uniphier-ld20-mio-reset",
.data = uniphier_pro5_mio_reset_data,
},
/* Peripheral reset */
{
.compatible = "socionext,uniphier-ld4-peri-reset",
.data = uniphier_ld4_peri_reset_data,
},
{
.compatible = "socionext,uniphier-pro4-peri-reset",
.data = uniphier_pro4_peri_reset_data,
},
{
.compatible = "socionext,uniphier-sld8-peri-reset",
.data = uniphier_ld4_peri_reset_data,
},
{
.compatible = "socionext,uniphier-pro5-peri-reset",
.data = uniphier_pro4_peri_reset_data,
},
{
.compatible = "socionext,uniphier-pxs2-peri-reset",
.data = uniphier_pro4_peri_reset_data,
},
{
.compatible = "socionext,uniphier-ld11-peri-reset",
.data = uniphier_pro4_peri_reset_data,
},
{
.compatible = "socionext,uniphier-ld20-peri-reset",
.data = uniphier_pro4_peri_reset_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, uniphier_reset_match);
static struct platform_driver uniphier_reset_driver = {
.probe = uniphier_reset_probe,
.driver = {
.name = "uniphier-reset",
.of_match_table = uniphier_reset_match,
},
};
module_platform_driver(uniphier_reset_driver);
MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
MODULE_DESCRIPTION("UniPhier Reset Controller Driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,98 @@
/*
* This header provides constants for the STM32F4 RCC IP
*/
#ifndef _DT_BINDINGS_MFD_STM32F4_RCC_H
#define _DT_BINDINGS_MFD_STM32F4_RCC_H
/* AHB1 */
#define STM32F4_RCC_AHB1_GPIOA 0
#define STM32F4_RCC_AHB1_GPIOB 1
#define STM32F4_RCC_AHB1_GPIOC 2
#define STM32F4_RCC_AHB1_GPIOD 3
#define STM32F4_RCC_AHB1_GPIOE 4
#define STM32F4_RCC_AHB1_GPIOF 5
#define STM32F4_RCC_AHB1_GPIOG 6
#define STM32F4_RCC_AHB1_GPIOH 7
#define STM32F4_RCC_AHB1_GPIOI 8
#define STM32F4_RCC_AHB1_GPIOJ 9
#define STM32F4_RCC_AHB1_GPIOK 10
#define STM32F4_RCC_AHB1_CRC 12
#define STM32F4_RCC_AHB1_DMA1 21
#define STM32F4_RCC_AHB1_DMA2 22
#define STM32F4_RCC_AHB1_DMA2D 23
#define STM32F4_RCC_AHB1_ETHMAC 25
#define STM32F4_RCC_AHB1_OTGHS 29
#define STM32F4_AHB1_RESET(bit) (STM32F4_RCC_AHB1_##bit + (0x10 * 8))
#define STM32F4_AHB1_CLOCK(bit) (STM32F4_RCC_AHB1_##bit + (0x30 * 8))
/* AHB2 */
#define STM32F4_RCC_AHB2_DCMI 0
#define STM32F4_RCC_AHB2_CRYP 4
#define STM32F4_RCC_AHB2_HASH 5
#define STM32F4_RCC_AHB2_RNG 6
#define STM32F4_RCC_AHB2_OTGFS 7
#define STM32F4_AHB2_RESET(bit) (STM32F4_RCC_AHB2_##bit + (0x14 * 8))
#define STM32F4_AHB2_CLOCK(bit) (STM32F4_RCC_AHB2_##bit + (0x34 * 8))
/* AHB3 */
#define STM32F4_RCC_AHB3_FMC 0
#define STM32F4_AHB3_RESET(bit) (STM32F4_RCC_AHB3_##bit + (0x18 * 8))
#define STM32F4_AHB3_CLOCK(bit) (STM32F4_RCC_AHB3_##bit + (0x38 * 8))
/* APB1 */
#define STM32F4_RCC_APB1_TIM2 0
#define STM32F4_RCC_APB1_TIM3 1
#define STM32F4_RCC_APB1_TIM4 2
#define STM32F4_RCC_APB1_TIM5 3
#define STM32F4_RCC_APB1_TIM6 4
#define STM32F4_RCC_APB1_TIM7 5
#define STM32F4_RCC_APB1_TIM12 6
#define STM32F4_RCC_APB1_TIM13 7
#define STM32F4_RCC_APB1_TIM14 8
#define STM32F4_RCC_APB1_WWDG 11
#define STM32F4_RCC_APB1_SPI2 14
#define STM32F4_RCC_APB1_SPI3 15
#define STM32F4_RCC_APB1_UART2 17
#define STM32F4_RCC_APB1_UART3 18
#define STM32F4_RCC_APB1_UART4 19
#define STM32F4_RCC_APB1_UART5 20
#define STM32F4_RCC_APB1_I2C1 21
#define STM32F4_RCC_APB1_I2C2 22
#define STM32F4_RCC_APB1_I2C3 23
#define STM32F4_RCC_APB1_CAN1 25
#define STM32F4_RCC_APB1_CAN2 26
#define STM32F4_RCC_APB1_PWR 28
#define STM32F4_RCC_APB1_DAC 29
#define STM32F4_RCC_APB1_UART7 30
#define STM32F4_RCC_APB1_UART8 31
#define STM32F4_APB1_RESET(bit) (STM32F4_RCC_APB1_##bit + (0x20 * 8))
#define STM32F4_APB1_CLOCK(bit) (STM32F4_RCC_APB1_##bit + (0x40 * 8))
/* APB2 */
#define STM32F4_RCC_APB2_TIM1 0
#define STM32F4_RCC_APB2_TIM8 1
#define STM32F4_RCC_APB2_USART1 4
#define STM32F4_RCC_APB2_USART6 5
#define STM32F4_RCC_APB2_ADC 8
#define STM32F4_RCC_APB2_SDIO 11
#define STM32F4_RCC_APB2_SPI1 12
#define STM32F4_RCC_APB2_SPI4 13
#define STM32F4_RCC_APB2_SYSCFG 14
#define STM32F4_RCC_APB2_TIM9 16
#define STM32F4_RCC_APB2_TIM10 17
#define STM32F4_RCC_APB2_TIM11 18
#define STM32F4_RCC_APB2_SPI5 20
#define STM32F4_RCC_APB2_SPI6 21
#define STM32F4_RCC_APB2_SAI1 22
#define STM32F4_RCC_APB2_LTDC 26
#define STM32F4_APB2_RESET(bit) (STM32F4_RCC_APB2_##bit + (0x24 * 8))
#define STM32F4_APB2_CLOCK(bit) (STM32F4_RCC_APB2_##bit + (0x44 * 8))
#endif /* _DT_BINDINGS_MFD_STM32F4_RCC_H */