162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Low-Level PCI Express Support for the SH7786
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2009 - 2011  Paul Mundt
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#define pr_fmt(fmt) "PCI: " fmt
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/pci.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/async.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/dma-map-ops.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/clk.h>
1862306a36Sopenharmony_ci#include <linux/sh_clk.h>
1962306a36Sopenharmony_ci#include <linux/sh_intc.h>
2062306a36Sopenharmony_ci#include <cpu/sh7786.h>
2162306a36Sopenharmony_ci#include "pcie-sh7786.h"
2262306a36Sopenharmony_ci#include <linux/sizes.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistruct sh7786_pcie_port {
2562306a36Sopenharmony_ci	struct pci_channel	*hose;
2662306a36Sopenharmony_ci	struct clk		*fclk, phy_clk;
2762306a36Sopenharmony_ci	unsigned int		index;
2862306a36Sopenharmony_ci	int			endpoint;
2962306a36Sopenharmony_ci	int			link;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic struct sh7786_pcie_port *sh7786_pcie_ports;
3362306a36Sopenharmony_cistatic unsigned int nr_ports;
3462306a36Sopenharmony_cisize_t memsize;
3562306a36Sopenharmony_ciu64 memstart;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic struct sh7786_pcie_hwops {
3862306a36Sopenharmony_ci	int (*core_init)(void);
3962306a36Sopenharmony_ci	async_func_t port_init_hw;
4062306a36Sopenharmony_ci} *sh7786_pcie_hwops;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic struct resource sh7786_pci0_resources[] = {
4362306a36Sopenharmony_ci	{
4462306a36Sopenharmony_ci		.name	= "PCIe0 MEM 0",
4562306a36Sopenharmony_ci		.start	= 0xfd000000,
4662306a36Sopenharmony_ci		.end	= 0xfd000000 + SZ_8M - 1,
4762306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
4862306a36Sopenharmony_ci	}, {
4962306a36Sopenharmony_ci		.name	= "PCIe0 MEM 1",
5062306a36Sopenharmony_ci		.start	= 0xc0000000,
5162306a36Sopenharmony_ci		.end	= 0xc0000000 + SZ_512M - 1,
5262306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
5362306a36Sopenharmony_ci	}, {
5462306a36Sopenharmony_ci		.name	= "PCIe0 MEM 2",
5562306a36Sopenharmony_ci		.start	= 0x10000000,
5662306a36Sopenharmony_ci		.end	= 0x10000000 + SZ_64M - 1,
5762306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
5862306a36Sopenharmony_ci	}, {
5962306a36Sopenharmony_ci		.name	= "PCIe0 IO",
6062306a36Sopenharmony_ci		.start	= 0xfe100000,
6162306a36Sopenharmony_ci		.end	= 0xfe100000 + SZ_1M - 1,
6262306a36Sopenharmony_ci		.flags	= IORESOURCE_IO,
6362306a36Sopenharmony_ci	},
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic struct resource sh7786_pci1_resources[] = {
6762306a36Sopenharmony_ci	{
6862306a36Sopenharmony_ci		.name	= "PCIe1 MEM 0",
6962306a36Sopenharmony_ci		.start	= 0xfd800000,
7062306a36Sopenharmony_ci		.end	= 0xfd800000 + SZ_8M - 1,
7162306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
7262306a36Sopenharmony_ci	}, {
7362306a36Sopenharmony_ci		.name	= "PCIe1 MEM 1",
7462306a36Sopenharmony_ci		.start	= 0xa0000000,
7562306a36Sopenharmony_ci		.end	= 0xa0000000 + SZ_512M - 1,
7662306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
7762306a36Sopenharmony_ci	}, {
7862306a36Sopenharmony_ci		.name	= "PCIe1 MEM 2",
7962306a36Sopenharmony_ci		.start	= 0x30000000,
8062306a36Sopenharmony_ci		.end	= 0x30000000 + SZ_256M - 1,
8162306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
8262306a36Sopenharmony_ci	}, {
8362306a36Sopenharmony_ci		.name	= "PCIe1 IO",
8462306a36Sopenharmony_ci		.start	= 0xfe300000,
8562306a36Sopenharmony_ci		.end	= 0xfe300000 + SZ_1M - 1,
8662306a36Sopenharmony_ci		.flags	= IORESOURCE_IO,
8762306a36Sopenharmony_ci	},
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic struct resource sh7786_pci2_resources[] = {
9162306a36Sopenharmony_ci	{
9262306a36Sopenharmony_ci		.name	= "PCIe2 MEM 0",
9362306a36Sopenharmony_ci		.start	= 0xfc800000,
9462306a36Sopenharmony_ci		.end	= 0xfc800000 + SZ_4M - 1,
9562306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
9662306a36Sopenharmony_ci	}, {
9762306a36Sopenharmony_ci		.name	= "PCIe2 MEM 1",
9862306a36Sopenharmony_ci		.start	= 0x80000000,
9962306a36Sopenharmony_ci		.end	= 0x80000000 + SZ_512M - 1,
10062306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
10162306a36Sopenharmony_ci	}, {
10262306a36Sopenharmony_ci		.name	= "PCIe2 MEM 2",
10362306a36Sopenharmony_ci		.start	= 0x20000000,
10462306a36Sopenharmony_ci		.end	= 0x20000000 + SZ_256M - 1,
10562306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
10662306a36Sopenharmony_ci	}, {
10762306a36Sopenharmony_ci		.name	= "PCIe2 IO",
10862306a36Sopenharmony_ci		.start	= 0xfcd00000,
10962306a36Sopenharmony_ci		.end	= 0xfcd00000 + SZ_1M - 1,
11062306a36Sopenharmony_ci		.flags	= IORESOURCE_IO,
11162306a36Sopenharmony_ci	},
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ciextern struct pci_ops sh7786_pci_ops;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#define DEFINE_CONTROLLER(start, idx)					\
11762306a36Sopenharmony_ci{									\
11862306a36Sopenharmony_ci	.pci_ops	= &sh7786_pci_ops,				\
11962306a36Sopenharmony_ci	.resources	= sh7786_pci##idx##_resources,			\
12062306a36Sopenharmony_ci	.nr_resources	= ARRAY_SIZE(sh7786_pci##idx##_resources),	\
12162306a36Sopenharmony_ci	.reg_base	= start,					\
12262306a36Sopenharmony_ci	.mem_offset	= 0,						\
12362306a36Sopenharmony_ci	.io_offset	= 0,						\
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic struct pci_channel sh7786_pci_channels[] = {
12762306a36Sopenharmony_ci	DEFINE_CONTROLLER(0xfe000000, 0),
12862306a36Sopenharmony_ci	DEFINE_CONTROLLER(0xfe200000, 1),
12962306a36Sopenharmony_ci	DEFINE_CONTROLLER(0xfcc00000, 2),
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic struct clk fixed_pciexclkp = {
13362306a36Sopenharmony_ci	.rate = 100000000,	/* 100 MHz reference clock */
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void sh7786_pci_fixup(struct pci_dev *dev)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	/*
13962306a36Sopenharmony_ci	 * Prevent enumeration of root complex resources.
14062306a36Sopenharmony_ci	 */
14162306a36Sopenharmony_ci	if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
14262306a36Sopenharmony_ci		struct resource *r;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		pci_dev_for_each_resource(dev, r) {
14562306a36Sopenharmony_ci			r->start	= 0;
14662306a36Sopenharmony_ci			r->end		= 0;
14762306a36Sopenharmony_ci			r->flags	= 0;
14862306a36Sopenharmony_ci		}
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
15262306a36Sopenharmony_ci			 sh7786_pci_fixup);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic int __init phy_wait_for_ack(struct pci_channel *chan)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	unsigned int timeout = 100;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	while (timeout--) {
15962306a36Sopenharmony_ci		if (pci_read_reg(chan, SH4A_PCIEPHYADRR) & (1 << BITS_ACK))
16062306a36Sopenharmony_ci			return 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		udelay(100);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return -ETIMEDOUT;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int __init pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	unsigned int timeout = 100;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	while (timeout--) {
17362306a36Sopenharmony_ci		if ((pci_read_reg(chan, SH4A_PCIEINTR) & mask) == mask)
17462306a36Sopenharmony_ci			return 0;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		udelay(100);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return -ETIMEDOUT;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic void __init phy_write_reg(struct pci_channel *chan, unsigned int addr,
18362306a36Sopenharmony_ci				 unsigned int lane, unsigned int data)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	unsigned long phyaddr;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) +
18862306a36Sopenharmony_ci			((addr & 0xff) << BITS_ADR);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* Set write data */
19162306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR);
19262306a36Sopenharmony_ci	pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	phy_wait_for_ack(chan);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* Clear command */
19762306a36Sopenharmony_ci	pci_write_reg(chan, 0, SH4A_PCIEPHYDOUTR);
19862306a36Sopenharmony_ci	pci_write_reg(chan, 0, SH4A_PCIEPHYADRR);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	phy_wait_for_ack(chan);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int __init pcie_clk_init(struct sh7786_pcie_port *port)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct pci_channel *chan = port->hose;
20662306a36Sopenharmony_ci	struct clk *clk;
20762306a36Sopenharmony_ci	char fclk_name[16];
20862306a36Sopenharmony_ci	int ret;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/*
21162306a36Sopenharmony_ci	 * First register the fixed clock
21262306a36Sopenharmony_ci	 */
21362306a36Sopenharmony_ci	ret = clk_register(&fixed_pciexclkp);
21462306a36Sopenharmony_ci	if (unlikely(ret != 0))
21562306a36Sopenharmony_ci		return ret;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/*
21862306a36Sopenharmony_ci	 * Grab the port's function clock, which the PHY clock depends
21962306a36Sopenharmony_ci	 * on. clock lookups don't help us much at this point, since no
22062306a36Sopenharmony_ci	 * dev_id is available this early. Lame.
22162306a36Sopenharmony_ci	 */
22262306a36Sopenharmony_ci	snprintf(fclk_name, sizeof(fclk_name), "pcie%d_fck", port->index);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	port->fclk = clk_get(NULL, fclk_name);
22562306a36Sopenharmony_ci	if (IS_ERR(port->fclk)) {
22662306a36Sopenharmony_ci		ret = PTR_ERR(port->fclk);
22762306a36Sopenharmony_ci		goto err_fclk;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	clk_enable(port->fclk);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/*
23362306a36Sopenharmony_ci	 * And now, set up the PHY clock
23462306a36Sopenharmony_ci	 */
23562306a36Sopenharmony_ci	clk = &port->phy_clk;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	memset(clk, 0, sizeof(struct clk));
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	clk->parent = &fixed_pciexclkp;
24062306a36Sopenharmony_ci	clk->enable_reg = (void __iomem *)(chan->reg_base + SH4A_PCIEPHYCTLR);
24162306a36Sopenharmony_ci	clk->enable_bit = BITS_CKE;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	ret = sh_clk_mstp_register(clk, 1);
24462306a36Sopenharmony_ci	if (unlikely(ret < 0))
24562306a36Sopenharmony_ci		goto err_phy;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cierr_phy:
25062306a36Sopenharmony_ci	clk_disable(port->fclk);
25162306a36Sopenharmony_ci	clk_put(port->fclk);
25262306a36Sopenharmony_cierr_fclk:
25362306a36Sopenharmony_ci	clk_unregister(&fixed_pciexclkp);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return ret;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic int __init phy_init(struct sh7786_pcie_port *port)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct pci_channel *chan = port->hose;
26162306a36Sopenharmony_ci	unsigned int timeout = 100;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	clk_enable(&port->phy_clk);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* Initialize the phy */
26662306a36Sopenharmony_ci	phy_write_reg(chan, 0x60, 0xf, 0x004b008b);
26762306a36Sopenharmony_ci	phy_write_reg(chan, 0x61, 0xf, 0x00007b41);
26862306a36Sopenharmony_ci	phy_write_reg(chan, 0x64, 0xf, 0x00ff4f00);
26962306a36Sopenharmony_ci	phy_write_reg(chan, 0x65, 0xf, 0x09070907);
27062306a36Sopenharmony_ci	phy_write_reg(chan, 0x66, 0xf, 0x00000010);
27162306a36Sopenharmony_ci	phy_write_reg(chan, 0x74, 0xf, 0x0007001c);
27262306a36Sopenharmony_ci	phy_write_reg(chan, 0x79, 0xf, 0x01fc000d);
27362306a36Sopenharmony_ci	phy_write_reg(chan, 0xb0, 0xf, 0x00000610);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Deassert Standby */
27662306a36Sopenharmony_ci	phy_write_reg(chan, 0x67, 0x1, 0x00000400);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* Disable clock */
27962306a36Sopenharmony_ci	clk_disable(&port->phy_clk);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	while (timeout--) {
28262306a36Sopenharmony_ci		if (pci_read_reg(chan, SH4A_PCIEPHYSR))
28362306a36Sopenharmony_ci			return 0;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		udelay(100);
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return -ETIMEDOUT;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic void __init pcie_reset(struct sh7786_pcie_port *port)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct pci_channel *chan = port->hose;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	pci_write_reg(chan, 1, SH4A_PCIESRSTR);
29662306a36Sopenharmony_ci	pci_write_reg(chan, 0, SH4A_PCIETCTLR);
29762306a36Sopenharmony_ci	pci_write_reg(chan, 0, SH4A_PCIESRSTR);
29862306a36Sopenharmony_ci	pci_write_reg(chan, 0, SH4A_PCIETXVC0SR);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic int __init pcie_init(struct sh7786_pcie_port *port)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct pci_channel *chan = port->hose;
30462306a36Sopenharmony_ci	unsigned int data;
30562306a36Sopenharmony_ci	phys_addr_t memstart, memend;
30662306a36Sopenharmony_ci	int ret, i, win;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* Begin initialization */
30962306a36Sopenharmony_ci	pcie_reset(port);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/*
31262306a36Sopenharmony_ci	 * Initial header for port config space is type 1, set the device
31362306a36Sopenharmony_ci	 * class to match. Hardware takes care of propagating the IDSETR
31462306a36Sopenharmony_ci	 * settings, so there is no need to bother with a quirk.
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI_NORMAL << 8, SH4A_PCIEIDSETR1);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* Initialize default capabilities. */
31962306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);
32062306a36Sopenharmony_ci	data &= ~(PCI_EXP_FLAGS_TYPE << 16);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if (port->endpoint)
32362306a36Sopenharmony_ci		data |= PCI_EXP_TYPE_ENDPOINT << 20;
32462306a36Sopenharmony_ci	else
32562306a36Sopenharmony_ci		data |= PCI_EXP_TYPE_ROOT_PORT << 20;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	data |= PCI_CAP_ID_EXP;
32862306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEEXPCAP0);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Enable data link layer active state reporting */
33162306a36Sopenharmony_ci	pci_write_reg(chan, PCI_EXP_LNKCAP_DLLLARC, SH4A_PCIEEXPCAP3);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Enable extended sync and ASPM L0s support */
33462306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIEEXPCAP4);
33562306a36Sopenharmony_ci	data &= ~PCI_EXP_LNKCTL_ASPMC;
33662306a36Sopenharmony_ci	data |= PCI_EXP_LNKCTL_ES | 1;
33762306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEEXPCAP4);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* Write out the physical slot number */
34062306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIEEXPCAP5);
34162306a36Sopenharmony_ci	data &= ~PCI_EXP_SLTCAP_PSN;
34262306a36Sopenharmony_ci	data |= (port->index + 1) << 19;
34362306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEEXPCAP5);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Set the completion timer timeout to the maximum 32ms. */
34662306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIETLCTLR);
34762306a36Sopenharmony_ci	data &= ~0x3f00;
34862306a36Sopenharmony_ci	data |= 0x32 << 8;
34962306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIETLCTLR);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/*
35262306a36Sopenharmony_ci	 * Set fast training sequences to the maximum 255,
35362306a36Sopenharmony_ci	 * and enable MAC data scrambling.
35462306a36Sopenharmony_ci	 */
35562306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIEMACCTLR);
35662306a36Sopenharmony_ci	data &= ~PCIEMACCTLR_SCR_DIS;
35762306a36Sopenharmony_ci	data |= (0xff << 16);
35862306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	memstart = __pa(memory_start);
36162306a36Sopenharmony_ci	memend   = __pa(memory_end);
36262306a36Sopenharmony_ci	memsize = roundup_pow_of_two(memend - memstart);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/*
36562306a36Sopenharmony_ci	 * The start address must be aligned on its size. So we round
36662306a36Sopenharmony_ci	 * it down, and then recalculate the size so that it covers
36762306a36Sopenharmony_ci	 * the entire memory.
36862306a36Sopenharmony_ci	 */
36962306a36Sopenharmony_ci	memstart = ALIGN_DOWN(memstart, memsize);
37062306a36Sopenharmony_ci	memsize = roundup_pow_of_two(memend - memstart);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/*
37362306a36Sopenharmony_ci	 * If there's more than 512MB of memory, we need to roll over to
37462306a36Sopenharmony_ci	 * LAR1/LAMR1.
37562306a36Sopenharmony_ci	 */
37662306a36Sopenharmony_ci	if (memsize > SZ_512M) {
37762306a36Sopenharmony_ci		pci_write_reg(chan, memstart + SZ_512M, SH4A_PCIELAR1);
37862306a36Sopenharmony_ci		pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
37962306a36Sopenharmony_ci			      SH4A_PCIELAMR1);
38062306a36Sopenharmony_ci		memsize = SZ_512M;
38162306a36Sopenharmony_ci	} else {
38262306a36Sopenharmony_ci		/*
38362306a36Sopenharmony_ci		 * Otherwise just zero it out and disable it.
38462306a36Sopenharmony_ci		 */
38562306a36Sopenharmony_ci		pci_write_reg(chan, 0, SH4A_PCIELAR1);
38662306a36Sopenharmony_ci		pci_write_reg(chan, 0, SH4A_PCIELAMR1);
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/*
39062306a36Sopenharmony_ci	 * LAR0/LAMR0 covers up to the first 512MB, which is enough to
39162306a36Sopenharmony_ci	 * cover all of lowmem on most platforms.
39262306a36Sopenharmony_ci	 */
39362306a36Sopenharmony_ci	pci_write_reg(chan, memstart, SH4A_PCIELAR0);
39462306a36Sopenharmony_ci	pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Finish initialization */
39762306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIETCTLR);
39862306a36Sopenharmony_ci	data |= 0x1;
39962306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIETCTLR);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* Let things settle down a bit.. */
40262306a36Sopenharmony_ci	mdelay(100);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* Enable DL_Active Interrupt generation */
40562306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIEDLINTENR);
40662306a36Sopenharmony_ci	data |= PCIEDLINTENR_DLL_ACT_ENABLE;
40762306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEDLINTENR);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* Disable MAC data scrambling. */
41062306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIEMACCTLR);
41162306a36Sopenharmony_ci	data |= PCIEMACCTLR_SCR_DIS | (0xff << 16);
41262306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/*
41562306a36Sopenharmony_ci	 * This will timeout if we don't have a link, but we permit the
41662306a36Sopenharmony_ci	 * port to register anyways in order to support hotplug on future
41762306a36Sopenharmony_ci	 * hardware.
41862306a36Sopenharmony_ci	 */
41962306a36Sopenharmony_ci	ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	data = pci_read_reg(chan, SH4A_PCIEPCICONF1);
42262306a36Sopenharmony_ci	data &= ~(PCI_STATUS_DEVSEL_MASK << 16);
42362306a36Sopenharmony_ci	data |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
42462306a36Sopenharmony_ci		(PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST) << 16;
42562306a36Sopenharmony_ci	pci_write_reg(chan, data, SH4A_PCIEPCICONF1);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	pci_write_reg(chan, 0x80888000, SH4A_PCIETXVC0DCTLR);
42862306a36Sopenharmony_ci	pci_write_reg(chan, 0x00222000, SH4A_PCIERXVC0DCTLR);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	wmb();
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (ret == 0) {
43362306a36Sopenharmony_ci		data = pci_read_reg(chan, SH4A_PCIEMACSR);
43462306a36Sopenharmony_ci		printk(KERN_NOTICE "PCI: PCIe#%d x%d link detected\n",
43562306a36Sopenharmony_ci		       port->index, (data >> 20) & 0x3f);
43662306a36Sopenharmony_ci	} else
43762306a36Sopenharmony_ci		printk(KERN_NOTICE "PCI: PCIe#%d link down\n",
43862306a36Sopenharmony_ci		       port->index);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	for (i = win = 0; i < chan->nr_resources; i++) {
44162306a36Sopenharmony_ci		struct resource *res = chan->resources + i;
44262306a36Sopenharmony_ci		resource_size_t size;
44362306a36Sopenharmony_ci		u32 mask;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		/*
44662306a36Sopenharmony_ci		 * We can't use the 32-bit mode windows in legacy 29-bit
44762306a36Sopenharmony_ci		 * mode, so just skip them entirely.
44862306a36Sopenharmony_ci		 */
44962306a36Sopenharmony_ci		if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
45062306a36Sopenharmony_ci			res->flags |= IORESOURCE_DISABLED;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		if (res->flags & IORESOURCE_DISABLED)
45362306a36Sopenharmony_ci			continue;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		/*
45862306a36Sopenharmony_ci		 * The PAMR mask is calculated in units of 256kB, which
45962306a36Sopenharmony_ci		 * keeps things pretty simple.
46062306a36Sopenharmony_ci		 */
46162306a36Sopenharmony_ci		size = resource_size(res);
46262306a36Sopenharmony_ci		mask = (roundup_pow_of_two(size) / SZ_256K) - 1;
46362306a36Sopenharmony_ci		pci_write_reg(chan, mask << 18, SH4A_PCIEPAMR(win));
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		pci_write_reg(chan, upper_32_bits(res->start),
46662306a36Sopenharmony_ci			      SH4A_PCIEPARH(win));
46762306a36Sopenharmony_ci		pci_write_reg(chan, lower_32_bits(res->start),
46862306a36Sopenharmony_ci			      SH4A_PCIEPARL(win));
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		mask = MASK_PARE;
47162306a36Sopenharmony_ci		if (res->flags & IORESOURCE_IO)
47262306a36Sopenharmony_ci			mask |= MASK_SPC;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		pci_write_reg(chan, mask, SH4A_PCIEPTCTLR(win));
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		win++;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return 0;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ciint pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci        return evt2irq(0xae0);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_civoid pcibios_bus_add_device(struct pci_dev *pdev)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	dma_direct_set_offset(&pdev->dev, __pa(memory_start),
49062306a36Sopenharmony_ci			      __pa(memory_start) - memstart, memsize);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int __init sh7786_pcie_core_init(void)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	/* Return the number of ports */
49662306a36Sopenharmony_ci	return test_mode_pin(MODE_PIN12) ? 3 : 2;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic void __init sh7786_pcie_init_hw(void *data, async_cookie_t cookie)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct sh7786_pcie_port *port = data;
50262306a36Sopenharmony_ci	int ret;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/*
50562306a36Sopenharmony_ci	 * Check if we are configured in endpoint or root complex mode,
50662306a36Sopenharmony_ci	 * this is a fixed pin setting that applies to all PCIe ports.
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	port->endpoint = test_mode_pin(MODE_PIN11);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/*
51162306a36Sopenharmony_ci	 * Setup clocks, needed both for PHY and PCIe registers.
51262306a36Sopenharmony_ci	 */
51362306a36Sopenharmony_ci	ret = pcie_clk_init(port);
51462306a36Sopenharmony_ci	if (unlikely(ret < 0)) {
51562306a36Sopenharmony_ci		pr_err("clock initialization failed for port#%d\n",
51662306a36Sopenharmony_ci		       port->index);
51762306a36Sopenharmony_ci		return;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	ret = phy_init(port);
52162306a36Sopenharmony_ci	if (unlikely(ret < 0)) {
52262306a36Sopenharmony_ci		pr_err("phy initialization failed for port#%d\n",
52362306a36Sopenharmony_ci		       port->index);
52462306a36Sopenharmony_ci		return;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	ret = pcie_init(port);
52862306a36Sopenharmony_ci	if (unlikely(ret < 0)) {
52962306a36Sopenharmony_ci		pr_err("core initialization failed for port#%d\n",
53062306a36Sopenharmony_ci			       port->index);
53162306a36Sopenharmony_ci		return;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	/* In the interest of preserving device ordering, synchronize */
53562306a36Sopenharmony_ci	async_synchronize_cookie(cookie);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	register_pci_controller(port->hose);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
54162306a36Sopenharmony_ci	.core_init	= sh7786_pcie_core_init,
54262306a36Sopenharmony_ci	.port_init_hw	= sh7786_pcie_init_hw,
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic int __init sh7786_pcie_init(void)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct clk *platclk;
54862306a36Sopenharmony_ci	u32 mm_sel;
54962306a36Sopenharmony_ci	int i;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	printk(KERN_NOTICE "PCI: Starting initialization.\n");
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	nr_ports = sh7786_pcie_hwops->core_init();
55662306a36Sopenharmony_ci	BUG_ON(nr_ports > ARRAY_SIZE(sh7786_pci_channels));
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (unlikely(nr_ports == 0))
55962306a36Sopenharmony_ci		return -ENODEV;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	sh7786_pcie_ports = kcalloc(nr_ports, sizeof(struct sh7786_pcie_port),
56262306a36Sopenharmony_ci				    GFP_KERNEL);
56362306a36Sopenharmony_ci	if (unlikely(!sh7786_pcie_ports))
56462306a36Sopenharmony_ci		return -ENOMEM;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/*
56762306a36Sopenharmony_ci	 * Fetch any optional platform clock associated with this block.
56862306a36Sopenharmony_ci	 *
56962306a36Sopenharmony_ci	 * This is a rather nasty hack for boards with spec-mocking FPGAs
57062306a36Sopenharmony_ci	 * that have a secondary set of clocks outside of the on-chip
57162306a36Sopenharmony_ci	 * ones that need to be accounted for before there is any chance
57262306a36Sopenharmony_ci	 * of touching the existing MSTP bits or CPG clocks.
57362306a36Sopenharmony_ci	 */
57462306a36Sopenharmony_ci	platclk = clk_get(NULL, "pcie_plat_clk");
57562306a36Sopenharmony_ci	if (IS_ERR(platclk)) {
57662306a36Sopenharmony_ci		/* Sane hardware should probably get a WARN_ON.. */
57762306a36Sopenharmony_ci		platclk = NULL;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	clk_enable(platclk);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	mm_sel = sh7786_mm_sel();
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/*
58562306a36Sopenharmony_ci	 * Depending on the MMSELR register value, the PCIe0 MEM 1
58662306a36Sopenharmony_ci	 * area may not be available. See Table 13.11 of the SH7786
58762306a36Sopenharmony_ci	 * datasheet.
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	if (mm_sel != 1 && mm_sel != 2 && mm_sel != 5 && mm_sel != 6)
59062306a36Sopenharmony_ci		sh7786_pci0_resources[2].flags |= IORESOURCE_DISABLED;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	for (i = 0; i < nr_ports; i++) {
59562306a36Sopenharmony_ci		struct sh7786_pcie_port *port = sh7786_pcie_ports + i;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		port->index		= i;
59862306a36Sopenharmony_ci		port->hose		= sh7786_pci_channels + i;
59962306a36Sopenharmony_ci		port->hose->io_map_base	= port->hose->resources[0].start;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		async_schedule(sh7786_pcie_hwops->port_init_hw, port);
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	async_synchronize_full();
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return 0;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ciarch_initcall(sh7786_pcie_init);
609