1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * System controller support for Armada 370, 375 and XP platforms. 4 * 5 * Copyright (C) 2012 Marvell 6 * 7 * Lior Amsalem <alior@marvell.com> 8 * Gregory CLEMENT <gregory.clement@free-electrons.com> 9 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 10 * 11 * The Armada 370, 375 and Armada XP SoCs have a range of 12 * miscellaneous registers, that do not belong to a particular device, 13 * but rather provide system-level features. This basic 14 * system-controller driver provides a device tree binding for those 15 * registers, and implements utility functions offering various 16 * features related to those registers. 17 * 18 * For now, the feature set is limited to restarting the platform by a 19 * soft-reset, but it might be extended in the future. 20 */ 21 22 #include <linux/kernel.h> 23 #include <linux/init.h> 24 #include <linux/of_address.h> 25 #include <linux/io.h> 26 #include <linux/reboot.h> 27 #include "common.h" 28 #include "mvebu-soc-id.h" 29 #include "pmsu.h" 30 31 #define ARMADA_375_CRYPT0_ENG_TARGET 41 32 #define ARMADA_375_CRYPT0_ENG_ATTR 1 33 34 static void __iomem *system_controller_base; 35 static phys_addr_t system_controller_phys_base; 36 37 struct mvebu_system_controller { 38 u32 rstoutn_mask_offset; 39 u32 system_soft_reset_offset; 40 41 u32 rstoutn_mask_reset_out_en; 42 u32 system_soft_reset; 43 44 u32 resume_boot_addr; 45 46 u32 dev_id; 47 u32 rev_id; 48 }; 49 static struct mvebu_system_controller *mvebu_sc; 50 51 static const struct mvebu_system_controller armada_370_xp_system_controller = { 52 .rstoutn_mask_offset = 0x60, 53 .system_soft_reset_offset = 0x64, 54 .rstoutn_mask_reset_out_en = 0x1, 55 .system_soft_reset = 0x1, 56 .dev_id = 0x38, 57 .rev_id = 0x3c, 58 }; 59 60 static const struct mvebu_system_controller armada_375_system_controller = { 61 .rstoutn_mask_offset = 0x54, 62 .system_soft_reset_offset = 0x58, 63 .rstoutn_mask_reset_out_en = 0x1, 64 .system_soft_reset = 0x1, 65 .resume_boot_addr = 0xd4, 66 .dev_id = 0x38, 67 .rev_id = 0x3c, 68 }; 69 70 static const struct mvebu_system_controller orion_system_controller = { 71 .rstoutn_mask_offset = 0x108, 72 .system_soft_reset_offset = 0x10c, 73 .rstoutn_mask_reset_out_en = 0x4, 74 .system_soft_reset = 0x1, 75 }; 76 77 static const struct of_device_id of_system_controller_table[] = { 78 { 79 .compatible = "marvell,orion-system-controller", 80 .data = (void *) &orion_system_controller, 81 }, { 82 .compatible = "marvell,armada-370-xp-system-controller", 83 .data = (void *) &armada_370_xp_system_controller, 84 }, { 85 .compatible = "marvell,armada-375-system-controller", 86 .data = (void *) &armada_375_system_controller, 87 }, 88 { /* end of list */ }, 89 }; 90 91 void mvebu_restart(enum reboot_mode mode, const char *cmd) 92 { 93 if (!system_controller_base) { 94 pr_err("Cannot restart, system-controller not available: check the device tree\n"); 95 } else { 96 /* 97 * Enable soft reset to assert RSTOUTn. 98 */ 99 writel(mvebu_sc->rstoutn_mask_reset_out_en, 100 system_controller_base + 101 mvebu_sc->rstoutn_mask_offset); 102 /* 103 * Assert soft reset. 104 */ 105 writel(mvebu_sc->system_soft_reset, 106 system_controller_base + 107 mvebu_sc->system_soft_reset_offset); 108 } 109 110 while (1) 111 ; 112 } 113 114 int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev) 115 { 116 if (of_machine_is_compatible("marvell,armada380") && 117 system_controller_base) { 118 *dev = readl(system_controller_base + mvebu_sc->dev_id) >> 16; 119 *rev = (readl(system_controller_base + mvebu_sc->rev_id) >> 8) 120 & 0xF; 121 return 0; 122 } else 123 return -ENODEV; 124 } 125 126 #if defined(CONFIG_SMP) && defined(CONFIG_MACH_MVEBU_V7) 127 static void mvebu_armada375_smp_wa_init(void) 128 { 129 u32 dev, rev; 130 phys_addr_t resume_addr_reg; 131 132 if (mvebu_get_soc_id(&dev, &rev) != 0) 133 return; 134 135 if (rev != ARMADA_375_Z1_REV) 136 return; 137 138 resume_addr_reg = system_controller_phys_base + 139 mvebu_sc->resume_boot_addr; 140 mvebu_setup_boot_addr_wa(ARMADA_375_CRYPT0_ENG_TARGET, 141 ARMADA_375_CRYPT0_ENG_ATTR, 142 resume_addr_reg); 143 } 144 145 void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) 146 { 147 BUG_ON(system_controller_base == NULL); 148 BUG_ON(mvebu_sc->resume_boot_addr == 0); 149 150 if (of_machine_is_compatible("marvell,armada375")) 151 mvebu_armada375_smp_wa_init(); 152 153 writel(__pa_symbol(boot_addr), system_controller_base + 154 mvebu_sc->resume_boot_addr); 155 } 156 #endif 157 158 static int __init mvebu_system_controller_init(void) 159 { 160 const struct of_device_id *match; 161 struct device_node *np; 162 163 np = of_find_matching_node_and_match(NULL, of_system_controller_table, 164 &match); 165 if (np) { 166 struct resource res; 167 system_controller_base = of_iomap(np, 0); 168 of_address_to_resource(np, 0, &res); 169 system_controller_phys_base = res.start; 170 mvebu_sc = (struct mvebu_system_controller *)match->data; 171 of_node_put(np); 172 } 173 174 return 0; 175 } 176 177 early_initcall(mvebu_system_controller_init); 178
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.