18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * GE IMP3A Board Setup
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author Martyn Welch <martyn.welch@ge.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright 2010 GE Intelligent Platforms Embedded Systems, Inc.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Based on: mpc85xx_ds.c (MPC85xx DS Board Setup)
108c2ecf20Sopenharmony_ci * Copyright 2007 Freescale Semiconductor Inc.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/stddef.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/pci.h>
168c2ecf20Sopenharmony_ci#include <linux/kdev_t.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
198c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
208c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <asm/time.h>
238c2ecf20Sopenharmony_ci#include <asm/machdep.h>
248c2ecf20Sopenharmony_ci#include <asm/pci-bridge.h>
258c2ecf20Sopenharmony_ci#include <mm/mmu_decl.h>
268c2ecf20Sopenharmony_ci#include <asm/prom.h>
278c2ecf20Sopenharmony_ci#include <asm/udbg.h>
288c2ecf20Sopenharmony_ci#include <asm/mpic.h>
298c2ecf20Sopenharmony_ci#include <asm/swiotlb.h>
308c2ecf20Sopenharmony_ci#include <asm/nvram.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h>
338c2ecf20Sopenharmony_ci#include <sysdev/fsl_pci.h>
348c2ecf20Sopenharmony_ci#include "smp.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include "mpc85xx.h"
378c2ecf20Sopenharmony_ci#include <sysdev/ge/ge_pic.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_civoid __iomem *imp3a_regs;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_civoid __init ge_imp3a_pic_init(void)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct mpic *mpic;
448c2ecf20Sopenharmony_ci	struct device_node *np;
458c2ecf20Sopenharmony_ci	struct device_node *cascade_node = NULL;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (of_machine_is_compatible("fsl,MPC8572DS-CAMP")) {
488c2ecf20Sopenharmony_ci		mpic = mpic_alloc(NULL, 0,
498c2ecf20Sopenharmony_ci			MPIC_NO_RESET |
508c2ecf20Sopenharmony_ci			MPIC_BIG_ENDIAN |
518c2ecf20Sopenharmony_ci			MPIC_SINGLE_DEST_CPU,
528c2ecf20Sopenharmony_ci			0, 256, " OpenPIC  ");
538c2ecf20Sopenharmony_ci	} else {
548c2ecf20Sopenharmony_ci		mpic = mpic_alloc(NULL, 0,
558c2ecf20Sopenharmony_ci			  MPIC_BIG_ENDIAN |
568c2ecf20Sopenharmony_ci			  MPIC_SINGLE_DEST_CPU,
578c2ecf20Sopenharmony_ci			0, 256, " OpenPIC  ");
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	BUG_ON(mpic == NULL);
618c2ecf20Sopenharmony_ci	mpic_init(mpic);
628c2ecf20Sopenharmony_ci	/*
638c2ecf20Sopenharmony_ci	 * There is a simple interrupt handler in the main FPGA, this needs
648c2ecf20Sopenharmony_ci	 * to be cascaded into the MPIC
658c2ecf20Sopenharmony_ci	 */
668c2ecf20Sopenharmony_ci	for_each_node_by_type(np, "interrupt-controller")
678c2ecf20Sopenharmony_ci		if (of_device_is_compatible(np, "gef,fpga-pic-1.00")) {
688c2ecf20Sopenharmony_ci			cascade_node = np;
698c2ecf20Sopenharmony_ci			break;
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (cascade_node == NULL) {
738c2ecf20Sopenharmony_ci		printk(KERN_WARNING "IMP3A: No FPGA PIC\n");
748c2ecf20Sopenharmony_ci		return;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	gef_pic_init(cascade_node);
788c2ecf20Sopenharmony_ci	of_node_put(cascade_node);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void ge_imp3a_pci_assign_primary(void)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
848c2ecf20Sopenharmony_ci	struct device_node *np;
858c2ecf20Sopenharmony_ci	struct resource rsrc;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	for_each_node_by_type(np, "pci") {
888c2ecf20Sopenharmony_ci		if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
898c2ecf20Sopenharmony_ci		    of_device_is_compatible(np, "fsl,mpc8548-pcie") ||
908c2ecf20Sopenharmony_ci		    of_device_is_compatible(np, "fsl,p2020-pcie")) {
918c2ecf20Sopenharmony_ci			of_address_to_resource(np, 0, &rsrc);
928c2ecf20Sopenharmony_ci			if ((rsrc.start & 0xfffff) == 0x9000)
938c2ecf20Sopenharmony_ci				fsl_pci_primary = np;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci#endif
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/*
1008c2ecf20Sopenharmony_ci * Setup the architecture
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_cistatic void __init ge_imp3a_setup_arch(void)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct device_node *regs;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (ppc_md.progress)
1078c2ecf20Sopenharmony_ci		ppc_md.progress("ge_imp3a_setup_arch()", 0);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	mpc85xx_smp_init();
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	ge_imp3a_pci_assign_primary();
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	swiotlb_detect_4g();
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* Remap basic board registers */
1168c2ecf20Sopenharmony_ci	regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs");
1178c2ecf20Sopenharmony_ci	if (regs) {
1188c2ecf20Sopenharmony_ci		imp3a_regs = of_iomap(regs, 0);
1198c2ecf20Sopenharmony_ci		if (imp3a_regs == NULL)
1208c2ecf20Sopenharmony_ci			printk(KERN_WARNING "Unable to map board registers\n");
1218c2ecf20Sopenharmony_ci		of_node_put(regs);
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci#if defined(CONFIG_MMIO_NVRAM)
1258c2ecf20Sopenharmony_ci	mmio_nvram_init();
1268c2ecf20Sopenharmony_ci#endif
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	printk(KERN_INFO "GE Intelligent Platforms IMP3A 3U cPCI SBC\n");
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/* Return the PCB revision */
1328c2ecf20Sopenharmony_cistatic unsigned int ge_imp3a_get_pcb_rev(void)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	unsigned int reg;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	reg = ioread16(imp3a_regs);
1378c2ecf20Sopenharmony_ci	return (reg >> 8) & 0xff;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/* Return the board (software) revision */
1418c2ecf20Sopenharmony_cistatic unsigned int ge_imp3a_get_board_rev(void)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	unsigned int reg;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	reg = ioread16(imp3a_regs + 0x2);
1468c2ecf20Sopenharmony_ci	return reg & 0xff;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/* Return the FPGA revision */
1508c2ecf20Sopenharmony_cistatic unsigned int ge_imp3a_get_fpga_rev(void)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	unsigned int reg;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	reg = ioread16(imp3a_regs + 0x2);
1558c2ecf20Sopenharmony_ci	return (reg >> 8) & 0xff;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/* Return compactPCI Geographical Address */
1598c2ecf20Sopenharmony_cistatic unsigned int ge_imp3a_get_cpci_geo_addr(void)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	unsigned int reg;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	reg = ioread16(imp3a_regs + 0x6);
1648c2ecf20Sopenharmony_ci	return (reg & 0x0f00) >> 8;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/* Return compactPCI System Controller Status */
1688c2ecf20Sopenharmony_cistatic unsigned int ge_imp3a_get_cpci_is_syscon(void)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	unsigned int reg;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	reg = ioread16(imp3a_regs + 0x6);
1738c2ecf20Sopenharmony_ci	return reg & (1 << 12);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void ge_imp3a_show_cpuinfo(struct seq_file *m)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n");
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	seq_printf(m, "Revision\t: %u%c\n", ge_imp3a_get_pcb_rev(),
1818c2ecf20Sopenharmony_ci		('A' + ge_imp3a_get_board_rev() - 1));
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	seq_printf(m, "FPGA Revision\t: %u\n", ge_imp3a_get_fpga_rev());
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	seq_printf(m, "cPCI geo. addr\t: %u\n", ge_imp3a_get_cpci_geo_addr());
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	seq_printf(m, "cPCI syscon\t: %s\n",
1888c2ecf20Sopenharmony_ci		ge_imp3a_get_cpci_is_syscon() ? "yes" : "no");
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci/*
1928c2ecf20Sopenharmony_ci * Called very early, device-tree isn't unflattened
1938c2ecf20Sopenharmony_ci */
1948c2ecf20Sopenharmony_cistatic int __init ge_imp3a_probe(void)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	return of_machine_is_compatible("ge,IMP3A");
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cimachine_arch_initcall(ge_imp3a, mpc85xx_common_publish_devices);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cidefine_machine(ge_imp3a) {
2028c2ecf20Sopenharmony_ci	.name			= "GE_IMP3A",
2038c2ecf20Sopenharmony_ci	.probe			= ge_imp3a_probe,
2048c2ecf20Sopenharmony_ci	.setup_arch		= ge_imp3a_setup_arch,
2058c2ecf20Sopenharmony_ci	.init_IRQ		= ge_imp3a_pic_init,
2068c2ecf20Sopenharmony_ci	.show_cpuinfo		= ge_imp3a_show_cpuinfo,
2078c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
2088c2ecf20Sopenharmony_ci	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
2098c2ecf20Sopenharmony_ci	.pcibios_fixup_phb      = fsl_pcibios_fixup_phb,
2108c2ecf20Sopenharmony_ci#endif
2118c2ecf20Sopenharmony_ci	.get_irq		= mpic_get_irq,
2128c2ecf20Sopenharmony_ci	.calibrate_decr		= generic_calibrate_decr,
2138c2ecf20Sopenharmony_ci	.progress		= udbg_progress,
2148c2ecf20Sopenharmony_ci};
215