162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2008-2011 DENX Software Engineering GmbH 462306a36Sopenharmony_ci * Author: Heiko Schocher <hs@denx.de> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Description: 762306a36Sopenharmony_ci * Keymile 83xx platform specific routines. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/stddef.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/reboot.h> 1562306a36Sopenharmony_ci#include <linux/pci.h> 1662306a36Sopenharmony_ci#include <linux/kdev_t.h> 1762306a36Sopenharmony_ci#include <linux/major.h> 1862306a36Sopenharmony_ci#include <linux/console.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/seq_file.h> 2162306a36Sopenharmony_ci#include <linux/root_dev.h> 2262306a36Sopenharmony_ci#include <linux/initrd.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/of_address.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/atomic.h> 2762306a36Sopenharmony_ci#include <linux/time.h> 2862306a36Sopenharmony_ci#include <linux/io.h> 2962306a36Sopenharmony_ci#include <asm/machdep.h> 3062306a36Sopenharmony_ci#include <asm/ipic.h> 3162306a36Sopenharmony_ci#include <asm/irq.h> 3262306a36Sopenharmony_ci#include <asm/udbg.h> 3362306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 3462306a36Sopenharmony_ci#include <sysdev/fsl_pci.h> 3562306a36Sopenharmony_ci#include <soc/fsl/qe/qe.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "mpc83xx.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define SVR_REV(svr) (((svr) >> 0) & 0xFFFF) /* Revision field */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic void __init quirk_mpc8360e_qe_enet10(void) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci /* 4462306a36Sopenharmony_ci * handle mpc8360E Erratum QE_ENET10: 4562306a36Sopenharmony_ci * RGMII AC values do not meet the specification 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci uint svid = mfspr(SPRN_SVR); 4862306a36Sopenharmony_ci struct device_node *np_par; 4962306a36Sopenharmony_ci struct resource res; 5062306a36Sopenharmony_ci void __iomem *base; 5162306a36Sopenharmony_ci int ret; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci np_par = of_find_node_by_name(NULL, "par_io"); 5462306a36Sopenharmony_ci if (np_par == NULL) { 5562306a36Sopenharmony_ci pr_warn("%s couldn't find par_io node\n", __func__); 5662306a36Sopenharmony_ci return; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci /* Map Parallel I/O ports registers */ 5962306a36Sopenharmony_ci ret = of_address_to_resource(np_par, 0, &res); 6062306a36Sopenharmony_ci if (ret) { 6162306a36Sopenharmony_ci pr_warn("%s couldn't map par_io registers\n", __func__); 6262306a36Sopenharmony_ci goto out; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci base = ioremap(res.start, resource_size(&res)); 6662306a36Sopenharmony_ci if (!base) 6762306a36Sopenharmony_ci goto out; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* 7062306a36Sopenharmony_ci * set output delay adjustments to default values according 7162306a36Sopenharmony_ci * table 5 in Errata Rev. 5, 9/2011: 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * write 0b01 to UCC1 bits 18:19 7462306a36Sopenharmony_ci * write 0b01 to UCC2 option 1 bits 4:5 7562306a36Sopenharmony_ci * write 0b01 to UCC2 option 2 bits 16:17 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci clrsetbits_be32((base + 0xa8), 0x0c00f000, 0x04005000); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * set output delay adjustments to default values according 8162306a36Sopenharmony_ci * table 3-13 in Reference Manual Rev.3 05/2010: 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * write 0b01 to UCC2 option 2 bits 16:17 8462306a36Sopenharmony_ci * write 0b0101 to UCC1 bits 20:23 8562306a36Sopenharmony_ci * write 0b0101 to UCC2 option 1 bits 24:27 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci clrsetbits_be32((base + 0xac), 0x0000cff0, 0x00004550); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (SVR_REV(svid) == 0x0021) { 9062306a36Sopenharmony_ci /* 9162306a36Sopenharmony_ci * UCC2 option 1: write 0b1010 to bits 24:27 9262306a36Sopenharmony_ci * at address IMMRBAR+0x14AC 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci clrsetbits_be32((base + 0xac), 0x000000f0, 0x000000a0); 9562306a36Sopenharmony_ci } else if (SVR_REV(svid) == 0x0020) { 9662306a36Sopenharmony_ci /* 9762306a36Sopenharmony_ci * UCC1: write 0b11 to bits 18:19 9862306a36Sopenharmony_ci * at address IMMRBAR+0x14A8 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci setbits32((base + 0xa8), 0x00003000); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* 10362306a36Sopenharmony_ci * UCC2 option 1: write 0b11 to bits 4:5 10462306a36Sopenharmony_ci * at address IMMRBAR+0x14A8 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci setbits32((base + 0xa8), 0x0c000000); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* 10962306a36Sopenharmony_ci * UCC2 option 2: write 0b11 to bits 16:17 11062306a36Sopenharmony_ci * at address IMMRBAR+0x14AC 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci setbits32((base + 0xac), 0x0000c000); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci iounmap(base); 11562306a36Sopenharmony_ciout: 11662306a36Sopenharmony_ci of_node_put(np_par); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* ************************************************************************ 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Setup the architecture 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_cistatic void __init mpc83xx_km_setup_arch(void) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE 12762306a36Sopenharmony_ci struct device_node *np; 12862306a36Sopenharmony_ci#endif 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci mpc83xx_setup_arch(); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE 13362306a36Sopenharmony_ci np = of_find_node_by_name(NULL, "par_io"); 13462306a36Sopenharmony_ci if (np != NULL) { 13562306a36Sopenharmony_ci par_io_init(np); 13662306a36Sopenharmony_ci of_node_put(np); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci for_each_node_by_name(np, "spi") 13962306a36Sopenharmony_ci par_io_of_config(np); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci for_each_node_by_name(np, "ucc") 14262306a36Sopenharmony_ci par_io_of_config(np); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* Only apply this quirk when par_io is available */ 14562306a36Sopenharmony_ci np = of_find_compatible_node(NULL, "network", "ucc_geth"); 14662306a36Sopenharmony_ci if (np != NULL) { 14762306a36Sopenharmony_ci quirk_mpc8360e_qe_enet10(); 14862306a36Sopenharmony_ci of_node_put(np); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci#endif /* CONFIG_QUICC_ENGINE */ 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cimachine_device_initcall(mpc83xx_km, mpc83xx_declare_of_platform_devices); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* list of the supported boards */ 15762306a36Sopenharmony_cistatic char *board[] __initdata = { 15862306a36Sopenharmony_ci "Keymile,KMETER1", 15962306a36Sopenharmony_ci "Keymile,kmpbec8321", 16062306a36Sopenharmony_ci NULL 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* 16462306a36Sopenharmony_ci * Called very early, MMU is off, device-tree isn't unflattened 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistatic int __init mpc83xx_km_probe(void) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int i = 0; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci while (board[i]) { 17162306a36Sopenharmony_ci if (of_machine_is_compatible(board[i])) 17262306a36Sopenharmony_ci break; 17362306a36Sopenharmony_ci i++; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci return (board[i] != NULL); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cidefine_machine(mpc83xx_km) { 17962306a36Sopenharmony_ci .name = "mpc83xx-km-platform", 18062306a36Sopenharmony_ci .probe = mpc83xx_km_probe, 18162306a36Sopenharmony_ci .setup_arch = mpc83xx_km_setup_arch, 18262306a36Sopenharmony_ci .discover_phbs = mpc83xx_setup_pci, 18362306a36Sopenharmony_ci .init_IRQ = mpc83xx_ipic_init_IRQ, 18462306a36Sopenharmony_ci .get_irq = ipic_get_irq, 18562306a36Sopenharmony_ci .restart = mpc83xx_restart, 18662306a36Sopenharmony_ci .time_init = mpc83xx_time_init, 18762306a36Sopenharmony_ci .progress = udbg_progress, 18862306a36Sopenharmony_ci}; 189