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
42 changed files with 2062 additions and 201 deletions
@@ -3,7 +3,8 @@ Broadcom GISB bus Arbiter controller
Required properties:
- compatible:
"brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for 28nm chips
"brcm,bcm7278-gisb-arb" for V7 28nm chips
"brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for other 28nm chips
"brcm,bcm7435-gisb-arb" for newer 40nm chips
"brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips
"brcm,bcm7038-gisb-arb" for 130nm chips
@@ -0,0 +1,62 @@
Texas Instruments System Control Interface (TI-SCI) Reset Controller
=====================================================================
Some TI SoCs contain a system controller (like the Power Management Micro
Controller (PMMC) on Keystone 66AK2G SoC) that are responsible for controlling
the state of the various hardware modules present on the SoC. Communication
between the host processor running an OS and the system controller happens
through a protocol called TI System Control Interface (TI-SCI protocol).
For TI SCI details, please refer to the document,
Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
TI-SCI Reset Controller Node
============================
This reset controller node uses the TI SCI protocol to perform the reset
management of various hardware modules present on the SoC. Must be a child
node of the associated TI-SCI system controller node.
Required properties:
--------------------
- compatible : Should be "ti,sci-reset"
- #reset-cells : Should be 2. Please see the reset consumer node below for
usage details.
TI-SCI Reset Consumer Nodes
===========================
Each of the reset consumer nodes should have the following properties,
in addition to their own properties.
Required properties:
--------------------
- resets : A phandle and reset specifier pair, one pair for each reset
signal that affects the device, or that the device manages.
The phandle should point to the TI-SCI reset controller node,
and the reset specifier should have 2 cell-values. The first
cell should contain the device ID. The second cell should
contain the reset mask value used by system controller.
Please refer to the protocol documentation for these values
to be used for different devices,
http://processors.wiki.ti.com/index.php/TISCI#66AK2G02_Data
Please also refer to Documentation/devicetree/bindings/reset/reset.txt for
common reset controller usage by consumers.
Example:
--------
The following example demonstrates both a TI-SCI reset controller node and a
consumer (a DSP device) on the 66AK2G SoC.
pmmc: pmmc {
compatible = "ti,k2g-sci";
k2g_reset: reset-controller {
compatible = "ti,sci-reset";
#reset-cells = <2>;
};
};
dsp0: dsp@10800000 {
...
resets = <&k2g_reset 0x0046 0x1>;
...
};
+2
View File
@@ -12682,6 +12682,8 @@ F: include/linux/soc/ti/ti_sci_protocol.h
F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
F: include/dt-bindings/genpd/k2g.h
F: drivers/soc/ti/ti_sci_pm_domains.c
F: Documentation/devicetree/bindings/reset/ti,sci-reset.txt
F: drivers/reset/reset-ti-sci.c
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
+4 -4
View File
@@ -1637,9 +1637,6 @@ EXPORT_SYMBOL_GPL(pm_genpd_remove);
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
void *data);
/*
* Device Tree based PM domain providers.
*
@@ -1795,6 +1792,9 @@ int of_genpd_add_provider_onecell(struct device_node *np,
mutex_lock(&gpd_list_lock);
if (!data->xlate)
data->xlate = genpd_xlate_onecell;
for (i = 0; i < data->num_domains; i++) {
if (!data->domains[i])
continue;
@@ -1805,7 +1805,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
data->domains[i]->has_provider = true;
}
ret = genpd_add_provider(np, genpd_xlate_onecell, data);
ret = genpd_add_provider(np, data->xlate, data);
if (ret < 0)
goto error;
+1 -1
View File
@@ -57,7 +57,7 @@ config ARM_CCN
config BRCMSTB_GISB_ARB
bool "Broadcom STB GISB bus arbiter"
depends on ARM || MIPS
depends on ARM || ARM64 || MIPS
default ARCH_BRCMSTB || BMIPS_GENERIC
help
Driver for the Broadcom Set Top Box System-on-a-chip internal bus
+72 -49
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Broadcom Corporation
* Copyright (C) 2014-2017 Broadcom
*
* 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
@@ -24,11 +24,9 @@
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/pm.h>
#ifdef CONFIG_ARM
#include <asm/bug.h>
#include <asm/signal.h>
#endif
#include <linux/kernel.h>
#include <linux/kdebug.h>
#include <linux/notifier.h>
#ifdef CONFIG_MIPS
#include <asm/traps.h>
@@ -37,8 +35,6 @@
#define ARB_ERR_CAP_CLEAR (1 << 0)
#define ARB_ERR_CAP_STATUS_TIMEOUT (1 << 12)
#define ARB_ERR_CAP_STATUS_TEA (1 << 11)
#define ARB_ERR_CAP_STATUS_BS_SHIFT (1 << 2)
#define ARB_ERR_CAP_STATUS_BS_MASK 0x3c
#define ARB_ERR_CAP_STATUS_WRITE (1 << 1)
#define ARB_ERR_CAP_STATUS_VALID (1 << 0)
@@ -47,7 +43,6 @@ enum {
ARB_ERR_CAP_CLR,
ARB_ERR_CAP_HI_ADDR,
ARB_ERR_CAP_ADDR,
ARB_ERR_CAP_DATA,
ARB_ERR_CAP_STATUS,
ARB_ERR_CAP_MASTER,
};
@@ -57,17 +52,24 @@ static const int gisb_offsets_bcm7038[] = {
[ARB_ERR_CAP_CLR] = 0x0c4,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0c8,
[ARB_ERR_CAP_DATA] = 0x0cc,
[ARB_ERR_CAP_STATUS] = 0x0d0,
[ARB_ERR_CAP_MASTER] = -1,
};
static const int gisb_offsets_bcm7278[] = {
[ARB_TIMER] = 0x008,
[ARB_ERR_CAP_CLR] = 0x7f8,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x7e0,
[ARB_ERR_CAP_STATUS] = 0x7f0,
[ARB_ERR_CAP_MASTER] = 0x7f4,
};
static const int gisb_offsets_bcm7400[] = {
[ARB_TIMER] = 0x00c,
[ARB_ERR_CAP_CLR] = 0x0c8,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0cc,
[ARB_ERR_CAP_DATA] = 0x0d0,
[ARB_ERR_CAP_STATUS] = 0x0d4,
[ARB_ERR_CAP_MASTER] = 0x0d8,
};
@@ -77,7 +79,6 @@ static const int gisb_offsets_bcm7435[] = {
[ARB_ERR_CAP_CLR] = 0x168,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x16c,
[ARB_ERR_CAP_DATA] = 0x170,
[ARB_ERR_CAP_STATUS] = 0x174,
[ARB_ERR_CAP_MASTER] = 0x178,
};
@@ -87,7 +88,6 @@ static const int gisb_offsets_bcm7445[] = {
[ARB_ERR_CAP_CLR] = 0x7e4,
[ARB_ERR_CAP_HI_ADDR] = 0x7e8,
[ARB_ERR_CAP_ADDR] = 0x7ec,
[ARB_ERR_CAP_DATA] = 0x7f0,
[ARB_ERR_CAP_STATUS] = 0x7f4,
[ARB_ERR_CAP_MASTER] = 0x7f8,
};
@@ -109,9 +109,13 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
{
int offset = gdev->gisb_offsets[reg];
/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
if (offset == -1)
return 1;
if (offset < 0) {
/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
if (reg == ARB_ERR_CAP_MASTER)
return 1;
else
return 0;
}
if (gdev->big_endian)
return ioread32be(gdev->base + offset);
@@ -119,6 +123,16 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
return ioread32(gdev->base + offset);
}
static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
{
u64 value;
value = gisb_read(gdev, ARB_ERR_CAP_ADDR);
value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
return value;
}
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
{
int offset = gdev->gisb_offsets[reg];
@@ -127,9 +141,9 @@ static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
return;
if (gdev->big_endian)
iowrite32be(val, gdev->base + reg);
iowrite32be(val, gdev->base + offset);
else
iowrite32(val, gdev->base + reg);
iowrite32(val, gdev->base + offset);
}
static ssize_t gisb_arb_get_timeout(struct device *dev,
@@ -185,7 +199,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
const char *reason)
{
u32 cap_status;
unsigned long arb_addr;
u64 arb_addr;
u32 master;
const char *m_name;
char m_fmt[11];
@@ -197,10 +211,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
return 1;
/* Read the address and master */
arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
#endif
arb_addr = gisb_read_address(gdev);
master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
m_name = brcmstb_gisb_master_to_str(gdev, master);
@@ -209,7 +220,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
m_name = m_fmt;
}
pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n",
pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
__func__, reason, arb_addr,
cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
@@ -221,27 +232,6 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
return 0;
}
#ifdef CONFIG_ARM
static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
int ret = 0;
struct brcmstb_gisb_arb_device *gdev;
/* iterate over each GISB arb registered handlers */
list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error");
/*
* If it was an imprecise abort, then we need to correct the
* return address to be _after_ the instruction.
*/
if (fsr & (1 << 10))
regs->ARM_pc += 4;
return ret;
}
#endif
#ifdef CONFIG_MIPS
static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
{
@@ -279,6 +269,36 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
/*
* Dump out gisb errors on die or panic.
*/
static int dump_gisb_error(struct notifier_block *self, unsigned long v,
void *p);
static struct notifier_block gisb_die_notifier = {
.notifier_call = dump_gisb_error,
};
static struct notifier_block gisb_panic_notifier = {
.notifier_call = dump_gisb_error,
};
static int dump_gisb_error(struct notifier_block *self, unsigned long v,
void *p)
{
struct brcmstb_gisb_arb_device *gdev;
const char *reason = "panic";
if (self == &gisb_die_notifier)
reason = "die";
/* iterate over each GISB arb registered handlers */
list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
brcmstb_gisb_arb_decode_addr(gdev, reason);
return NOTIFY_DONE;
}
static DEVICE_ATTR(gisb_arb_timeout, S_IWUSR | S_IRUGO,
gisb_arb_get_timeout, gisb_arb_set_timeout);
@@ -296,6 +316,7 @@ static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
{ .compatible = "brcm,bcm7445-gisb-arb", .data = gisb_offsets_bcm7445 },
{ .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 },
{ .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 },
{ .compatible = "brcm,bcm7278-gisb-arb", .data = gisb_offsets_bcm7278 },
{ .compatible = "brcm,bcm7038-gisb-arb", .data = gisb_offsets_bcm7038 },
{ },
};
@@ -378,14 +399,16 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list);
#ifdef CONFIG_ARM
hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
"imprecise external abort");
#endif
#ifdef CONFIG_MIPS
board_be_handler = brcmstb_bus_error_handler;
#endif
if (list_is_singular(&brcmstb_gisb_arb_device_list)) {
register_die_notifier(&gisb_die_notifier);
atomic_notifier_chain_register(&panic_notifier_list,
&gisb_panic_notifier);
}
dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
gdev->base, timeout_irq, tea_irq);
+7
View File
@@ -103,6 +103,13 @@ config ORION_TIMER
help
Enables the support for the Orion timer driver
config OWL_TIMER
bool "Owl timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO
help
Enables the support for the Actions Semi Owl timer driver.
config SUN4I_TIMER
bool "Sun4i timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS
+1
View File
@@ -52,6 +52,7 @@ obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o
obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
obj-$(CONFIG_OWL_TIMER) += owl-timer.o
obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
+172
View File
@@ -0,0 +1,172 @@
/*
* Actions Semi Owl timer
*
* Copyright 2012 Actions Semi Inc.
* Author: Actions Semi, Inc.
*
* Copyright (c) 2017 SUSE Linux GmbH
* Author: Andreas Färber
*
* 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.
*/
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>
#include <linux/sched_clock.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#define OWL_Tx_CTL 0x0
#define OWL_Tx_CMP 0x4
#define OWL_Tx_VAL 0x8
#define OWL_Tx_CTL_PD BIT(0)
#define OWL_Tx_CTL_INTEN BIT(1)
#define OWL_Tx_CTL_EN BIT(2)
static void __iomem *owl_timer_base;
static void __iomem *owl_clksrc_base;
static void __iomem *owl_clkevt_base;
static inline void owl_timer_reset(void __iomem *base)
{
writel(0, base + OWL_Tx_CTL);
writel(0, base + OWL_Tx_VAL);
writel(0, base + OWL_Tx_CMP);
}
static inline void owl_timer_set_enabled(void __iomem *base, bool enabled)
{
u32 ctl = readl(base + OWL_Tx_CTL);
/* PD bit is cleared when set */
ctl &= ~OWL_Tx_CTL_PD;
if (enabled)
ctl |= OWL_Tx_CTL_EN;
else
ctl &= ~OWL_Tx_CTL_EN;
writel(ctl, base + OWL_Tx_CTL);
}
static u64 notrace owl_timer_sched_read(void)
{
return (u64)readl(owl_clksrc_base + OWL_Tx_VAL);
}
static int owl_timer_set_state_shutdown(struct clock_event_device *evt)
{
owl_timer_set_enabled(owl_clkevt_base, false);
return 0;
}
static int owl_timer_set_state_oneshot(struct clock_event_device *evt)
{
owl_timer_reset(owl_clkevt_base);
return 0;
}
static int owl_timer_tick_resume(struct clock_event_device *evt)
{
return 0;
}
static int owl_timer_set_next_event(unsigned long evt,
struct clock_event_device *ev)
{
void __iomem *base = owl_clkevt_base;
owl_timer_set_enabled(base, false);
writel(OWL_Tx_CTL_INTEN, base + OWL_Tx_CTL);
writel(0, base + OWL_Tx_VAL);
writel(evt, base + OWL_Tx_CMP);
owl_timer_set_enabled(base, true);
return 0;
}
static struct clock_event_device owl_clockevent = {
.name = "owl_tick",
.rating = 200,
.features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_DYNIRQ,
.set_state_shutdown = owl_timer_set_state_shutdown,
.set_state_oneshot = owl_timer_set_state_oneshot,
.tick_resume = owl_timer_tick_resume,
.set_next_event = owl_timer_set_next_event,
};
static irqreturn_t owl_timer1_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = (struct clock_event_device *)dev_id;
writel(OWL_Tx_CTL_PD, owl_clkevt_base + OWL_Tx_CTL);
evt->event_handler(evt);
return IRQ_HANDLED;
}
static int __init owl_timer_init(struct device_node *node)
{
struct clk *clk;
unsigned long rate;
int timer1_irq, ret;
owl_timer_base = of_io_request_and_map(node, 0, "owl-timer");
if (IS_ERR(owl_timer_base)) {
pr_err("Can't map timer registers");
return PTR_ERR(owl_timer_base);
}
owl_clksrc_base = owl_timer_base + 0x08;
owl_clkevt_base = owl_timer_base + 0x14;
timer1_irq = of_irq_get_byname(node, "timer1");
if (timer1_irq <= 0) {
pr_err("Can't parse timer1 IRQ");
return -EINVAL;
}
clk = of_clk_get(node, 0);
if (IS_ERR(clk))
return PTR_ERR(clk);
rate = clk_get_rate(clk);
owl_timer_reset(owl_clksrc_base);
owl_timer_set_enabled(owl_clksrc_base, true);
sched_clock_register(owl_timer_sched_read, 32, rate);
clocksource_mmio_init(owl_clksrc_base + OWL_Tx_VAL, node->name,
rate, 200, 32, clocksource_mmio_readl_up);
owl_timer_reset(owl_clkevt_base);
ret = request_irq(timer1_irq, owl_timer1_interrupt, IRQF_TIMER,
"owl-timer", &owl_clockevent);
if (ret) {
pr_err("failed to request irq %d\n", timer1_irq);
return ret;
}
owl_clockevent.cpumask = cpumask_of(0);
owl_clockevent.irq = timer1_irq;
clockevents_config_and_register(&owl_clockevent, rate,
0xf, 0xffffffff);
return 0;
}
CLOCKSOURCE_OF_DECLARE(owl_s500, "actions,s500-timer", owl_timer_init);
CLOCKSOURCE_OF_DECLARE(owl_s900, "actions,s900-timer", owl_timer_init);
+6 -32
View File
@@ -30,46 +30,20 @@
static struct scpi_ops *scpi_ops;
static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
{
int domain = topology_physical_package_id(cpu_dev->id);
if (domain < 0)
return ERR_PTR(-EINVAL);
return scpi_ops->dvfs_get_info(domain);
}
static int scpi_get_transition_latency(struct device *cpu_dev)
{
struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
if (IS_ERR(info))
return PTR_ERR(info);
return info->latency;
return scpi_ops->get_transition_latency(cpu_dev);
}
static int scpi_init_opp_table(const struct cpumask *cpumask)
{
int idx, ret;
struct scpi_opp *opp;
int ret;
struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask));
struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
if (IS_ERR(info))
return PTR_ERR(info);
if (!info->opps)
return -EIO;
for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
ret = dev_pm_opp_add(cpu_dev, opp->freq, opp->m_volt * 1000);
if (ret) {
dev_warn(cpu_dev, "failed to add opp %uHz %umV\n",
opp->freq, opp->m_volt);
while (idx-- > 0)
dev_pm_opp_remove(cpu_dev, (--opp)->freq);
return ret;
}
ret = scpi_ops->add_opps_to_device(cpu_dev);
if (ret) {
dev_warn(cpu_dev, "failed to add opps to the device\n");
return ret;
}
ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask);
+63
View File
@@ -39,6 +39,7 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/pm_opp.h>
#include <linux/scpi_protocol.h>
#include <linux/slab.h>
#include <linux/sort.h>
@@ -684,6 +685,65 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
return info;
}
static int scpi_dev_domain_id(struct device *dev)
{
struct of_phandle_args clkspec;
if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells",
0, &clkspec))
return -EINVAL;
return clkspec.args[0];
}
static struct scpi_dvfs_info *scpi_dvfs_info(struct device *dev)
{
int domain = scpi_dev_domain_id(dev);
if (domain < 0)
return ERR_PTR(domain);
return scpi_dvfs_get_info(domain);
}
static int scpi_dvfs_get_transition_latency(struct device *dev)
{
struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
if (IS_ERR(info))
return PTR_ERR(info);
if (!info->latency)
return 0;
return info->latency;
}
static int scpi_dvfs_add_opps_to_device(struct device *dev)
{
int idx, ret;
struct scpi_opp *opp;
struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
if (IS_ERR(info))
return PTR_ERR(info);
if (!info->opps)
return -EIO;
for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
ret = dev_pm_opp_add(dev, opp->freq, opp->m_volt * 1000);
if (ret) {
dev_warn(dev, "failed to add opp %uHz %umV\n",
opp->freq, opp->m_volt);
while (idx-- > 0)
dev_pm_opp_remove(dev, (--opp)->freq);
return ret;
}
}
return 0;
}
static int scpi_sensor_get_capability(u16 *sensors)
{
struct sensor_capabilities cap_buf;
@@ -765,6 +825,9 @@ static struct scpi_ops scpi_ops = {
.dvfs_get_idx = scpi_dvfs_get_idx,
.dvfs_set_idx = scpi_dvfs_set_idx,
.dvfs_get_info = scpi_dvfs_get_info,
.device_domain_id = scpi_dev_domain_id,
.get_transition_latency = scpi_dvfs_get_transition_latency,
.add_opps_to_device = scpi_dvfs_add_opps_to_device,
.sensor_get_capability = scpi_sensor_get_capability,
.sensor_get_info = scpi_sensor_get_info,
.sensor_get_value = scpi_sensor_get_value,
+22 -10
View File
@@ -211,14 +211,17 @@ static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
int index;
index = tegra_bpmp_channel_get_thread_index(channel);
if (index < 0)
return index;
if (index < 0) {
err = index;
goto unlock;
}
spin_lock_irqsave(&bpmp->lock, flags);
err = __tegra_bpmp_channel_read(channel, data, size);
clear_bit(index, bpmp->threaded.allocated);
spin_unlock_irqrestore(&bpmp->lock, flags);
unlock:
up(&bpmp->threaded.lock);
return err;
@@ -256,18 +259,18 @@ tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq,
index = find_first_zero_bit(bpmp->threaded.allocated, count);
if (index == count) {
channel = ERR_PTR(-EBUSY);
err = -EBUSY;
goto unlock;
}
channel = tegra_bpmp_channel_get_thread(bpmp, index);
if (!channel) {
channel = ERR_PTR(-EINVAL);
err = -EINVAL;
goto unlock;
}
if (!tegra_bpmp_master_free(channel)) {
channel = ERR_PTR(-EBUSY);
err = -EBUSY;
goto unlock;
}
@@ -275,16 +278,21 @@ tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq,
err = __tegra_bpmp_channel_write(channel, mrq, MSG_ACK | MSG_RING,
data, size);
if (err < 0) {
clear_bit(index, bpmp->threaded.allocated);
goto unlock;
}
if (err < 0)
goto clear_allocated;
set_bit(index, bpmp->threaded.busy);
unlock:
spin_unlock_irqrestore(&bpmp->lock, flags);
return channel;
clear_allocated:
clear_bit(index, bpmp->threaded.allocated);
unlock:
spin_unlock_irqrestore(&bpmp->lock, flags);
up(&bpmp->threaded.lock);
return ERR_PTR(err);
}
static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
@@ -810,6 +818,10 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
if (err < 0)
goto free_mrq;
err = tegra_bpmp_init_powergates(bpmp);
if (err < 0)
goto free_mrq;
platform_set_drvdata(pdev, bpmp);
return 0;
+6 -3
View File
@@ -460,12 +460,12 @@ static int get_gpmc_timing_reg(
if (l)
time_ns_min = gpmc_clk_ticks_to_ns(l - 1, cs, cd) + 1;
time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
pr_info("gpmc,%s = <%u> /* %u ns - %u ns; %i ticks%s*/\n",
pr_info("gpmc,%s = <%u>; /* %u ns - %u ns; %i ticks%s*/\n",
name, time_ns, time_ns_min, time_ns, l,
invalid ? "; invalid " : " ");
} else {
/* raw format */
pr_info("gpmc,%s = <%u>%s\n", name, l,
pr_info("gpmc,%s = <%u>;%s\n", name, l,
invalid ? " /* invalid */" : "");
}
@@ -2083,8 +2083,11 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
} else {
ret = of_property_read_u32(child, "bank-width",
&gpmc_s.device_width);
if (ret < 0)
if (ret < 0) {
dev_err(&pdev->dev, "%s has no 'bank-width' property\n",
child->full_name);
goto err;
}
}
/* Reserve wait pin if it is required and valid */
+16 -1
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
+3 -1
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
+18 -11
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))
+110
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);
+269
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 <afd@ti.com>");
MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver");
MODULE_LICENSE("GPL v2");
+2 -4
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;
+1
View File
@@ -7,6 +7,7 @@ source "drivers/soc/fsl/Kconfig"
source "drivers/soc/imx/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/samsung/Kconfig"
source "drivers/soc/sunxi/Kconfig"

Some files were not shown because too many files have changed in this diff Show More