Reset controller changes for v4.17, part 2

This tag contains reset lookup support, similar to pwm lookups, for legacy
 non-DT platforms, a few new reset controls and a Kconfig fix for uniphier
 SoCs, as well as a new driver for the STM32MP1 peripheral reset controller.
 
 The reset lookups are merged from a separate, immutable branch, that may
 also be merged into the davinci tree.
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCAA1FiEEBsBxhV1FaKwXuCOBUMKIHHCeYOsFAlq6UAwXHHAuemFiZWxA
 cGVuZ3V0cm9uaXguZGUACgkQUMKIHHCeYOuXDBAA0rkV2QOjJQEhpL/jWEukmrAi
 NtNeREToKjUwfkfZFrgdCRQjm5adz+qrXUuTOK6SeqRWdW3chfeNhJoAdpPH7p54
 odAiqtAz/M5dwh6iy/VJZxFba6j9dJkTa29tKs93XKL0vjN4//AEYEuKF5HG70+E
 xm6V9ZnD4qPrCYuHZvQoiOeyrnxqaKWjRXLSAqHqv6hfg8OsJ9IRaC2SR1Asx/0A
 MkaAvLTEZj65xcA1WsOwKAtgcDDsyUt5VJcA3DW6v+YKoE59DVhlVR76dI2SijoG
 gkTOn/zCxHCVi3GjSpYRsE1ywey7XofCDiwtsV35FXIoGL3RkqcSWAwtWjrHsuHT
 2PQ3QLQzqinyPU72iu+4b1lMKzT8aJh6w03ENxVvRDQNIBS7P9xMvOd5Wj45++QG
 Z5Xt23kMKFamMGSa6eD67ul17bnfjY2IZrQjWgsuIPec0eAJ1FsraTJ/zW4cKmEa
 FhW172r5udAlypV7lFdwuzYtQXuU4LaGQNoDjVgrGqhaz/TWMFtsOFvhmww76/jU
 JcmJxuqAyh0l9Iwh7icJo6gsTdW7dvbwv5wCrBEW4W53mscUOLUiPpKaExXWnkOU
 4oi7D7dIWvV/rqMf5VBnQaZXYtPZegh97nRh9Etb5FcbhRCpDJjTp28ZagixqjiG
 4U0AvT4sahcktL3Y3lw=
 =LU35
 -----END PGP SIGNATURE-----

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

Pull "Reset controller changes for v4.17, part 2" from Philipp Zabel:

This tag contains reset lookup support, similar to pwm lookups, for legacy
non-DT platforms, a few new reset controls and a Kconfig fix for uniphier
SoCs, as well as a new driver for the STM32MP1 peripheral reset controller.

The reset lookups are merged from a separate, immutable branch, that may
also be merged into the davinci tree.

* tag 'reset-for-4.17-2' of git://git.pengutronix.de/git/pza/linux:
  reset: uniphier: add ethernet reset control support for PXs3
  reset: stm32mp1: Enable stm32mp1 reset driver
  dt-bindings: reset: add STM32MP1 resets
  reset: uniphier: add Pro4/Pro5/PXs2 audio systems reset control
  reset: imx7: add 'depends on HAS_IOMEM' to fix unmet dependency
  reset: modify the way reset lookup works for board files
  reset: add support for non-DT systems
This commit is contained in:
Arnd Bergmann 2018-03-28 17:02:22 +02:00
commit 7f95de5e4a
8 changed files with 367 additions and 1 deletions

View File

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

View File

@ -49,6 +49,7 @@ config RESET_HSDK
config RESET_IMX7 config RESET_IMX7
bool "i.MX7 Reset Driver" if COMPILE_TEST bool "i.MX7 Reset Driver" if COMPILE_TEST
depends on HAS_IOMEM
default SOC_IMX7D default SOC_IMX7D
select MFD_SYSCON select MFD_SYSCON
help help
@ -96,6 +97,12 @@ config RESET_SIMPLE
- Allwinner SoCs - Allwinner SoCs
- ZTE's zx2967 family - ZTE's zx2967 family
config RESET_STM32MP157
bool "STM32MP157 Reset Driver" if COMPILE_TEST
default MACH_STM32MP157
help
This enables the RCC reset controller driver for STM32 MPUs.
config RESET_SUNXI config RESET_SUNXI
bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
default ARCH_SUNXI default ARCH_SUNXI

View File

@ -15,6 +15,7 @@ obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o

View File

@ -23,6 +23,9 @@
static DEFINE_MUTEX(reset_list_mutex); static DEFINE_MUTEX(reset_list_mutex);
static LIST_HEAD(reset_controller_list); static LIST_HEAD(reset_controller_list);
static DEFINE_MUTEX(reset_lookup_mutex);
static LIST_HEAD(reset_lookup_list);
/** /**
* struct reset_control - a reset control * struct reset_control - a reset control
* @rcdev: a pointer to the reset controller device * @rcdev: a pointer to the reset controller device
@ -148,6 +151,33 @@ int devm_reset_controller_register(struct device *dev,
} }
EXPORT_SYMBOL_GPL(devm_reset_controller_register); EXPORT_SYMBOL_GPL(devm_reset_controller_register);
/**
* reset_controller_add_lookup - register a set of lookup entries
* @lookup: array of reset lookup entries
* @num_entries: number of entries in the lookup array
*/
void reset_controller_add_lookup(struct reset_control_lookup *lookup,
unsigned int num_entries)
{
struct reset_control_lookup *entry;
unsigned int i;
mutex_lock(&reset_lookup_mutex);
for (i = 0; i < num_entries; i++) {
entry = &lookup[i];
if (!entry->dev_id || !entry->provider) {
pr_warn("%s(): reset lookup entry badly specified, skipping\n",
__func__);
continue;
}
list_add_tail(&entry->list, &reset_lookup_list);
}
mutex_unlock(&reset_lookup_mutex);
}
EXPORT_SYMBOL_GPL(reset_controller_add_lookup);
static inline struct reset_control_array * static inline struct reset_control_array *
rstc_to_array(struct reset_control *rstc) { rstc_to_array(struct reset_control *rstc) {
return container_of(rstc, struct reset_control_array, base); return container_of(rstc, struct reset_control_array, base);
@ -493,6 +523,70 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
} }
EXPORT_SYMBOL_GPL(__of_reset_control_get); EXPORT_SYMBOL_GPL(__of_reset_control_get);
static struct reset_controller_dev *
__reset_controller_by_name(const char *name)
{
struct reset_controller_dev *rcdev;
lockdep_assert_held(&reset_list_mutex);
list_for_each_entry(rcdev, &reset_controller_list, list) {
if (!rcdev->dev)
continue;
if (!strcmp(name, dev_name(rcdev->dev)))
return rcdev;
}
return NULL;
}
static struct reset_control *
__reset_control_get_from_lookup(struct device *dev, const char *con_id,
bool shared, bool optional)
{
const struct reset_control_lookup *lookup;
struct reset_controller_dev *rcdev;
const char *dev_id = dev_name(dev);
struct reset_control *rstc = NULL;
if (!dev)
return ERR_PTR(-EINVAL);
mutex_lock(&reset_lookup_mutex);
list_for_each_entry(lookup, &reset_lookup_list, list) {
if (strcmp(lookup->dev_id, dev_id))
continue;
if ((!con_id && !lookup->con_id) ||
((con_id && lookup->con_id) &&
!strcmp(con_id, lookup->con_id))) {
mutex_lock(&reset_list_mutex);
rcdev = __reset_controller_by_name(lookup->provider);
if (!rcdev) {
mutex_unlock(&reset_list_mutex);
mutex_unlock(&reset_lookup_mutex);
/* Reset provider may not be ready yet. */
return ERR_PTR(-EPROBE_DEFER);
}
rstc = __reset_control_get_internal(rcdev,
lookup->index,
shared);
mutex_unlock(&reset_list_mutex);
break;
}
}
mutex_unlock(&reset_lookup_mutex);
if (!rstc)
return optional ? NULL : ERR_PTR(-ENOENT);
return rstc;
}
struct reset_control *__reset_control_get(struct device *dev, const char *id, struct reset_control *__reset_control_get(struct device *dev, const char *id,
int index, bool shared, bool optional) int index, bool shared, bool optional)
{ {
@ -500,7 +594,7 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
return __of_reset_control_get(dev->of_node, id, index, shared, return __of_reset_control_get(dev->of_node, id, index, shared,
optional); optional);
return optional ? NULL : ERR_PTR(-EINVAL); return __reset_control_get_from_lookup(dev, id, shared, optional);
} }
EXPORT_SYMBOL_GPL(__reset_control_get); EXPORT_SYMBOL_GPL(__reset_control_get);

View File

@ -0,0 +1,115 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics 2018 - All Rights Reserved
* Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#define CLR_OFFSET 0x4
struct stm32_reset_data {
struct reset_controller_dev rcdev;
void __iomem *membase;
};
static inline struct stm32_reset_data *
to_stm32_reset_data(struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct stm32_reset_data, rcdev);
}
static int stm32_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
int reg_width = sizeof(u32);
int bank = id / (reg_width * BITS_PER_BYTE);
int offset = id % (reg_width * BITS_PER_BYTE);
void __iomem *addr;
addr = data->membase + (bank * reg_width);
if (!assert)
addr += CLR_OFFSET;
writel(BIT(offset), addr);
return 0;
}
static int stm32_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return stm32_reset_update(rcdev, id, true);
}
static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return stm32_reset_update(rcdev, id, false);
}
static int stm32_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
int reg_width = sizeof(u32);
int bank = id / (reg_width * BITS_PER_BYTE);
int offset = id % (reg_width * BITS_PER_BYTE);
u32 reg;
reg = readl(data->membase + (bank * reg_width));
return !!(reg & BIT(offset));
}
static const struct reset_control_ops stm32_reset_ops = {
.assert = stm32_reset_assert,
.deassert = stm32_reset_deassert,
.status = stm32_reset_status,
};
static const struct of_device_id stm32_reset_dt_ids[] = {
{ .compatible = "st,stm32mp1-rcc"},
{ /* sentinel */ },
};
static int stm32_reset_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct stm32_reset_data *data;
void __iomem *membase;
struct resource *res;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
membase = devm_ioremap_resource(dev, res);
if (IS_ERR(membase))
return PTR_ERR(membase);
data->membase = membase;
data->rcdev.owner = THIS_MODULE;
data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE;
data->rcdev.ops = &stm32_reset_ops;
data->rcdev.of_node = dev->of_node;
return devm_reset_controller_register(dev, &data->rcdev);
}
static struct platform_driver stm32_reset_driver = {
.probe = stm32_reset_probe,
.driver = {
.name = "stm32mp1-reset",
.of_match_table = stm32_reset_dt_ids,
},
};
builtin_platform_driver(stm32_reset_driver);

View File

@ -63,6 +63,7 @@ static const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (Ether, SATA, USB3) */ UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (Ether, SATA, USB3) */
UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */
UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */
UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */
UNIPHIER_RESET_END, UNIPHIER_RESET_END,
}; };
@ -72,6 +73,7 @@ static const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = {
UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (PCIe, USB3) */ UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (PCIe, USB3) */
UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */
UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */
UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */
UNIPHIER_RESET_END, UNIPHIER_RESET_END,
}; };
@ -88,6 +90,7 @@ static const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = {
UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */ UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */
UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */ UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */
UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */ UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */
UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */
UNIPHIER_RESET_END, UNIPHIER_RESET_END,
}; };
@ -121,6 +124,8 @@ static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = { static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = {
UNIPHIER_RESETX(2, 0x200c, 0), /* NAND */ UNIPHIER_RESETX(2, 0x200c, 0), /* NAND */
UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */
UNIPHIER_RESETX(6, 0x200c, 9), /* Ether0 */
UNIPHIER_RESETX(7, 0x200c, 10), /* Ether1 */
UNIPHIER_RESETX(8, 0x200c, 12), /* STDMAC */ UNIPHIER_RESETX(8, 0x200c, 12), /* STDMAC */
UNIPHIER_RESETX(12, 0x200c, 4), /* USB30 link (GIO0) */ UNIPHIER_RESETX(12, 0x200c, 4), /* USB30 link (GIO0) */
UNIPHIER_RESETX(13, 0x200c, 5), /* USB31 link (GIO1) */ UNIPHIER_RESETX(13, 0x200c, 5), /* USB31 link (GIO1) */

View File

@ -0,0 +1,108 @@
/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
/*
* Copyright (C) STMicroelectronics 2018 - All Rights Reserved
* Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
*/
#ifndef _DT_BINDINGS_STM32MP1_RESET_H_
#define _DT_BINDINGS_STM32MP1_RESET_H_
#define LTDC_R 3072
#define DSI_R 3076
#define DDRPERFM_R 3080
#define USBPHY_R 3088
#define SPI6_R 3136
#define I2C4_R 3138
#define I2C6_R 3139
#define USART1_R 3140
#define STGEN_R 3156
#define GPIOZ_R 3200
#define CRYP1_R 3204
#define HASH1_R 3205
#define RNG1_R 3206
#define AXIM_R 3216
#define GPU_R 3269
#define ETHMAC_R 3274
#define FMC_R 3276
#define QSPI_R 3278
#define SDMMC1_R 3280
#define SDMMC2_R 3281
#define CRC1_R 3284
#define USBH_R 3288
#define MDMA_R 3328
#define MCU_R 8225
#define TIM2_R 19456
#define TIM3_R 19457
#define TIM4_R 19458
#define TIM5_R 19459
#define TIM6_R 19460
#define TIM7_R 19461
#define TIM12_R 16462
#define TIM13_R 16463
#define TIM14_R 16464
#define LPTIM1_R 19465
#define SPI2_R 19467
#define SPI3_R 19468
#define USART2_R 19470
#define USART3_R 19471
#define UART4_R 19472
#define UART5_R 19473
#define UART7_R 19474
#define UART8_R 19475
#define I2C1_R 19477
#define I2C2_R 19478
#define I2C3_R 19479
#define I2C5_R 19480
#define SPDIF_R 19482
#define CEC_R 19483
#define DAC12_R 19485
#define MDIO_R 19847
#define TIM1_R 19520
#define TIM8_R 19521
#define TIM15_R 19522
#define TIM16_R 19523
#define TIM17_R 19524
#define SPI1_R 19528
#define SPI4_R 19529
#define SPI5_R 19530
#define USART6_R 19533
#define SAI1_R 19536
#define SAI2_R 19537
#define SAI3_R 19538
#define DFSDM_R 19540
#define FDCAN_R 19544
#define LPTIM2_R 19584
#define LPTIM3_R 19585
#define LPTIM4_R 19586
#define LPTIM5_R 19587
#define SAI4_R 19592
#define SYSCFG_R 19595
#define VREF_R 19597
#define TMPSENS_R 19600
#define PMBCTRL_R 19601
#define DMA1_R 19648
#define DMA2_R 19649
#define DMAMUX_R 19650
#define ADC12_R 19653
#define USBO_R 19656
#define SDMMC3_R 19664
#define CAMITF_R 19712
#define CRYP2_R 19716
#define HASH2_R 19717
#define RNG2_R 19718
#define CRC2_R 19719
#define HSEM_R 19723
#define MBOX_R 19724
#define GPIOA_R 19776
#define GPIOB_R 19777
#define GPIOC_R 19778
#define GPIOD_R 19779
#define GPIOE_R 19780
#define GPIOF_R 19781
#define GPIOG_R 19782
#define GPIOH_R 19783
#define GPIOI_R 19784
#define GPIOJ_R 19785
#define GPIOK_R 19786
#endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */

View File

@ -26,6 +26,31 @@ struct module;
struct device_node; struct device_node;
struct of_phandle_args; struct of_phandle_args;
/**
* struct reset_control_lookup - represents a single lookup entry
*
* @list: internal list of all reset lookup entries
* @provider: name of the reset controller device controlling this reset line
* @index: ID of the reset controller in the reset controller device
* @dev_id: name of the device associated with this reset line
* @con_id name of the reset line (can be NULL)
*/
struct reset_control_lookup {
struct list_head list;
const char *provider;
unsigned int index;
const char *dev_id;
const char *con_id;
};
#define RESET_LOOKUP(_provider, _index, _dev_id, _con_id) \
{ \
.provider = _provider, \
.index = _index, \
.dev_id = _dev_id, \
.con_id = _con_id, \
}
/** /**
* struct reset_controller_dev - reset controller entity that might * struct reset_controller_dev - reset controller entity that might
* provide multiple reset controls * provide multiple reset controls
@ -33,6 +58,7 @@ struct of_phandle_args;
* @owner: kernel module of the reset controller driver * @owner: kernel module of the reset controller driver
* @list: internal list of reset controller devices * @list: internal list of reset controller devices
* @reset_control_head: head of internal list of requested reset controls * @reset_control_head: head of internal list of requested reset controls
* @dev: corresponding driver model device struct
* @of_node: corresponding device tree node as phandle target * @of_node: corresponding device tree node as phandle target
* @of_reset_n_cells: number of cells in reset line specifiers * @of_reset_n_cells: number of cells in reset line specifiers
* @of_xlate: translation function to translate from specifier as found in the * @of_xlate: translation function to translate from specifier as found in the
@ -44,6 +70,7 @@ struct reset_controller_dev {
struct module *owner; struct module *owner;
struct list_head list; struct list_head list;
struct list_head reset_control_head; struct list_head reset_control_head;
struct device *dev;
struct device_node *of_node; struct device_node *of_node;
int of_reset_n_cells; int of_reset_n_cells;
int (*of_xlate)(struct reset_controller_dev *rcdev, int (*of_xlate)(struct reset_controller_dev *rcdev,
@ -58,4 +85,7 @@ struct device;
int devm_reset_controller_register(struct device *dev, int devm_reset_controller_register(struct device *dev,
struct reset_controller_dev *rcdev); struct reset_controller_dev *rcdev);
void reset_controller_add_lookup(struct reset_control_lookup *lookup,
unsigned int num_entries);
#endif #endif