Commit bd2fad8c authored by Olof Johansson's avatar Olof Johansson

Merge tag 'arm-soc/for-5.10/drivers' of https://github.com/Broadcom/stblinux into arm/drivers

This pull request contains Broadcom SoCs drivers changes for 5.10,
please pull the following:

- Alvaro adds support for the BCM63xx (DSL) SoCs power domain controller
  and adds support for the 6318, 6328, 6362, 63268.

- Florian adds support for tuning the Bus Interface Unit on 72164 and
  72165, enables the Brahma-B53 and Cortex-A72 read-ahead cache for the
  64-bit capable ARCH_BRCMSTB platforms, and finally updates the GISB
  driver to support breakpoint notifications.

* tag 'arm-soc/for-5.10/drivers' of https://github.com/Broadcom/stblinux:
  bus: brcmstb_gisb: Add support for breakpoint interrupts
  dt-bindings: bus: Document breakpoint interrupt for gisb-arb
  soc: bcm: brcmstb: biuctrl: Change RAC data line prefetching after 4 consecutive lines
  soc: bcm: brcmstb: biuctrl: Change RAC prefetch distance from +/-1 to +/- 2
  soc: bcm: brcmstb: biuctrl: Tune MCP settings for 72165
  soc: bcm: brcmstb: biuctrl: Tune MCP settings for 72164
  MIPS: BMIPS: dts: add BCM63268 power domain support
  MIPS: BMIPS: dts: add BCM6362 power domain support
  MIPS: BMIPS: dts: add BCM6328 power domain support
  soc: bcm: add BCM63xx power domain driver
  MIPS: BMIPS: add BCM6318 power domain definitions
  MIPS: BMIPS: add BCM63268 power domain definitions
  MIPS: BMIPS: add BCM6362 power domain definitions
  MIPS: BMIPS: add BCM6328 power domain definitions
  dt-bindings: soc: brcm: add BCM63xx power domain binding
  soc: bcm: brcmstb: biuctrl: Enable Read-ahead cache
  bus: brcmstb_gisb: Shorten prints

Link: https://lore.kernel.org/r/20200912032153.1216354-3-f.fainelli@gmail.comSigned-off-by: default avatarOlof Johansson <olof@lixom.net>
parents bac9bd95 fb8a0b80
...@@ -10,7 +10,8 @@ Required properties: ...@@ -10,7 +10,8 @@ Required properties:
"brcm,bcm7038-gisb-arb" for 130nm chips "brcm,bcm7038-gisb-arb" for 130nm chips
- reg: specifies the base physical address and size of the registers - reg: specifies the base physical address and size of the registers
- interrupts: specifies the two interrupts (timeout and TEA) to be used from - interrupts: specifies the two interrupts (timeout and TEA) to be used from
the parent interrupt controller the parent interrupt controller. A third optional interrupt may be specified
for breakpoints.
Optional properties: Optional properties:
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/power/brcm,bcm63xx-power.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: BCM63xx power domain driver
maintainers:
- Álvaro Fernández Rojas <noltari@gmail.com>
description: |
BCM6318, BCM6328, BCM6362 and BCM63268 SoCs have a power domain controller
to enable/disable certain components in order to save power.
properties:
compatible:
items:
- enum:
- brcm,bcm6318-power-controller
- brcm,bcm6328-power-controller
- brcm,bcm6362-power-controller
- brcm,bcm63268-power-controller
reg:
maxItems: 1
"#power-domain-cells":
const: 1
required:
- compatible
- reg
- "#power-domain-cells"
additionalProperties: false
examples:
- |
periph_pwr: power-controller@10001848 {
compatible = "brcm,bcm6328-power-controller";
reg = <0x10001848 0x4>;
#power-domain-cells = <1>;
};
...@@ -3491,6 +3491,7 @@ F: arch/mips/bmips/* ...@@ -3491,6 +3491,7 @@ F: arch/mips/bmips/*
F: arch/mips/boot/dts/brcm/bcm*.dts* F: arch/mips/boot/dts/brcm/bcm*.dts*
F: arch/mips/include/asm/mach-bmips/* F: arch/mips/include/asm/mach-bmips/*
F: arch/mips/kernel/*bmips* F: arch/mips/kernel/*bmips*
F: drivers/soc/bcm/bcm63xx
F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm63*
F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-bcm7*
F: drivers/irqchip/irq-brcmstb* F: drivers/irqchip/irq-brcmstb*
......
...@@ -117,6 +117,12 @@ leds0: led-controller@10001900 { ...@@ -117,6 +117,12 @@ leds0: led-controller@10001900 {
status = "disabled"; status = "disabled";
}; };
periph_pwr: power-controller@1000184c {
compatible = "brcm,bcm6328-power-controller";
reg = <0x1000184c 0x4>;
#power-domain-cells = <1>;
};
ehci: usb@10002500 { ehci: usb@10002500 {
compatible = "brcm,bcm63268-ehci", "generic-ehci"; compatible = "brcm,bcm63268-ehci", "generic-ehci";
reg = <0x10002500 0x100>; reg = <0x10002500 0x100>;
......
...@@ -110,6 +110,12 @@ leds0: led-controller@10000800 { ...@@ -110,6 +110,12 @@ leds0: led-controller@10000800 {
status = "disabled"; status = "disabled";
}; };
periph_pwr: power-controller@10001848 {
compatible = "brcm,bcm6328-power-controller";
reg = <0x10001848 0x4>;
#power-domain-cells = <1>;
};
ehci: usb@10002500 { ehci: usb@10002500 {
compatible = "brcm,bcm6328-ehci", "generic-ehci"; compatible = "brcm,bcm6328-ehci", "generic-ehci";
reg = <0x10002500 0x100>; reg = <0x10002500 0x100>;
......
...@@ -108,6 +108,12 @@ uart1: serial@10000120 { ...@@ -108,6 +108,12 @@ uart1: serial@10000120 {
status = "disabled"; status = "disabled";
}; };
periph_pwr: power-controller@10001848 {
compatible = "brcm,bcm6362-power-controller";
reg = <0x10001848 0x4>;
#power-domain-cells = <1>;
};
leds0: led-controller@10001900 { leds0: led-controller@10001900 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
...@@ -30,8 +30,22 @@ ...@@ -30,8 +30,22 @@
#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)
#define ARB_BP_CAP_CLEAR (1 << 0)
#define ARB_BP_CAP_STATUS_PROT_SHIFT 14
#define ARB_BP_CAP_STATUS_TYPE (1 << 13)
#define ARB_BP_CAP_STATUS_RSP_SHIFT 10
#define ARB_BP_CAP_STATUS_MASK GENMASK(1, 0)
#define ARB_BP_CAP_STATUS_BS_SHIFT 2
#define ARB_BP_CAP_STATUS_WRITE (1 << 1)
#define ARB_BP_CAP_STATUS_VALID (1 << 0)
enum { enum {
ARB_TIMER, ARB_TIMER,
ARB_BP_CAP_CLR,
ARB_BP_CAP_HI_ADDR,
ARB_BP_CAP_ADDR,
ARB_BP_CAP_STATUS,
ARB_BP_CAP_MASTER,
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,
...@@ -41,6 +55,11 @@ enum { ...@@ -41,6 +55,11 @@ enum {
static const int gisb_offsets_bcm7038[] = { static const int gisb_offsets_bcm7038[] = {
[ARB_TIMER] = 0x00c, [ARB_TIMER] = 0x00c,
[ARB_BP_CAP_CLR] = 0x014,
[ARB_BP_CAP_HI_ADDR] = -1,
[ARB_BP_CAP_ADDR] = 0x0b8,
[ARB_BP_CAP_STATUS] = 0x0c0,
[ARB_BP_CAP_MASTER] = -1,
[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,
...@@ -50,6 +69,11 @@ static const int gisb_offsets_bcm7038[] = { ...@@ -50,6 +69,11 @@ static const int gisb_offsets_bcm7038[] = {
static const int gisb_offsets_bcm7278[] = { static const int gisb_offsets_bcm7278[] = {
[ARB_TIMER] = 0x008, [ARB_TIMER] = 0x008,
[ARB_BP_CAP_CLR] = 0x01c,
[ARB_BP_CAP_HI_ADDR] = -1,
[ARB_BP_CAP_ADDR] = 0x220,
[ARB_BP_CAP_STATUS] = 0x230,
[ARB_BP_CAP_MASTER] = 0x234,
[ARB_ERR_CAP_CLR] = 0x7f8, [ARB_ERR_CAP_CLR] = 0x7f8,
[ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x7e0, [ARB_ERR_CAP_ADDR] = 0x7e0,
...@@ -59,6 +83,11 @@ static const int gisb_offsets_bcm7278[] = { ...@@ -59,6 +83,11 @@ static const int gisb_offsets_bcm7278[] = {
static const int gisb_offsets_bcm7400[] = { static const int gisb_offsets_bcm7400[] = {
[ARB_TIMER] = 0x00c, [ARB_TIMER] = 0x00c,
[ARB_BP_CAP_CLR] = 0x014,
[ARB_BP_CAP_HI_ADDR] = -1,
[ARB_BP_CAP_ADDR] = 0x0b8,
[ARB_BP_CAP_STATUS] = 0x0c0,
[ARB_BP_CAP_MASTER] = 0x0c4,
[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,
...@@ -68,6 +97,11 @@ static const int gisb_offsets_bcm7400[] = { ...@@ -68,6 +97,11 @@ static const int gisb_offsets_bcm7400[] = {
static const int gisb_offsets_bcm7435[] = { static const int gisb_offsets_bcm7435[] = {
[ARB_TIMER] = 0x00c, [ARB_TIMER] = 0x00c,
[ARB_BP_CAP_CLR] = 0x014,
[ARB_BP_CAP_HI_ADDR] = -1,
[ARB_BP_CAP_ADDR] = 0x158,
[ARB_BP_CAP_STATUS] = 0x160,
[ARB_BP_CAP_MASTER] = 0x164,
[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,
...@@ -77,6 +111,11 @@ static const int gisb_offsets_bcm7435[] = { ...@@ -77,6 +111,11 @@ static const int gisb_offsets_bcm7435[] = {
static const int gisb_offsets_bcm7445[] = { static const int gisb_offsets_bcm7445[] = {
[ARB_TIMER] = 0x008, [ARB_TIMER] = 0x008,
[ARB_BP_CAP_CLR] = 0x010,
[ARB_BP_CAP_HI_ADDR] = -1,
[ARB_BP_CAP_ADDR] = 0x1d8,
[ARB_BP_CAP_STATUS] = 0x1e0,
[ARB_BP_CAP_MASTER] = 0x1e4,
[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,
...@@ -125,6 +164,16 @@ static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev) ...@@ -125,6 +164,16 @@ static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
return value; return value;
} }
static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev)
{
u64 value;
value = gisb_read(gdev, ARB_BP_CAP_ADDR);
value |= (u64)gisb_read(gdev, ARB_BP_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];
...@@ -210,8 +259,8 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev, ...@@ -210,8 +259,8 @@ 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%llx [%c %s], core: %s\n", pr_crit("GISB: %s at 0x%llx [%c %s], core: %s\n",
__func__, reason, arb_addr, 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" : "",
m_name); m_name);
...@@ -259,6 +308,41 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id) ...@@ -259,6 +308,41 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id)
{
struct brcmstb_gisb_arb_device *gdev = dev_id;
const char *m_name;
u32 bp_status;
u64 arb_addr;
u32 master;
char m_fmt[11];
bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS);
/* Invalid captured address, bail out */
if (!(bp_status & ARB_BP_CAP_STATUS_VALID))
return IRQ_HANDLED;
/* Read the address and master */
arb_addr = gisb_read_bp_address(gdev);
master = gisb_read(gdev, ARB_BP_CAP_MASTER);
m_name = brcmstb_gisb_master_to_str(gdev, master);
if (!m_name) {
snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master);
m_name = m_fmt;
}
pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n",
arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R',
m_name);
/* clear the GISB error */
gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);
return IRQ_HANDLED;
}
/* /*
* Dump out gisb errors on die or panic. * Dump out gisb errors on die or panic.
*/ */
...@@ -317,13 +401,14 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) ...@@ -317,13 +401,14 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
struct brcmstb_gisb_arb_device *gdev; struct brcmstb_gisb_arb_device *gdev;
const struct of_device_id *of_id; const struct of_device_id *of_id;
struct resource *r; struct resource *r;
int err, timeout_irq, tea_irq; int err, timeout_irq, tea_irq, bp_irq;
unsigned int num_masters, j = 0; unsigned int num_masters, j = 0;
int i, first, last; int i, first, last;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
timeout_irq = platform_get_irq(pdev, 0); timeout_irq = platform_get_irq(pdev, 0);
tea_irq = platform_get_irq(pdev, 1); tea_irq = platform_get_irq(pdev, 1);
bp_irq = platform_get_irq(pdev, 2);
gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL); gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL);
if (!gdev) if (!gdev)
...@@ -356,6 +441,15 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) ...@@ -356,6 +441,15 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
return err; return err;
/* Interrupt is optional */
if (bp_irq > 0) {
err = devm_request_irq(&pdev->dev, bp_irq,
brcmstb_gisb_bp_handler, 0, pdev->name,
gdev);
if (err < 0)
return err;
}
/* If we do not have a valid mask, assume all masters are enabled */ /* If we do not have a valid mask, assume all masters are enabled */
if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask", if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask",
&gdev->valid_mask)) &gdev->valid_mask))
......
...@@ -22,6 +22,15 @@ config RASPBERRYPI_POWER ...@@ -22,6 +22,15 @@ config RASPBERRYPI_POWER
This enables support for the RPi power domains which can be enabled This enables support for the RPi power domains which can be enabled
or disabled via the RPi firmware. or disabled via the RPi firmware.
config SOC_BCM63XX
bool "Broadcom 63xx SoC drivers"
depends on BMIPS_GENERIC || COMPILE_TEST
help
Enables drivers for the Broadcom 63xx series of chips.
Drivers can be enabled individually within this menu.
If unsure, say N.
config SOC_BRCMSTB config SOC_BRCMSTB
bool "Broadcom STB SoC drivers" bool "Broadcom STB SoC drivers"
depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
...@@ -33,6 +42,7 @@ config SOC_BRCMSTB ...@@ -33,6 +42,7 @@ config SOC_BRCMSTB
If unsure, say N. If unsure, say N.
source "drivers/soc/bcm/bcm63xx/Kconfig"
source "drivers/soc/bcm/brcmstb/Kconfig" source "drivers/soc/bcm/brcmstb/Kconfig"
endmenu endmenu
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
obj-$(CONFIG_SOC_BCM63XX) += bcm63xx/
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/ obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
# SPDX-License-Identifier: GPL-2.0-only
if SOC_BCM63XX
config BCM63XX_POWER
bool "BCM63xx power domain driver"
depends on BMIPS_GENERIC || (COMPILE_TEST && OF)
select PM_GENERIC_DOMAINS if PM
help
This enables support for the BCM63xx power domains controller on
BCM6318, BCM6328, BCM6362 and BCM63268 SoCs.
endif # SOC_BCM63XX
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* BCM63xx Power Domain Controller Driver
*
* Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
*/
#include <dt-bindings/soc/bcm6318-pm.h>
#include <dt-bindings/soc/bcm6328-pm.h>
#include <dt-bindings/soc/bcm6362-pm.h>
#include <dt-bindings/soc/bcm63268-pm.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/of.h>
#include <linux/of_device.h>
struct bcm63xx_power_dev {
struct generic_pm_domain genpd;
struct bcm63xx_power *power;
uint32_t mask;
};
struct bcm63xx_power {
void __iomem *base;
spinlock_t lock;
struct bcm63xx_power_dev *dev;
struct genpd_onecell_data genpd_data;
struct generic_pm_domain **genpd;
};
struct bcm63xx_power_data {
const char * const name;
uint8_t bit;
unsigned int flags;
};
static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
{
struct bcm63xx_power *power = pmd->power;
if (!pmd->mask) {
*is_on = false;
return -EINVAL;
}
*is_on = !(__raw_readl(power->base) & pmd->mask);
return 0;
}
static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
{
struct bcm63xx_power *power = pmd->power;
unsigned long flags;
uint32_t val;
if (!pmd->mask)
return -EINVAL;
spin_lock_irqsave(&power->lock, flags);
val = __raw_readl(power->base);
if (on)
val &= ~pmd->mask;
else
val |= pmd->mask;
__raw_writel(val, power->base);
spin_unlock_irqrestore(&power->lock, flags);
return 0;
}
static int bcm63xx_power_on(struct generic_pm_domain *genpd)
{
struct bcm63xx_power_dev *pmd = container_of(genpd,
struct bcm63xx_power_dev, genpd);
return bcm63xx_power_set_state(pmd, true);
}
static int bcm63xx_power_off(struct generic_pm_domain *genpd)
{
struct bcm63xx_power_dev *pmd = container_of(genpd,
struct bcm63xx_power_dev, genpd);
return bcm63xx_power_set_state(pmd, false);
}
static int bcm63xx_power_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct resource *res;
const struct bcm63xx_power_data *entry, *table;
struct bcm63xx_power *power;
unsigned int ndom;
uint8_t max_bit = 0;
int ret;
power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
if (!power)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
power->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(power->base))
return PTR_ERR(power->base);
table = of_device_get_match_data(dev);
if (!table)
return -EINVAL;
power->genpd_data.num_domains = 0;
ndom = 0;
for (entry = table; entry->name; entry++) {
max_bit = max(max_bit, entry->bit);
ndom++;
}
if (!ndom)
return -ENODEV;
power->genpd_data.num_domains = max_bit + 1;
power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
sizeof(struct bcm63xx_power_dev),
GFP_KERNEL);
if (!power->dev)
return -ENOMEM;
power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
sizeof(struct generic_pm_domain *),
GFP_KERNEL);
if (!power->genpd)
return -ENOMEM;
power->genpd_data.domains = power->genpd;
ndom = 0;
for (entry = table; entry->name; entry++) {
struct bcm63xx_power_dev *pmd = &power->dev[ndom];
bool is_on;
pmd->power = power;
pmd->mask = BIT(entry->bit);
pmd->genpd.name = entry->name;
pmd->genpd.flags = entry->flags;
ret = bcm63xx_power_get_state(pmd, &is_on);
if (ret)
dev_warn(dev, "unable to get current state for %s\n",
pmd->genpd.name);
pmd->genpd.power_on = bcm63xx_power_on;
pmd->genpd.power_off = bcm63xx_power_off;
pm_genpd_init(&pmd->genpd, NULL, !is_on);
power->genpd[entry->bit] = &pmd->genpd;
ndom++;
}
spin_lock_init(&power->lock);
ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
if (ret) {
dev_err(dev, "failed to register genpd driver: %d\n", ret);
return ret;
}
dev_info(dev, "registered %u power domains\n", ndom);
return 0;
}
static const struct bcm63xx_power_data bcm6318_power_domains[] = {
{
.name = "pcie",
.bit = BCM6318_POWER_DOMAIN_PCIE,
}, {
.name = "usb",
.bit = BCM6318_POWER_DOMAIN_USB,
}, {
.name = "ephy0",
.bit = BCM6318_POWER_DOMAIN_EPHY0,
}, {
.name = "ephy1",
.bit = BCM6318_POWER_DOMAIN_EPHY1,
}, {
.name = "ephy2",
.bit = BCM6318_POWER_DOMAIN_EPHY2,
}, {
.name = "ephy3",
.bit = BCM6318_POWER_DOMAIN_EPHY3,
}, {
.name = "ldo2p5",
.bit = BCM6318_POWER_DOMAIN_LDO2P5,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
.name = "ldo2p9",
.bit = BCM6318_POWER_DOMAIN_LDO2P9,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
.name = "sw1p0",
.bit = BCM6318_POWER_DOMAIN_SW1P0,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
.name = "pad",
.bit = BCM6318_POWER_DOMAIN_PAD,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
/* sentinel */
},
};
static const struct bcm63xx_power_data bcm6328_power_domains[] = {
{
.name = "adsl2-mips",
.bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
}, {
.name = "adsl2-phy",
.bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
}, {
.name = "adsl2-afe",
.bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
}, {
.name = "sar",
.bit = BCM6328_POWER_DOMAIN_SAR,
}, {
.name = "pcm",
.bit = BCM6328_POWER_DOMAIN_PCM,
}, {
.name = "usbd",
.bit = BCM6328_POWER_DOMAIN_USBD,
}, {
.name = "usbh",
.bit = BCM6328_POWER_DOMAIN_USBH,
}, {
.name = "pcie",
.bit = BCM6328_POWER_DOMAIN_PCIE,
}, {
.name = "robosw",
.bit = BCM6328_POWER_DOMAIN_ROBOSW,
}, {
.name = "ephy",
.bit = BCM6328_POWER_DOMAIN_EPHY,
}, {
/* sentinel */
},
};
static const struct bcm63xx_power_data bcm6362_power_domains[] = {
{
.name = "sar",
.bit = BCM6362_POWER_DOMAIN_SAR,
}, {
.name = "ipsec",
.bit = BCM6362_POWER_DOMAIN_IPSEC,
}, {
.name = "mips",
.bit = BCM6362_POWER_DOMAIN_MIPS,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
.name = "dect",
.bit = BCM6362_POWER_DOMAIN_DECT,
}, {
.name = "usbh",
.bit = BCM6362_POWER_DOMAIN_USBH,
}, {
.name = "usbd",
.bit = BCM6362_POWER_DOMAIN_USBD,
}, {
.name = "robosw",
.bit = BCM6362_POWER_DOMAIN_ROBOSW,
}, {
.name = "pcm",
.bit = BCM6362_POWER_DOMAIN_PCM,
}, {
.name = "periph",
.bit = BCM6362_POWER_DOMAIN_PERIPH,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
.name = "adsl-phy",
.bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
}, {
.name = "gmii-pads",
.bit = BCM6362_POWER_DOMAIN_GMII_PADS,
}, {
.name = "fap",
.bit = BCM6362_POWER_DOMAIN_FAP,
}, {
.name = "pcie",
.bit = BCM6362_POWER_DOMAIN_PCIE,
}, {
.name = "wlan-pads",
.bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
}, {
/* sentinel */
},
};
static const struct bcm63xx_power_data bcm63268_power_domains[] = {
{
.name = "sar",
.bit = BCM63268_POWER_DOMAIN_SAR,
}, {
.name = "ipsec",
.bit = BCM63268_POWER_DOMAIN_IPSEC,
}, {
.name = "mips",
.bit = BCM63268_POWER_DOMAIN_MIPS,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
.name = "dect",
.bit = BCM63268_POWER_DOMAIN_DECT,
}, {
.name = "usbh",
.bit = BCM63268_POWER_DOMAIN_USBH,
}, {
.name = "usbd",
.bit = BCM63268_POWER_DOMAIN_USBD,
}, {
.name = "robosw",
.bit = BCM63268_POWER_DOMAIN_ROBOSW,
}, {
.name = "pcm",
.bit = BCM63268_POWER_DOMAIN_PCM,
}, {
.name = "periph",
.bit = BCM63268_POWER_DOMAIN_PERIPH,
.flags = GENPD_FLAG_ALWAYS_ON,
}, {
.name = "vdsl-phy",
.bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
}, {
.name = "vdsl-mips",
.bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
}, {
.name = "fap",
.bit = BCM63268_POWER_DOMAIN_FAP,
}, {
.name = "pcie",
.bit = BCM63268_POWER_DOMAIN_PCIE,
}, {
.name = "wlan-pads",
.bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
}, {
/* sentinel */
},
};
static const struct of_device_id bcm63xx_power_of_match[] = {
{
.compatible = "brcm,bcm6318-power-controller",
.data = &bcm6318_power_domains,
}, {
.compatible = "brcm,bcm6328-power-controller",
.data = &bcm6328_power_domains,
}, {
.compatible = "brcm,bcm6362-power-controller",
.data = &bcm6362_power_domains,
}, {
.compatible = "brcm,bcm63268-power-controller",
.data = &bcm63268_power_domains,
}, {
/* sentinel */
}
};
static struct platform_driver bcm63xx_power_driver = {
.driver = {
.name = "bcm63xx-power-controller",
.of_match_table = bcm63xx_power_of_match,
},
.probe = bcm63xx_power_probe,
};
builtin_platform_driver(bcm63xx_power_driver);
...@@ -13,6 +13,22 @@ ...@@ -13,6 +13,22 @@
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/soc/brcmstb/brcmstb.h> #include <linux/soc/brcmstb/brcmstb.h>
#define RACENPREF_MASK 0x3
#define RACPREFINST_SHIFT 0
#define RACENINST_SHIFT 2
#define RACPREFDATA_SHIFT 4
#define RACENDATA_SHIFT 6
#define RAC_CPU_SHIFT 8
#define RACCFG_MASK 0xff
#define DPREF_LINE_2_SHIFT 24
#define DPREF_LINE_2_MASK 0xff
/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */
#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \
RACENPREF_MASK << RACENINST_SHIFT | \
1 << RACPREFDATA_SHIFT | \
RACENPREF_MASK << RACENDATA_SHIFT)
#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000 #define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
#define CPU_CREDIT_REG_MCPx_READ_CRED_MASK 0xf #define CPU_CREDIT_REG_MCPx_READ_CRED_MASK 0xf
#define CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK 0xf #define CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK 0xf
...@@ -31,11 +47,21 @@ static void __iomem *cpubiuctrl_base; ...@@ -31,11 +47,21 @@ static void __iomem *cpubiuctrl_base;
static bool mcp_wr_pairing_en; static bool mcp_wr_pairing_en;
static const int *cpubiuctrl_regs; static const int *cpubiuctrl_regs;
enum cpubiuctrl_regs {
CPU_CREDIT_REG = 0,
CPU_MCP_FLOW_REG,
CPU_WRITEBACK_CTRL_REG,
RAC_CONFIG0_REG,
RAC_CONFIG1_REG,
NUM_CPU_BIUCTRL_REGS,
};
static inline u32 cbc_readl(int reg) static inline u32 cbc_readl(int reg)
{ {
int offset = cpubiuctrl_regs[reg]; int offset = cpubiuctrl_regs[reg];
if (offset == -1) if (offset == -1 ||
(IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
return (u32)-1; return (u32)-1;
return readl_relaxed(cpubiuctrl_base + offset); return readl_relaxed(cpubiuctrl_base + offset);
...@@ -45,22 +71,19 @@ static inline void cbc_writel(u32 val, int reg) ...@@ -45,22 +71,19 @@ static inline void cbc_writel(u32 val, int reg)
{ {
int offset = cpubiuctrl_regs[reg]; int offset = cpubiuctrl_regs[reg];
if (offset == -1) if (offset == -1 ||
(IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
return; return;
writel(val, cpubiuctrl_base + offset); writel(val, cpubiuctrl_base + offset);
} }
enum cpubiuctrl_regs {
CPU_CREDIT_REG = 0,
CPU_MCP_FLOW_REG,
CPU_WRITEBACK_CTRL_REG
};
static const int b15_cpubiuctrl_regs[] = { static const int b15_cpubiuctrl_regs[] = {
[CPU_CREDIT_REG] = 0x184, [CPU_CREDIT_REG] = 0x184,
[CPU_MCP_FLOW_REG] = -1, [CPU_MCP_FLOW_REG] = -1,
[CPU_WRITEBACK_CTRL_REG] = -1, [CPU_WRITEBACK_CTRL_REG] = -1,
[RAC_CONFIG0_REG] = -1,
[RAC_CONFIG1_REG] = -1,
}; };
/* Odd cases, e.g: 7260A0 */ /* Odd cases, e.g: 7260A0 */
...@@ -68,22 +91,26 @@ static const int b53_cpubiuctrl_no_wb_regs[] = { ...@@ -68,22 +91,26 @@ static const int b53_cpubiuctrl_no_wb_regs[] = {
[CPU_CREDIT_REG] = 0x0b0, [CPU_CREDIT_REG] = 0x0b0,
[CPU_MCP_FLOW_REG] = 0x0b4, [CPU_MCP_FLOW_REG] = 0x0b4,
[CPU_WRITEBACK_CTRL_REG] = -1, [CPU_WRITEBACK_CTRL_REG] = -1,
[RAC_CONFIG0_REG] = 0x78,
[RAC_CONFIG1_REG] = 0x7c,
}; };
static const int b53_cpubiuctrl_regs[] = { static const int b53_cpubiuctrl_regs[] = {
[CPU_CREDIT_REG] = 0x0b0, [CPU_CREDIT_REG] = 0x0b0,
[CPU_MCP_FLOW_REG] = 0x0b4, [CPU_MCP_FLOW_REG] = 0x0b4,
[CPU_WRITEBACK_CTRL_REG] = 0x22c, [CPU_WRITEBACK_CTRL_REG] = 0x22c,
[RAC_CONFIG0_REG] = 0x78,
[RAC_CONFIG1_REG] = 0x7c,
}; };
static const int a72_cpubiuctrl_regs[] = { static const int a72_cpubiuctrl_regs[] = {
[CPU_CREDIT_REG] = 0x18, [CPU_CREDIT_REG] = 0x18,
[CPU_MCP_FLOW_REG] = 0x1c, [CPU_MCP_FLOW_REG] = 0x1c,
[CPU_WRITEBACK_CTRL_REG] = 0x20, [CPU_WRITEBACK_CTRL_REG] = 0x20,
[RAC_CONFIG0_REG] = 0x08,
[RAC_CONFIG1_REG] = 0x0c,
}; };
#define NUM_CPU_BIUCTRL_REGS 3
static int __init mcp_write_pairing_set(void) static int __init mcp_write_pairing_set(void)
{ {
u32 creds = 0; u32 creds = 0;
...@@ -110,6 +137,8 @@ static int __init mcp_write_pairing_set(void) ...@@ -110,6 +137,8 @@ static int __init mcp_write_pairing_set(void)
static const u32 a72_b53_mach_compat[] = { static const u32 a72_b53_mach_compat[] = {
0x7211, 0x7211,
0x7216, 0x7216,
0x72164,
0x72165,
0x7255, 0x7255,
0x7260, 0x7260,
0x7268, 0x7268,
...@@ -117,6 +146,61 @@ static const u32 a72_b53_mach_compat[] = { ...@@ -117,6 +146,61 @@ static const u32 a72_b53_mach_compat[] = {
0x7278, 0x7278,
}; };
/* The read-ahead cache present in the Brahma-B53 CPU is a special piece of
* hardware after the integrated L2 cache of the B53 CPU complex whose purpose
* is to prefetch instruction and/or data with a line size of either 64 bytes
* or 256 bytes. The rationale is that the data-bus of the CPU interface is
* optimized for 256-byte transactions, and enabling the read-ahead cache
* provides a significant performance boost (typically twice the performance
* for a memcpy benchmark application).
*
* The read-ahead cache is transparent for Virtual Address cache maintenance
* operations: IC IVAU, DC IVAC, DC CVAC, DC CVAU and DC CIVAC. So no special
* handling is needed for the DMA API above and beyond what is included in the
* arm64 implementation.
*
* In addition, since the Point of Unification is typically between L1 and L2
* for the Brahma-B53 processor no special read-ahead cache handling is needed
* for the IC IALLU and IC IALLUIS cache maintenance operations.
*
* However, it is not possible to specify the cache level (L3) for the cache
* maintenance instructions operating by set/way to operate on the read-ahead
* cache. The read-ahead cache will maintain coherency when inner cache lines
* are cleaned by set/way, but if it is necessary to invalidate inner cache
* lines by set/way to maintain coherency with system masters operating on
* shared memory that does not have hardware support for coherency, then it
* will also be necessary to explicitly invalidate the read-ahead cache.
*/
static void __init a72_b53_rac_enable_all(struct device_node *np)
{
unsigned int cpu;
u32 enable = 0, pref_dist, shift;
if (IS_ENABLED(CONFIG_CACHE_B15_RAC))
return;
if (WARN(num_possible_cpus() > 4, "RAC only supports 4 CPUs\n"))
return;
pref_dist = cbc_readl(RAC_CONFIG1_REG);
for_each_possible_cpu(cpu) {
shift = cpu * RAC_CPU_SHIFT + RACPREFDATA_SHIFT;
enable |= RAC_DATA_INST_EN_MASK << (cpu * RAC_CPU_SHIFT);
if (cpubiuctrl_regs == a72_cpubiuctrl_regs) {
enable &= ~(RACENPREF_MASK << shift);
enable |= 3 << shift;
pref_dist |= 1 << (cpu + DPREF_LINE_2_SHIFT);
}
}
cbc_writel(enable, RAC_CONFIG0_REG);
cbc_writel(pref_dist, RAC_CONFIG1_REG);
pr_info("%pOF: Broadcom %s read-ahead cache\n",
np, cpubiuctrl_regs == a72_cpubiuctrl_regs ?
"Cortex-A72" : "Brahma-B53");
}
static void __init mcp_a72_b53_set(void) static void __init mcp_a72_b53_set(void)
{ {
unsigned int i; unsigned int i;
...@@ -262,6 +346,7 @@ static int __init brcmstb_biuctrl_init(void) ...@@ -262,6 +346,7 @@ static int __init brcmstb_biuctrl_init(void)
return ret; return ret;
} }
a72_b53_rac_enable_all(np);
mcp_a72_b53_set(); mcp_a72_b53_set();
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
register_syscore_ops(&brcmstb_cpu_credit_syscore_ops); register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
......
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_BMIPS_BCM6318_PM_H
#define __DT_BINDINGS_BMIPS_BCM6318_PM_H
#define BCM6318_POWER_DOMAIN_PCIE 0
#define BCM6318_POWER_DOMAIN_USB 1
#define BCM6318_POWER_DOMAIN_EPHY0 2
#define BCM6318_POWER_DOMAIN_EPHY1 3
#define BCM6318_POWER_DOMAIN_EPHY2 4
#define BCM6318_POWER_DOMAIN_EPHY3 5
#define BCM6318_POWER_DOMAIN_LDO2P5 6
#define BCM6318_POWER_DOMAIN_LDO2P9 7
#define BCM6318_POWER_DOMAIN_SW1P0 8
#define BCM6318_POWER_DOMAIN_PAD 9
#endif /* __DT_BINDINGS_BMIPS_BCM6318_PM_H */
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_BMIPS_BCM63268_PM_H
#define __DT_BINDINGS_BMIPS_BCM63268_PM_H
#define BCM63268_POWER_DOMAIN_SAR 0
#define BCM63268_POWER_DOMAIN_IPSEC 1
#define BCM63268_POWER_DOMAIN_MIPS 2
#define BCM63268_POWER_DOMAIN_DECT 3
#define BCM63268_POWER_DOMAIN_USBH 4
#define BCM63268_POWER_DOMAIN_USBD 5
#define BCM63268_POWER_DOMAIN_ROBOSW 6
#define BCM63268_POWER_DOMAIN_PCM 7
#define BCM63268_POWER_DOMAIN_PERIPH 8
#define BCM63268_POWER_DOMAIN_VDSL_PHY 9
#define BCM63268_POWER_DOMAIN_VDSL_MIPS 10
#define BCM63268_POWER_DOMAIN_FAP 11
#define BCM63268_POWER_DOMAIN_PCIE 12
#define BCM63268_POWER_DOMAIN_WLAN_PADS 13
#endif /* __DT_BINDINGS_BMIPS_BCM63268_PM_H */
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_BMIPS_BCM6328_PM_H
#define __DT_BINDINGS_BMIPS_BCM6328_PM_H
#define BCM6328_POWER_DOMAIN_ADSL2_MIPS 0
#define BCM6328_POWER_DOMAIN_ADSL2_PHY 1
#define BCM6328_POWER_DOMAIN_ADSL2_AFE 2
#define BCM6328_POWER_DOMAIN_SAR 3
#define BCM6328_POWER_DOMAIN_PCM 4
#define BCM6328_POWER_DOMAIN_USBD 5
#define BCM6328_POWER_DOMAIN_USBH 6
#define BCM6328_POWER_DOMAIN_PCIE 7
#define BCM6328_POWER_DOMAIN_ROBOSW 8
#define BCM6328_POWER_DOMAIN_EPHY 9
#endif /* __DT_BINDINGS_BMIPS_BCM6328_PM_H */
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_BMIPS_BCM6362_PM_H
#define __DT_BINDINGS_BMIPS_BCM6362_PM_H
#define BCM6362_POWER_DOMAIN_SAR 0
#define BCM6362_POWER_DOMAIN_IPSEC 1
#define BCM6362_POWER_DOMAIN_MIPS 2
#define BCM6362_POWER_DOMAIN_DECT 3
#define BCM6362_POWER_DOMAIN_USBH 4
#define BCM6362_POWER_DOMAIN_USBD 5
#define BCM6362_POWER_DOMAIN_ROBOSW 6
#define BCM6362_POWER_DOMAIN_PCM 7
#define BCM6362_POWER_DOMAIN_PERIPH 8
#define BCM6362_POWER_DOMAIN_ADSL_PHY 9
#define BCM6362_POWER_DOMAIN_GMII_PADS 10
#define BCM6362_POWER_DOMAIN_FAP 11
#define BCM6362_POWER_DOMAIN_PCIE 12
#define BCM6362_POWER_DOMAIN_WLAN_PADS 13
#endif /* __DT_BINDINGS_BMIPS_BCM6362_PM_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment