]>
Commit | Line | Data |
---|---|---|
b61cbbdc HS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * (C) Copyright 2019 | |
4 | * Heiko Schocher, DENX Software Engineering, hs@denx.de. | |
5 | * | |
6 | */ | |
d678a59d | 7 | #include <common.h> |
cd93d625 | 8 | #include <asm/bitops.h> |
b61cbbdc HS |
9 | #include <pci.h> |
10 | #include <dm.h> | |
11 | #include <asm/fsl_law.h> | |
12 | ||
13 | struct mpc85xx_pci_priv { | |
14 | void __iomem *cfg_addr; | |
15 | void __iomem *cfg_data; | |
16 | }; | |
17 | ||
c4e72c4a | 18 | static int mpc85xx_pci_dm_read_config(const struct udevice *dev, pci_dev_t bdf, |
b61cbbdc HS |
19 | uint offset, ulong *value, |
20 | enum pci_size_t size) | |
21 | { | |
22 | struct mpc85xx_pci_priv *priv = dev_get_priv(dev); | |
23 | u32 addr; | |
24 | ||
159f1040 T |
25 | if (offset > 0xff) { |
26 | *value = pci_get_ff(size); | |
27 | return 0; | |
28 | } | |
29 | ||
c06597ff T |
30 | /* Skip mpc85xx PCI controller's ATMU inbound registers */ |
31 | if (PCI_BUS(bdf) == 0 && PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 && | |
32 | (offset & ~3) >= PCI_BASE_ADDRESS_0 && (offset & ~3) <= PCI_BASE_ADDRESS_5) { | |
33 | *value = 0; | |
34 | return 0; | |
35 | } | |
36 | ||
159f1040 | 37 | addr = PCI_CONF1_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset); |
b61cbbdc HS |
38 | out_be32(priv->cfg_addr, addr); |
39 | sync(); | |
f5375a45 T |
40 | |
41 | switch (size) { | |
42 | case PCI_SIZE_8: | |
43 | *value = in_8(priv->cfg_data + (offset & 3)); | |
44 | break; | |
45 | case PCI_SIZE_16: | |
46 | *value = in_le16(priv->cfg_data + (offset & 2)); | |
47 | break; | |
48 | case PCI_SIZE_32: | |
49 | *value = in_le32(priv->cfg_data); | |
50 | break; | |
51 | } | |
b61cbbdc HS |
52 | |
53 | return 0; | |
54 | } | |
55 | ||
56 | static int mpc85xx_pci_dm_write_config(struct udevice *dev, pci_dev_t bdf, | |
57 | uint offset, ulong value, | |
58 | enum pci_size_t size) | |
59 | { | |
60 | struct mpc85xx_pci_priv *priv = dev_get_priv(dev); | |
61 | u32 addr; | |
62 | ||
159f1040 T |
63 | if (offset > 0xff) |
64 | return 0; | |
65 | ||
c06597ff T |
66 | /* Skip mpc85xx PCI controller's ATMU inbound registers */ |
67 | if (PCI_BUS(bdf) == 0 && PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 && | |
68 | (offset & ~3) >= PCI_BASE_ADDRESS_0 && (offset & ~3) <= PCI_BASE_ADDRESS_5) | |
69 | return 0; | |
70 | ||
159f1040 | 71 | addr = PCI_CONF1_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset); |
b61cbbdc HS |
72 | out_be32(priv->cfg_addr, addr); |
73 | sync(); | |
f5375a45 T |
74 | |
75 | switch (size) { | |
76 | case PCI_SIZE_8: | |
77 | out_8(priv->cfg_data + (offset & 3), value); | |
78 | break; | |
79 | case PCI_SIZE_16: | |
80 | out_le16(priv->cfg_data + (offset & 2), value); | |
81 | break; | |
82 | case PCI_SIZE_32: | |
83 | out_le32(priv->cfg_data, value); | |
84 | break; | |
85 | } | |
76c72930 | 86 | sync(); |
b61cbbdc HS |
87 | |
88 | return 0; | |
89 | } | |
90 | ||
5a40f5c0 | 91 | #ifdef CONFIG_FSL_LAW |
b61cbbdc HS |
92 | static int |
93 | mpc85xx_pci_dm_setup_laws(struct pci_region *io, struct pci_region *mem, | |
94 | struct pci_region *pre) | |
95 | { | |
96 | /* | |
97 | * Unfortunately we have defines for this addresse, | |
98 | * as we have to setup the TLB, and at this stage | |
99 | * we have no access to DT ... may we check here | |
100 | * if the value in the define is the same ? | |
101 | */ | |
102 | if (mem) | |
103 | set_next_law(mem->phys_start, law_size_bits(mem->size), | |
104 | LAW_TRGT_IF_PCI); | |
105 | if (io) | |
106 | set_next_law(io->phys_start, law_size_bits(io->size), | |
107 | LAW_TRGT_IF_PCI); | |
108 | if (pre) | |
109 | set_next_law(pre->phys_start, law_size_bits(pre->size), | |
110 | LAW_TRGT_IF_PCI); | |
111 | ||
112 | return 0; | |
113 | } | |
5a40f5c0 | 114 | #endif |
b61cbbdc HS |
115 | |
116 | static int mpc85xx_pci_dm_probe(struct udevice *dev) | |
117 | { | |
118 | struct mpc85xx_pci_priv *priv = dev_get_priv(dev); | |
119 | struct pci_region *io; | |
120 | struct pci_region *mem; | |
121 | struct pci_region *pre; | |
122 | int count; | |
123 | ccsr_pcix_t *pcix; | |
124 | ||
125 | count = pci_get_regions(dev, &io, &mem, &pre); | |
126 | if (count != 2) { | |
127 | printf("%s: wrong count of regions %d only 2 allowed\n", | |
128 | __func__, count); | |
129 | return -EINVAL; | |
130 | } | |
131 | ||
5a40f5c0 | 132 | #ifdef CONFIG_FSL_LAW |
b61cbbdc | 133 | mpc85xx_pci_dm_setup_laws(io, mem, pre); |
5a40f5c0 | 134 | #endif |
b61cbbdc HS |
135 | |
136 | pcix = priv->cfg_addr; | |
137 | /* BAR 1: memory */ | |
8461ee51 BM |
138 | out_be32(&pcix->potar1, mem->bus_start >> 12); |
139 | out_be32(&pcix->potear1, (u64)mem->bus_start >> 44); | |
140 | out_be32(&pcix->powbar1, mem->phys_start >> 12); | |
141 | out_be32(&pcix->powbear1, (u64)mem->phys_start >> 44); | |
b61cbbdc HS |
142 | out_be32(&pcix->powar1, (POWAR_EN | POWAR_MEM_READ | |
143 | POWAR_MEM_WRITE | (__ilog2(mem->size) - 1))); | |
144 | ||
145 | /* BAR 1: IO */ | |
8461ee51 BM |
146 | out_be32(&pcix->potar2, io->bus_start >> 12); |
147 | out_be32(&pcix->potear2, (u64)io->bus_start >> 44); | |
148 | out_be32(&pcix->powbar2, io->phys_start >> 12); | |
149 | out_be32(&pcix->powbear2, (u64)io->phys_start >> 44); | |
b61cbbdc HS |
150 | out_be32(&pcix->powar2, (POWAR_EN | POWAR_IO_READ | |
151 | POWAR_IO_WRITE | (__ilog2(io->size) - 1))); | |
152 | ||
153 | out_be32(&pcix->pitar1, 0); | |
154 | out_be32(&pcix->piwbar1, 0); | |
155 | out_be32(&pcix->piwar1, (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | | |
156 | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G)); | |
157 | ||
158 | out_be32(&pcix->powar3, 0); | |
159 | out_be32(&pcix->powar4, 0); | |
160 | out_be32(&pcix->piwar2, 0); | |
161 | out_be32(&pcix->piwar3, 0); | |
162 | ||
163 | return 0; | |
164 | } | |
165 | ||
166 | static int mpc85xx_pci_dm_remove(struct udevice *dev) | |
167 | { | |
168 | return 0; | |
169 | } | |
170 | ||
d1998a9f | 171 | static int mpc85xx_pci_of_to_plat(struct udevice *dev) |
b61cbbdc HS |
172 | { |
173 | struct mpc85xx_pci_priv *priv = dev_get_priv(dev); | |
174 | fdt_addr_t addr; | |
175 | ||
176 | addr = devfdt_get_addr_index(dev, 0); | |
177 | if (addr == FDT_ADDR_T_NONE) | |
178 | return -EINVAL; | |
03ff970a BM |
179 | priv->cfg_addr = (void __iomem *)map_physmem(addr, 0, MAP_NOCACHE); |
180 | priv->cfg_data = (void __iomem *)((ulong)priv->cfg_addr + 4); | |
b61cbbdc HS |
181 | |
182 | return 0; | |
183 | } | |
184 | ||
185 | static const struct dm_pci_ops mpc85xx_pci_ops = { | |
186 | .read_config = mpc85xx_pci_dm_read_config, | |
187 | .write_config = mpc85xx_pci_dm_write_config, | |
188 | }; | |
189 | ||
190 | static const struct udevice_id mpc85xx_pci_ids[] = { | |
191 | { .compatible = "fsl,mpc8540-pci" }, | |
192 | { } | |
193 | }; | |
194 | ||
195 | U_BOOT_DRIVER(mpc85xx_pci) = { | |
196 | .name = "mpc85xx_pci", | |
197 | .id = UCLASS_PCI, | |
198 | .of_match = mpc85xx_pci_ids, | |
199 | .ops = &mpc85xx_pci_ops, | |
200 | .probe = mpc85xx_pci_dm_probe, | |
201 | .remove = mpc85xx_pci_dm_remove, | |
d1998a9f | 202 | .of_to_plat = mpc85xx_pci_of_to_plat, |
41575d8e | 203 | .priv_auto = sizeof(struct mpc85xx_pci_priv), |
b61cbbdc | 204 | }; |