1cb165c52SRabin Vincent /* 2c15def1cSLinus Walleij * Copyright (C) 2008-2009 ST-Ericsson SA 3cb165c52SRabin Vincent * 4cb165c52SRabin Vincent * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> 5cb165c52SRabin Vincent * 6cb165c52SRabin Vincent * This program is free software; you can redistribute it and/or modify 7cb165c52SRabin Vincent * it under the terms of the GNU General Public License version 2, as 8cb165c52SRabin Vincent * published by the Free Software Foundation. 9cb165c52SRabin Vincent * 10cb165c52SRabin Vincent */ 11cb165c52SRabin Vincent #include <linux/types.h> 12cb165c52SRabin Vincent #include <linux/init.h> 13cb165c52SRabin Vincent #include <linux/device.h> 14cb165c52SRabin Vincent #include <linux/amba/bus.h> 15aa90eb9dSRabin Vincent #include <linux/interrupt.h> 16cb165c52SRabin Vincent #include <linux/irq.h> 17a16729eaSArnd Bergmann #include <linux/irqchip.h> 18a16729eaSArnd Bergmann #include <linux/irqchip/arm-gic.h> 19a16729eaSArnd Bergmann #include <linux/mfd/dbx500-prcmu.h> 20a16729eaSArnd Bergmann #include <linux/platform_data/arm-ux500-pm.h> 21cb165c52SRabin Vincent #include <linux/platform_device.h> 22cb165c52SRabin Vincent #include <linux/io.h> 23fa86a764SLee Jones #include <linux/of.h> 24a16729eaSArnd Bergmann #include <linux/of_address.h> 25fa86a764SLee Jones #include <linux/of_platform.h> 26fa86a764SLee Jones #include <linux/regulator/machine.h> 27cb165c52SRabin Vincent 28a16729eaSArnd Bergmann #include <asm/outercache.h> 29a16729eaSArnd Bergmann #include <asm/hardware/cache-l2x0.h> 30cb165c52SRabin Vincent #include <asm/mach/map.h> 31a16729eaSArnd Bergmann #include <asm/mach/arch.h> 32b8edf848SLinus Torvalds 336f6d6433SLee Jones #include "db8500-regs.h" 3472ecd793SUlf Hansson #include "pm_domains.h" 35cb165c52SRabin Vincent 36a16729eaSArnd Bergmann static int __init ux500_l2x0_unlock(void) 37a16729eaSArnd Bergmann { 38a16729eaSArnd Bergmann int i; 39a16729eaSArnd Bergmann struct device_node *np; 40a16729eaSArnd Bergmann void __iomem *l2x0_base; 41a16729eaSArnd Bergmann 42a16729eaSArnd Bergmann np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache"); 43a16729eaSArnd Bergmann l2x0_base = of_iomap(np, 0); 44a16729eaSArnd Bergmann of_node_put(np); 45a16729eaSArnd Bergmann if (!l2x0_base) 46a16729eaSArnd Bergmann return -ENODEV; 47a16729eaSArnd Bergmann 48a16729eaSArnd Bergmann /* 49a16729eaSArnd Bergmann * Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions 50a16729eaSArnd Bergmann * apparently locks both caches before jumping to the kernel. The 51a16729eaSArnd Bergmann * l2x0 core will not touch the unlock registers if the l2x0 is 52a16729eaSArnd Bergmann * already enabled, so we do it right here instead. The PL310 has 53a16729eaSArnd Bergmann * 8 sets of registers, one per possible CPU. 54a16729eaSArnd Bergmann */ 55a16729eaSArnd Bergmann for (i = 0; i < 8; i++) { 56a16729eaSArnd Bergmann writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE + 57a16729eaSArnd Bergmann i * L2X0_LOCKDOWN_STRIDE); 58a16729eaSArnd Bergmann writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE + 59a16729eaSArnd Bergmann i * L2X0_LOCKDOWN_STRIDE); 60a16729eaSArnd Bergmann } 61a16729eaSArnd Bergmann iounmap(l2x0_base); 62a16729eaSArnd Bergmann return 0; 63a16729eaSArnd Bergmann } 64a16729eaSArnd Bergmann 65a16729eaSArnd Bergmann static void ux500_l2c310_write_sec(unsigned long val, unsigned reg) 66a16729eaSArnd Bergmann { 67a16729eaSArnd Bergmann /* 68a16729eaSArnd Bergmann * We can't write to secure registers as we are in non-secure 69a16729eaSArnd Bergmann * mode, until we have some SMI service available. 70a16729eaSArnd Bergmann */ 71a16729eaSArnd Bergmann } 72a16729eaSArnd Bergmann 73a16729eaSArnd Bergmann /* 74a16729eaSArnd Bergmann * FIXME: Should we set up the GPIO domain here? 75a16729eaSArnd Bergmann * 76a16729eaSArnd Bergmann * The problem is that we cannot put the interrupt resources into the platform 77a16729eaSArnd Bergmann * device until the irqdomain has been added. Right now, we set the GIC interrupt 78a16729eaSArnd Bergmann * domain from init_irq(), then load the gpio driver from 79a16729eaSArnd Bergmann * core_initcall(nmk_gpio_init) and add the platform devices from 80a16729eaSArnd Bergmann * arch_initcall(customize_machine). 81a16729eaSArnd Bergmann * 82a16729eaSArnd Bergmann * This feels fragile because it depends on the gpio device getting probed 83a16729eaSArnd Bergmann * _before_ any device uses the gpio interrupts. 84a16729eaSArnd Bergmann */ 85a16729eaSArnd Bergmann static void __init ux500_init_irq(void) 86a16729eaSArnd Bergmann { 87a16729eaSArnd Bergmann struct device_node *np; 88a16729eaSArnd Bergmann struct resource r; 89a16729eaSArnd Bergmann 90a16729eaSArnd Bergmann irqchip_init(); 91a16729eaSArnd Bergmann np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu"); 92a16729eaSArnd Bergmann of_address_to_resource(np, 0, &r); 93a16729eaSArnd Bergmann of_node_put(np); 94a16729eaSArnd Bergmann if (!r.start) { 95a16729eaSArnd Bergmann pr_err("could not find PRCMU base resource\n"); 96a16729eaSArnd Bergmann return; 97a16729eaSArnd Bergmann } 98a16729eaSArnd Bergmann prcmu_early_init(r.start, r.end-r.start); 99a16729eaSArnd Bergmann ux500_pm_init(r.start, r.end-r.start); 100a16729eaSArnd Bergmann 101a16729eaSArnd Bergmann /* Unlock before init */ 102a16729eaSArnd Bergmann ux500_l2x0_unlock(); 103a16729eaSArnd Bergmann outer_cache.write_sec = ux500_l2c310_write_sec; 104a16729eaSArnd Bergmann } 105a16729eaSArnd Bergmann 106a16729eaSArnd Bergmann static void ux500_restart(enum reboot_mode mode, const char *cmd) 107a16729eaSArnd Bergmann { 108a16729eaSArnd Bergmann local_irq_disable(); 109a16729eaSArnd Bergmann local_fiq_disable(); 110a16729eaSArnd Bergmann 111a16729eaSArnd Bergmann prcmu_system_reset(0); 112a16729eaSArnd Bergmann } 113a16729eaSArnd Bergmann 114c21a43b7SLee Jones static struct of_dev_auxdata u8540_auxdata_lookup[] __initdata = { 1154e657946SArnd Bergmann OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", NULL), 116c21a43b7SLee Jones {}, 117c21a43b7SLee Jones }; 118c21a43b7SLee Jones 119fa86a764SLee Jones static const struct of_device_id u8500_local_bus_nodes[] = { 120fa86a764SLee Jones /* only create devices below soc node */ 121fa86a764SLee Jones { .compatible = "stericsson,db8500", }, 122fa86a764SLee Jones { .compatible = "stericsson,db8500-prcmu", }, 123fa86a764SLee Jones { .compatible = "simple-bus"}, 124fa86a764SLee Jones { }, 125fa86a764SLee Jones }; 126fa86a764SLee Jones 127fa86a764SLee Jones static void __init u8500_init_machine(void) 128fa86a764SLee Jones { 12972ecd793SUlf Hansson /* Initialize ux500 power domains */ 13072ecd793SUlf Hansson ux500_pm_domains_init(); 13172ecd793SUlf Hansson 132c21a43b7SLee Jones /* automatically probe child nodes of dbx5x0 devices */ 133c21a43b7SLee Jones if (of_machine_is_compatible("st-ericsson,u8540")) 134c21a43b7SLee Jones of_platform_populate(NULL, u8500_local_bus_nodes, 13518a99278SArnd Bergmann u8540_auxdata_lookup, NULL); 136dbe8a9dfSLinus Walleij else 137dbe8a9dfSLinus Walleij of_platform_populate(NULL, u8500_local_bus_nodes, 138dbe8a9dfSLinus Walleij NULL, NULL); 139fa86a764SLee Jones } 140fa86a764SLee Jones 14179b40753SLee Jones static const char * stericsson_dt_platform_compat[] = { 14279b40753SLee Jones "st-ericsson,u8500", 14379b40753SLee Jones "st-ericsson,u8540", 14479b40753SLee Jones "st-ericsson,u9500", 14579b40753SLee Jones "st-ericsson,u9540", 146fa86a764SLee Jones NULL, 147fa86a764SLee Jones }; 148fa86a764SLee Jones 14946c1bf81SLee Jones DT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)") 1501e6cbc06SArnd Bergmann .l2c_aux_val = 0, 1511e6cbc06SArnd Bergmann .l2c_aux_mask = ~0, 152fa86a764SLee Jones .init_irq = ux500_init_irq, 153fa86a764SLee Jones .init_machine = u8500_init_machine, 15479b40753SLee Jones .dt_compat = stericsson_dt_platform_compat, 155bd93ec50SFabio Baltieri .restart = ux500_restart, 156fa86a764SLee Jones MACHINE_END 157