17480e0aaSRich Felker /* 27480e0aaSRich Felker * SH generic board support, using device tree 37480e0aaSRich Felker * 47480e0aaSRich Felker * Copyright (C) 2015-2016 Smart Energy Instruments, Inc. 57480e0aaSRich Felker * 67480e0aaSRich Felker * This file is subject to the terms and conditions of the GNU General Public 77480e0aaSRich Felker * License. See the file "COPYING" in the main directory of this archive 87480e0aaSRich Felker * for more details. 97480e0aaSRich Felker */ 107480e0aaSRich Felker 117480e0aaSRich Felker #include <linux/of.h> 127480e0aaSRich Felker #include <linux/of_platform.h> 137480e0aaSRich Felker #include <linux/of_fdt.h> 147480e0aaSRich Felker #include <linux/of_iommu.h> 157480e0aaSRich Felker #include <linux/clocksource.h> 167480e0aaSRich Felker #include <linux/irqchip.h> 177480e0aaSRich Felker #include <linux/clk-provider.h> 187480e0aaSRich Felker #include <asm/machvec.h> 197480e0aaSRich Felker #include <asm/rtc.h> 207480e0aaSRich Felker 21044b81f8SRich Felker #ifdef CONFIG_SMP 22044b81f8SRich Felker 23044b81f8SRich Felker static void dummy_smp_setup(void) 24044b81f8SRich Felker { 25044b81f8SRich Felker } 26044b81f8SRich Felker 27044b81f8SRich Felker static void dummy_prepare_cpus(unsigned int max_cpus) 28044b81f8SRich Felker { 29044b81f8SRich Felker } 30044b81f8SRich Felker 31044b81f8SRich Felker static void dummy_start_cpu(unsigned int cpu, unsigned long entry_point) 32044b81f8SRich Felker { 33044b81f8SRich Felker } 34044b81f8SRich Felker 35044b81f8SRich Felker static unsigned int dummy_smp_processor_id(void) 36044b81f8SRich Felker { 37044b81f8SRich Felker return 0; 38044b81f8SRich Felker } 39044b81f8SRich Felker 40044b81f8SRich Felker static void dummy_send_ipi(unsigned int cpu, unsigned int message) 41044b81f8SRich Felker { 42044b81f8SRich Felker } 43044b81f8SRich Felker 44044b81f8SRich Felker static struct plat_smp_ops dummy_smp_ops = { 45044b81f8SRich Felker .smp_setup = dummy_smp_setup, 46044b81f8SRich Felker .prepare_cpus = dummy_prepare_cpus, 47044b81f8SRich Felker .start_cpu = dummy_start_cpu, 48044b81f8SRich Felker .smp_processor_id = dummy_smp_processor_id, 49044b81f8SRich Felker .send_ipi = dummy_send_ipi, 50044b81f8SRich Felker .cpu_die = native_cpu_die, 51044b81f8SRich Felker .cpu_disable = native_cpu_disable, 52044b81f8SRich Felker .play_dead = native_play_dead, 53044b81f8SRich Felker }; 54044b81f8SRich Felker 55044b81f8SRich Felker extern const struct of_cpu_method __cpu_method_of_table[]; 56044b81f8SRich Felker const struct of_cpu_method __cpu_method_of_table_sentinel 57044b81f8SRich Felker __section(__cpu_method_of_table_end); 58044b81f8SRich Felker 59044b81f8SRich Felker static void sh_of_smp_probe(void) 60044b81f8SRich Felker { 61044b81f8SRich Felker struct device_node *np = 0; 62044b81f8SRich Felker const char *method = 0; 63044b81f8SRich Felker const struct of_cpu_method *m = __cpu_method_of_table; 64044b81f8SRich Felker 65044b81f8SRich Felker pr_info("SH generic board support: scanning for cpus\n"); 66044b81f8SRich Felker 67044b81f8SRich Felker init_cpu_possible(cpumask_of(0)); 68044b81f8SRich Felker 69044b81f8SRich Felker while ((np = of_find_node_by_type(np, "cpu"))) { 70044b81f8SRich Felker const __be32 *cell = of_get_property(np, "reg", NULL); 71044b81f8SRich Felker u64 id = -1; 72044b81f8SRich Felker if (cell) id = of_read_number(cell, of_n_addr_cells(np)); 73044b81f8SRich Felker if (id < NR_CPUS) { 74044b81f8SRich Felker if (!method) 75044b81f8SRich Felker of_property_read_string(np, "enable-method", &method); 76044b81f8SRich Felker set_cpu_possible(id, true); 77044b81f8SRich Felker set_cpu_present(id, true); 78044b81f8SRich Felker __cpu_number_map[id] = id; 79044b81f8SRich Felker __cpu_logical_map[id] = id; 80044b81f8SRich Felker } 81044b81f8SRich Felker } 82044b81f8SRich Felker if (!method) { 83044b81f8SRich Felker np = of_find_node_by_name(NULL, "cpus"); 84044b81f8SRich Felker of_property_read_string(np, "enable-method", &method); 85044b81f8SRich Felker } 86044b81f8SRich Felker 87044b81f8SRich Felker pr_info("CPU enable method: %s\n", method); 88044b81f8SRich Felker if (method) 89044b81f8SRich Felker for (; m->method; m++) 90044b81f8SRich Felker if (!strcmp(m->method, method)) { 91044b81f8SRich Felker register_smp_ops(m->ops); 92044b81f8SRich Felker return; 93044b81f8SRich Felker } 94044b81f8SRich Felker 95044b81f8SRich Felker register_smp_ops(&dummy_smp_ops); 96044b81f8SRich Felker } 97044b81f8SRich Felker 98044b81f8SRich Felker #else 99044b81f8SRich Felker 100044b81f8SRich Felker static void sh_of_smp_probe(void) 101044b81f8SRich Felker { 102044b81f8SRich Felker } 103044b81f8SRich Felker 104044b81f8SRich Felker #endif 105044b81f8SRich Felker 1067480e0aaSRich Felker static void noop(void) 1077480e0aaSRich Felker { 1087480e0aaSRich Felker } 1097480e0aaSRich Felker 1107480e0aaSRich Felker static int noopi(void) 1117480e0aaSRich Felker { 1127480e0aaSRich Felker return 0; 1137480e0aaSRich Felker } 1147480e0aaSRich Felker 1157480e0aaSRich Felker static void __init sh_of_mem_reserve(void) 1167480e0aaSRich Felker { 1177480e0aaSRich Felker early_init_fdt_reserve_self(); 1187480e0aaSRich Felker early_init_fdt_scan_reserved_mem(); 1197480e0aaSRich Felker } 1207480e0aaSRich Felker 1217480e0aaSRich Felker static void __init sh_of_time_init(void) 1227480e0aaSRich Felker { 1237480e0aaSRich Felker pr_info("SH generic board support: scanning for clocksource devices\n"); 1247480e0aaSRich Felker clocksource_probe(); 1257480e0aaSRich Felker } 1267480e0aaSRich Felker 1277480e0aaSRich Felker static void __init sh_of_setup(char **cmdline_p) 1287480e0aaSRich Felker { 1297480e0aaSRich Felker unflatten_device_tree(); 1307480e0aaSRich Felker 1317480e0aaSRich Felker board_time_init = sh_of_time_init; 1327480e0aaSRich Felker 1337480e0aaSRich Felker sh_mv.mv_name = of_flat_dt_get_machine_name(); 1347480e0aaSRich Felker if (!sh_mv.mv_name) 1357480e0aaSRich Felker sh_mv.mv_name = "Unknown SH model"; 1367480e0aaSRich Felker 137044b81f8SRich Felker sh_of_smp_probe(); 1387480e0aaSRich Felker } 1397480e0aaSRich Felker 1407480e0aaSRich Felker static int sh_of_irq_demux(int irq) 1417480e0aaSRich Felker { 1427480e0aaSRich Felker /* FIXME: eventually this should not be used at all; 1437480e0aaSRich Felker * the interrupt controller should set_handle_irq(). */ 1447480e0aaSRich Felker return irq; 1457480e0aaSRich Felker } 1467480e0aaSRich Felker 1477480e0aaSRich Felker static void __init sh_of_init_irq(void) 1487480e0aaSRich Felker { 1497480e0aaSRich Felker pr_info("SH generic board support: scanning for interrupt controllers\n"); 1507480e0aaSRich Felker irqchip_init(); 1517480e0aaSRich Felker } 1527480e0aaSRich Felker 1537480e0aaSRich Felker static int __init sh_of_clk_init(void) 1547480e0aaSRich Felker { 1557480e0aaSRich Felker #ifdef CONFIG_COMMON_CLK 1567480e0aaSRich Felker /* Disabled pending move to COMMON_CLK framework. */ 1577480e0aaSRich Felker pr_info("SH generic board support: scanning for clk providers\n"); 1587480e0aaSRich Felker of_clk_init(NULL); 1597480e0aaSRich Felker #endif 1607480e0aaSRich Felker return 0; 1617480e0aaSRich Felker } 1627480e0aaSRich Felker 1637480e0aaSRich Felker static struct sh_machine_vector __initmv sh_of_generic_mv = { 1647480e0aaSRich Felker .mv_setup = sh_of_setup, 1657480e0aaSRich Felker .mv_name = "devicetree", /* replaced by DT root's model */ 1667480e0aaSRich Felker .mv_irq_demux = sh_of_irq_demux, 1677480e0aaSRich Felker .mv_init_irq = sh_of_init_irq, 1687480e0aaSRich Felker .mv_clk_init = sh_of_clk_init, 1697480e0aaSRich Felker .mv_mode_pins = noopi, 1707480e0aaSRich Felker .mv_mem_init = noop, 1717480e0aaSRich Felker .mv_mem_reserve = sh_of_mem_reserve, 1727480e0aaSRich Felker }; 1737480e0aaSRich Felker 1747480e0aaSRich Felker struct sh_clk_ops; 1757480e0aaSRich Felker 1767480e0aaSRich Felker void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx) 1777480e0aaSRich Felker { 1787480e0aaSRich Felker } 1797480e0aaSRich Felker 1807480e0aaSRich Felker void __init plat_irq_setup(void) 1817480e0aaSRich Felker { 1827480e0aaSRich Felker } 1837480e0aaSRich Felker 1847480e0aaSRich Felker static int __init sh_of_device_init(void) 1857480e0aaSRich Felker { 1867480e0aaSRich Felker pr_info("SH generic board support: populating platform devices\n"); 1877480e0aaSRich Felker if (of_have_populated_dt()) { 1887480e0aaSRich Felker of_iommu_init(); 1897480e0aaSRich Felker of_platform_populate(NULL, of_default_bus_match_table, 1907480e0aaSRich Felker NULL, NULL); 1917480e0aaSRich Felker } else { 1927480e0aaSRich Felker pr_crit("Device tree not populated\n"); 1937480e0aaSRich Felker } 1947480e0aaSRich Felker return 0; 1957480e0aaSRich Felker } 1967480e0aaSRich Felker arch_initcall_sync(sh_of_device_init); 197