1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * PCIe driver for Renesas R-Car SoCs |
4 | * Copyright (C) 2014-2020 Renesas Electronics Europe Ltd |
5 | * |
6 | * Author: Phil Edworthy <phil.edworthy@renesas.com> |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/pci.h> |
11 | |
12 | #include "pcie-rcar.h" |
13 | |
14 | void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, unsigned int reg) |
15 | { |
16 | writel(val, addr: pcie->base + reg); |
17 | } |
18 | |
19 | u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg) |
20 | { |
21 | return readl(addr: pcie->base + reg); |
22 | } |
23 | |
24 | void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) |
25 | { |
26 | unsigned int shift = BITS_PER_BYTE * (where & 3); |
27 | u32 val = rcar_pci_read_reg(pcie, reg: where & ~3); |
28 | |
29 | val &= ~(mask << shift); |
30 | val |= data << shift; |
31 | rcar_pci_write_reg(pcie, val, reg: where & ~3); |
32 | } |
33 | |
34 | int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie) |
35 | { |
36 | unsigned int timeout = 10; |
37 | |
38 | while (timeout--) { |
39 | if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY) |
40 | return 0; |
41 | |
42 | msleep(msecs: 5); |
43 | } |
44 | |
45 | return -ETIMEDOUT; |
46 | } |
47 | |
48 | int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie) |
49 | { |
50 | unsigned int timeout = 10000; |
51 | |
52 | while (timeout--) { |
53 | if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE)) |
54 | return 0; |
55 | |
56 | udelay(5); |
57 | cpu_relax(); |
58 | } |
59 | |
60 | return -ETIMEDOUT; |
61 | } |
62 | |
63 | void rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win, |
64 | struct resource_entry *window) |
65 | { |
66 | /* Setup PCIe address space mappings for each resource */ |
67 | struct resource *res = window->res; |
68 | resource_size_t res_start; |
69 | resource_size_t size; |
70 | u32 mask; |
71 | |
72 | rcar_pci_write_reg(pcie, val: 0x00000000, PCIEPTCTLR(win)); |
73 | |
74 | /* |
75 | * The PAMR mask is calculated in units of 128Bytes, which |
76 | * keeps things pretty simple. |
77 | */ |
78 | size = resource_size(res); |
79 | if (size > 128) |
80 | mask = (roundup_pow_of_two(size) / SZ_128) - 1; |
81 | else |
82 | mask = 0x0; |
83 | rcar_pci_write_reg(pcie, val: mask << 7, PCIEPAMR(win)); |
84 | |
85 | if (res->flags & IORESOURCE_IO) |
86 | res_start = pci_pio_to_address(pio: res->start) - window->offset; |
87 | else |
88 | res_start = res->start - window->offset; |
89 | |
90 | rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPAUR(win)); |
91 | rcar_pci_write_reg(pcie, lower_32_bits(res_start) & ~0x7F, |
92 | PCIEPALR(win)); |
93 | |
94 | /* First resource is for IO */ |
95 | mask = PAR_ENABLE; |
96 | if (res->flags & IORESOURCE_IO) |
97 | mask |= IO_SPACE; |
98 | |
99 | rcar_pci_write_reg(pcie, val: mask, PCIEPTCTLR(win)); |
100 | } |
101 | |
102 | void rcar_pcie_set_inbound(struct rcar_pcie *pcie, u64 cpu_addr, |
103 | u64 pci_addr, u64 flags, int idx, bool host) |
104 | { |
105 | /* |
106 | * Set up 64-bit inbound regions as the range parser doesn't |
107 | * distinguish between 32 and 64-bit types. |
108 | */ |
109 | if (host) |
110 | rcar_pci_write_reg(pcie, lower_32_bits(pci_addr), |
111 | PCIEPRAR(idx)); |
112 | rcar_pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx)); |
113 | rcar_pci_write_reg(pcie, val: flags, PCIELAMR(idx)); |
114 | |
115 | if (host) |
116 | rcar_pci_write_reg(pcie, upper_32_bits(pci_addr), |
117 | PCIEPRAR(idx + 1)); |
118 | rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx + 1)); |
119 | rcar_pci_write_reg(pcie, val: 0, PCIELAMR(idx + 1)); |
120 | } |
121 | |