162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Embedded Planet EP8248E support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2007 Freescale Semiconductor, Inc.
662306a36Sopenharmony_ci * Author: Scott Wood <scottwood@freescale.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/fsl_devices.h>
1262306a36Sopenharmony_ci#include <linux/mdio-bitbang.h>
1362306a36Sopenharmony_ci#include <linux/of_mdio.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/of_platform.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/io.h>
1962306a36Sopenharmony_ci#include <asm/cpm2.h>
2062306a36Sopenharmony_ci#include <asm/udbg.h>
2162306a36Sopenharmony_ci#include <asm/machdep.h>
2262306a36Sopenharmony_ci#include <asm/time.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <sysdev/fsl_soc.h>
2562306a36Sopenharmony_ci#include <sysdev/cpm2_pic.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "pq2.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic u8 __iomem *ep8248e_bcsr;
3062306a36Sopenharmony_cistatic struct device_node *ep8248e_bcsr_node;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define BCSR7_SCC2_ENABLE 0x10
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define BCSR8_PHY1_ENABLE 0x80
3562306a36Sopenharmony_ci#define BCSR8_PHY1_POWER  0x40
3662306a36Sopenharmony_ci#define BCSR8_PHY2_ENABLE 0x20
3762306a36Sopenharmony_ci#define BCSR8_PHY2_POWER  0x10
3862306a36Sopenharmony_ci#define BCSR8_MDIO_READ   0x04
3962306a36Sopenharmony_ci#define BCSR8_MDIO_CLOCK  0x02
4062306a36Sopenharmony_ci#define BCSR8_MDIO_DATA   0x01
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define BCSR9_USB_ENABLE  0x80
4362306a36Sopenharmony_ci#define BCSR9_USB_POWER   0x40
4462306a36Sopenharmony_ci#define BCSR9_USB_HOST    0x20
4562306a36Sopenharmony_ci#define BCSR9_USB_FULL_SPEED_TARGET 0x10
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic void __init ep8248e_pic_init(void)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic");
5062306a36Sopenharmony_ci	if (!np) {
5162306a36Sopenharmony_ci		printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
5262306a36Sopenharmony_ci		return;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	cpm2_pic_init(np);
5662306a36Sopenharmony_ci	of_node_put(np);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void ep8248e_set_mdc(struct mdiobb_ctrl *ctrl, int level)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	if (level)
6262306a36Sopenharmony_ci		setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK);
6362306a36Sopenharmony_ci	else
6462306a36Sopenharmony_ci		clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Read back to flush the write. */
6762306a36Sopenharmony_ci	in_8(&ep8248e_bcsr[8]);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void ep8248e_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	if (output)
7362306a36Sopenharmony_ci		clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ);
7462306a36Sopenharmony_ci	else
7562306a36Sopenharmony_ci		setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* Read back to flush the write. */
7862306a36Sopenharmony_ci	in_8(&ep8248e_bcsr[8]);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void ep8248e_set_mdio_data(struct mdiobb_ctrl *ctrl, int data)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	if (data)
8462306a36Sopenharmony_ci		setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA);
8562306a36Sopenharmony_ci	else
8662306a36Sopenharmony_ci		clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* Read back to flush the write. */
8962306a36Sopenharmony_ci	in_8(&ep8248e_bcsr[8]);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int ep8248e_get_mdio_data(struct mdiobb_ctrl *ctrl)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	return in_8(&ep8248e_bcsr[8]) & BCSR8_MDIO_DATA;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic const struct mdiobb_ops ep8248e_mdio_ops = {
9862306a36Sopenharmony_ci	.set_mdc = ep8248e_set_mdc,
9962306a36Sopenharmony_ci	.set_mdio_dir = ep8248e_set_mdio_dir,
10062306a36Sopenharmony_ci	.set_mdio_data = ep8248e_set_mdio_data,
10162306a36Sopenharmony_ci	.get_mdio_data = ep8248e_get_mdio_data,
10262306a36Sopenharmony_ci	.owner = THIS_MODULE,
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic struct mdiobb_ctrl ep8248e_mdio_ctrl = {
10662306a36Sopenharmony_ci	.ops = &ep8248e_mdio_ops,
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic int ep8248e_mdio_probe(struct platform_device *ofdev)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct mii_bus *bus;
11262306a36Sopenharmony_ci	struct resource res;
11362306a36Sopenharmony_ci	struct device_node *node;
11462306a36Sopenharmony_ci	int ret;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	node = of_get_parent(ofdev->dev.of_node);
11762306a36Sopenharmony_ci	of_node_put(node);
11862306a36Sopenharmony_ci	if (node != ep8248e_bcsr_node)
11962306a36Sopenharmony_ci		return -ENODEV;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
12262306a36Sopenharmony_ci	if (ret)
12362306a36Sopenharmony_ci		return ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	bus = alloc_mdio_bitbang(&ep8248e_mdio_ctrl);
12662306a36Sopenharmony_ci	if (!bus)
12762306a36Sopenharmony_ci		return -ENOMEM;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	bus->name = "ep8248e-mdio-bitbang";
13062306a36Sopenharmony_ci	bus->parent = &ofdev->dev;
13162306a36Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	ret = of_mdiobus_register(bus, ofdev->dev.of_node);
13462306a36Sopenharmony_ci	if (ret)
13562306a36Sopenharmony_ci		goto err_free_bus;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return 0;
13862306a36Sopenharmony_cierr_free_bus:
13962306a36Sopenharmony_ci	free_mdio_bitbang(bus);
14062306a36Sopenharmony_ci	return ret;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic const struct of_device_id ep8248e_mdio_match[] = {
14462306a36Sopenharmony_ci	{
14562306a36Sopenharmony_ci		.compatible = "fsl,ep8248e-mdio-bitbang",
14662306a36Sopenharmony_ci	},
14762306a36Sopenharmony_ci	{},
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic struct platform_driver ep8248e_mdio_driver = {
15162306a36Sopenharmony_ci	.driver = {
15262306a36Sopenharmony_ci		.name = "ep8248e-mdio-bitbang",
15362306a36Sopenharmony_ci		.of_match_table = ep8248e_mdio_match,
15462306a36Sopenharmony_ci		.suppress_bind_attrs = true,
15562306a36Sopenharmony_ci	},
15662306a36Sopenharmony_ci	.probe = ep8248e_mdio_probe,
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistruct cpm_pin {
16062306a36Sopenharmony_ci	int port, pin, flags;
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic __initdata struct cpm_pin ep8248e_pins[] = {
16462306a36Sopenharmony_ci	/* SMC1 */
16562306a36Sopenharmony_ci	{2, 4, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
16662306a36Sopenharmony_ci	{2, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* SCC1 */
16962306a36Sopenharmony_ci	{2, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
17062306a36Sopenharmony_ci	{2, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
17162306a36Sopenharmony_ci	{3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
17262306a36Sopenharmony_ci	{3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
17362306a36Sopenharmony_ci	{3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* FCC1 */
17662306a36Sopenharmony_ci	{0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
17762306a36Sopenharmony_ci	{0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
17862306a36Sopenharmony_ci	{0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
17962306a36Sopenharmony_ci	{0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
18062306a36Sopenharmony_ci	{0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
18162306a36Sopenharmony_ci	{0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
18262306a36Sopenharmony_ci	{0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
18362306a36Sopenharmony_ci	{0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
18462306a36Sopenharmony_ci	{0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
18562306a36Sopenharmony_ci	{0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
18662306a36Sopenharmony_ci	{0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
18762306a36Sopenharmony_ci	{0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
18862306a36Sopenharmony_ci	{0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
18962306a36Sopenharmony_ci	{0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
19062306a36Sopenharmony_ci	{2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
19162306a36Sopenharmony_ci	{2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* FCC2 */
19462306a36Sopenharmony_ci	{1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
19562306a36Sopenharmony_ci	{1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
19662306a36Sopenharmony_ci	{1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
19762306a36Sopenharmony_ci	{1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
19862306a36Sopenharmony_ci	{1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
19962306a36Sopenharmony_ci	{1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
20062306a36Sopenharmony_ci	{1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
20162306a36Sopenharmony_ci	{1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
20262306a36Sopenharmony_ci	{1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
20362306a36Sopenharmony_ci	{1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
20462306a36Sopenharmony_ci	{1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
20562306a36Sopenharmony_ci	{1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
20662306a36Sopenharmony_ci	{1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
20762306a36Sopenharmony_ci	{1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
20862306a36Sopenharmony_ci	{2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
20962306a36Sopenharmony_ci	{2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* I2C */
21262306a36Sopenharmony_ci	{4, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
21362306a36Sopenharmony_ci	{4, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* USB */
21662306a36Sopenharmony_ci	{2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
21762306a36Sopenharmony_ci	{2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
21862306a36Sopenharmony_ci	{2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
21962306a36Sopenharmony_ci	{2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
22062306a36Sopenharmony_ci	{3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
22162306a36Sopenharmony_ci	{3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
22262306a36Sopenharmony_ci	{3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void __init init_ioports(void)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	int i;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ep8248e_pins); i++) {
23062306a36Sopenharmony_ci		const struct cpm_pin *pin = &ep8248e_pins[i];
23162306a36Sopenharmony_ci		cpm2_set_pin(pin->port, pin->pin, pin->flags);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	cpm2_smc_clk_setup(CPM_CLK_SMC1, CPM_BRG7);
23562306a36Sopenharmony_ci	cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX);
23662306a36Sopenharmony_ci	cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX);
23762306a36Sopenharmony_ci	cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX); /* USB */
23862306a36Sopenharmony_ci	cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX);
23962306a36Sopenharmony_ci	cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX);
24062306a36Sopenharmony_ci	cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX);
24162306a36Sopenharmony_ci	cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic void __init ep8248e_setup_arch(void)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	if (ppc_md.progress)
24762306a36Sopenharmony_ci		ppc_md.progress("ep8248e_setup_arch()", 0);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	cpm2_reset();
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* When this is set, snooping CPM DMA from RAM causes
25262306a36Sopenharmony_ci	 * machine checks.  See erratum SIU18.
25362306a36Sopenharmony_ci	 */
25462306a36Sopenharmony_ci	clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_bcr, MPC82XX_BCR_PLDP);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	ep8248e_bcsr_node =
25762306a36Sopenharmony_ci		of_find_compatible_node(NULL, NULL, "fsl,ep8248e-bcsr");
25862306a36Sopenharmony_ci	if (!ep8248e_bcsr_node) {
25962306a36Sopenharmony_ci		printk(KERN_ERR "No bcsr in device tree\n");
26062306a36Sopenharmony_ci		return;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	ep8248e_bcsr = of_iomap(ep8248e_bcsr_node, 0);
26462306a36Sopenharmony_ci	if (!ep8248e_bcsr) {
26562306a36Sopenharmony_ci		printk(KERN_ERR "Cannot map BCSR registers\n");
26662306a36Sopenharmony_ci		of_node_put(ep8248e_bcsr_node);
26762306a36Sopenharmony_ci		ep8248e_bcsr_node = NULL;
26862306a36Sopenharmony_ci		return;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	setbits8(&ep8248e_bcsr[7], BCSR7_SCC2_ENABLE);
27262306a36Sopenharmony_ci	setbits8(&ep8248e_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER |
27362306a36Sopenharmony_ci	                           BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	init_ioports();
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (ppc_md.progress)
27862306a36Sopenharmony_ci		ppc_md.progress("ep8248e_setup_arch(), finish", 0);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic const struct of_device_id of_bus_ids[] __initconst = {
28262306a36Sopenharmony_ci	{ .compatible = "simple-bus", },
28362306a36Sopenharmony_ci	{ .compatible = "fsl,ep8248e-bcsr", },
28462306a36Sopenharmony_ci	{},
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic int __init declare_of_platform_devices(void)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	of_platform_bus_probe(NULL, of_bus_ids, NULL);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_MDIO_BITBANG))
29262306a36Sopenharmony_ci		platform_driver_register(&ep8248e_mdio_driver);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return 0;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_cimachine_device_initcall(ep8248e, declare_of_platform_devices);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cidefine_machine(ep8248e)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	.name = "Embedded Planet EP8248E",
30162306a36Sopenharmony_ci	.compatible = "fsl,ep8248e",
30262306a36Sopenharmony_ci	.setup_arch = ep8248e_setup_arch,
30362306a36Sopenharmony_ci	.init_IRQ = ep8248e_pic_init,
30462306a36Sopenharmony_ci	.get_irq = cpm2_get_irq,
30562306a36Sopenharmony_ci	.restart = pq2_restart,
30662306a36Sopenharmony_ci	.progress = udbg_progress,
30762306a36Sopenharmony_ci};
308