18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2008-2011 DENX Software Engineering GmbH 48c2ecf20Sopenharmony_ci * Author: Heiko Schocher <hs@denx.de> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Description: 78c2ecf20Sopenharmony_ci * Keymile 83xx platform specific routines. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/stddef.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/reboot.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <linux/kdev_t.h> 178c2ecf20Sopenharmony_ci#include <linux/major.h> 188c2ecf20Sopenharmony_ci#include <linux/console.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 218c2ecf20Sopenharmony_ci#include <linux/root_dev.h> 228c2ecf20Sopenharmony_ci#include <linux/initrd.h> 238c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 248c2ecf20Sopenharmony_ci#include <linux/of_device.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/atomic.h> 278c2ecf20Sopenharmony_ci#include <linux/time.h> 288c2ecf20Sopenharmony_ci#include <linux/io.h> 298c2ecf20Sopenharmony_ci#include <asm/machdep.h> 308c2ecf20Sopenharmony_ci#include <asm/ipic.h> 318c2ecf20Sopenharmony_ci#include <asm/irq.h> 328c2ecf20Sopenharmony_ci#include <asm/prom.h> 338c2ecf20Sopenharmony_ci#include <asm/udbg.h> 348c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h> 358c2ecf20Sopenharmony_ci#include <sysdev/fsl_pci.h> 368c2ecf20Sopenharmony_ci#include <soc/fsl/qe/qe.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "mpc83xx.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define SVR_REV(svr) (((svr) >> 0) & 0xFFFF) /* Revision field */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void quirk_mpc8360e_qe_enet10(void) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci /* 458c2ecf20Sopenharmony_ci * handle mpc8360E Erratum QE_ENET10: 468c2ecf20Sopenharmony_ci * RGMII AC values do not meet the specification 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci uint svid = mfspr(SPRN_SVR); 498c2ecf20Sopenharmony_ci struct device_node *np_par; 508c2ecf20Sopenharmony_ci struct resource res; 518c2ecf20Sopenharmony_ci void __iomem *base; 528c2ecf20Sopenharmony_ci int ret; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci np_par = of_find_node_by_name(NULL, "par_io"); 558c2ecf20Sopenharmony_ci if (np_par == NULL) { 568c2ecf20Sopenharmony_ci pr_warn("%s couldn't find par_io node\n", __func__); 578c2ecf20Sopenharmony_ci return; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci /* Map Parallel I/O ports registers */ 608c2ecf20Sopenharmony_ci ret = of_address_to_resource(np_par, 0, &res); 618c2ecf20Sopenharmony_ci if (ret) { 628c2ecf20Sopenharmony_ci pr_warn("%s couldn't map par_io registers\n", __func__); 638c2ecf20Sopenharmony_ci goto out; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci base = ioremap(res.start, resource_size(&res)); 678c2ecf20Sopenharmony_ci if (!base) 688c2ecf20Sopenharmony_ci goto out; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* 718c2ecf20Sopenharmony_ci * set output delay adjustments to default values according 728c2ecf20Sopenharmony_ci * table 5 in Errata Rev. 5, 9/2011: 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * write 0b01 to UCC1 bits 18:19 758c2ecf20Sopenharmony_ci * write 0b01 to UCC2 option 1 bits 4:5 768c2ecf20Sopenharmony_ci * write 0b01 to UCC2 option 2 bits 16:17 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci clrsetbits_be32((base + 0xa8), 0x0c00f000, 0x04005000); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * set output delay adjustments to default values according 828c2ecf20Sopenharmony_ci * table 3-13 in Reference Manual Rev.3 05/2010: 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * write 0b01 to UCC2 option 2 bits 16:17 858c2ecf20Sopenharmony_ci * write 0b0101 to UCC1 bits 20:23 868c2ecf20Sopenharmony_ci * write 0b0101 to UCC2 option 1 bits 24:27 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci clrsetbits_be32((base + 0xac), 0x0000cff0, 0x00004550); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (SVR_REV(svid) == 0x0021) { 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * UCC2 option 1: write 0b1010 to bits 24:27 938c2ecf20Sopenharmony_ci * at address IMMRBAR+0x14AC 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci clrsetbits_be32((base + 0xac), 0x000000f0, 0x000000a0); 968c2ecf20Sopenharmony_ci } else if (SVR_REV(svid) == 0x0020) { 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * UCC1: write 0b11 to bits 18:19 998c2ecf20Sopenharmony_ci * at address IMMRBAR+0x14A8 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci setbits32((base + 0xa8), 0x00003000); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * UCC2 option 1: write 0b11 to bits 4:5 1058c2ecf20Sopenharmony_ci * at address IMMRBAR+0x14A8 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci setbits32((base + 0xa8), 0x0c000000); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * UCC2 option 2: write 0b11 to bits 16:17 1118c2ecf20Sopenharmony_ci * at address IMMRBAR+0x14AC 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci setbits32((base + 0xac), 0x0000c000); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci iounmap(base); 1168c2ecf20Sopenharmony_ciout: 1178c2ecf20Sopenharmony_ci of_node_put(np_par); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* ************************************************************************ 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * Setup the architecture 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistatic void __init mpc83xx_km_setup_arch(void) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE 1288c2ecf20Sopenharmony_ci struct device_node *np; 1298c2ecf20Sopenharmony_ci#endif 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci mpc83xx_setup_arch(); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE 1348c2ecf20Sopenharmony_ci np = of_find_node_by_name(NULL, "par_io"); 1358c2ecf20Sopenharmony_ci if (np != NULL) { 1368c2ecf20Sopenharmony_ci par_io_init(np); 1378c2ecf20Sopenharmony_ci of_node_put(np); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for_each_node_by_name(np, "spi") 1408c2ecf20Sopenharmony_ci par_io_of_config(np); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci for_each_node_by_name(np, "ucc") 1438c2ecf20Sopenharmony_ci par_io_of_config(np); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* Only apply this quirk when par_io is available */ 1468c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, "network", "ucc_geth"); 1478c2ecf20Sopenharmony_ci if (np != NULL) { 1488c2ecf20Sopenharmony_ci quirk_mpc8360e_qe_enet10(); 1498c2ecf20Sopenharmony_ci of_node_put(np); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci#endif /* CONFIG_QUICC_ENGINE */ 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cimachine_device_initcall(mpc83xx_km, mpc83xx_declare_of_platform_devices); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* list of the supported boards */ 1588c2ecf20Sopenharmony_cistatic char *board[] __initdata = { 1598c2ecf20Sopenharmony_ci "Keymile,KMETER1", 1608c2ecf20Sopenharmony_ci "Keymile,kmpbec8321", 1618c2ecf20Sopenharmony_ci NULL 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* 1658c2ecf20Sopenharmony_ci * Called very early, MMU is off, device-tree isn't unflattened 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic int __init mpc83xx_km_probe(void) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci int i = 0; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci while (board[i]) { 1728c2ecf20Sopenharmony_ci if (of_machine_is_compatible(board[i])) 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci i++; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci return (board[i] != NULL); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cidefine_machine(mpc83xx_km) { 1808c2ecf20Sopenharmony_ci .name = "mpc83xx-km-platform", 1818c2ecf20Sopenharmony_ci .probe = mpc83xx_km_probe, 1828c2ecf20Sopenharmony_ci .setup_arch = mpc83xx_km_setup_arch, 1838c2ecf20Sopenharmony_ci .init_IRQ = mpc83xx_ipic_init_IRQ, 1848c2ecf20Sopenharmony_ci .get_irq = ipic_get_irq, 1858c2ecf20Sopenharmony_ci .restart = mpc83xx_restart, 1868c2ecf20Sopenharmony_ci .time_init = mpc83xx_time_init, 1878c2ecf20Sopenharmony_ci .calibrate_decr = generic_calibrate_decr, 1888c2ecf20Sopenharmony_ci .progress = udbg_progress, 1898c2ecf20Sopenharmony_ci}; 190