18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCIe driver for Renesas R-Car SoCs
48c2ecf20Sopenharmony_ci *  Copyright (C) 2014-2020 Renesas Electronics Europe Ltd
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Author: Phil Edworthy <phil.edworthy@renesas.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/pci.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "pcie-rcar.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_civoid rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, unsigned int reg)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	writel(val, pcie->base + reg);
178c2ecf20Sopenharmony_ci}
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciu32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	return readl(pcie->base + reg);
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_civoid rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	unsigned int shift = BITS_PER_BYTE * (where & 3);
278c2ecf20Sopenharmony_ci	u32 val = rcar_pci_read_reg(pcie, where & ~3);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	val &= ~(mask << shift);
308c2ecf20Sopenharmony_ci	val |= data << shift;
318c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, val, where & ~3);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciint rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	unsigned int timeout = 10;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	while (timeout--) {
398c2ecf20Sopenharmony_ci		if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY)
408c2ecf20Sopenharmony_ci			return 0;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci		msleep(5);
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciint rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	unsigned int timeout = 10000;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	while (timeout--) {
538c2ecf20Sopenharmony_ci		if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
548c2ecf20Sopenharmony_ci			return 0;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		udelay(5);
578c2ecf20Sopenharmony_ci		cpu_relax();
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_civoid rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win,
648c2ecf20Sopenharmony_ci			    struct resource_entry *window)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	/* Setup PCIe address space mappings for each resource */
678c2ecf20Sopenharmony_ci	struct resource *res = window->res;
688c2ecf20Sopenharmony_ci	resource_size_t res_start;
698c2ecf20Sopenharmony_ci	resource_size_t size;
708c2ecf20Sopenharmony_ci	u32 mask;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win));
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/*
758c2ecf20Sopenharmony_ci	 * The PAMR mask is calculated in units of 128Bytes, which
768c2ecf20Sopenharmony_ci	 * keeps things pretty simple.
778c2ecf20Sopenharmony_ci	 */
788c2ecf20Sopenharmony_ci	size = resource_size(res);
798c2ecf20Sopenharmony_ci	if (size > 128)
808c2ecf20Sopenharmony_ci		mask = (roundup_pow_of_two(size) / SZ_128) - 1;
818c2ecf20Sopenharmony_ci	else
828c2ecf20Sopenharmony_ci		mask = 0x0;
838c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win));
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO)
868c2ecf20Sopenharmony_ci		res_start = pci_pio_to_address(res->start) - window->offset;
878c2ecf20Sopenharmony_ci	else
888c2ecf20Sopenharmony_ci		res_start = res->start - window->offset;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPAUR(win));
918c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, lower_32_bits(res_start) & ~0x7F,
928c2ecf20Sopenharmony_ci			   PCIEPALR(win));
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* First resource is for IO */
958c2ecf20Sopenharmony_ci	mask = PAR_ENABLE;
968c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO)
978c2ecf20Sopenharmony_ci		mask |= IO_SPACE;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win));
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_civoid rcar_pcie_set_inbound(struct rcar_pcie *pcie, u64 cpu_addr,
1038c2ecf20Sopenharmony_ci			   u64 pci_addr, u64 flags, int idx, bool host)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	/*
1068c2ecf20Sopenharmony_ci	 * Set up 64-bit inbound regions as the range parser doesn't
1078c2ecf20Sopenharmony_ci	 * distinguish between 32 and 64-bit types.
1088c2ecf20Sopenharmony_ci	 */
1098c2ecf20Sopenharmony_ci	if (host)
1108c2ecf20Sopenharmony_ci		rcar_pci_write_reg(pcie, lower_32_bits(pci_addr),
1118c2ecf20Sopenharmony_ci				   PCIEPRAR(idx));
1128c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx));
1138c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, flags, PCIELAMR(idx));
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (host)
1168c2ecf20Sopenharmony_ci		rcar_pci_write_reg(pcie, upper_32_bits(pci_addr),
1178c2ecf20Sopenharmony_ci				   PCIEPRAR(idx + 1));
1188c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx + 1));
1198c2ecf20Sopenharmony_ci	rcar_pci_write_reg(pcie, 0, PCIELAMR(idx + 1));
1208c2ecf20Sopenharmony_ci}
121