18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2012 (C), Jason Cooper <jason@lakedaemon.net> 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * arch/arm/mach-mvebu/kirkwood.c 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Flattened Device Tree board initialization 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 98c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 108c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/clk.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/mbus.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_address.h> 198c2ecf20Sopenharmony_ci#include <linux/of_net.h> 208c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <asm/hardware/cache-feroceon-l2.h> 238c2ecf20Sopenharmony_ci#include <asm/mach/arch.h> 248c2ecf20Sopenharmony_ci#include <asm/mach/map.h> 258c2ecf20Sopenharmony_ci#include "kirkwood.h" 268c2ecf20Sopenharmony_ci#include "kirkwood-pm.h" 278c2ecf20Sopenharmony_ci#include "common.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct resource kirkwood_cpufreq_resources[] = { 308c2ecf20Sopenharmony_ci [0] = { 318c2ecf20Sopenharmony_ci .start = CPU_CONTROL_PHYS, 328c2ecf20Sopenharmony_ci .end = CPU_CONTROL_PHYS + 3, 338c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 348c2ecf20Sopenharmony_ci }, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct platform_device kirkwood_cpufreq_device = { 388c2ecf20Sopenharmony_ci .name = "kirkwood-cpufreq", 398c2ecf20Sopenharmony_ci .id = -1, 408c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(kirkwood_cpufreq_resources), 418c2ecf20Sopenharmony_ci .resource = kirkwood_cpufreq_resources, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void __init kirkwood_cpufreq_init(void) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci platform_device_register(&kirkwood_cpufreq_device); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic struct resource kirkwood_cpuidle_resource[] = { 508c2ecf20Sopenharmony_ci { 518c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 528c2ecf20Sopenharmony_ci .start = DDR_OPERATION_BASE, 538c2ecf20Sopenharmony_ci .end = DDR_OPERATION_BASE + 3, 548c2ecf20Sopenharmony_ci }, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct platform_device kirkwood_cpuidle = { 588c2ecf20Sopenharmony_ci .name = "kirkwood_cpuidle", 598c2ecf20Sopenharmony_ci .id = -1, 608c2ecf20Sopenharmony_ci .resource = kirkwood_cpuidle_resource, 618c2ecf20Sopenharmony_ci .num_resources = 1, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void __init kirkwood_cpuidle_init(void) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci platform_device_register(&kirkwood_cpuidle); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define MV643XX_ETH_MAC_ADDR_LOW 0x0414 708c2ecf20Sopenharmony_ci#define MV643XX_ETH_MAC_ADDR_HIGH 0x0418 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void __init kirkwood_dt_eth_fixup(void) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct device_node *np; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* 778c2ecf20Sopenharmony_ci * The ethernet interfaces forget the MAC address assigned by u-boot 788c2ecf20Sopenharmony_ci * if the clocks are turned off. Usually, u-boot on kirkwood boards 798c2ecf20Sopenharmony_ci * has no DT support to properly set local-mac-address property. 808c2ecf20Sopenharmony_ci * As a workaround, we get the MAC address from mv643xx_eth registers 818c2ecf20Sopenharmony_ci * and update the port device node if no valid MAC address is set. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci for_each_compatible_node(np, NULL, "marvell,kirkwood-eth-port") { 848c2ecf20Sopenharmony_ci struct device_node *pnp = of_get_parent(np); 858c2ecf20Sopenharmony_ci struct clk *clk; 868c2ecf20Sopenharmony_ci struct property *pmac; 878c2ecf20Sopenharmony_ci void __iomem *io; 888c2ecf20Sopenharmony_ci u8 *macaddr; 898c2ecf20Sopenharmony_ci u32 reg; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!pnp) 928c2ecf20Sopenharmony_ci continue; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* skip disabled nodes or nodes with valid MAC address*/ 958c2ecf20Sopenharmony_ci if (!of_device_is_available(pnp) || 968c2ecf20Sopenharmony_ci !IS_ERR(of_get_mac_address(np))) 978c2ecf20Sopenharmony_ci goto eth_fixup_skip; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci clk = of_clk_get(pnp, 0); 1008c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 1018c2ecf20Sopenharmony_ci goto eth_fixup_skip; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci io = of_iomap(pnp, 0); 1048c2ecf20Sopenharmony_ci if (!io) 1058c2ecf20Sopenharmony_ci goto eth_fixup_no_map; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* ensure port clock is not gated to not hang CPU */ 1088c2ecf20Sopenharmony_ci clk_prepare_enable(clk); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* store MAC address register contents in local-mac-address */ 1118c2ecf20Sopenharmony_ci pmac = kzalloc(sizeof(*pmac) + 6, GFP_KERNEL); 1128c2ecf20Sopenharmony_ci if (!pmac) 1138c2ecf20Sopenharmony_ci goto eth_fixup_no_mem; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci pmac->value = pmac + 1; 1168c2ecf20Sopenharmony_ci pmac->length = 6; 1178c2ecf20Sopenharmony_ci pmac->name = kstrdup("local-mac-address", GFP_KERNEL); 1188c2ecf20Sopenharmony_ci if (!pmac->name) { 1198c2ecf20Sopenharmony_ci kfree(pmac); 1208c2ecf20Sopenharmony_ci goto eth_fixup_no_mem; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci macaddr = pmac->value; 1248c2ecf20Sopenharmony_ci reg = readl(io + MV643XX_ETH_MAC_ADDR_HIGH); 1258c2ecf20Sopenharmony_ci macaddr[0] = (reg >> 24) & 0xff; 1268c2ecf20Sopenharmony_ci macaddr[1] = (reg >> 16) & 0xff; 1278c2ecf20Sopenharmony_ci macaddr[2] = (reg >> 8) & 0xff; 1288c2ecf20Sopenharmony_ci macaddr[3] = reg & 0xff; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci reg = readl(io + MV643XX_ETH_MAC_ADDR_LOW); 1318c2ecf20Sopenharmony_ci macaddr[4] = (reg >> 8) & 0xff; 1328c2ecf20Sopenharmony_ci macaddr[5] = reg & 0xff; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci of_update_property(np, pmac); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cieth_fixup_no_mem: 1378c2ecf20Sopenharmony_ci iounmap(io); 1388c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 1398c2ecf20Sopenharmony_cieth_fixup_no_map: 1408c2ecf20Sopenharmony_ci clk_put(clk); 1418c2ecf20Sopenharmony_cieth_fixup_skip: 1428c2ecf20Sopenharmony_ci of_node_put(pnp); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Disable propagation of mbus errors to the CPU local bus, as this 1488c2ecf20Sopenharmony_ci * causes mbus errors (which can occur for example for PCI aborts) to 1498c2ecf20Sopenharmony_ci * throw CPU aborts, which we're not set up to deal with. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistatic void kirkwood_disable_mbus_error_propagation(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci void __iomem *cpu_config; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci cpu_config = ioremap(CPU_CONFIG_PHYS, 4); 1568c2ecf20Sopenharmony_ci writel(readl(cpu_config) & ~CPU_CONFIG_ERROR_PROP, cpu_config); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic struct of_dev_auxdata auxdata[] __initdata = { 1608c2ecf20Sopenharmony_ci OF_DEV_AUXDATA("marvell,kirkwood-audio", 0xf10a0000, 1618c2ecf20Sopenharmony_ci "mvebu-audio", NULL), 1628c2ecf20Sopenharmony_ci { /* sentinel */ } 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void __init kirkwood_dt_init(void) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci kirkwood_disable_mbus_error_propagation(); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci BUG_ON(mvebu_mbus_dt_init(false)); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#ifdef CONFIG_CACHE_FEROCEON_L2 1728c2ecf20Sopenharmony_ci feroceon_of_init(); 1738c2ecf20Sopenharmony_ci#endif 1748c2ecf20Sopenharmony_ci kirkwood_cpufreq_init(); 1758c2ecf20Sopenharmony_ci kirkwood_cpuidle_init(); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci kirkwood_pm_init(); 1788c2ecf20Sopenharmony_ci kirkwood_dt_eth_fixup(); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci of_platform_default_populate(NULL, auxdata, NULL); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const char * const kirkwood_dt_board_compat[] __initconst = { 1848c2ecf20Sopenharmony_ci "marvell,kirkwood", 1858c2ecf20Sopenharmony_ci NULL 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciDT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)") 1898c2ecf20Sopenharmony_ci /* Maintainer: Jason Cooper <jason@lakedaemon.net> */ 1908c2ecf20Sopenharmony_ci .init_machine = kirkwood_dt_init, 1918c2ecf20Sopenharmony_ci .restart = mvebu_restart, 1928c2ecf20Sopenharmony_ci .dt_compat = kirkwood_dt_board_compat, 1938c2ecf20Sopenharmony_ciMACHINE_END 194