xref: /openbmc/linux/drivers/bcma/host_pci.c (revision 7fe2f639)
1 /*
2  * Broadcom specific AMBA
3  * PCI Host
4  *
5  * Licensed under the GNU/GPL. See COPYING for details.
6  */
7 
8 #include "bcma_private.h"
9 #include <linux/slab.h>
10 #include <linux/bcma/bcma.h>
11 #include <linux/pci.h>
12 
13 static void bcma_host_pci_switch_core(struct bcma_device *core)
14 {
15 	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
16 			       core->addr);
17 	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
18 			       core->wrap);
19 	core->bus->mapped_core = core;
20 	pr_debug("Switched to core: 0x%X\n", core->id.id);
21 }
22 
23 static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
24 {
25 	if (core->bus->mapped_core != core)
26 		bcma_host_pci_switch_core(core);
27 	return ioread8(core->bus->mmio + offset);
28 }
29 
30 static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
31 {
32 	if (core->bus->mapped_core != core)
33 		bcma_host_pci_switch_core(core);
34 	return ioread16(core->bus->mmio + offset);
35 }
36 
37 static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
38 {
39 	if (core->bus->mapped_core != core)
40 		bcma_host_pci_switch_core(core);
41 	return ioread32(core->bus->mmio + offset);
42 }
43 
44 static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
45 				 u8 value)
46 {
47 	if (core->bus->mapped_core != core)
48 		bcma_host_pci_switch_core(core);
49 	iowrite8(value, core->bus->mmio + offset);
50 }
51 
52 static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
53 				 u16 value)
54 {
55 	if (core->bus->mapped_core != core)
56 		bcma_host_pci_switch_core(core);
57 	iowrite16(value, core->bus->mmio + offset);
58 }
59 
60 static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
61 				 u32 value)
62 {
63 	if (core->bus->mapped_core != core)
64 		bcma_host_pci_switch_core(core);
65 	iowrite32(value, core->bus->mmio + offset);
66 }
67 
68 static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
69 {
70 	if (core->bus->mapped_core != core)
71 		bcma_host_pci_switch_core(core);
72 	return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
73 }
74 
75 static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
76 				  u32 value)
77 {
78 	if (core->bus->mapped_core != core)
79 		bcma_host_pci_switch_core(core);
80 	iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
81 }
82 
83 const struct bcma_host_ops bcma_host_pci_ops = {
84 	.read8		= bcma_host_pci_read8,
85 	.read16		= bcma_host_pci_read16,
86 	.read32		= bcma_host_pci_read32,
87 	.write8		= bcma_host_pci_write8,
88 	.write16	= bcma_host_pci_write16,
89 	.write32	= bcma_host_pci_write32,
90 	.aread32	= bcma_host_pci_aread32,
91 	.awrite32	= bcma_host_pci_awrite32,
92 };
93 
94 static int bcma_host_pci_probe(struct pci_dev *dev,
95 			     const struct pci_device_id *id)
96 {
97 	struct bcma_bus *bus;
98 	int err = -ENOMEM;
99 	const char *name;
100 	u32 val;
101 
102 	/* Alloc */
103 	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
104 	if (!bus)
105 		goto out;
106 
107 	/* Basic PCI configuration */
108 	err = pci_enable_device(dev);
109 	if (err)
110 		goto err_kfree_bus;
111 
112 	name = dev_name(&dev->dev);
113 	if (dev->driver && dev->driver->name)
114 		name = dev->driver->name;
115 	err = pci_request_regions(dev, name);
116 	if (err)
117 		goto err_pci_disable;
118 	pci_set_master(dev);
119 
120 	/* Disable the RETRY_TIMEOUT register (0x41) to keep
121 	 * PCI Tx retries from interfering with C3 CPU state */
122 	pci_read_config_dword(dev, 0x40, &val);
123 	if ((val & 0x0000ff00) != 0)
124 		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
125 
126 	/* SSB needed additional powering up, do we have any AMBA PCI cards? */
127 	if (!pci_is_pcie(dev))
128 		pr_err("PCI card detected, report problems.\n");
129 
130 	/* Map MMIO */
131 	err = -ENOMEM;
132 	bus->mmio = pci_iomap(dev, 0, ~0UL);
133 	if (!bus->mmio)
134 		goto err_pci_release_regions;
135 
136 	/* Host specific */
137 	bus->host_pci = dev;
138 	bus->hosttype = BCMA_HOSTTYPE_PCI;
139 	bus->ops = &bcma_host_pci_ops;
140 
141 	/* Register */
142 	err = bcma_bus_register(bus);
143 	if (err)
144 		goto err_pci_unmap_mmio;
145 
146 	pci_set_drvdata(dev, bus);
147 
148 out:
149 	return err;
150 
151 err_pci_unmap_mmio:
152 	pci_iounmap(dev, bus->mmio);
153 err_pci_release_regions:
154 	pci_release_regions(dev);
155 err_pci_disable:
156 	pci_disable_device(dev);
157 err_kfree_bus:
158 	kfree(bus);
159 	return err;
160 }
161 
162 static void bcma_host_pci_remove(struct pci_dev *dev)
163 {
164 	struct bcma_bus *bus = pci_get_drvdata(dev);
165 
166 	bcma_bus_unregister(bus);
167 	pci_iounmap(dev, bus->mmio);
168 	pci_release_regions(dev);
169 	pci_disable_device(dev);
170 	kfree(bus);
171 	pci_set_drvdata(dev, NULL);
172 }
173 
174 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
175 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
176 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
177 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
178 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
179 	{ 0, },
180 };
181 MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
182 
183 static struct pci_driver bcma_pci_bridge_driver = {
184 	.name = "bcma-pci-bridge",
185 	.id_table = bcma_pci_bridge_tbl,
186 	.probe = bcma_host_pci_probe,
187 	.remove = bcma_host_pci_remove,
188 };
189 
190 int __init bcma_host_pci_init(void)
191 {
192 	return pci_register_driver(&bcma_pci_bridge_driver);
193 }
194 
195 void __exit bcma_host_pci_exit(void)
196 {
197 	pci_unregister_driver(&bcma_pci_bridge_driver);
198 }
199