99#include <linux/of_pci.h>
1010#include <linux/pci.h>
1111#include <linux/pci_ids.h>
12+ #include <linux/pci-acpi.h>
13+ #include <linux/pci-ecam.h>
1214
1315#include "../pci.h"
1416
1820#define DEV_PCIE_PORT_2 0x7a29
1921
2022#define DEV_LS2K_APB 0x7a02
21- #define DEV_LS7A_CONF 0x7a10
23+ #define DEV_LS7A_GMAC 0x7a03
24+ #define DEV_LS7A_DC1 0x7a06
2225#define DEV_LS7A_LPC 0x7a0c
26+ #define DEV_LS7A_AHCI 0x7a08
27+ #define DEV_LS7A_CONF 0x7a10
28+ #define DEV_LS7A_GNET 0x7a13
29+ #define DEV_LS7A_EHCI 0x7a14
30+ #define DEV_LS7A_DC2 0x7a36
31+ #define DEV_LS7A_HDMI 0x7a37
2332
2433#define FLAG_CFG0 BIT(0)
2534#define FLAG_CFG1 BIT(1)
2635#define FLAG_DEV_FIX BIT(2)
36+ #define FLAG_DEV_HIDDEN BIT(3)
37+
38+ struct loongson_pci_data {
39+ u32 flags ;
40+ struct pci_ops * ops ;
41+ };
2742
2843struct loongson_pci {
2944 void __iomem * cfg0_base ;
3045 void __iomem * cfg1_base ;
3146 struct platform_device * pdev ;
32- u32 flags ;
47+ const struct loongson_pci_data * data ;
3348};
3449
3550/* Fixup wrong class code in PCIe bridges */
@@ -92,55 +107,106 @@ static void loongson_mrrs_quirk(struct pci_dev *dev)
92107}
93108DECLARE_PCI_FIXUP_ENABLE (PCI_ANY_ID , PCI_ANY_ID , loongson_mrrs_quirk );
94109
95- static void __iomem * cfg1_map (struct loongson_pci * priv , int bus ,
96- unsigned int devfn , int where )
110+ static void loongson_pci_pin_quirk (struct pci_dev * pdev )
97111{
98- unsigned long addroff = 0x0 ;
112+ pdev -> pin = 1 + (PCI_FUNC (pdev -> devfn ) & 3 );
113+ }
114+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
115+ DEV_LS7A_DC1 , loongson_pci_pin_quirk );
116+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
117+ DEV_LS7A_DC2 , loongson_pci_pin_quirk );
118+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
119+ DEV_LS7A_GMAC , loongson_pci_pin_quirk );
120+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
121+ DEV_LS7A_AHCI , loongson_pci_pin_quirk );
122+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
123+ DEV_LS7A_EHCI , loongson_pci_pin_quirk );
124+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
125+ DEV_LS7A_GNET , loongson_pci_pin_quirk );
126+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
127+ DEV_LS7A_HDMI , loongson_pci_pin_quirk );
128+
129+ static struct loongson_pci * pci_bus_to_loongson_pci (struct pci_bus * bus )
130+ {
131+ struct pci_config_window * cfg ;
99132
100- if (bus != 0 )
101- addroff |= BIT ( 28 ); /* Type 1 Access */
102- addroff |= ( where & 0xff ) | (( where & 0xf00 ) << 16 );
103- addroff |= ( bus << 16 ) | ( devfn << 8 ) ;
104- return priv -> cfg1_base + addroff ;
133+ if (acpi_disabled )
134+ return ( struct loongson_pci * )( bus -> sysdata );
135+
136+ cfg = bus -> sysdata ;
137+ return ( struct loongson_pci * )( cfg -> priv ) ;
105138}
106139
107- static void __iomem * cfg0_map (struct loongson_pci * priv , int bus ,
108- unsigned int devfn , int where )
140+ static void __iomem * cfg0_map (struct loongson_pci * priv , struct pci_bus * bus ,
141+ unsigned int devfn , int where )
109142{
110143 unsigned long addroff = 0x0 ;
144+ unsigned char busnum = bus -> number ;
111145
112- if (bus != 0 )
146+ if (! pci_is_root_bus ( bus )) {
113147 addroff |= BIT (24 ); /* Type 1 Access */
114- addroff |= (bus << 16 ) | (devfn << 8 ) | where ;
148+ addroff |= (busnum << 16 );
149+ }
150+ addroff |= (devfn << 8 ) | where ;
115151 return priv -> cfg0_base + addroff ;
116152}
117153
118- static void __iomem * pci_loongson_map_bus (struct pci_bus * bus , unsigned int devfn ,
119- int where )
154+ static void __iomem * cfg1_map (struct loongson_pci * priv , struct pci_bus * bus ,
155+ unsigned int devfn , int where )
120156{
157+ unsigned long addroff = 0x0 ;
121158 unsigned char busnum = bus -> number ;
122- struct pci_host_bridge * bridge = pci_find_host_bridge (bus );
123- struct loongson_pci * priv = pci_host_bridge_priv (bridge );
159+
160+ if (!pci_is_root_bus (bus )) {
161+ addroff |= BIT (28 ); /* Type 1 Access */
162+ addroff |= (busnum << 16 );
163+ }
164+ addroff |= (devfn << 8 ) | (where & 0xff ) | ((where & 0xf00 ) << 16 );
165+ return priv -> cfg1_base + addroff ;
166+ }
167+
168+ static bool pdev_may_exist (struct pci_bus * bus , unsigned int device ,
169+ unsigned int function )
170+ {
171+ return !(pci_is_root_bus (bus ) &&
172+ (device >= 9 && device <= 20 ) && (function > 0 ));
173+ }
174+
175+ static void __iomem * pci_loongson_map_bus (struct pci_bus * bus ,
176+ unsigned int devfn , int where )
177+ {
178+ unsigned int device = PCI_SLOT (devfn );
179+ unsigned int function = PCI_FUNC (devfn );
180+ struct loongson_pci * priv = pci_bus_to_loongson_pci (bus );
124181
125182 /*
126183 * Do not read more than one device on the bus other than
127- * the host bus. For our hardware the root bus is always bus 0.
184+ * the host bus.
128185 */
129- if (priv -> flags & FLAG_DEV_FIX && busnum != 0 &&
130- PCI_SLOT (devfn ) > 0 )
131- return NULL ;
186+ if ((priv -> data -> flags & FLAG_DEV_FIX ) && bus -> self ) {
187+ if (!pci_is_root_bus (bus ) && (device > 0 ))
188+ return NULL ;
189+ }
190+
191+ /* Don't access non-existent devices */
192+ if (priv -> data -> flags & FLAG_DEV_HIDDEN ) {
193+ if (!pdev_may_exist (bus , device , function ))
194+ return NULL ;
195+ }
132196
133197 /* CFG0 can only access standard space */
134198 if (where < PCI_CFG_SPACE_SIZE && priv -> cfg0_base )
135- return cfg0_map (priv , busnum , devfn , where );
199+ return cfg0_map (priv , bus , devfn , where );
136200
137201 /* CFG1 can access extended space */
138202 if (where < PCI_CFG_SPACE_EXP_SIZE && priv -> cfg1_base )
139- return cfg1_map (priv , busnum , devfn , where );
203+ return cfg1_map (priv , bus , devfn , where );
140204
141205 return NULL ;
142206}
143207
208+ #ifdef CONFIG_OF
209+
144210static int loongson_map_irq (const struct pci_dev * dev , u8 slot , u8 pin )
145211{
146212 int irq ;
@@ -159,20 +225,42 @@ static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
159225 return val ;
160226}
161227
162- /* H/w only accept 32-bit PCI operations */
228+ /* LS2K/LS7A accept 8/16/ 32-bit PCI config operations */
163229static struct pci_ops loongson_pci_ops = {
230+ .map_bus = pci_loongson_map_bus ,
231+ .read = pci_generic_config_read ,
232+ .write = pci_generic_config_write ,
233+ };
234+
235+ /* RS780/SR5690 only accept 32-bit PCI config operations */
236+ static struct pci_ops loongson_pci_ops32 = {
164237 .map_bus = pci_loongson_map_bus ,
165238 .read = pci_generic_config_read32 ,
166239 .write = pci_generic_config_write32 ,
167240};
168241
242+ static const struct loongson_pci_data ls2k_pci_data = {
243+ .flags = FLAG_CFG1 | FLAG_DEV_FIX | FLAG_DEV_HIDDEN ,
244+ .ops = & loongson_pci_ops ,
245+ };
246+
247+ static const struct loongson_pci_data ls7a_pci_data = {
248+ .flags = FLAG_CFG1 | FLAG_DEV_FIX | FLAG_DEV_HIDDEN ,
249+ .ops = & loongson_pci_ops ,
250+ };
251+
252+ static const struct loongson_pci_data rs780e_pci_data = {
253+ .flags = FLAG_CFG0 ,
254+ .ops = & loongson_pci_ops32 ,
255+ };
256+
169257static const struct of_device_id loongson_pci_of_match [] = {
170258 { .compatible = "loongson,ls2k-pci" ,
171- .data = ( void * )( FLAG_CFG0 | FLAG_CFG1 | FLAG_DEV_FIX ) , },
259+ .data = & ls2k_pci_data , },
172260 { .compatible = "loongson,ls7a-pci" ,
173- .data = ( void * )( FLAG_CFG0 | FLAG_CFG1 | FLAG_DEV_FIX ) , },
261+ .data = & ls7a_pci_data , },
174262 { .compatible = "loongson,rs780e-pci" ,
175- .data = ( void * )( FLAG_CFG0 ) , },
263+ .data = & rs780e_pci_data , },
176264 {}
177265};
178266
@@ -193,20 +281,20 @@ static int loongson_pci_probe(struct platform_device *pdev)
193281
194282 priv = pci_host_bridge_priv (bridge );
195283 priv -> pdev = pdev ;
196- priv -> flags = ( unsigned long ) of_device_get_match_data (dev );
284+ priv -> data = of_device_get_match_data (dev );
197285
198- regs = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
199- if (!regs ) {
200- dev_err (dev , "missing mem resources for cfg0\n" );
201- return - EINVAL ;
286+ if (priv -> data -> flags & FLAG_CFG0 ) {
287+ regs = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
288+ if (!regs )
289+ dev_err (dev , "missing mem resources for cfg0\n" );
290+ else {
291+ priv -> cfg0_base = devm_pci_remap_cfg_resource (dev , regs );
292+ if (IS_ERR (priv -> cfg0_base ))
293+ return PTR_ERR (priv -> cfg0_base );
294+ }
202295 }
203296
204- priv -> cfg0_base = devm_pci_remap_cfg_resource (dev , regs );
205- if (IS_ERR (priv -> cfg0_base ))
206- return PTR_ERR (priv -> cfg0_base );
207-
208- /* CFG1 is optional */
209- if (priv -> flags & FLAG_CFG1 ) {
297+ if (priv -> data -> flags & FLAG_CFG1 ) {
210298 regs = platform_get_resource (pdev , IORESOURCE_MEM , 1 );
211299 if (!regs )
212300 dev_info (dev , "missing mem resource for cfg1\n" );
@@ -218,7 +306,7 @@ static int loongson_pci_probe(struct platform_device *pdev)
218306 }
219307
220308 bridge -> sysdata = priv ;
221- bridge -> ops = & loongson_pci_ops ;
309+ bridge -> ops = priv -> data -> ops ;
222310 bridge -> map_irq = loongson_map_irq ;
223311
224312 return pci_host_probe (bridge );
@@ -232,3 +320,41 @@ static struct platform_driver loongson_pci_driver = {
232320 .probe = loongson_pci_probe ,
233321};
234322builtin_platform_driver (loongson_pci_driver );
323+
324+ #endif
325+
326+ #ifdef CONFIG_ACPI
327+
328+ static int loongson_pci_ecam_init (struct pci_config_window * cfg )
329+ {
330+ struct device * dev = cfg -> parent ;
331+ struct loongson_pci * priv ;
332+ struct loongson_pci_data * data ;
333+
334+ priv = devm_kzalloc (dev , sizeof (* priv ), GFP_KERNEL );
335+ if (!priv )
336+ return - ENOMEM ;
337+
338+ data = devm_kzalloc (dev , sizeof (* data ), GFP_KERNEL );
339+ if (!data )
340+ return - ENOMEM ;
341+
342+ cfg -> priv = priv ;
343+ data -> flags = FLAG_CFG1 | FLAG_DEV_HIDDEN ;
344+ priv -> data = data ;
345+ priv -> cfg1_base = cfg -> win - (cfg -> busr .start << 16 );
346+
347+ return 0 ;
348+ }
349+
350+ const struct pci_ecam_ops loongson_pci_ecam_ops = {
351+ .bus_shift = 16 ,
352+ .init = loongson_pci_ecam_init ,
353+ .pci_ops = {
354+ .map_bus = pci_loongson_map_bus ,
355+ .read = pci_generic_config_read ,
356+ .write = pci_generic_config_write ,
357+ }
358+ };
359+
360+ #endif
0 commit comments