xref: /linux/drivers/pci/setup-cardbus.c (revision 08b3af830a35b66e0d40975dbf02feacc5d2aaa2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Cardbus bridge setup routines.
4  */
5 
6 #include <linux/errno.h>
7 #include <linux/ioport.h>
8 #include <linux/pci.h>
9 #include <linux/sizes.h>
10 #include <linux/types.h>
11 
12 #include "pci.h"
13 
14 #define DEFAULT_CARDBUS_IO_SIZE		SZ_256
15 #define DEFAULT_CARDBUS_MEM_SIZE	SZ_64M
16 /* pci=cbmemsize=nnM,cbiosize=nn can override this */
17 static unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
18 static unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
19 
20 unsigned long pci_cardbus_resource_alignment(struct resource *res)
21 {
22 	if (res->flags & IORESOURCE_IO)
23 		return pci_cardbus_io_size;
24 	if (res->flags & IORESOURCE_MEM)
25 		return pci_cardbus_mem_size;
26 	return 0;
27 }
28 
29 int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
30 				struct list_head *realloc_head)
31 {
32 	struct pci_dev *bridge = bus->self;
33 	struct resource *b_res;
34 	resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
35 	u16 ctrl;
36 
37 	b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
38 	if (resource_assigned(b_res))
39 		goto handle_b_res_1;
40 	/*
41 	 * Reserve some resources for CardBus.  We reserve a fixed amount
42 	 * of bus space for CardBus bridges.
43 	 */
44 	resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
45 	b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
46 	if (realloc_head) {
47 		b_res->end -= pci_cardbus_io_size;
48 		pci_dev_res_add_to_list(realloc_head, bridge, b_res,
49 					pci_cardbus_io_size,
50 					pci_cardbus_io_size);
51 	}
52 
53 handle_b_res_1:
54 	b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
55 	if (resource_assigned(b_res))
56 		goto handle_b_res_2;
57 	resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
58 	b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
59 	if (realloc_head) {
60 		b_res->end -= pci_cardbus_io_size;
61 		pci_dev_res_add_to_list(realloc_head, bridge, b_res,
62 					pci_cardbus_io_size,
63 					pci_cardbus_io_size);
64 	}
65 
66 handle_b_res_2:
67 	/* MEM1 must not be pref MMIO */
68 	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
69 	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
70 		ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
71 		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
72 		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
73 	}
74 
75 	/* Check whether prefetchable memory is supported by this bridge. */
76 	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
77 	if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
78 		ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
79 		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
80 		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
81 	}
82 
83 	b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
84 	if (resource_assigned(b_res))
85 		goto handle_b_res_3;
86 	/*
87 	 * If we have prefetchable memory support, allocate two regions.
88 	 * Otherwise, allocate one region of twice the size.
89 	 */
90 	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
91 		resource_set_range(b_res, pci_cardbus_mem_size,
92 				   pci_cardbus_mem_size);
93 		b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
94 				    IORESOURCE_STARTALIGN;
95 		if (realloc_head) {
96 			b_res->end -= pci_cardbus_mem_size;
97 			pci_dev_res_add_to_list(realloc_head, bridge, b_res,
98 						pci_cardbus_mem_size,
99 						pci_cardbus_mem_size);
100 		}
101 
102 		/* Reduce that to half */
103 		b_res_3_size = pci_cardbus_mem_size;
104 	}
105 
106 handle_b_res_3:
107 	b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
108 	if (resource_assigned(b_res))
109 		goto handle_done;
110 	resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size);
111 	b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
112 	if (realloc_head) {
113 		b_res->end -= b_res_3_size;
114 		pci_dev_res_add_to_list(realloc_head, bridge, b_res,
115 					b_res_3_size, pci_cardbus_mem_size);
116 	}
117 
118 handle_done:
119 	return 0;
120 }
121 
122 void pci_setup_cardbus_bridge(struct pci_bus *bus)
123 {
124 	struct pci_dev *bridge = bus->self;
125 	struct resource *res;
126 	struct pci_bus_region region;
127 
128 	pci_info(bridge, "CardBus bridge to %pR\n",
129 		 &bus->busn_res);
130 
131 	res = bus->resource[0];
132 	pcibios_resource_to_bus(bridge->bus, &region, res);
133 	if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
134 		/*
135 		 * The IO resource is allocated a range twice as large as it
136 		 * would normally need.  This allows us to set both IO regs.
137 		 */
138 		pci_info(bridge, "  bridge window %pR\n", res);
139 		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
140 					region.start);
141 		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
142 					region.end);
143 	}
144 
145 	res = bus->resource[1];
146 	pcibios_resource_to_bus(bridge->bus, &region, res);
147 	if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
148 		pci_info(bridge, "  bridge window %pR\n", res);
149 		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
150 					region.start);
151 		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
152 					region.end);
153 	}
154 
155 	res = bus->resource[2];
156 	pcibios_resource_to_bus(bridge->bus, &region, res);
157 	if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
158 		pci_info(bridge, "  bridge window %pR\n", res);
159 		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
160 					region.start);
161 		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
162 					region.end);
163 	}
164 
165 	res = bus->resource[3];
166 	pcibios_resource_to_bus(bridge->bus, &region, res);
167 	if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
168 		pci_info(bridge, "  bridge window %pR\n", res);
169 		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
170 					region.start);
171 		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
172 					region.end);
173 	}
174 }
175 EXPORT_SYMBOL(pci_setup_cardbus_bridge);
176 
177 int pci_setup_cardbus(char *str)
178 {
179 	if (!strncmp(str, "cbiosize=", 9)) {
180 		pci_cardbus_io_size = memparse(str + 9, &str);
181 		return 0;
182 	} else if (!strncmp(str, "cbmemsize=", 10)) {
183 		pci_cardbus_mem_size = memparse(str + 10, &str);
184 		return 0;
185 	}
186 
187 	return -ENOENT;
188 }
189