diff options
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 178 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.h | 8 |
2 files changed, 162 insertions, 24 deletions
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index a625dcf26b2b..3f415e252ea5 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c | |||
@@ -22,10 +22,13 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/interrupt.h> | ||
25 | #include <linux/bootmem.h> | 26 | #include <linux/bootmem.h> |
26 | #include <linux/memblock.h> | 27 | #include <linux/memblock.h> |
27 | #include <linux/log2.h> | 28 | #include <linux/log2.h> |
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/suspend.h> | ||
31 | #include <linux/syscore_ops.h> | ||
29 | #include <linux/uaccess.h> | 32 | #include <linux/uaccess.h> |
30 | 33 | ||
31 | #include <asm/io.h> | 34 | #include <asm/io.h> |
@@ -868,6 +871,14 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose) | |||
868 | 871 | ||
869 | pci_bus_read_config_dword(hose->bus, | 872 | pci_bus_read_config_dword(hose->bus, |
870 | PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base); | 873 | PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base); |
874 | |||
875 | /* | ||
876 | * For PEXCSRBAR, bit 3-0 indicate prefetchable and | ||
877 | * address type. So when getting base address, these | ||
878 | * bits should be masked | ||
879 | */ | ||
880 | base &= PCI_BASE_ADDRESS_MEM_MASK; | ||
881 | |||
871 | return base; | 882 | return base; |
872 | } | 883 | } |
873 | #endif | 884 | #endif |
@@ -1086,55 +1097,171 @@ void fsl_pci_assign_primary(void) | |||
1086 | } | 1097 | } |
1087 | } | 1098 | } |
1088 | 1099 | ||
1089 | static int fsl_pci_probe(struct platform_device *pdev) | 1100 | #ifdef CONFIG_PM_SLEEP |
1101 | static irqreturn_t fsl_pci_pme_handle(int irq, void *dev_id) | ||
1090 | { | 1102 | { |
1091 | int ret; | 1103 | struct pci_controller *hose = dev_id; |
1092 | struct device_node *node; | 1104 | struct ccsr_pci __iomem *pci = hose->private_data; |
1105 | u32 dr; | ||
1093 | 1106 | ||
1094 | node = pdev->dev.of_node; | 1107 | dr = in_be32(&pci->pex_pme_mes_dr); |
1095 | ret = fsl_add_bridge(pdev, fsl_pci_primary == node); | 1108 | if (!dr) |
1109 | return IRQ_NONE; | ||
1096 | 1110 | ||
1097 | mpc85xx_pci_err_probe(pdev); | 1111 | out_be32(&pci->pex_pme_mes_dr, dr); |
1098 | 1112 | ||
1099 | return 0; | 1113 | return IRQ_HANDLED; |
1100 | } | 1114 | } |
1101 | 1115 | ||
1102 | #ifdef CONFIG_PM | 1116 | static int fsl_pci_pme_probe(struct pci_controller *hose) |
1103 | static int fsl_pci_resume(struct device *dev) | ||
1104 | { | 1117 | { |
1105 | struct pci_controller *hose; | 1118 | struct ccsr_pci __iomem *pci; |
1106 | struct resource pci_rsrc; | 1119 | struct pci_dev *dev; |
1120 | int pme_irq; | ||
1121 | int res; | ||
1122 | u16 pms; | ||
1107 | 1123 | ||
1108 | hose = pci_find_hose_for_OF_device(dev->of_node); | 1124 | /* Get hose's pci_dev */ |
1109 | if (!hose) | 1125 | dev = list_first_entry(&hose->bus->devices, typeof(*dev), bus_list); |
1110 | return -ENODEV; | 1126 | |
1127 | /* PME Disable */ | ||
1128 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms); | ||
1129 | pms &= ~PCI_PM_CTRL_PME_ENABLE; | ||
1130 | pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms); | ||
1131 | |||
1132 | pme_irq = irq_of_parse_and_map(hose->dn, 0); | ||
1133 | if (!pme_irq) { | ||
1134 | dev_err(&dev->dev, "Failed to map PME interrupt.\n"); | ||
1135 | |||
1136 | return -ENXIO; | ||
1137 | } | ||
1138 | |||
1139 | res = devm_request_irq(hose->parent, pme_irq, | ||
1140 | fsl_pci_pme_handle, | ||
1141 | IRQF_SHARED, | ||
1142 | "[PCI] PME", hose); | ||
1143 | if (res < 0) { | ||
1144 | dev_err(&dev->dev, "Unable to requiest irq %d for PME\n", pme_irq); | ||
1145 | irq_dispose_mapping(pme_irq); | ||
1111 | 1146 | ||
1112 | if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) { | ||
1113 | dev_err(dev, "Get pci register base failed."); | ||
1114 | return -ENODEV; | 1147 | return -ENODEV; |
1115 | } | 1148 | } |
1116 | 1149 | ||
1117 | setup_pci_atmu(hose); | 1150 | pci = hose->private_data; |
1151 | |||
1152 | /* Enable PTOD, ENL23D & EXL23D */ | ||
1153 | out_be32(&pci->pex_pme_mes_disr, 0); | ||
1154 | setbits32(&pci->pex_pme_mes_disr, | ||
1155 | PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D); | ||
1156 | |||
1157 | out_be32(&pci->pex_pme_mes_ier, 0); | ||
1158 | setbits32(&pci->pex_pme_mes_ier, | ||
1159 | PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D); | ||
1160 | |||
1161 | /* PME Enable */ | ||
1162 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms); | ||
1163 | pms |= PCI_PM_CTRL_PME_ENABLE; | ||
1164 | pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms); | ||
1118 | 1165 | ||
1119 | return 0; | 1166 | return 0; |
1120 | } | 1167 | } |
1121 | 1168 | ||
1122 | static const struct dev_pm_ops pci_pm_ops = { | 1169 | static void send_pme_turnoff_message(struct pci_controller *hose) |
1123 | .resume = fsl_pci_resume, | 1170 | { |
1124 | }; | 1171 | struct ccsr_pci __iomem *pci = hose->private_data; |
1172 | u32 dr; | ||
1173 | int i; | ||
1125 | 1174 | ||
1126 | #define PCI_PM_OPS (&pci_pm_ops) | 1175 | /* Send PME_Turn_Off Message Request */ |
1176 | setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR); | ||
1127 | 1177 | ||
1128 | #else | 1178 | /* Wait trun off done */ |
1179 | for (i = 0; i < 150; i++) { | ||
1180 | dr = in_be32(&pci->pex_pme_mes_dr); | ||
1181 | if (dr) { | ||
1182 | out_be32(&pci->pex_pme_mes_dr, dr); | ||
1183 | break; | ||
1184 | } | ||
1185 | |||
1186 | udelay(1000); | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1190 | static void fsl_pci_syscore_do_suspend(struct pci_controller *hose) | ||
1191 | { | ||
1192 | send_pme_turnoff_message(hose); | ||
1193 | } | ||
1194 | |||
1195 | static int fsl_pci_syscore_suspend(void) | ||
1196 | { | ||
1197 | struct pci_controller *hose, *tmp; | ||
1129 | 1198 | ||
1130 | #define PCI_PM_OPS NULL | 1199 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) |
1200 | fsl_pci_syscore_do_suspend(hose); | ||
1131 | 1201 | ||
1202 | return 0; | ||
1203 | } | ||
1204 | |||
1205 | static void fsl_pci_syscore_do_resume(struct pci_controller *hose) | ||
1206 | { | ||
1207 | struct ccsr_pci __iomem *pci = hose->private_data; | ||
1208 | u32 dr; | ||
1209 | int i; | ||
1210 | |||
1211 | /* Send Exit L2 State Message */ | ||
1212 | setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S); | ||
1213 | |||
1214 | /* Wait exit done */ | ||
1215 | for (i = 0; i < 150; i++) { | ||
1216 | dr = in_be32(&pci->pex_pme_mes_dr); | ||
1217 | if (dr) { | ||
1218 | out_be32(&pci->pex_pme_mes_dr, dr); | ||
1219 | break; | ||
1220 | } | ||
1221 | |||
1222 | udelay(1000); | ||
1223 | } | ||
1224 | |||
1225 | setup_pci_atmu(hose); | ||
1226 | } | ||
1227 | |||
1228 | static void fsl_pci_syscore_resume(void) | ||
1229 | { | ||
1230 | struct pci_controller *hose, *tmp; | ||
1231 | |||
1232 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) | ||
1233 | fsl_pci_syscore_do_resume(hose); | ||
1234 | } | ||
1235 | |||
1236 | static struct syscore_ops pci_syscore_pm_ops = { | ||
1237 | .suspend = fsl_pci_syscore_suspend, | ||
1238 | .resume = fsl_pci_syscore_resume, | ||
1239 | }; | ||
1132 | #endif | 1240 | #endif |
1133 | 1241 | ||
1242 | void fsl_pcibios_fixup_phb(struct pci_controller *phb) | ||
1243 | { | ||
1244 | #ifdef CONFIG_PM_SLEEP | ||
1245 | fsl_pci_pme_probe(phb); | ||
1246 | #endif | ||
1247 | } | ||
1248 | |||
1249 | static int fsl_pci_probe(struct platform_device *pdev) | ||
1250 | { | ||
1251 | struct device_node *node; | ||
1252 | int ret; | ||
1253 | |||
1254 | node = pdev->dev.of_node; | ||
1255 | ret = fsl_add_bridge(pdev, fsl_pci_primary == node); | ||
1256 | |||
1257 | mpc85xx_pci_err_probe(pdev); | ||
1258 | |||
1259 | return 0; | ||
1260 | } | ||
1261 | |||
1134 | static struct platform_driver fsl_pci_driver = { | 1262 | static struct platform_driver fsl_pci_driver = { |
1135 | .driver = { | 1263 | .driver = { |
1136 | .name = "fsl-pci", | 1264 | .name = "fsl-pci", |
1137 | .pm = PCI_PM_OPS, | ||
1138 | .of_match_table = pci_ids, | 1265 | .of_match_table = pci_ids, |
1139 | }, | 1266 | }, |
1140 | .probe = fsl_pci_probe, | 1267 | .probe = fsl_pci_probe, |
@@ -1142,6 +1269,9 @@ static struct platform_driver fsl_pci_driver = { | |||
1142 | 1269 | ||
1143 | static int __init fsl_pci_init(void) | 1270 | static int __init fsl_pci_init(void) |
1144 | { | 1271 | { |
1272 | #ifdef CONFIG_PM_SLEEP | ||
1273 | register_syscore_ops(&pci_syscore_pm_ops); | ||
1274 | #endif | ||
1145 | return platform_driver_register(&fsl_pci_driver); | 1275 | return platform_driver_register(&fsl_pci_driver); |
1146 | } | 1276 | } |
1147 | arch_initcall(fsl_pci_init); | 1277 | arch_initcall(fsl_pci_init); |
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h index 8d455df58471..c1cec771d5ea 100644 --- a/arch/powerpc/sysdev/fsl_pci.h +++ b/arch/powerpc/sysdev/fsl_pci.h | |||
@@ -32,6 +32,13 @@ struct platform_device; | |||
32 | #define PIWAR_WRITE_SNOOP 0x00005000 | 32 | #define PIWAR_WRITE_SNOOP 0x00005000 |
33 | #define PIWAR_SZ_MASK 0x0000003f | 33 | #define PIWAR_SZ_MASK 0x0000003f |
34 | 34 | ||
35 | #define PEX_PMCR_PTOMR 0x1 | ||
36 | #define PEX_PMCR_EXL2S 0x2 | ||
37 | |||
38 | #define PME_DISR_EN_PTOD 0x00008000 | ||
39 | #define PME_DISR_EN_ENL23D 0x00002000 | ||
40 | #define PME_DISR_EN_EXL23D 0x00001000 | ||
41 | |||
35 | /* PCI/PCI Express outbound window reg */ | 42 | /* PCI/PCI Express outbound window reg */ |
36 | struct pci_outbound_window_regs { | 43 | struct pci_outbound_window_regs { |
37 | __be32 potar; /* 0x.0 - Outbound translation address register */ | 44 | __be32 potar; /* 0x.0 - Outbound translation address register */ |
@@ -111,6 +118,7 @@ struct ccsr_pci { | |||
111 | 118 | ||
112 | extern int fsl_add_bridge(struct platform_device *pdev, int is_primary); | 119 | extern int fsl_add_bridge(struct platform_device *pdev, int is_primary); |
113 | extern void fsl_pcibios_fixup_bus(struct pci_bus *bus); | 120 | extern void fsl_pcibios_fixup_bus(struct pci_bus *bus); |
121 | extern void fsl_pcibios_fixup_phb(struct pci_controller *phb); | ||
114 | extern int mpc83xx_add_bridge(struct device_node *dev); | 122 | extern int mpc83xx_add_bridge(struct device_node *dev); |
115 | u64 fsl_pci_immrbar_base(struct pci_controller *hose); | 123 | u64 fsl_pci_immrbar_base(struct pci_controller *hose); |
116 | 124 | ||