ARM: SoC driver updates

- New SoC specific drivers
   - NVIDIA Tegra PM Domain support for newer SoCs (Tegra186 and later)
     based on the "BPMP" firmware
   - Clocksource and system controller drivers for the newly added
     Action Semi platforms (both arm and arm64).
 
 - Reset subsystem, merged through arm-soc by tradition:
   - New drivers for Altera Stratix10, TI Keystone and Cortina Gemini SoCs
   - Various subsystem-wide cleanups
 
 - Updates for existing SoC-specific drivers
   - TI GPMC (General Purpose Memory Controller)
   - Mediatek "scpsys" system controller support for MT6797
   - Broadcom "brcmstb_gisb" bus arbitrer
   - ARM SCPI firmware
   - Renesas "SYSC" system controller
 
 One more driver update was submitted for the Freescale/NXP DPAA
 data path acceleration that has previously been used on PowerPC
 chips. I ended up postponing the merge until some API questions
 for its unusual MMIO access are resolved.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIVAwUAWVpDFmCrR//JCVInAQKoihAAosgC3+3IHppOhHid+HepkOcp2teyKknw
 42fSXVpTdfWa8Oe7q80Kzmz2CPNfFq2SzHz6oXb9WCcDFqSGr0b9aSE7NnksRjTf
 2euHVJ4MnJpkRewvorRmcpK8dPXDcHwEw/8hU3yZtJUGI0IKtlrqXis+evgkz9cn
 YDynuVdAZgZiEfiNeSeadyNLcxaQCc3x9ovvsBXxBa1/x1pfeRnTbp+6hiHilCJu
 Szts/yAzZzZE9Jkf9dLKfNlsT6m2SgtjukqqOR+zHAhi7/BdTFSVUP6L8u7QjrR+
 +ijTICg8FMJGiWLAOe6ED2qZVByN92EJ2AGwriYlSles9ouoGfRkJ2rwxyjbete7
 avy0HP+PSBFXWdwbOcq8HX8CrbuBltagl5fkMokct6biWLLMshNZ33WWdQ6/DsM2
 b9mAAZuhbs0g1qWUBD3+q6qBytSuGme6Px6fMoVEc4GQ2YVFUQOoEfZOGKRv1U1o
 aMWGt/6qeF8SG288rYAnQ/TuYWpOLtksV6yhotA00HUHhkTCy0xVCdyWGZtNyKhG
 o/x4YnhWFzHsXmqKcR1sM7LzfZY/WNmbrOLvK6i83Z0P7QptqrdaLAylL3iSPEyX
 ZDUgExf6PYXkWIewc3KwC5sJjuD05z3ZCgIR+mCezwbuD+3Z2fOdjodY/VBZ74hq
 URcM/BqtuWE=
 =5L6n
 -----END PGP SIGNATURE-----

Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC driver updates from Arnd Bergmann:
 "New SoC specific drivers:

   - NVIDIA Tegra PM Domain support for newer SoCs (Tegra186 and later)
     based on the "BPMP" firmware

   - Clocksource and system controller drivers for the newly added
     Action Semi platforms (both arm and arm64).

  Reset subsystem, merged through arm-soc by tradition:

   - New drivers for Altera Stratix10, TI Keystone and Cortina Gemini
     SoCs

   - Various subsystem-wide cleanups

  Updates for existing SoC-specific drivers

   - TI GPMC (General Purpose Memory Controller)

   - Mediatek "scpsys" system controller support for MT6797

   - Broadcom "brcmstb_gisb" bus arbitrer

   - ARM SCPI firmware

   - Renesas "SYSC" system controller

  One more driver update was submitted for the Freescale/NXP DPAA data
  path acceleration that has previously been used on PowerPC chips. I
  ended up postponing the merge until some API questions for its unusual
  MMIO access are resolved"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (35 commits)
  clocksource: owl: Add S900 support
  clocksource: Add Owl timer
  soc: renesas: rcar-sysc: Use GENPD_FLAG_ALWAYS_ON
  firmware: tegra: Fix locking bugs in BPMP
  soc/tegra: flowctrl: Fix error handling
  soc/tegra: bpmp: Implement generic PM domains
  soc/tegra: bpmp: Update ABI header
  PM / Domains: Allow overriding the ->xlate() callback
  soc: brcmstb: enable drivers for ARM64 and BMIPS
  soc: renesas: Rework Kconfig and Makefile logic
  reset: Add the TI SCI reset driver
  dt-bindings: reset: Add TI SCI reset binding
  reset: use kref for reference counting
  soc: qcom: smsm: Improve error handling, quiesce probe deferral
  cpufreq: scpi: use new scpi_ops functions to remove duplicate code
  firmware: arm_scpi: add support to populate OPPs and get transition latency
  dt-bindings: reset: Add reset manager offsets for Stratix10
  memory: omap-gpmc: add error message if bank-width property is absent
  memory: omap-gpmc: make dts snippet include semicolon
  reset: Add a Gemini reset controller
  ...
This commit is contained in:
Linus Torvalds 2017-07-04 14:47:47 -07:00
commit e854711291
42 changed files with 2059 additions and 198 deletions

View file

@ -34,6 +34,13 @@ config RESET_BERLIN
help
This enables the reset controller driver for Marvell Berlin SoCs.
config RESET_GEMINI
bool "Gemini Reset Driver" if COMPILE_TEST
default ARCH_GEMINI
select MFD_SYSCON
help
This enables the reset controller driver for Cortina Systems Gemini.
config RESET_IMX7
bool "i.MX7 Reset Driver" if COMPILE_TEST
default SOC_IMX7D
@ -80,7 +87,15 @@ config RESET_SUNXI
help
This enables the reset driver for Allwinner SoCs.
config TI_SYSCON_RESET
config RESET_TI_SCI
tristate "TI System Control Interface (TI-SCI) reset driver"
depends on TI_SCI_PROTOCOL
help
This enables the reset driver support over TI System Control Interface
available on some new TI's SoCs. If you wish to use reset resources
managed by the TI System Controller, say Y here. Otherwise, say N.
config RESET_TI_SYSCON
tristate "TI SYSCON Reset Driver"
depends on HAS_IOMEM
select MFD_SYSCON

View file

@ -5,6 +5,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o
obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
obj-$(CONFIG_RESET_GEMINI) += reset-gemini.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
@ -13,7 +14,8 @@ 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_TI_SCI) += reset-ti-sci.o
obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o

View file

@ -13,6 +13,7 @@
#include <linux/err.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/reset.h>
@ -40,7 +41,7 @@ struct reset_control {
struct reset_controller_dev *rcdev;
struct list_head list;
unsigned int id;
unsigned int refcnt;
struct kref refcnt;
bool shared;
atomic_t deassert_count;
atomic_t triggered_count;
@ -288,7 +289,7 @@ static struct reset_control *__reset_control_get_internal(
if (WARN_ON(!rstc->shared || !shared))
return ERR_PTR(-EBUSY);
rstc->refcnt++;
kref_get(&rstc->refcnt);
return rstc;
}
}
@ -302,23 +303,30 @@ static struct reset_control *__reset_control_get_internal(
rstc->rcdev = rcdev;
list_add(&rstc->list, &rcdev->reset_control_head);
rstc->id = index;
rstc->refcnt = 1;
kref_init(&rstc->refcnt);
rstc->shared = shared;
return rstc;
}
static void __reset_control_release(struct kref *kref)
{
struct reset_control *rstc = container_of(kref, struct reset_control,
refcnt);
lockdep_assert_held(&reset_list_mutex);
module_put(rstc->rcdev->owner);
list_del(&rstc->list);
kfree(rstc);
}
static void __reset_control_put_internal(struct reset_control *rstc)
{
lockdep_assert_held(&reset_list_mutex);
if (--rstc->refcnt)
return;
module_put(rstc->rcdev->owner);
list_del(&rstc->list);
kfree(rstc);
kref_put(&rstc->refcnt, __reset_control_release);
}
struct reset_control *__of_reset_control_get(struct device_node *node,
@ -400,7 +408,6 @@ EXPORT_SYMBOL_GPL(__reset_control_get);
* reset_control_put - free the reset controller
* @rstc: reset controller
*/
void reset_control_put(struct reset_control *rstc)
{
if (IS_ERR_OR_NULL(rstc))

View file

@ -0,0 +1,110 @@
/*
* Cortina Gemini Reset controller driver
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <dt-bindings/reset/cortina,gemini-reset.h>
/**
* struct gemini_reset - gemini reset controller
* @map: regmap to access the containing system controller
* @rcdev: reset controller device
*/
struct gemini_reset {
struct regmap *map;
struct reset_controller_dev rcdev;
};
#define GEMINI_GLOBAL_SOFT_RESET 0x0c
#define to_gemini_reset(p) \
container_of((p), struct gemini_reset, rcdev)
/*
* This is a self-deasserting reset controller.
*/
static int gemini_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct gemini_reset *gr = to_gemini_reset(rcdev);
/* Manual says to always set BIT 30 (CPU1) to 1 */
return regmap_write(gr->map,
GEMINI_GLOBAL_SOFT_RESET,
BIT(GEMINI_RESET_CPU1) | BIT(id));
}
static int gemini_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct gemini_reset *gr = to_gemini_reset(rcdev);
u32 val;
int ret;
ret = regmap_read(gr->map, GEMINI_GLOBAL_SOFT_RESET, &val);
if (ret)
return ret;
return !!(val & BIT(id));
}
static const struct reset_control_ops gemini_reset_ops = {
.reset = gemini_reset,
.status = gemini_reset_status,
};
static int gemini_reset_probe(struct platform_device *pdev)
{
struct gemini_reset *gr;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret;
gr = devm_kzalloc(dev, sizeof(*gr), GFP_KERNEL);
if (!gr)
return -ENOMEM;
gr->map = syscon_node_to_regmap(np);
if (IS_ERR(gr->map)) {
ret = PTR_ERR(gr->map);
dev_err(dev, "unable to get regmap (%d)", ret);
return ret;
}
gr->rcdev.owner = THIS_MODULE;
gr->rcdev.nr_resets = 32;
gr->rcdev.ops = &gemini_reset_ops;
gr->rcdev.of_node = pdev->dev.of_node;
ret = devm_reset_controller_register(&pdev->dev, &gr->rcdev);
if (ret)
return ret;
dev_info(dev, "registered Gemini reset controller\n");
return 0;
}
static const struct of_device_id gemini_reset_dt_ids[] = {
{ .compatible = "cortina,gemini-syscon", },
{ /* sentinel */ },
};
static struct platform_driver gemini_reset_driver = {
.probe = gemini_reset_probe,
.driver = {
.name = "gemini-reset",
.of_match_table = gemini_reset_dt_ids,
.suppress_bind_attrs = true,
},
};
builtin_platform_driver(gemini_reset_driver);

View file

@ -0,0 +1,269 @@
/*
* Texas Instrument's System Control Interface (TI-SCI) reset driver
*
* Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/soc/ti/ti_sci_protocol.h>
/**
* struct ti_sci_reset_control - reset control structure
* @dev_id: SoC-specific device identifier
* @reset_mask: reset mask to use for toggling reset
* @lock: synchronize reset_mask read-modify-writes
*/
struct ti_sci_reset_control {
u32 dev_id;
u32 reset_mask;
struct mutex lock;
};
/**
* struct ti_sci_reset_data - reset controller information structure
* @rcdev: reset controller entity
* @dev: reset controller device pointer
* @sci: TI SCI handle used for communication with system controller
* @idr: idr structure for mapping ids to reset control structures
*/
struct ti_sci_reset_data {
struct reset_controller_dev rcdev;
struct device *dev;
const struct ti_sci_handle *sci;
struct idr idr;
};
#define to_ti_sci_reset_data(p) \
container_of((p), struct ti_sci_reset_data, rcdev)
/**
* ti_sci_reset_set() - program a device's reset
* @rcdev: reset controller entity
* @id: ID of the reset to toggle
* @assert: boolean flag to indicate assert or deassert
*
* This is a common internal function used to assert or deassert a device's
* reset using the TI SCI protocol. The device's reset is asserted if the
* @assert argument is true, or deasserted if @assert argument is false.
* The mechanism itself is a read-modify-write procedure, the current device
* reset register is read using a TI SCI device operation, the new value is
* set or un-set using the reset's mask, and the new reset value written by
* using another TI SCI device operation.
*
* Return: 0 for successful request, else a corresponding error value
*/
static int ti_sci_reset_set(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
const struct ti_sci_handle *sci = data->sci;
const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
struct ti_sci_reset_control *control;
u32 reset_state;
int ret;
control = idr_find(&data->idr, id);
if (!control)
return -EINVAL;
mutex_lock(&control->lock);
ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
if (ret)
goto out;
if (assert)
reset_state |= control->reset_mask;
else
reset_state &= ~control->reset_mask;
ret = dev_ops->set_device_resets(sci, control->dev_id, reset_state);
out:
mutex_unlock(&control->lock);
return ret;
}
/**
* ti_sci_reset_assert() - assert device reset
* @rcdev: reset controller entity
* @id: ID of the reset to be asserted
*
* This function implements the reset driver op to assert a device's reset
* using the TI SCI protocol. This invokes the function ti_sci_reset_set()
* with the corresponding parameters as passed in, but with the @assert
* argument set to true for asserting the reset.
*
* Return: 0 for successful request, else a corresponding error value
*/
static int ti_sci_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return ti_sci_reset_set(rcdev, id, true);
}
/**
* ti_sci_reset_deassert() - deassert device reset
* @rcdev: reset controller entity
* @id: ID of the reset to be deasserted
*
* This function implements the reset driver op to deassert a device's reset
* using the TI SCI protocol. This invokes the function ti_sci_reset_set()
* with the corresponding parameters as passed in, but with the @assert
* argument set to false for deasserting the reset.
*
* Return: 0 for successful request, else a corresponding error value
*/
static int ti_sci_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return ti_sci_reset_set(rcdev, id, false);
}
/**
* ti_sci_reset_status() - check device reset status
* @rcdev: reset controller entity
* @id: ID of reset to be checked
*
* This function implements the reset driver op to return the status of a
* device's reset using the TI SCI protocol. The reset register value is read
* by invoking the TI SCI device operation .get_device_resets(), and the
* status of the specific reset is extracted and returned using this reset's
* reset mask.
*
* Return: 0 if reset is deasserted, or a non-zero value if reset is asserted
*/
static int ti_sci_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
const struct ti_sci_handle *sci = data->sci;
const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
struct ti_sci_reset_control *control;
u32 reset_state;
int ret;
control = idr_find(&data->idr, id);
if (!control)
return -EINVAL;
ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
if (ret)
return ret;
return reset_state & control->reset_mask;
}
static const struct reset_control_ops ti_sci_reset_ops = {
.assert = ti_sci_reset_assert,
.deassert = ti_sci_reset_deassert,
.status = ti_sci_reset_status,
};
/**
* ti_sci_reset_of_xlate() - translate a set of OF arguments to a reset ID
* @rcdev: reset controller entity
* @reset_spec: OF reset argument specifier
*
* This function performs the translation of the reset argument specifier
* values defined in a reset consumer device node. The function allocates a
* reset control structure for that device reset, and will be used by the
* driver for performing any reset functions on that reset. An idr structure
* is allocated and used to map to the reset control structure. This idr
* is used by the driver to do reset lookups.
*
* Return: 0 for successful request, else a corresponding error value
*/
static int ti_sci_reset_of_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
{
struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
struct ti_sci_reset_control *control;
if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
return -EINVAL;
control = devm_kzalloc(data->dev, sizeof(*control), GFP_KERNEL);
if (!control)
return -ENOMEM;
control->dev_id = reset_spec->args[0];
control->reset_mask = reset_spec->args[1];
mutex_init(&control->lock);
return idr_alloc(&data->idr, control, 0, 0, GFP_KERNEL);
}
static const struct of_device_id ti_sci_reset_of_match[] = {
{ .compatible = "ti,sci-reset", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, ti_sci_reset_of_match);
static int ti_sci_reset_probe(struct platform_device *pdev)
{
struct ti_sci_reset_data *data;
if (!pdev->dev.of_node)
return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->sci = devm_ti_sci_get_handle(&pdev->dev);
if (IS_ERR(data->sci))
return PTR_ERR(data->sci);
data->rcdev.ops = &ti_sci_reset_ops;
data->rcdev.owner = THIS_MODULE;
data->rcdev.of_node = pdev->dev.of_node;
data->rcdev.of_reset_n_cells = 2;
data->rcdev.of_xlate = ti_sci_reset_of_xlate;
data->dev = &pdev->dev;
idr_init(&data->idr);
platform_set_drvdata(pdev, data);
return reset_controller_register(&data->rcdev);
}
static int ti_sci_reset_remove(struct platform_device *pdev)
{
struct ti_sci_reset_data *data = platform_get_drvdata(pdev);
reset_controller_unregister(&data->rcdev);
idr_destroy(&data->idr);
return 0;
}
static struct platform_driver ti_sci_reset_driver = {
.probe = ti_sci_reset_probe,
.remove = ti_sci_reset_remove,
.driver = {
.name = "ti-sci-reset",
.of_match_table = ti_sci_reset_of_match,
},
};
module_platform_driver(ti_sci_reset_driver);
MODULE_AUTHOR("Andrew F. Davis <[email protected]>");
MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver");
MODULE_LICENSE("GPL v2");

View file

@ -145,16 +145,14 @@ static int syscfg_reset_controller_register(struct device *dev,
const struct syscfg_reset_controller_data *data)
{
struct syscfg_reset_controller *rc;
size_t size;
int i, err;
rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL);
if (!rc)
return -ENOMEM;
size = sizeof(struct syscfg_reset_channel) * data->nr_channels;
rc->channels = devm_kzalloc(dev, size, GFP_KERNEL);
rc->channels = devm_kcalloc(dev, data->nr_channels,
sizeof(*rc->channels), GFP_KERNEL);
if (!rc->channels)
return -ENOMEM;