6
6
*/
7
7
8
8
#include <linux/kernel.h>
9
+ #include <linux/module.h>
9
10
#include <linux/pci.h>
10
11
#include <linux/clk.h>
11
12
#include <linux/delay.h>
@@ -154,22 +155,13 @@ static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr)
154
155
mvebu_writel (port , stat , PCIE_STAT_OFF );
155
156
}
156
157
157
- /*
158
- * Setup PCIE BARs and Address Decode Wins:
159
- * BAR[0] -> internal registers (needed for MSI)
160
- * BAR[1] -> covers all DRAM banks
161
- * BAR[2] -> Disabled
162
- * WIN[0-3] -> DRAM bank[0-3]
163
- */
164
- static void mvebu_pcie_setup_wins (struct mvebu_pcie_port * port )
158
+ static void mvebu_pcie_disable_wins (struct mvebu_pcie_port * port )
165
159
{
166
- const struct mbus_dram_target_info * dram ;
167
- u32 size ;
168
160
int i ;
169
161
170
- dram = mv_mbus_dram_info ();
162
+ mvebu_writel (port , 0 , PCIE_BAR_LO_OFF (0 ));
163
+ mvebu_writel (port , 0 , PCIE_BAR_HI_OFF (0 ));
171
164
172
- /* First, disable and clear BARs and windows. */
173
165
for (i = 1 ; i < 3 ; i ++ ) {
174
166
mvebu_writel (port , 0 , PCIE_BAR_CTRL_OFF (i ));
175
167
mvebu_writel (port , 0 , PCIE_BAR_LO_OFF (i ));
@@ -185,6 +177,25 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
185
177
mvebu_writel (port , 0 , PCIE_WIN5_CTRL_OFF );
186
178
mvebu_writel (port , 0 , PCIE_WIN5_BASE_OFF );
187
179
mvebu_writel (port , 0 , PCIE_WIN5_REMAP_OFF );
180
+ }
181
+
182
+ /*
183
+ * Setup PCIE BARs and Address Decode Wins:
184
+ * BAR[0] -> internal registers (needed for MSI)
185
+ * BAR[1] -> covers all DRAM banks
186
+ * BAR[2] -> Disabled
187
+ * WIN[0-3] -> DRAM bank[0-3]
188
+ */
189
+ static void mvebu_pcie_setup_wins (struct mvebu_pcie_port * port )
190
+ {
191
+ const struct mbus_dram_target_info * dram ;
192
+ u32 size ;
193
+ int i ;
194
+
195
+ dram = mv_mbus_dram_info ();
196
+
197
+ /* First, disable and clear BARs and windows. */
198
+ mvebu_pcie_disable_wins (port );
188
199
189
200
/* Setup windows for DDR banks. Count total DDR size on the fly. */
190
201
size = 0 ;
@@ -1327,6 +1338,52 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
1327
1338
return pci_host_probe (bridge );
1328
1339
}
1329
1340
1341
+ static int mvebu_pcie_remove (struct platform_device * pdev )
1342
+ {
1343
+ struct mvebu_pcie * pcie = platform_get_drvdata (pdev );
1344
+ struct pci_host_bridge * bridge = pci_host_bridge_from_priv (pcie );
1345
+ u32 cmd ;
1346
+ int i ;
1347
+
1348
+ /* Remove PCI bus with all devices. */
1349
+ pci_lock_rescan_remove ();
1350
+ pci_stop_root_bus (bridge -> bus );
1351
+ pci_remove_root_bus (bridge -> bus );
1352
+ pci_unlock_rescan_remove ();
1353
+
1354
+ for (i = 0 ; i < pcie -> nports ; i ++ ) {
1355
+ struct mvebu_pcie_port * port = & pcie -> ports [i ];
1356
+
1357
+ if (!port -> base )
1358
+ continue ;
1359
+
1360
+ /* Disable Root Bridge I/O space, memory space and bus mastering. */
1361
+ cmd = mvebu_readl (port , PCIE_CMD_OFF );
1362
+ cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER );
1363
+ mvebu_writel (port , cmd , PCIE_CMD_OFF );
1364
+
1365
+ /* Mask all interrupt sources. */
1366
+ mvebu_writel (port , 0 , PCIE_MASK_OFF );
1367
+
1368
+ /* Free config space for emulated root bridge. */
1369
+ pci_bridge_emul_cleanup (& port -> bridge );
1370
+
1371
+ /* Disable and clear BARs and windows. */
1372
+ mvebu_pcie_disable_wins (port );
1373
+
1374
+ /* Delete PCIe IO and MEM windows. */
1375
+ if (port -> iowin .size )
1376
+ mvebu_pcie_del_windows (port , port -> iowin .base , port -> iowin .size );
1377
+ if (port -> memwin .size )
1378
+ mvebu_pcie_del_windows (port , port -> memwin .base , port -> memwin .size );
1379
+
1380
+ /* Power down card and disable clocks. Must be the last step. */
1381
+ mvebu_pcie_powerdown (port );
1382
+ }
1383
+
1384
+ return 0 ;
1385
+ }
1386
+
1330
1387
static const struct of_device_id mvebu_pcie_of_match_table [] = {
1331
1388
{ .compatible = "marvell,armada-xp-pcie" , },
1332
1389
{ .compatible = "marvell,armada-370-pcie" , },
@@ -1343,10 +1400,14 @@ static struct platform_driver mvebu_pcie_driver = {
1343
1400
.driver = {
1344
1401
.name = "mvebu-pcie" ,
1345
1402
.of_match_table = mvebu_pcie_of_match_table ,
1346
- /* driver unloading/unbinding currently not supported */
1347
- .suppress_bind_attrs = true,
1348
1403
.pm = & mvebu_pcie_pm_ops ,
1349
1404
},
1350
1405
.probe = mvebu_pcie_probe ,
1406
+ .remove = mvebu_pcie_remove ,
1351
1407
};
1352
- builtin_platform_driver (mvebu_pcie_driver );
1408
+ module_platform_driver (mvebu_pcie_driver );
1409
+
1410
+ MODULE_AUTHOR (
"Thomas Petazzoni <[email protected] >" );
1411
+ MODULE_AUTHOR (
"Pali Rohár <[email protected] >" );
1412
+ MODULE_DESCRIPTION ("Marvell EBU PCIe controller" );
1413
+ MODULE_LICENSE ("GPL v2" );
0 commit comments