Skip to content

Commit

Permalink
Merge tag 'mvebu-soc-3.19' of git://git.infradead.org/linux-mvebu int…
Browse files Browse the repository at this point in the history
…o next/soc

Pull "mvebu SoC changes for v3.19" from Jason Cooper:

 - Armada 38x
    - Implement CPU hotplug support

 - Armada 375
    - Remove Z1 stepping support (limited dist. of SoC)

* tag 'mvebu-soc-3.19' of git://git.infradead.org/linux-mvebu:
  ARM: mvebu: Implement the CPU hotplug support for the Armada 38x SoCs
  ARM: mvebu: Fix the secondary startup for Cortex A9 SoC
  ARM: mvebu: Move SCU power up in a function
  ARM: mvebu: Clean-up the Armada XP support
  ARM: mvebu: update comments in coherency.c
  ARM: mvebu: remove Armada 375 Z1 workaround for I/O coherency
  ARM: mvebu: remove unused register offset definition
  ARM: mvebu: disable I/O coherency on non-SMP situations on Armada 370/375/38x/XP
  ARM: mvebu: make the coherency_ll.S functions work with no coherency fabric
  ARM: mvebu: Remove thermal quirk for A375 Z1 revision
  ARM: mvebu: add missing of_node_put() call in coherency.c
  ARM: orion: Fix for certain sequence of request_irq can cause irq storm
  ARM: mvebu: armada xp: Generalize use of i2c quirk

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Arnd Bergmann committed Nov 28, 2014
2 parents d5bd4e8 + 626d686 commit 756f80c
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 275 deletions.
6 changes: 0 additions & 6 deletions arch/arm/mach-mvebu/armada-370-xp.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,8 @@
#define __MACH_ARMADA_370_XP_H

#ifdef CONFIG_SMP
#include <linux/cpumask.h>

#define ARMADA_XP_MAX_CPUS 4

void armada_xp_secondary_startup(void);
extern struct smp_operations armada_xp_smp_ops;
#endif

int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);

#endif /* __MACH_ARMADA_370_XP_H */
73 changes: 7 additions & 66 deletions arch/arm/mach-mvebu/board-v7.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,76 +124,12 @@ static void __init i2c_quirk(void)
return;
}

#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc

static void __init thermal_quirk(void)
{
struct device_node *np;
u32 dev, rev;
int res;

/*
* The early SoC Z1 revision needs a quirk to be applied in order
* for the thermal controller to work properly. This quirk breaks
* the thermal support if applied on a SoC that doesn't need it,
* so we enforce the SoC revision to be known.
*/
res = mvebu_get_soc_id(&dev, &rev);
if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV))
return;

for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
struct property *prop;
__be32 newval, *newprop, *oldprop;
int len;

/*
* The register offset is at a wrong location. This quirk
* creates a new reg property as a clone of the previous
* one and corrects the offset.
*/
oldprop = (__be32 *)of_get_property(np, "reg", &len);
if (!oldprop)
continue;

/* Create a duplicate of the 'reg' property */
prop = kzalloc(sizeof(*prop), GFP_KERNEL);
prop->length = len;
prop->name = kstrdup("reg", GFP_KERNEL);
prop->value = kzalloc(len, GFP_KERNEL);
memcpy(prop->value, oldprop, len);

/* Fixup the register offset of the second entry */
oldprop += 2;
newprop = (__be32 *)prop->value + 2;
newval = cpu_to_be32(be32_to_cpu(*oldprop) -
A375_Z1_THERMAL_FIXUP_OFFSET);
*newprop = newval;
of_update_property(np, prop);

/*
* The thermal controller needs some quirk too, so let's change
* the compatible string to reflect this and allow the driver
* the take the necessary action.
*/
prop = kzalloc(sizeof(*prop), GFP_KERNEL);
prop->name = kstrdup("compatible", GFP_KERNEL);
prop->length = sizeof("marvell,armada375-z1-thermal");
prop->value = kstrdup("marvell,armada375-z1-thermal",
GFP_KERNEL);
of_update_property(np, prop);
}
return;
}

static void __init mvebu_dt_init(void)
{
if (of_machine_is_compatible("plathome,openblocks-ax3-4"))
if (of_machine_is_compatible("marvell,armadaxp"))
i2c_quirk();
if (of_machine_is_compatible("marvell,a375-db")) {
if (of_machine_is_compatible("marvell,a375-db"))
external_abort_quirk();
thermal_quirk();
}

of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
Expand All @@ -206,6 +142,11 @@ static const char * const armada_370_xp_dt_compat[] = {
DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
/*
* The following field (.smp) is still needed to ensure backward
* compatibility with old Device Trees that were not specifying the
* cpus enable-method property.
*/
.smp = smp_ops(armada_xp_smp_ops),
.init_machine = mvebu_dt_init,
.init_irq = mvebu_init_irq,
Expand Down
223 changes: 38 additions & 185 deletions arch/arm/mach-mvebu/coherency.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Coherency fabric (Aurora) support for Armada 370 and XP platforms.
* Coherency fabric (Aurora) support for Armada 370, 375, 38x and XP
* platforms.
*
* Copyright (C) 2012 Marvell
*
Expand All @@ -11,7 +12,7 @@
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada 370 and Armada XP SOCs have a coherency fabric which is
* The Armada 370, 375, 38x and XP SOCs have a coherency fabric which is
* responsible for ensuring hardware coherency between all CPUs and between
* CPUs and I/O masters. This file initializes the coherency fabric and
* supplies basic routines for configuring and controlling hardware coherency
Expand All @@ -28,12 +29,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mbus.h>
#include <linux/clk.h>
#include <linux/pci.h>
#include <asm/smp_plat.h>
#include <asm/cacheflush.h>
#include <asm/mach/map.h>
#include "armada-370-xp.h"
#include "coherency.h"
#include "mvebu-soc-id.h"

Expand All @@ -42,8 +41,6 @@ void __iomem *coherency_base;
static void __iomem *coherency_cpu_base;

/* Coherency fabric registers */
#define COHERENCY_FABRIC_CFG_OFFSET 0x4

#define IO_SYNC_BARRIER_CTL_OFFSET 0x0

enum {
Expand Down Expand Up @@ -79,157 +76,8 @@ int set_cpu_coherent(void)
return ll_enable_coherency();
}

/*
* The below code implements the I/O coherency workaround on Armada
* 375. This workaround consists in using the two channels of the
* first XOR engine to trigger a XOR transaction that serves as the
* I/O coherency barrier.
*/

static void __iomem *xor_base, *xor_high_base;
static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS];
static void *coherency_wa_buf[CONFIG_NR_CPUS];
static bool coherency_wa_enabled;

#define XOR_CONFIG(chan) (0x10 + (chan * 4))
#define XOR_ACTIVATION(chan) (0x20 + (chan * 4))
#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2))
#define WINDOW_BASE(w) (0x250 + ((w) << 2))
#define WINDOW_SIZE(w) (0x270 + ((w) << 2))
#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2))
#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2))
#define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4))
#define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4))
#define XOR_INIT_VALUE_LOW 0x2E0
#define XOR_INIT_VALUE_HIGH 0x2E4

static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void)
{
int idx = smp_processor_id();

/* Write '1' to the first word of the buffer */
writel(0x1, coherency_wa_buf[idx]);

/* Wait until the engine is idle */
while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3)
;

dmb();

/* Trigger channel */
writel(0x1, xor_base + XOR_ACTIVATION(idx));

/* Poll the data until it is cleared by the XOR transaction */
while (readl(coherency_wa_buf[idx]))
;
}

static void __init armada_375_coherency_init_wa(void)
{
const struct mbus_dram_target_info *dram;
struct device_node *xor_node;
struct property *xor_status;
struct clk *xor_clk;
u32 win_enable = 0;
int i;

pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n");

/*
* Since the workaround uses one XOR engine, we grab a
* reference to its Device Tree node first.
*/
xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor");
BUG_ON(!xor_node);

/*
* Then we mark it as disabled so that the real XOR driver
* will not use it.
*/
xor_status = kzalloc(sizeof(struct property), GFP_KERNEL);
BUG_ON(!xor_status);

xor_status->value = kstrdup("disabled", GFP_KERNEL);
BUG_ON(!xor_status->value);

xor_status->length = 8;
xor_status->name = kstrdup("status", GFP_KERNEL);
BUG_ON(!xor_status->name);

of_update_property(xor_node, xor_status);

/*
* And we remap the registers, get the clock, and do the
* initial configuration of the XOR engine.
*/
xor_base = of_iomap(xor_node, 0);
xor_high_base = of_iomap(xor_node, 1);

xor_clk = of_clk_get_by_name(xor_node, NULL);
BUG_ON(!xor_clk);

clk_prepare_enable(xor_clk);

dram = mv_mbus_dram_info();

for (i = 0; i < 8; i++) {
writel(0, xor_base + WINDOW_BASE(i));
writel(0, xor_base + WINDOW_SIZE(i));
if (i < 4)
writel(0, xor_base + WINDOW_REMAP_HIGH(i));
}

for (i = 0; i < dram->num_cs; i++) {
const struct mbus_dram_window *cs = dram->cs + i;
writel((cs->base & 0xffff0000) |
(cs->mbus_attr << 8) |
dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i));
writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i));

win_enable |= (1 << i);
win_enable |= 3 << (16 + (2 * i));
}

writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0));
writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1));
writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0));
writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1));

for (i = 0; i < CONFIG_NR_CPUS; i++) {
coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL);
BUG_ON(!coherency_wa_buf[i]);

/*
* We can't use the DMA mapping API, since we don't
* have a valid 'struct device' pointer
*/
coherency_wa_buf_phys[i] =
virt_to_phys(coherency_wa_buf[i]);
BUG_ON(!coherency_wa_buf_phys[i]);

/*
* Configure the XOR engine for memset operation, with
* a 128 bytes block size
*/
writel(0x444, xor_base + XOR_CONFIG(i));
writel(128, xor_base + XOR_BLOCK_SIZE(i));
writel(coherency_wa_buf_phys[i],
xor_base + XOR_DEST_POINTER(i));
}

writel(0x0, xor_base + XOR_INIT_VALUE_LOW);
writel(0x0, xor_base + XOR_INIT_VALUE_HIGH);

coherency_wa_enabled = true;
}

static inline void mvebu_hwcc_sync_io_barrier(void)
{
if (coherency_wa_enabled) {
mvebu_hwcc_armada375_sync_io_barrier_wa();
return;
}

writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
}
Expand Down Expand Up @@ -361,25 +209,41 @@ static int coherency_type(void)
{
struct device_node *np;
const struct of_device_id *match;
int type;

np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
if (np) {
int type = (int) match->data;
/*
* The coherency fabric is needed:
* - For coherency between processors on Armada XP, so only
* when SMP is enabled.
* - For coherency between the processor and I/O devices, but
* this coherency requires many pre-requisites (write
* allocate cache policy, shareable pages, SMP bit set) that
* are only meant in SMP situations.
*
* Note that this means that on Armada 370, there is currently
* no way to use hardware I/O coherency, because even when
* CONFIG_SMP is enabled, is_smp() returns false due to the
* Armada 370 being a single-core processor. To lift this
* limitation, we would have to find a way to make the cache
* policy set to write-allocate (on all Armada SoCs), and to
* set the shareable attribute in page tables (on all Armada
* SoCs except the Armada 370). Unfortunately, such decisions
* are taken very early in the kernel boot process, at a point
* where we don't know yet on which SoC we are running.
/* Armada 370/XP coherency works in both UP and SMP */
if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
return type;
*/
if (!is_smp())
return COHERENCY_FABRIC_TYPE_NONE;

/* Armada 375 coherency works only on SMP */
else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp())
return type;
np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
if (!np)
return COHERENCY_FABRIC_TYPE_NONE;

/* Armada 380 coherency works only on SMP */
else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp())
return type;
}
type = (int) match->data;

return COHERENCY_FABRIC_TYPE_NONE;
of_node_put(np);

return type;
}

int coherency_available(void)
Expand All @@ -400,27 +264,16 @@ int __init coherency_init(void)
type == COHERENCY_FABRIC_TYPE_ARMADA_380)
armada_375_380_coherency_init(np);

of_node_put(np);

return 0;
}

static int __init coherency_late_init(void)
{
int type = coherency_type();

if (type == COHERENCY_FABRIC_TYPE_NONE)
return 0;

if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) {
u32 dev, rev;

if (mvebu_get_soc_id(&dev, &rev) == 0 &&
rev == ARMADA_375_Z1_REV)
armada_375_coherency_init_wa();
}

bus_register_notifier(&platform_bus_type,
&mvebu_hwcc_nb);

if (coherency_available())
bus_register_notifier(&platform_bus_type,
&mvebu_hwcc_nb);
return 0;
}

Expand Down
Loading

0 comments on commit 756f80c

Please sign in to comment.