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