Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c2f8a2f authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'arm-soc/for-4.13/drivers' of http://github.com/Broadcom/stblinux into next/drivers

This pull request contains Broadcom ARM/ARM64 SoCs specific driver changes for
4.13, please pull the following:

- Doug adds support for the latest generation GISB bus arbiter (v7), he starts by
  fixing two issues in how registers are written, and how 64-bit addresses are captured
  and then he simplifies the error interception by using notifiers, which allows him
  to add support for ARM64

- Markus updates the SOC_BRCMSTB Kconfig depends to cover ARM64 and BMIPS_GENERIC
  systems where this code is now also used

* tag 'arm-soc/for-4.13/drivers' of http://github.com/Broadcom/stblinux

:
  soc: brcmstb: enable drivers for ARM64 and BMIPS
  bus: brcmstb_gisb: update to support new revision
  bus: brcmstb_gisb: enable driver for ARM64 architecture
  bus: brcmstb_gisb: remove low-level ARM hooks
  bus: brcmstb_gisb: add notifier handling
  bus: brcmstb_gisb: correct support for 64-bit address output
  bus: brcmstb_gisb: Use register offsets with writes too

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 7a699a85 1f6ab20f
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -3,7 +3,8 @@ Broadcom GISB bus Arbiter controller
Required properties:
Required properties:


- compatible:
- 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,bcm7435-gisb-arb" for newer 40nm chips
    "brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips
    "brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips
    "brcm,bcm7038-gisb-arb" for 130nm chips
    "brcm,bcm7038-gisb-arb" for 130nm chips
+1 −1
Original line number Original line Diff line number Diff line
@@ -57,7 +57,7 @@ config ARM_CCN


config BRCMSTB_GISB_ARB
config BRCMSTB_GISB_ARB
	bool "Broadcom STB GISB bus arbiter"
	bool "Broadcom STB GISB bus arbiter"
	depends on ARM || MIPS
	depends on ARM || ARM64 || MIPS
	default ARCH_BRCMSTB || BMIPS_GENERIC
	default ARCH_BRCMSTB || BMIPS_GENERIC
	help
	help
	  Driver for the Broadcom Set Top Box System-on-a-chip internal bus
	  Driver for the Broadcom Set Top Box System-on-a-chip internal bus
+72 −49
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (C) 2014 Broadcom Corporation
 * Copyright (C) 2014-2017 Broadcom
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * 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
 * it under the terms of the GNU General Public License version 2 as
@@ -24,11 +24,9 @@
#include <linux/of.h>
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/bitops.h>
#include <linux/pm.h>
#include <linux/pm.h>

#include <linux/kernel.h>
#ifdef CONFIG_ARM
#include <linux/kdebug.h>
#include <asm/bug.h>
#include <linux/notifier.h>
#include <asm/signal.h>
#endif


#ifdef CONFIG_MIPS
#ifdef CONFIG_MIPS
#include <asm/traps.h>
#include <asm/traps.h>
@@ -37,8 +35,6 @@
#define  ARB_ERR_CAP_CLEAR		(1 << 0)
#define  ARB_ERR_CAP_CLEAR		(1 << 0)
#define  ARB_ERR_CAP_STATUS_TIMEOUT	(1 << 12)
#define  ARB_ERR_CAP_STATUS_TIMEOUT	(1 << 12)
#define  ARB_ERR_CAP_STATUS_TEA		(1 << 11)
#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_WRITE	(1 << 1)
#define  ARB_ERR_CAP_STATUS_VALID	(1 << 0)
#define  ARB_ERR_CAP_STATUS_VALID	(1 << 0)


@@ -47,7 +43,6 @@ enum {
	ARB_ERR_CAP_CLR,
	ARB_ERR_CAP_CLR,
	ARB_ERR_CAP_HI_ADDR,
	ARB_ERR_CAP_HI_ADDR,
	ARB_ERR_CAP_ADDR,
	ARB_ERR_CAP_ADDR,
	ARB_ERR_CAP_DATA,
	ARB_ERR_CAP_STATUS,
	ARB_ERR_CAP_STATUS,
	ARB_ERR_CAP_MASTER,
	ARB_ERR_CAP_MASTER,
};
};
@@ -57,17 +52,24 @@ static const int gisb_offsets_bcm7038[] = {
	[ARB_ERR_CAP_CLR]	= 0x0c4,
	[ARB_ERR_CAP_CLR]	= 0x0c4,
	[ARB_ERR_CAP_HI_ADDR]	= -1,
	[ARB_ERR_CAP_HI_ADDR]	= -1,
	[ARB_ERR_CAP_ADDR]	= 0x0c8,
	[ARB_ERR_CAP_ADDR]	= 0x0c8,
	[ARB_ERR_CAP_DATA]	= 0x0cc,
	[ARB_ERR_CAP_STATUS]	= 0x0d0,
	[ARB_ERR_CAP_STATUS]	= 0x0d0,
	[ARB_ERR_CAP_MASTER]	= -1,
	[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[] = {
static const int gisb_offsets_bcm7400[] = {
	[ARB_TIMER]		= 0x00c,
	[ARB_TIMER]		= 0x00c,
	[ARB_ERR_CAP_CLR]	= 0x0c8,
	[ARB_ERR_CAP_CLR]	= 0x0c8,
	[ARB_ERR_CAP_HI_ADDR]	= -1,
	[ARB_ERR_CAP_HI_ADDR]	= -1,
	[ARB_ERR_CAP_ADDR]	= 0x0cc,
	[ARB_ERR_CAP_ADDR]	= 0x0cc,
	[ARB_ERR_CAP_DATA]	= 0x0d0,
	[ARB_ERR_CAP_STATUS]	= 0x0d4,
	[ARB_ERR_CAP_STATUS]	= 0x0d4,
	[ARB_ERR_CAP_MASTER]	= 0x0d8,
	[ARB_ERR_CAP_MASTER]	= 0x0d8,
};
};
@@ -77,7 +79,6 @@ static const int gisb_offsets_bcm7435[] = {
	[ARB_ERR_CAP_CLR]	= 0x168,
	[ARB_ERR_CAP_CLR]	= 0x168,
	[ARB_ERR_CAP_HI_ADDR]	= -1,
	[ARB_ERR_CAP_HI_ADDR]	= -1,
	[ARB_ERR_CAP_ADDR]	= 0x16c,
	[ARB_ERR_CAP_ADDR]	= 0x16c,
	[ARB_ERR_CAP_DATA]	= 0x170,
	[ARB_ERR_CAP_STATUS]	= 0x174,
	[ARB_ERR_CAP_STATUS]	= 0x174,
	[ARB_ERR_CAP_MASTER]	= 0x178,
	[ARB_ERR_CAP_MASTER]	= 0x178,
};
};
@@ -87,7 +88,6 @@ static const int gisb_offsets_bcm7445[] = {
	[ARB_ERR_CAP_CLR]	= 0x7e4,
	[ARB_ERR_CAP_CLR]	= 0x7e4,
	[ARB_ERR_CAP_HI_ADDR]	= 0x7e8,
	[ARB_ERR_CAP_HI_ADDR]	= 0x7e8,
	[ARB_ERR_CAP_ADDR]	= 0x7ec,
	[ARB_ERR_CAP_ADDR]	= 0x7ec,
	[ARB_ERR_CAP_DATA]	= 0x7f0,
	[ARB_ERR_CAP_STATUS]	= 0x7f4,
	[ARB_ERR_CAP_STATUS]	= 0x7f4,
	[ARB_ERR_CAP_MASTER]	= 0x7f8,
	[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];
	int offset = gdev->gisb_offsets[reg];


	if (offset < 0) {
		/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
		/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
	if (offset == -1)
		if (reg == ARB_ERR_CAP_MASTER)
			return 1;
			return 1;
		else
			return 0;
	}


	if (gdev->big_endian)
	if (gdev->big_endian)
		return ioread32be(gdev->base + offset);
		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);
		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)
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
{
{
	int offset = gdev->gisb_offsets[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;
		return;


	if (gdev->big_endian)
	if (gdev->big_endian)
		iowrite32be(val, gdev->base + reg);
		iowrite32be(val, gdev->base + offset);
	else
	else
		iowrite32(val, gdev->base + reg);
		iowrite32(val, gdev->base + offset);
}
}


static ssize_t gisb_arb_get_timeout(struct device *dev,
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)
					const char *reason)
{
{
	u32 cap_status;
	u32 cap_status;
	unsigned long arb_addr;
	u64 arb_addr;
	u32 master;
	u32 master;
	const char *m_name;
	const char *m_name;
	char m_fmt[11];
	char m_fmt[11];
@@ -197,10 +211,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
		return 1;
		return 1;


	/* Read the address and master */
	/* Read the address and master */
	arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
	arb_addr = gisb_read_address(gdev);
#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
	arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
#endif
	master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
	master = gisb_read(gdev, ARB_ERR_CAP_MASTER);


	m_name = brcmstb_gisb_master_to_str(gdev, 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;
		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,
		__func__, reason, arb_addr,
		cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
		cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
		cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
		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;
	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
#ifdef CONFIG_MIPS
static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
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;
	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,
static DEVICE_ATTR(gisb_arb_timeout, S_IWUSR | S_IRUGO,
		gisb_arb_get_timeout, gisb_arb_set_timeout);
		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,bcm7445-gisb-arb", .data = gisb_offsets_bcm7445 },
	{ .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 },
	{ .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 },
	{ .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 },
	{ .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 },
	{ .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);
	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
#ifdef CONFIG_MIPS
	board_be_handler = brcmstb_bus_error_handler;
	board_be_handler = brcmstb_bus_error_handler;
#endif
#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",
	dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
			gdev->base, timeout_irq, tea_irq);
			gdev->base, timeout_irq, tea_irq);


+1 −1
Original line number Original line Diff line number Diff line
@@ -11,7 +11,7 @@ config RASPBERRYPI_POWER


config SOC_BRCMSTB
config SOC_BRCMSTB
	bool "Broadcom STB SoC drivers"
	bool "Broadcom STB SoC drivers"
	depends on ARM
	depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
	select SOC_BUS
	select SOC_BUS
	help
	help
	  Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
	  Enables drivers for the Broadcom Set-Top Box (STB) series of chips.