Path: blob/master/arch/arm/mach-mvebu/system-controller.c
26292 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* System controller support for Armada 370, 375 and XP platforms.3*4* Copyright (C) 2012 Marvell5*6* Lior Amsalem <[email protected]>7* Gregory CLEMENT <[email protected]>8* Thomas Petazzoni <[email protected]>9*10* The Armada 370, 375 and Armada XP SoCs have a range of11* miscellaneous registers, that do not belong to a particular device,12* but rather provide system-level features. This basic13* system-controller driver provides a device tree binding for those14* registers, and implements utility functions offering various15* features related to those registers.16*17* For now, the feature set is limited to restarting the platform by a18* soft-reset, but it might be extended in the future.19*/2021#include <linux/kernel.h>22#include <linux/init.h>23#include <linux/of_address.h>24#include <linux/io.h>25#include <linux/reboot.h>26#include "common.h"27#include "mvebu-soc-id.h"28#include "pmsu.h"2930#define ARMADA_375_CRYPT0_ENG_TARGET 4131#define ARMADA_375_CRYPT0_ENG_ATTR 13233static void __iomem *system_controller_base;34static phys_addr_t system_controller_phys_base;3536struct mvebu_system_controller {37u32 rstoutn_mask_offset;38u32 system_soft_reset_offset;3940u32 rstoutn_mask_reset_out_en;41u32 system_soft_reset;4243u32 resume_boot_addr;4445u32 dev_id;46u32 rev_id;47};48static struct mvebu_system_controller *mvebu_sc;4950static const struct mvebu_system_controller armada_370_xp_system_controller = {51.rstoutn_mask_offset = 0x60,52.system_soft_reset_offset = 0x64,53.rstoutn_mask_reset_out_en = 0x1,54.system_soft_reset = 0x1,55.dev_id = 0x38,56.rev_id = 0x3c,57};5859static const struct mvebu_system_controller armada_375_system_controller = {60.rstoutn_mask_offset = 0x54,61.system_soft_reset_offset = 0x58,62.rstoutn_mask_reset_out_en = 0x1,63.system_soft_reset = 0x1,64.resume_boot_addr = 0xd4,65.dev_id = 0x38,66.rev_id = 0x3c,67};6869static const struct mvebu_system_controller orion_system_controller = {70.rstoutn_mask_offset = 0x108,71.system_soft_reset_offset = 0x10c,72.rstoutn_mask_reset_out_en = 0x4,73.system_soft_reset = 0x1,74};7576static const struct of_device_id of_system_controller_table[] = {77{78.compatible = "marvell,orion-system-controller",79.data = (void *) &orion_system_controller,80}, {81.compatible = "marvell,armada-370-xp-system-controller",82.data = (void *) &armada_370_xp_system_controller,83}, {84.compatible = "marvell,armada-375-system-controller",85.data = (void *) &armada_375_system_controller,86},87{ /* end of list */ },88};8990void mvebu_restart(enum reboot_mode mode, const char *cmd)91{92if (!system_controller_base) {93pr_err("Cannot restart, system-controller not available: check the device tree\n");94} else {95/*96* Enable soft reset to assert RSTOUTn.97*/98writel(mvebu_sc->rstoutn_mask_reset_out_en,99system_controller_base +100mvebu_sc->rstoutn_mask_offset);101/*102* Assert soft reset.103*/104writel(mvebu_sc->system_soft_reset,105system_controller_base +106mvebu_sc->system_soft_reset_offset);107}108109while (1)110;111}112113int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev)114{115if (of_machine_is_compatible("marvell,armada380") &&116system_controller_base) {117*dev = readl(system_controller_base + mvebu_sc->dev_id) >> 16;118*rev = (readl(system_controller_base + mvebu_sc->rev_id) >> 8)119& 0xF;120return 0;121} else122return -ENODEV;123}124125#if defined(CONFIG_SMP) && defined(CONFIG_MACH_MVEBU_V7)126static void mvebu_armada375_smp_wa_init(void)127{128u32 dev, rev;129phys_addr_t resume_addr_reg;130131if (mvebu_get_soc_id(&dev, &rev) != 0)132return;133134if (rev != ARMADA_375_Z1_REV)135return;136137resume_addr_reg = system_controller_phys_base +138mvebu_sc->resume_boot_addr;139mvebu_setup_boot_addr_wa(ARMADA_375_CRYPT0_ENG_TARGET,140ARMADA_375_CRYPT0_ENG_ATTR,141resume_addr_reg);142}143144void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)145{146BUG_ON(system_controller_base == NULL);147BUG_ON(mvebu_sc->resume_boot_addr == 0);148149if (of_machine_is_compatible("marvell,armada375"))150mvebu_armada375_smp_wa_init();151152writel(__pa_symbol(boot_addr), system_controller_base +153mvebu_sc->resume_boot_addr);154}155#endif156157static int __init mvebu_system_controller_init(void)158{159const struct of_device_id *match;160struct device_node *np;161162np = of_find_matching_node_and_match(NULL, of_system_controller_table,163&match);164if (np) {165struct resource res;166system_controller_base = of_iomap(np, 0);167of_address_to_resource(np, 0, &res);168system_controller_phys_base = res.start;169mvebu_sc = (struct mvebu_system_controller *)match->data;170of_node_put(np);171}172173return 0;174}175176early_initcall(mvebu_system_controller_init);177178179