162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2012 (C), Jason Cooper <jason@lakedaemon.net> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * arch/arm/mach-mvebu/kirkwood.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Flattened Device Tree board initialization 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/mbus.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/of_address.h> 1662306a36Sopenharmony_ci#include <linux/of_net.h> 1762306a36Sopenharmony_ci#include <linux/of_platform.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <asm/hardware/cache-feroceon-l2.h> 2162306a36Sopenharmony_ci#include <asm/mach/arch.h> 2262306a36Sopenharmony_ci#include <asm/mach/map.h> 2362306a36Sopenharmony_ci#include "kirkwood.h" 2462306a36Sopenharmony_ci#include "kirkwood-pm.h" 2562306a36Sopenharmony_ci#include "common.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic struct resource kirkwood_cpufreq_resources[] = { 2862306a36Sopenharmony_ci [0] = { 2962306a36Sopenharmony_ci .start = CPU_CONTROL_PHYS, 3062306a36Sopenharmony_ci .end = CPU_CONTROL_PHYS + 3, 3162306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 3262306a36Sopenharmony_ci }, 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic struct platform_device kirkwood_cpufreq_device = { 3662306a36Sopenharmony_ci .name = "kirkwood-cpufreq", 3762306a36Sopenharmony_ci .id = -1, 3862306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(kirkwood_cpufreq_resources), 3962306a36Sopenharmony_ci .resource = kirkwood_cpufreq_resources, 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void __init kirkwood_cpufreq_init(void) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci platform_device_register(&kirkwood_cpufreq_device); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic struct resource kirkwood_cpuidle_resource[] = { 4862306a36Sopenharmony_ci { 4962306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 5062306a36Sopenharmony_ci .start = DDR_OPERATION_BASE, 5162306a36Sopenharmony_ci .end = DDR_OPERATION_BASE + 3, 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic struct platform_device kirkwood_cpuidle = { 5662306a36Sopenharmony_ci .name = "kirkwood_cpuidle", 5762306a36Sopenharmony_ci .id = -1, 5862306a36Sopenharmony_ci .resource = kirkwood_cpuidle_resource, 5962306a36Sopenharmony_ci .num_resources = 1, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void __init kirkwood_cpuidle_init(void) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci platform_device_register(&kirkwood_cpuidle); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define MV643XX_ETH_MAC_ADDR_LOW 0x0414 6862306a36Sopenharmony_ci#define MV643XX_ETH_MAC_ADDR_HIGH 0x0418 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void __init kirkwood_dt_eth_fixup(void) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct device_node *np; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* 7562306a36Sopenharmony_ci * The ethernet interfaces forget the MAC address assigned by u-boot 7662306a36Sopenharmony_ci * if the clocks are turned off. Usually, u-boot on kirkwood boards 7762306a36Sopenharmony_ci * has no DT support to properly set local-mac-address property. 7862306a36Sopenharmony_ci * As a workaround, we get the MAC address from mv643xx_eth registers 7962306a36Sopenharmony_ci * and update the port device node if no valid MAC address is set. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci for_each_compatible_node(np, NULL, "marvell,kirkwood-eth-port") { 8262306a36Sopenharmony_ci struct device_node *pnp = of_get_parent(np); 8362306a36Sopenharmony_ci struct clk *clk; 8462306a36Sopenharmony_ci struct property *pmac; 8562306a36Sopenharmony_ci u8 tmpmac[ETH_ALEN]; 8662306a36Sopenharmony_ci void __iomem *io; 8762306a36Sopenharmony_ci u8 *macaddr; 8862306a36Sopenharmony_ci u32 reg; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!pnp) 9162306a36Sopenharmony_ci continue; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* skip disabled nodes or nodes with valid MAC address*/ 9462306a36Sopenharmony_ci if (!of_device_is_available(pnp) || 9562306a36Sopenharmony_ci !of_get_mac_address(np, tmpmac)) 9662306a36Sopenharmony_ci goto eth_fixup_skip; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci clk = of_clk_get(pnp, 0); 9962306a36Sopenharmony_ci if (IS_ERR(clk)) 10062306a36Sopenharmony_ci goto eth_fixup_skip; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci io = of_iomap(pnp, 0); 10362306a36Sopenharmony_ci if (!io) 10462306a36Sopenharmony_ci goto eth_fixup_no_map; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* ensure port clock is not gated to not hang CPU */ 10762306a36Sopenharmony_ci clk_prepare_enable(clk); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* store MAC address register contents in local-mac-address */ 11062306a36Sopenharmony_ci pmac = kzalloc(sizeof(*pmac) + 6, GFP_KERNEL); 11162306a36Sopenharmony_ci if (!pmac) 11262306a36Sopenharmony_ci goto eth_fixup_no_mem; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci pmac->value = pmac + 1; 11562306a36Sopenharmony_ci pmac->length = 6; 11662306a36Sopenharmony_ci pmac->name = kstrdup("local-mac-address", GFP_KERNEL); 11762306a36Sopenharmony_ci if (!pmac->name) { 11862306a36Sopenharmony_ci kfree(pmac); 11962306a36Sopenharmony_ci goto eth_fixup_no_mem; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci macaddr = pmac->value; 12362306a36Sopenharmony_ci reg = readl(io + MV643XX_ETH_MAC_ADDR_HIGH); 12462306a36Sopenharmony_ci macaddr[0] = (reg >> 24) & 0xff; 12562306a36Sopenharmony_ci macaddr[1] = (reg >> 16) & 0xff; 12662306a36Sopenharmony_ci macaddr[2] = (reg >> 8) & 0xff; 12762306a36Sopenharmony_ci macaddr[3] = reg & 0xff; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci reg = readl(io + MV643XX_ETH_MAC_ADDR_LOW); 13062306a36Sopenharmony_ci macaddr[4] = (reg >> 8) & 0xff; 13162306a36Sopenharmony_ci macaddr[5] = reg & 0xff; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci of_update_property(np, pmac); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cieth_fixup_no_mem: 13662306a36Sopenharmony_ci iounmap(io); 13762306a36Sopenharmony_ci clk_disable_unprepare(clk); 13862306a36Sopenharmony_cieth_fixup_no_map: 13962306a36Sopenharmony_ci clk_put(clk); 14062306a36Sopenharmony_cieth_fixup_skip: 14162306a36Sopenharmony_ci of_node_put(pnp); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * Disable propagation of mbus errors to the CPU local bus, as this 14762306a36Sopenharmony_ci * causes mbus errors (which can occur for example for PCI aborts) to 14862306a36Sopenharmony_ci * throw CPU aborts, which we're not set up to deal with. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_cistatic void kirkwood_disable_mbus_error_propagation(void) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci void __iomem *cpu_config; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci cpu_config = ioremap(CPU_CONFIG_PHYS, 4); 15562306a36Sopenharmony_ci writel(readl(cpu_config) & ~CPU_CONFIG_ERROR_PROP, cpu_config); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic struct of_dev_auxdata auxdata[] __initdata = { 15962306a36Sopenharmony_ci OF_DEV_AUXDATA("marvell,kirkwood-audio", 0xf10a0000, 16062306a36Sopenharmony_ci "mvebu-audio", NULL), 16162306a36Sopenharmony_ci { /* sentinel */ } 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void __init kirkwood_dt_init(void) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci kirkwood_disable_mbus_error_propagation(); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci BUG_ON(mvebu_mbus_dt_init(false)); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#ifdef CONFIG_CACHE_FEROCEON_L2 17162306a36Sopenharmony_ci feroceon_of_init(); 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci kirkwood_cpufreq_init(); 17462306a36Sopenharmony_ci kirkwood_cpuidle_init(); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci kirkwood_pm_init(); 17762306a36Sopenharmony_ci kirkwood_dt_eth_fixup(); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci of_platform_default_populate(NULL, auxdata, NULL); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const char * const kirkwood_dt_board_compat[] __initconst = { 18362306a36Sopenharmony_ci "marvell,kirkwood", 18462306a36Sopenharmony_ci NULL 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciDT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)") 18862306a36Sopenharmony_ci /* Maintainer: Jason Cooper <jason@lakedaemon.net> */ 18962306a36Sopenharmony_ci .init_machine = kirkwood_dt_init, 19062306a36Sopenharmony_ci .restart = mvebu_restart, 19162306a36Sopenharmony_ci .dt_compat = kirkwood_dt_board_compat, 19262306a36Sopenharmony_ciMACHINE_END 193