diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 00:47:47 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 00:47:47 +0300 |
commit | e8547112910540afb71589ee807ae6a4259f9755 (patch) | |
tree | 7d3d7eb17be4e6d2b181bffc4d471e93063674b4 /drivers/bus | |
parent | 9ce32ac8f83729aca9f45ce9598dbc5451d1044b (diff) | |
parent | ffe3744a591fdce695da6b891378261e2caedc69 (diff) | |
download | linux-e8547112910540afb71589ee807ae6a4259f9755.tar.xz |
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
...
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/Kconfig | 2 | ||||
-rw-r--r-- | drivers/bus/brcmstb_gisb.c | 121 |
2 files changed, 73 insertions, 50 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 0a52da439abf..d2a5f1184022 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -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 diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index 72fe0a5a8bf3..68ac3e93b600 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -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); |