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