18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FSL SoC setup code 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Maintained by Kumar Gala (see MAINTAINERS for contact information) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * 2006 (c) MontaVista Software, Inc. 88c2ecf20Sopenharmony_ci * Vitaly Bordug <vbordug@ru.mvista.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/stddef.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/major.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/irq.h> 188c2ecf20Sopenharmony_ci#include <linux/export.h> 198c2ecf20Sopenharmony_ci#include <linux/device.h> 208c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 238c2ecf20Sopenharmony_ci#include <linux/phy.h> 248c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 258c2ecf20Sopenharmony_ci#include <linux/fsl_devices.h> 268c2ecf20Sopenharmony_ci#include <linux/fs_enet_pd.h> 278c2ecf20Sopenharmony_ci#include <linux/fs_uart_pd.h> 288c2ecf20Sopenharmony_ci#include <linux/reboot.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/atomic.h> 318c2ecf20Sopenharmony_ci#include <asm/io.h> 328c2ecf20Sopenharmony_ci#include <asm/irq.h> 338c2ecf20Sopenharmony_ci#include <asm/time.h> 348c2ecf20Sopenharmony_ci#include <asm/prom.h> 358c2ecf20Sopenharmony_ci#include <asm/machdep.h> 368c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h> 378c2ecf20Sopenharmony_ci#include <mm/mmu_decl.h> 388c2ecf20Sopenharmony_ci#include <asm/cpm2.h> 398c2ecf20Sopenharmony_ci#include <asm/fsl_hcalls.h> /* For the Freescale hypervisor */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciextern void init_fcc_ioports(struct fs_platform_info*); 428c2ecf20Sopenharmony_ciextern void init_fec_ioports(struct fs_platform_info*); 438c2ecf20Sopenharmony_ciextern void init_smc_ioports(struct fs_uart_platform_info*); 448c2ecf20Sopenharmony_cistatic phys_addr_t immrbase = -1; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciphys_addr_t get_immrbase(void) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct device_node *soc; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (immrbase != -1) 518c2ecf20Sopenharmony_ci return immrbase; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci soc = of_find_node_by_type(NULL, "soc"); 548c2ecf20Sopenharmony_ci if (soc) { 558c2ecf20Sopenharmony_ci int size; 568c2ecf20Sopenharmony_ci u32 naddr; 578c2ecf20Sopenharmony_ci const __be32 *prop = of_get_property(soc, "#address-cells", &size); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (prop && size == 4) 608c2ecf20Sopenharmony_ci naddr = be32_to_cpup(prop); 618c2ecf20Sopenharmony_ci else 628c2ecf20Sopenharmony_ci naddr = 2; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci prop = of_get_property(soc, "ranges", &size); 658c2ecf20Sopenharmony_ci if (prop) 668c2ecf20Sopenharmony_ci immrbase = of_translate_address(soc, prop + naddr); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci of_node_put(soc); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return immrbase; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(get_immrbase); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciu32 fsl_get_sys_freq(void) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci static u32 sysfreq = -1; 798c2ecf20Sopenharmony_ci struct device_node *soc; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (sysfreq != -1) 828c2ecf20Sopenharmony_ci return sysfreq; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci soc = of_find_node_by_type(NULL, "soc"); 858c2ecf20Sopenharmony_ci if (!soc) 868c2ecf20Sopenharmony_ci return -1; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci of_property_read_u32(soc, "clock-frequency", &sysfreq); 898c2ecf20Sopenharmony_ci if (sysfreq == -1 || !sysfreq) 908c2ecf20Sopenharmony_ci of_property_read_u32(soc, "bus-frequency", &sysfreq); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci of_node_put(soc); 938c2ecf20Sopenharmony_ci return sysfreq; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fsl_get_sys_freq); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciu32 get_brgfreq(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci static u32 brgfreq = -1; 1028c2ecf20Sopenharmony_ci struct device_node *node; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (brgfreq != -1) 1058c2ecf20Sopenharmony_ci return brgfreq; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci node = of_find_compatible_node(NULL, NULL, "fsl,cpm-brg"); 1088c2ecf20Sopenharmony_ci if (node) { 1098c2ecf20Sopenharmony_ci of_property_read_u32(node, "clock-frequency", &brgfreq); 1108c2ecf20Sopenharmony_ci of_node_put(node); 1118c2ecf20Sopenharmony_ci return brgfreq; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Legacy device binding -- will go away when no users are left. */ 1158c2ecf20Sopenharmony_ci node = of_find_node_by_type(NULL, "cpm"); 1168c2ecf20Sopenharmony_ci if (!node) 1178c2ecf20Sopenharmony_ci node = of_find_compatible_node(NULL, NULL, "fsl,qe"); 1188c2ecf20Sopenharmony_ci if (!node) 1198c2ecf20Sopenharmony_ci node = of_find_node_by_type(NULL, "qe"); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (node) { 1228c2ecf20Sopenharmony_ci of_property_read_u32(node, "brg-frequency", &brgfreq); 1238c2ecf20Sopenharmony_ci if (brgfreq == -1 || !brgfreq) 1248c2ecf20Sopenharmony_ci if (!of_property_read_u32(node, "bus-frequency", 1258c2ecf20Sopenharmony_ci &brgfreq)) 1268c2ecf20Sopenharmony_ci brgfreq /= 2; 1278c2ecf20Sopenharmony_ci of_node_put(node); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return brgfreq; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(get_brgfreq); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ciu32 get_baudrate(void) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci static u32 fs_baudrate = -1; 1388c2ecf20Sopenharmony_ci struct device_node *node; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (fs_baudrate != -1) 1418c2ecf20Sopenharmony_ci return fs_baudrate; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci node = of_find_node_by_type(NULL, "serial"); 1448c2ecf20Sopenharmony_ci if (node) { 1458c2ecf20Sopenharmony_ci of_property_read_u32(node, "current-speed", &fs_baudrate); 1468c2ecf20Sopenharmony_ci of_node_put(node); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return fs_baudrate; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(get_baudrate); 1538c2ecf20Sopenharmony_ci#endif /* CONFIG_CPM2 */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) 1568c2ecf20Sopenharmony_cistatic __be32 __iomem *rstcr; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int fsl_rstcr_restart(struct notifier_block *this, 1598c2ecf20Sopenharmony_ci unsigned long mode, void *cmd) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci local_irq_disable(); 1628c2ecf20Sopenharmony_ci /* set reset control register */ 1638c2ecf20Sopenharmony_ci out_be32(rstcr, 0x2); /* HRESET_REQ */ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return NOTIFY_DONE; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int __init setup_rstcr(void) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct device_node *np; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci static struct notifier_block restart_handler = { 1738c2ecf20Sopenharmony_ci .notifier_call = fsl_rstcr_restart, 1748c2ecf20Sopenharmony_ci .priority = 128, 1758c2ecf20Sopenharmony_ci }; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci for_each_node_by_name(np, "global-utilities") { 1788c2ecf20Sopenharmony_ci if ((of_get_property(np, "fsl,has-rstcr", NULL))) { 1798c2ecf20Sopenharmony_ci rstcr = of_iomap(np, 0) + 0xb0; 1808c2ecf20Sopenharmony_ci if (!rstcr) { 1818c2ecf20Sopenharmony_ci printk (KERN_ERR "Error: reset control " 1828c2ecf20Sopenharmony_ci "register not mapped!\n"); 1838c2ecf20Sopenharmony_ci } else { 1848c2ecf20Sopenharmony_ci register_restart_handler(&restart_handler); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci of_node_put(np); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciarch_initcall(setup_rstcr); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 2008c2ecf20Sopenharmony_cistruct platform_diu_data_ops diu_ops; 2018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(diu_ops); 2028c2ecf20Sopenharmony_ci#endif 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#ifdef CONFIG_EPAPR_PARAVIRT 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * Restart the current partition 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * This function should be assigned to the ppc_md.restart function pointer, 2098c2ecf20Sopenharmony_ci * to initiate a partition restart when we're running under the Freescale 2108c2ecf20Sopenharmony_ci * hypervisor. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_civoid __noreturn fsl_hv_restart(char *cmd) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci pr_info("hv restart\n"); 2158c2ecf20Sopenharmony_ci fh_partition_restart(-1); 2168c2ecf20Sopenharmony_ci while (1) ; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * Halt the current partition 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * This function should be assigned to the pm_power_off and ppc_md.halt 2238c2ecf20Sopenharmony_ci * function pointers, to shut down the partition when we're running under 2248c2ecf20Sopenharmony_ci * the Freescale hypervisor. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_civoid __noreturn fsl_hv_halt(void) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci pr_info("hv exit\n"); 2298c2ecf20Sopenharmony_ci fh_partition_stop(-1); 2308c2ecf20Sopenharmony_ci while (1) ; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci#endif 233