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