Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / arch / mips / pci / pci-malta.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 1999, 2000, 2004, 2005  MIPS Technologies, Inc.
4  *      All rights reserved.
5  *      Authors: Carsten Langgaard <carstenl@mips.com>
6  *               Maciej W. Rozycki <macro@mips.com>
7  *
8  * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
9  *
10  * MIPS boards specific PCI support.
11  */
12 #include <linux/types.h>
13 #include <linux/pci.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16
17 #include <asm/gt64120.h>
18 #include <asm/mips-cps.h>
19 #include <asm/mips-boards/generic.h>
20 #include <asm/mips-boards/bonito64.h>
21 #include <asm/mips-boards/msc01_pci.h>
22
23 static struct resource bonito64_mem_resource = {
24         .name   = "Bonito PCI MEM",
25         .flags  = IORESOURCE_MEM,
26 };
27
28 static struct resource bonito64_io_resource = {
29         .name   = "Bonito PCI I/O",
30         .start  = 0x00000000UL,
31         .end    = 0x000fffffUL,
32         .flags  = IORESOURCE_IO,
33 };
34
35 static struct resource gt64120_mem_resource = {
36         .name   = "GT-64120 PCI MEM",
37         .flags  = IORESOURCE_MEM,
38 };
39
40 static struct resource gt64120_io_resource = {
41         .name   = "GT-64120 PCI I/O",
42         .flags  = IORESOURCE_IO,
43 };
44
45 static struct resource msc_mem_resource = {
46         .name   = "MSC PCI MEM",
47         .flags  = IORESOURCE_MEM,
48 };
49
50 static struct resource msc_io_resource = {
51         .name   = "MSC PCI I/O",
52         .flags  = IORESOURCE_IO,
53 };
54
55 extern struct pci_ops bonito64_pci_ops;
56 extern struct pci_ops gt64xxx_pci0_ops;
57 extern struct pci_ops msc_pci_ops;
58
59 static struct pci_controller bonito64_controller = {
60         .pci_ops        = &bonito64_pci_ops,
61         .io_resource    = &bonito64_io_resource,
62         .mem_resource   = &bonito64_mem_resource,
63         .io_offset      = 0x00000000UL,
64 };
65
66 static struct pci_controller gt64120_controller = {
67         .pci_ops        = &gt64xxx_pci0_ops,
68         .io_resource    = &gt64120_io_resource,
69         .mem_resource   = &gt64120_mem_resource,
70 };
71
72 static struct pci_controller msc_controller = {
73         .pci_ops        = &msc_pci_ops,
74         .io_resource    = &msc_io_resource,
75         .mem_resource   = &msc_mem_resource,
76 };
77
78 void __init mips_pcibios_init(void)
79 {
80         struct pci_controller *controller;
81         resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
82
83         switch (mips_revision_sconid) {
84         case MIPS_REVISION_SCON_GT64120:
85                 /*
86                  * Due to a bug in the Galileo system controller, we need
87                  * to setup the PCI BAR for the Galileo internal registers.
88                  * This should be done in the bios/bootprom and will be
89                  * fixed in a later revision of YAMON (the MIPS boards
90                  * boot prom).
91                  */
92                 GT_WRITE(GT_PCI0_CFGADDR_OFS,
93                          (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
94                          (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
95                          (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/
96                          ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/
97                          GT_PCI0_CFGADDR_CONFIGEN_BIT);
98
99                 /* Perform the write */
100                 GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE));
101
102                 /* Set up resource ranges from the controller's registers.  */
103                 start = GT_READ(GT_PCI0M0LD_OFS);
104                 end = GT_READ(GT_PCI0M0HD_OFS);
105                 map = GT_READ(GT_PCI0M0REMAP_OFS);
106                 end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
107                 start1 = GT_READ(GT_PCI0M1LD_OFS);
108                 end1 = GT_READ(GT_PCI0M1HD_OFS);
109                 map1 = GT_READ(GT_PCI0M1REMAP_OFS);
110                 end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK);
111                 /* Cannot support multiple windows, use the wider.  */
112                 if (end1 - start1 > end - start) {
113                         start = start1;
114                         end = end1;
115                         map = map1;
116                 }
117                 mask = ~(start ^ end);
118                 /* We don't support remapping with a discontiguous mask.  */
119                 BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
120                        mask != ~((mask & -mask) - 1));
121                 gt64120_mem_resource.start = start;
122                 gt64120_mem_resource.end = end;
123                 gt64120_controller.mem_offset = (start & mask) - (map & mask);
124                 /* Addresses are 36-bit, so do shifts in the destinations.  */
125                 gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF;
126                 gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF;
127                 gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
128                 gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF;
129
130                 start = GT_READ(GT_PCI0IOLD_OFS);
131                 end = GT_READ(GT_PCI0IOHD_OFS);
132                 map = GT_READ(GT_PCI0IOREMAP_OFS);
133                 end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
134                 mask = ~(start ^ end);
135                 /* We don't support remapping with a discontiguous mask.  */
136                 BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
137                        mask != ~((mask & -mask) - 1));
138                 gt64120_io_resource.start = map & mask;
139                 gt64120_io_resource.end = (map & mask) | ~mask;
140                 gt64120_controller.io_offset = 0;
141                 /* Addresses are 36-bit, so do shifts in the destinations.  */
142                 gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;
143                 gt64120_io_resource.end <<= GT_PCI_DCRM_SHF;
144                 gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
145
146                 controller = &gt64120_controller;
147                 break;
148
149         case MIPS_REVISION_SCON_BONITO:
150                 /* Set up resource ranges from the controller's registers.  */
151                 map = BONITO_PCIMAP;
152                 map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >>
153                        BONITO_PCIMAP_PCIMAP_LO0_SHIFT;
154                 map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >>
155                        BONITO_PCIMAP_PCIMAP_LO1_SHIFT;
156                 map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >>
157                        BONITO_PCIMAP_PCIMAP_LO2_SHIFT;
158                 /* Combine as many adjacent windows as possible.  */
159                 map = map1;
160                 start = BONITO_PCILO0_BASE;
161                 end = 1;
162                 if (map3 == map2 + 1) {
163                         map = map2;
164                         start = BONITO_PCILO1_BASE;
165                         end++;
166                 }
167                 if (map2 == map1 + 1) {
168                         map = map1;
169                         start = BONITO_PCILO0_BASE;
170                         end++;
171                 }
172                 bonito64_mem_resource.start = start;
173                 bonito64_mem_resource.end = start +
174                                             BONITO_PCIMAP_WINBASE(end) - 1;
175                 bonito64_controller.mem_offset = start -
176                                                  BONITO_PCIMAP_WINBASE(map);
177
178                 controller = &bonito64_controller;
179                 break;
180
181         case MIPS_REVISION_SCON_SOCIT:
182         case MIPS_REVISION_SCON_ROCIT:
183         case MIPS_REVISION_SCON_SOCITSC:
184         case MIPS_REVISION_SCON_SOCITSCP:
185                 /* Set up resource ranges from the controller's registers.  */
186                 MSC_READ(MSC01_PCI_SC2PMBASL, start);
187                 MSC_READ(MSC01_PCI_SC2PMMSKL, mask);
188                 MSC_READ(MSC01_PCI_SC2PMMAPL, map);
189                 msc_mem_resource.start = start & mask;
190                 msc_mem_resource.end = (start & mask) | ~mask;
191                 msc_controller.mem_offset = (start & mask) - (map & mask);
192                 if (mips_cps_numiocu(0)) {
193                         write_gcr_reg0_base(start);
194                         write_gcr_reg0_mask(mask |
195                                             CM_GCR_REGn_MASK_CMTGT_IOCU0);
196                 }
197                 MSC_READ(MSC01_PCI_SC2PIOBASL, start);
198                 MSC_READ(MSC01_PCI_SC2PIOMSKL, mask);
199                 MSC_READ(MSC01_PCI_SC2PIOMAPL, map);
200                 msc_io_resource.start = map & mask;
201                 msc_io_resource.end = (map & mask) | ~mask;
202                 msc_controller.io_offset = 0;
203                 ioport_resource.end = ~mask;
204                 if (mips_cps_numiocu(0)) {
205                         write_gcr_reg1_base(start);
206                         write_gcr_reg1_mask(mask |
207                                             CM_GCR_REGn_MASK_CMTGT_IOCU0);
208                 }
209                 /* If ranges overlap I/O takes precedence.  */
210                 start = start & mask;
211                 end = start | ~mask;
212                 if ((start >= msc_mem_resource.start &&
213                      start <= msc_mem_resource.end) ||
214                     (end >= msc_mem_resource.start &&
215                      end <= msc_mem_resource.end)) {
216                         /* Use the larger space.  */
217                         start = max(start, msc_mem_resource.start);
218                         end = min(end, msc_mem_resource.end);
219                         if (start - msc_mem_resource.start >=
220                             msc_mem_resource.end - end)
221                                 msc_mem_resource.end = start - 1;
222                         else
223                                 msc_mem_resource.start = end + 1;
224                 }
225
226                 controller = &msc_controller;
227                 break;
228         default:
229                 return;
230         }
231
232         /* PIIX4 ACPI starts at 0x1000 */
233         if (controller->io_resource->start < 0x00001000UL)
234                 controller->io_resource->start = 0x00001000UL;
235
236         iomem_resource.end &= 0xfffffffffULL;                   /* 64 GB */
237         ioport_resource.end = controller->io_resource->end;
238
239         controller->io_map_base = mips_io_port_base;
240
241         register_pci_controller(controller);
242 }