diff options
-rw-r--r-- | arch/x86/include/asm/iosf_mbi.h | 39 | ||||
-rw-r--r-- | arch/x86/platform/intel/iosf_mbi.c | 217 | ||||
-rw-r--r-- | drivers/acpi/Kconfig | 2 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic_xpower.c | 21 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-baytrail.c | 139 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-common.c | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 2 |
8 files changed, 250 insertions, 183 deletions
diff --git a/arch/x86/include/asm/iosf_mbi.h b/arch/x86/include/asm/iosf_mbi.h index 3de0489deade..5270ff39b9af 100644 --- a/arch/x86/include/asm/iosf_mbi.h +++ b/arch/x86/include/asm/iosf_mbi.h | |||
@@ -105,8 +105,10 @@ int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask); | |||
105 | * the PMIC bus while another driver is also accessing the PMIC bus various bad | 105 | * the PMIC bus while another driver is also accessing the PMIC bus various bad |
106 | * things happen. | 106 | * things happen. |
107 | * | 107 | * |
108 | * To avoid these problems this function must be called before accessing the | 108 | * Call this function before sending requests to the P-Unit which may make it |
109 | * P-Unit or the PMIC, be it through iosf_mbi* functions or through other means. | 109 | * access the PMIC, be it through iosf_mbi* functions or through other means. |
110 | * This function will block all kernel access to the PMIC I2C bus, so that the | ||
111 | * P-Unit can safely access the PMIC over the shared I2C bus. | ||
110 | * | 112 | * |
111 | * Note on these systems the i2c-bus driver will request a sempahore from the | 113 | * Note on these systems the i2c-bus driver will request a sempahore from the |
112 | * P-Unit for exclusive access to the PMIC bus when i2c drivers are accessing | 114 | * P-Unit for exclusive access to the PMIC bus when i2c drivers are accessing |
@@ -123,6 +125,31 @@ void iosf_mbi_punit_acquire(void); | |||
123 | void iosf_mbi_punit_release(void); | 125 | void iosf_mbi_punit_release(void); |
124 | 126 | ||
125 | /** | 127 | /** |
128 | * iosf_mbi_block_punit_i2c_access() - Block P-Unit accesses to the PMIC bus | ||
129 | * | ||
130 | * Call this function to block P-Unit access to the PMIC I2C bus, so that the | ||
131 | * kernel can safely access the PMIC over the shared I2C bus. | ||
132 | * | ||
133 | * This function acquires the P-Unit bus semaphore and notifies | ||
134 | * pmic_bus_access_notifier listeners that they may no longer access the | ||
135 | * P-Unit in a way which may cause it to access the shared I2C bus. | ||
136 | * | ||
137 | * Note this function may be called multiple times and the bus will not | ||
138 | * be released until iosf_mbi_unblock_punit_i2c_access() has been called the | ||
139 | * same amount of times. | ||
140 | * | ||
141 | * Return: Nonzero on error | ||
142 | */ | ||
143 | int iosf_mbi_block_punit_i2c_access(void); | ||
144 | |||
145 | /* | ||
146 | * iosf_mbi_unblock_punit_i2c_access() - Release PMIC I2C bus block | ||
147 | * | ||
148 | * Release i2c access block gotten through iosf_mbi_block_punit_i2c_access(). | ||
149 | */ | ||
150 | void iosf_mbi_unblock_punit_i2c_access(void); | ||
151 | |||
152 | /** | ||
126 | * iosf_mbi_register_pmic_bus_access_notifier - Register PMIC bus notifier | 153 | * iosf_mbi_register_pmic_bus_access_notifier - Register PMIC bus notifier |
127 | * | 154 | * |
128 | * This function can be used by drivers which may need to acquire P-Unit | 155 | * This function can be used by drivers which may need to acquire P-Unit |
@@ -159,14 +186,6 @@ int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked( | |||
159 | struct notifier_block *nb); | 186 | struct notifier_block *nb); |
160 | 187 | ||
161 | /** | 188 | /** |
162 | * iosf_mbi_call_pmic_bus_access_notifier_chain - Call PMIC bus notifier chain | ||
163 | * | ||
164 | * @val: action to pass into listener's notifier_call function | ||
165 | * @v: data pointer to pass into listener's notifier_call function | ||
166 | */ | ||
167 | int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v); | ||
168 | |||
169 | /** | ||
170 | * iosf_mbi_assert_punit_acquired - Assert that the P-Unit has been acquired. | 189 | * iosf_mbi_assert_punit_acquired - Assert that the P-Unit has been acquired. |
171 | */ | 190 | */ |
172 | void iosf_mbi_assert_punit_acquired(void); | 191 | void iosf_mbi_assert_punit_acquired(void); |
diff --git a/arch/x86/platform/intel/iosf_mbi.c b/arch/x86/platform/intel/iosf_mbi.c index 6f37a2137a79..2e569d10f2d0 100644 --- a/arch/x86/platform/intel/iosf_mbi.c +++ b/arch/x86/platform/intel/iosf_mbi.c | |||
@@ -18,24 +18,26 @@ | |||
18 | * enumerate the device using PCI. | 18 | * enumerate the device using PCI. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/delay.h> | ||
21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
22 | #include <linux/init.h> | 23 | #include <linux/init.h> |
23 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
24 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
25 | #include <linux/debugfs.h> | 26 | #include <linux/debugfs.h> |
26 | #include <linux/capability.h> | 27 | #include <linux/capability.h> |
28 | #include <linux/pm_qos.h> | ||
27 | 29 | ||
28 | #include <asm/iosf_mbi.h> | 30 | #include <asm/iosf_mbi.h> |
29 | 31 | ||
30 | #define PCI_DEVICE_ID_BAYTRAIL 0x0F00 | 32 | #define PCI_DEVICE_ID_INTEL_BAYTRAIL 0x0F00 |
31 | #define PCI_DEVICE_ID_BRASWELL 0x2280 | 33 | #define PCI_DEVICE_ID_INTEL_BRASWELL 0x2280 |
32 | #define PCI_DEVICE_ID_QUARK_X1000 0x0958 | 34 | #define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0958 |
33 | #define PCI_DEVICE_ID_TANGIER 0x1170 | 35 | #define PCI_DEVICE_ID_INTEL_TANGIER 0x1170 |
34 | 36 | ||
35 | static struct pci_dev *mbi_pdev; | 37 | static struct pci_dev *mbi_pdev; |
36 | static DEFINE_SPINLOCK(iosf_mbi_lock); | 38 | static DEFINE_SPINLOCK(iosf_mbi_lock); |
37 | static DEFINE_MUTEX(iosf_mbi_punit_mutex); | 39 | |
38 | static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier); | 40 | /**************** Generic iosf_mbi access helpers ****************/ |
39 | 41 | ||
40 | static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset) | 42 | static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset) |
41 | { | 43 | { |
@@ -192,6 +194,30 @@ bool iosf_mbi_available(void) | |||
192 | } | 194 | } |
193 | EXPORT_SYMBOL(iosf_mbi_available); | 195 | EXPORT_SYMBOL(iosf_mbi_available); |
194 | 196 | ||
197 | /* | ||
198 | **************** P-Unit/kernel shared I2C bus arbritration **************** | ||
199 | * | ||
200 | * Some Bay Trail and Cherry Trail devices have the P-Unit and us (the kernel) | ||
201 | * share a single I2C bus to the PMIC. Below are helpers to arbitrate the | ||
202 | * accesses between the kernel and the P-Unit. | ||
203 | * | ||
204 | * See arch/x86/include/asm/iosf_mbi.h for kernel-doc text for each function. | ||
205 | */ | ||
206 | |||
207 | #define SEMAPHORE_TIMEOUT 500 | ||
208 | #define PUNIT_SEMAPHORE_BYT 0x7 | ||
209 | #define PUNIT_SEMAPHORE_CHT 0x10e | ||
210 | #define PUNIT_SEMAPHORE_BIT BIT(0) | ||
211 | #define PUNIT_SEMAPHORE_ACQUIRE BIT(1) | ||
212 | |||
213 | static DEFINE_MUTEX(iosf_mbi_punit_mutex); | ||
214 | static DEFINE_MUTEX(iosf_mbi_block_punit_i2c_access_count_mutex); | ||
215 | static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier); | ||
216 | static u32 iosf_mbi_block_punit_i2c_access_count; | ||
217 | static u32 iosf_mbi_sem_address; | ||
218 | static unsigned long iosf_mbi_sem_acquired; | ||
219 | static struct pm_qos_request iosf_mbi_pm_qos; | ||
220 | |||
195 | void iosf_mbi_punit_acquire(void) | 221 | void iosf_mbi_punit_acquire(void) |
196 | { | 222 | { |
197 | mutex_lock(&iosf_mbi_punit_mutex); | 223 | mutex_lock(&iosf_mbi_punit_mutex); |
@@ -204,6 +230,159 @@ void iosf_mbi_punit_release(void) | |||
204 | } | 230 | } |
205 | EXPORT_SYMBOL(iosf_mbi_punit_release); | 231 | EXPORT_SYMBOL(iosf_mbi_punit_release); |
206 | 232 | ||
233 | static int iosf_mbi_get_sem(u32 *sem) | ||
234 | { | ||
235 | int ret; | ||
236 | |||
237 | ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, | ||
238 | iosf_mbi_sem_address, sem); | ||
239 | if (ret) { | ||
240 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n"); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | *sem &= PUNIT_SEMAPHORE_BIT; | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static void iosf_mbi_reset_semaphore(void) | ||
249 | { | ||
250 | if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, | ||
251 | iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT)) | ||
252 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n"); | ||
253 | |||
254 | pm_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE); | ||
255 | |||
256 | blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier, | ||
257 | MBI_PMIC_BUS_ACCESS_END, NULL); | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * This function blocks P-Unit accesses to the PMIC I2C bus, so that kernel | ||
262 | * I2C code, such as e.g. a fuel-gauge driver, can access it safely. | ||
263 | * | ||
264 | * This function may be called by I2C controller code while an I2C driver has | ||
265 | * already blocked P-Unit accesses because it wants them blocked over multiple | ||
266 | * i2c-transfers, for e.g. read-modify-write of an I2C client register. | ||
267 | * | ||
268 | * The P-Unit accesses already being blocked is tracked through the | ||
269 | * iosf_mbi_block_punit_i2c_access_count variable which is protected by the | ||
270 | * iosf_mbi_block_punit_i2c_access_count_mutex this mutex is hold for the | ||
271 | * entire duration of the function. | ||
272 | * | ||
273 | * If access is not blocked yet, this function takes the following steps: | ||
274 | * | ||
275 | * 1) Some code sends request to the P-Unit which make it access the PMIC | ||
276 | * I2C bus. Testing has shown that the P-Unit does not check its internal | ||
277 | * PMIC bus semaphore for these requests. Callers of these requests call | ||
278 | * iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these | ||
279 | * functions lock/unlock the iosf_mbi_punit_mutex. | ||
280 | * As the first step we lock the iosf_mbi_punit_mutex, to wait for any in | ||
281 | * flight requests to finish and to block any new requests. | ||
282 | * | ||
283 | * 2) Some code makes such P-Unit requests from atomic contexts where it | ||
284 | * cannot call iosf_mbi_punit_acquire() as that may sleep. | ||
285 | * As the second step we call a notifier chain which allows any code | ||
286 | * needing P-Unit resources from atomic context to acquire them before | ||
287 | * we take control over the PMIC I2C bus. | ||
288 | * | ||
289 | * 3) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC | ||
290 | * if this happens while the kernel itself is accessing the PMIC I2C bus | ||
291 | * the SoC hangs. | ||
292 | * As the third step we call pm_qos_update_request() to disallow the CPU | ||
293 | * to enter C6 or C7. | ||
294 | * | ||
295 | * 4) The P-Unit has a PMIC bus semaphore which we can request to stop | ||
296 | * autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it. | ||
297 | * As the fourth and final step we request this semaphore and wait for our | ||
298 | * request to be acknowledged. | ||
299 | */ | ||
300 | int iosf_mbi_block_punit_i2c_access(void) | ||
301 | { | ||
302 | unsigned long start, end; | ||
303 | int ret = 0; | ||
304 | u32 sem; | ||
305 | |||
306 | if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address)) | ||
307 | return -ENXIO; | ||
308 | |||
309 | mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex); | ||
310 | |||
311 | if (iosf_mbi_block_punit_i2c_access_count > 0) | ||
312 | goto success; | ||
313 | |||
314 | mutex_lock(&iosf_mbi_punit_mutex); | ||
315 | blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier, | ||
316 | MBI_PMIC_BUS_ACCESS_BEGIN, NULL); | ||
317 | |||
318 | /* | ||
319 | * Disallow the CPU to enter C6 or C7 state, entering these states | ||
320 | * requires the P-Unit to talk to the PMIC and if this happens while | ||
321 | * we're holding the semaphore, the SoC hangs. | ||
322 | */ | ||
323 | pm_qos_update_request(&iosf_mbi_pm_qos, 0); | ||
324 | |||
325 | /* host driver writes to side band semaphore register */ | ||
326 | ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, | ||
327 | iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE); | ||
328 | if (ret) { | ||
329 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n"); | ||
330 | goto error; | ||
331 | } | ||
332 | |||
333 | /* host driver waits for bit 0 to be set in semaphore register */ | ||
334 | start = jiffies; | ||
335 | end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT); | ||
336 | do { | ||
337 | ret = iosf_mbi_get_sem(&sem); | ||
338 | if (!ret && sem) { | ||
339 | iosf_mbi_sem_acquired = jiffies; | ||
340 | dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n", | ||
341 | jiffies_to_msecs(jiffies - start)); | ||
342 | /* | ||
343 | * Success, keep iosf_mbi_punit_mutex locked till | ||
344 | * iosf_mbi_unblock_punit_i2c_access() gets called. | ||
345 | */ | ||
346 | goto success; | ||
347 | } | ||
348 | |||
349 | usleep_range(1000, 2000); | ||
350 | } while (time_before(jiffies, end)); | ||
351 | |||
352 | ret = -ETIMEDOUT; | ||
353 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n"); | ||
354 | error: | ||
355 | iosf_mbi_reset_semaphore(); | ||
356 | mutex_unlock(&iosf_mbi_punit_mutex); | ||
357 | |||
358 | if (!iosf_mbi_get_sem(&sem)) | ||
359 | dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem); | ||
360 | success: | ||
361 | if (!WARN_ON(ret)) | ||
362 | iosf_mbi_block_punit_i2c_access_count++; | ||
363 | |||
364 | mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex); | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access); | ||
369 | |||
370 | void iosf_mbi_unblock_punit_i2c_access(void) | ||
371 | { | ||
372 | mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex); | ||
373 | |||
374 | iosf_mbi_block_punit_i2c_access_count--; | ||
375 | if (iosf_mbi_block_punit_i2c_access_count == 0) { | ||
376 | iosf_mbi_reset_semaphore(); | ||
377 | mutex_unlock(&iosf_mbi_punit_mutex); | ||
378 | dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n", | ||
379 | jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired)); | ||
380 | } | ||
381 | |||
382 | mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex); | ||
383 | } | ||
384 | EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access); | ||
385 | |||
207 | int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb) | 386 | int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb) |
208 | { | 387 | { |
209 | int ret; | 388 | int ret; |
@@ -241,19 +420,14 @@ int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb) | |||
241 | } | 420 | } |
242 | EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier); | 421 | EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier); |
243 | 422 | ||
244 | int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v) | ||
245 | { | ||
246 | return blocking_notifier_call_chain( | ||
247 | &iosf_mbi_pmic_bus_access_notifier, val, v); | ||
248 | } | ||
249 | EXPORT_SYMBOL(iosf_mbi_call_pmic_bus_access_notifier_chain); | ||
250 | |||
251 | void iosf_mbi_assert_punit_acquired(void) | 423 | void iosf_mbi_assert_punit_acquired(void) |
252 | { | 424 | { |
253 | WARN_ON(!mutex_is_locked(&iosf_mbi_punit_mutex)); | 425 | WARN_ON(!mutex_is_locked(&iosf_mbi_punit_mutex)); |
254 | } | 426 | } |
255 | EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired); | 427 | EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired); |
256 | 428 | ||
429 | /**************** iosf_mbi debug code ****************/ | ||
430 | |||
257 | #ifdef CONFIG_IOSF_MBI_DEBUG | 431 | #ifdef CONFIG_IOSF_MBI_DEBUG |
258 | static u32 dbg_mdr; | 432 | static u32 dbg_mdr; |
259 | static u32 dbg_mcr; | 433 | static u32 dbg_mcr; |
@@ -338,7 +512,7 @@ static inline void iosf_debugfs_remove(void) { } | |||
338 | #endif /* CONFIG_IOSF_MBI_DEBUG */ | 512 | #endif /* CONFIG_IOSF_MBI_DEBUG */ |
339 | 513 | ||
340 | static int iosf_mbi_probe(struct pci_dev *pdev, | 514 | static int iosf_mbi_probe(struct pci_dev *pdev, |
341 | const struct pci_device_id *unused) | 515 | const struct pci_device_id *dev_id) |
342 | { | 516 | { |
343 | int ret; | 517 | int ret; |
344 | 518 | ||
@@ -349,14 +523,16 @@ static int iosf_mbi_probe(struct pci_dev *pdev, | |||
349 | } | 523 | } |
350 | 524 | ||
351 | mbi_pdev = pci_dev_get(pdev); | 525 | mbi_pdev = pci_dev_get(pdev); |
526 | iosf_mbi_sem_address = dev_id->driver_data; | ||
527 | |||
352 | return 0; | 528 | return 0; |
353 | } | 529 | } |
354 | 530 | ||
355 | static const struct pci_device_id iosf_mbi_pci_ids[] = { | 531 | static const struct pci_device_id iosf_mbi_pci_ids[] = { |
356 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BAYTRAIL) }, | 532 | { PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) }, |
357 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BRASWELL) }, | 533 | { PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) }, |
358 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_QUARK_X1000) }, | 534 | { PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) }, |
359 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_TANGIER) }, | 535 | { PCI_DEVICE_DATA(INTEL, TANGIER, 0) }, |
360 | { 0, }, | 536 | { 0, }, |
361 | }; | 537 | }; |
362 | MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids); | 538 | MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids); |
@@ -371,6 +547,9 @@ static int __init iosf_mbi_init(void) | |||
371 | { | 547 | { |
372 | iosf_debugfs_init(); | 548 | iosf_debugfs_init(); |
373 | 549 | ||
550 | pm_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_CPU_DMA_LATENCY, | ||
551 | PM_QOS_DEFAULT_VALUE); | ||
552 | |||
374 | return pci_register_driver(&iosf_mbi_pci_driver); | 553 | return pci_register_driver(&iosf_mbi_pci_driver); |
375 | } | 554 | } |
376 | 555 | ||
@@ -381,6 +560,8 @@ static void __exit iosf_mbi_exit(void) | |||
381 | pci_unregister_driver(&iosf_mbi_pci_driver); | 560 | pci_unregister_driver(&iosf_mbi_pci_driver); |
382 | pci_dev_put(mbi_pdev); | 561 | pci_dev_put(mbi_pdev); |
383 | mbi_pdev = NULL; | 562 | mbi_pdev = NULL; |
563 | |||
564 | pm_qos_remove_request(&iosf_mbi_pm_qos); | ||
384 | } | 565 | } |
385 | 566 | ||
386 | module_init(iosf_mbi_init); | 567 | module_init(iosf_mbi_init); |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 365e6c1a729e..8f3a444c6ea9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -512,7 +512,7 @@ config CRC_PMIC_OPREGION | |||
512 | 512 | ||
513 | config XPOWER_PMIC_OPREGION | 513 | config XPOWER_PMIC_OPREGION |
514 | bool "ACPI operation region support for XPower AXP288 PMIC" | 514 | bool "ACPI operation region support for XPower AXP288 PMIC" |
515 | depends on MFD_AXP20X_I2C | 515 | depends on MFD_AXP20X_I2C && IOSF_MBI |
516 | help | 516 | help |
517 | This config adds ACPI operation region support for XPower AXP288 PMIC. | 517 | This config adds ACPI operation region support for XPower AXP288 PMIC. |
518 | 518 | ||
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index aadc86db804c..2579675b7082 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c | |||
@@ -8,8 +8,9 @@ | |||
8 | #include <linux/acpi.h> | 8 | #include <linux/acpi.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/mfd/axp20x.h> | 10 | #include <linux/mfd/axp20x.h> |
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/regmap.h> | 11 | #include <linux/regmap.h> |
12 | #include <linux/platform_device.h> | ||
13 | #include <asm/iosf_mbi.h> | ||
13 | #include "intel_pmic.h" | 14 | #include "intel_pmic.h" |
14 | 15 | ||
15 | #define XPOWER_GPADC_LOW 0x5b | 16 | #define XPOWER_GPADC_LOW 0x5b |
@@ -172,15 +173,21 @@ static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg, | |||
172 | static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, | 173 | static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, |
173 | int bit, bool on) | 174 | int bit, bool on) |
174 | { | 175 | { |
175 | int data; | 176 | int data, ret; |
176 | 177 | ||
177 | /* GPIO1 LDO regulator needs special handling */ | 178 | /* GPIO1 LDO regulator needs special handling */ |
178 | if (reg == XPOWER_GPI1_CTRL) | 179 | if (reg == XPOWER_GPI1_CTRL) |
179 | return regmap_update_bits(regmap, reg, GPI1_LDO_MASK, | 180 | return regmap_update_bits(regmap, reg, GPI1_LDO_MASK, |
180 | on ? GPI1_LDO_ON : GPI1_LDO_OFF); | 181 | on ? GPI1_LDO_ON : GPI1_LDO_OFF); |
181 | 182 | ||
182 | if (regmap_read(regmap, reg, &data)) | 183 | ret = iosf_mbi_block_punit_i2c_access(); |
183 | return -EIO; | 184 | if (ret) |
185 | return ret; | ||
186 | |||
187 | if (regmap_read(regmap, reg, &data)) { | ||
188 | ret = -EIO; | ||
189 | goto out; | ||
190 | } | ||
184 | 191 | ||
185 | if (on) | 192 | if (on) |
186 | data |= BIT(bit); | 193 | data |= BIT(bit); |
@@ -188,9 +195,11 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, | |||
188 | data &= ~BIT(bit); | 195 | data &= ~BIT(bit); |
189 | 196 | ||
190 | if (regmap_write(regmap, reg, data)) | 197 | if (regmap_write(regmap, reg, data)) |
191 | return -EIO; | 198 | ret = -EIO; |
199 | out: | ||
200 | iosf_mbi_unblock_punit_i2c_access(); | ||
192 | 201 | ||
193 | return 0; | 202 | return ret; |
194 | } | 203 | } |
195 | 204 | ||
196 | /** | 205 | /** |
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index 9ca1feaba98f..33da07d64494 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c | |||
@@ -3,141 +3,15 @@ | |||
3 | * Intel BayTrail PMIC I2C bus semaphore implementaion | 3 | * Intel BayTrail PMIC I2C bus semaphore implementaion |
4 | * Copyright (c) 2014, Intel Corporation. | 4 | * Copyright (c) 2014, Intel Corporation. |
5 | */ | 5 | */ |
6 | #include <linux/delay.h> | ||
7 | #include <linux/device.h> | 6 | #include <linux/device.h> |
8 | #include <linux/acpi.h> | 7 | #include <linux/acpi.h> |
9 | #include <linux/i2c.h> | 8 | #include <linux/i2c.h> |
10 | #include <linux/interrupt.h> | 9 | #include <linux/interrupt.h> |
11 | #include <linux/pm_qos.h> | ||
12 | 10 | ||
13 | #include <asm/iosf_mbi.h> | 11 | #include <asm/iosf_mbi.h> |
14 | 12 | ||
15 | #include "i2c-designware-core.h" | 13 | #include "i2c-designware-core.h" |
16 | 14 | ||
17 | #define SEMAPHORE_TIMEOUT 500 | ||
18 | #define PUNIT_SEMAPHORE 0x7 | ||
19 | #define PUNIT_SEMAPHORE_CHT 0x10e | ||
20 | #define PUNIT_SEMAPHORE_BIT BIT(0) | ||
21 | #define PUNIT_SEMAPHORE_ACQUIRE BIT(1) | ||
22 | |||
23 | static unsigned long acquired; | ||
24 | |||
25 | static u32 get_sem_addr(struct dw_i2c_dev *dev) | ||
26 | { | ||
27 | if (dev->flags & MODEL_CHERRYTRAIL) | ||
28 | return PUNIT_SEMAPHORE_CHT; | ||
29 | else | ||
30 | return PUNIT_SEMAPHORE; | ||
31 | } | ||
32 | |||
33 | static int get_sem(struct dw_i2c_dev *dev, u32 *sem) | ||
34 | { | ||
35 | u32 addr = get_sem_addr(dev); | ||
36 | u32 data; | ||
37 | int ret; | ||
38 | |||
39 | ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &data); | ||
40 | if (ret) { | ||
41 | dev_err(dev->dev, "iosf failed to read punit semaphore\n"); | ||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | *sem = data & PUNIT_SEMAPHORE_BIT; | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void reset_semaphore(struct dw_i2c_dev *dev) | ||
51 | { | ||
52 | if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, get_sem_addr(dev), | ||
53 | 0, PUNIT_SEMAPHORE_BIT)) | ||
54 | dev_err(dev->dev, "iosf failed to reset punit semaphore during write\n"); | ||
55 | |||
56 | pm_qos_update_request(&dev->pm_qos, PM_QOS_DEFAULT_VALUE); | ||
57 | |||
58 | iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_END, | ||
59 | NULL); | ||
60 | iosf_mbi_punit_release(); | ||
61 | } | ||
62 | |||
63 | static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) | ||
64 | { | ||
65 | u32 addr; | ||
66 | u32 sem = PUNIT_SEMAPHORE_ACQUIRE; | ||
67 | int ret; | ||
68 | unsigned long start, end; | ||
69 | |||
70 | might_sleep(); | ||
71 | |||
72 | if (!dev || !dev->dev) | ||
73 | return -ENODEV; | ||
74 | |||
75 | if (!dev->release_lock) | ||
76 | return 0; | ||
77 | |||
78 | iosf_mbi_punit_acquire(); | ||
79 | iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_BEGIN, | ||
80 | NULL); | ||
81 | |||
82 | /* | ||
83 | * Disallow the CPU to enter C6 or C7 state, entering these states | ||
84 | * requires the punit to talk to the pmic and if this happens while | ||
85 | * we're holding the semaphore, the SoC hangs. | ||
86 | */ | ||
87 | pm_qos_update_request(&dev->pm_qos, 0); | ||
88 | |||
89 | addr = get_sem_addr(dev); | ||
90 | |||
91 | /* host driver writes to side band semaphore register */ | ||
92 | ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem); | ||
93 | if (ret) { | ||
94 | dev_err(dev->dev, "iosf punit semaphore request failed\n"); | ||
95 | goto out; | ||
96 | } | ||
97 | |||
98 | /* host driver waits for bit 0 to be set in semaphore register */ | ||
99 | start = jiffies; | ||
100 | end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT); | ||
101 | do { | ||
102 | ret = get_sem(dev, &sem); | ||
103 | if (!ret && sem) { | ||
104 | acquired = jiffies; | ||
105 | dev_dbg(dev->dev, "punit semaphore acquired after %ums\n", | ||
106 | jiffies_to_msecs(jiffies - start)); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | usleep_range(1000, 2000); | ||
111 | } while (time_before(jiffies, end)); | ||
112 | |||
113 | dev_err(dev->dev, "punit semaphore timed out, resetting\n"); | ||
114 | out: | ||
115 | reset_semaphore(dev); | ||
116 | |||
117 | ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &sem); | ||
118 | if (ret) | ||
119 | dev_err(dev->dev, "iosf failed to read punit semaphore\n"); | ||
120 | else | ||
121 | dev_err(dev->dev, "PUNIT SEM: %d\n", sem); | ||
122 | |||
123 | WARN_ON(1); | ||
124 | |||
125 | return -ETIMEDOUT; | ||
126 | } | ||
127 | |||
128 | static void baytrail_i2c_release(struct dw_i2c_dev *dev) | ||
129 | { | ||
130 | if (!dev || !dev->dev) | ||
131 | return; | ||
132 | |||
133 | if (!dev->acquire_lock) | ||
134 | return; | ||
135 | |||
136 | reset_semaphore(dev); | ||
137 | dev_dbg(dev->dev, "punit semaphore held for %ums\n", | ||
138 | jiffies_to_msecs(jiffies - acquired)); | ||
139 | } | ||
140 | |||
141 | int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) | 15 | int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) |
142 | { | 16 | { |
143 | acpi_status status; | 17 | acpi_status status; |
@@ -162,18 +36,9 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) | |||
162 | return -EPROBE_DEFER; | 36 | return -EPROBE_DEFER; |
163 | 37 | ||
164 | dev_info(dev->dev, "I2C bus managed by PUNIT\n"); | 38 | dev_info(dev->dev, "I2C bus managed by PUNIT\n"); |
165 | dev->acquire_lock = baytrail_i2c_acquire; | 39 | dev->acquire_lock = iosf_mbi_block_punit_i2c_access; |
166 | dev->release_lock = baytrail_i2c_release; | 40 | dev->release_lock = iosf_mbi_unblock_punit_i2c_access; |
167 | dev->shared_with_punit = true; | 41 | dev->shared_with_punit = true; |
168 | 42 | ||
169 | pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY, | ||
170 | PM_QOS_DEFAULT_VALUE); | ||
171 | |||
172 | return 0; | 43 | return 0; |
173 | } | 44 | } |
174 | |||
175 | void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) | ||
176 | { | ||
177 | if (dev->acquire_lock) | ||
178 | pm_qos_remove_request(&dev->pm_qos); | ||
179 | } | ||
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 36271cd75342..a4730111d290 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c | |||
@@ -269,7 +269,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) | |||
269 | if (!dev->acquire_lock) | 269 | if (!dev->acquire_lock) |
270 | return 0; | 270 | return 0; |
271 | 271 | ||
272 | ret = dev->acquire_lock(dev); | 272 | ret = dev->acquire_lock(); |
273 | if (!ret) | 273 | if (!ret) |
274 | return 0; | 274 | return 0; |
275 | 275 | ||
@@ -281,7 +281,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) | |||
281 | void i2c_dw_release_lock(struct dw_i2c_dev *dev) | 281 | void i2c_dw_release_lock(struct dw_i2c_dev *dev) |
282 | { | 282 | { |
283 | if (dev->release_lock) | 283 | if (dev->release_lock) |
284 | dev->release_lock(dev); | 284 | dev->release_lock(); |
285 | } | 285 | } |
286 | 286 | ||
287 | /* | 287 | /* |
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 9ec8394f4787..b4a0b2b99a78 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h | |||
@@ -10,7 +10,6 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
13 | #include <linux/pm_qos.h> | ||
14 | 13 | ||
15 | #define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ | 14 | #define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ |
16 | I2C_FUNC_SMBUS_BYTE | \ | 15 | I2C_FUNC_SMBUS_BYTE | \ |
@@ -209,7 +208,6 @@ | |||
209 | * @fp_lcnt: fast plus LCNT value | 208 | * @fp_lcnt: fast plus LCNT value |
210 | * @hs_hcnt: high speed HCNT value | 209 | * @hs_hcnt: high speed HCNT value |
211 | * @hs_lcnt: high speed LCNT value | 210 | * @hs_lcnt: high speed LCNT value |
212 | * @pm_qos: pm_qos_request used while holding a hardware lock on the bus | ||
213 | * @acquire_lock: function to acquire a hardware lock on the bus | 211 | * @acquire_lock: function to acquire a hardware lock on the bus |
214 | * @release_lock: function to release a hardware lock on the bus | 212 | * @release_lock: function to release a hardware lock on the bus |
215 | * @shared_with_punit: true if this bus is shared with the SoCs PUNIT | 213 | * @shared_with_punit: true if this bus is shared with the SoCs PUNIT |
@@ -263,9 +261,8 @@ struct dw_i2c_dev { | |||
263 | u16 fp_lcnt; | 261 | u16 fp_lcnt; |
264 | u16 hs_hcnt; | 262 | u16 hs_hcnt; |
265 | u16 hs_lcnt; | 263 | u16 hs_lcnt; |
266 | struct pm_qos_request pm_qos; | 264 | int (*acquire_lock)(void); |
267 | int (*acquire_lock)(struct dw_i2c_dev *dev); | 265 | void (*release_lock)(void); |
268 | void (*release_lock)(struct dw_i2c_dev *dev); | ||
269 | bool shared_with_punit; | 266 | bool shared_with_punit; |
270 | void (*disable)(struct dw_i2c_dev *dev); | 267 | void (*disable)(struct dw_i2c_dev *dev); |
271 | void (*disable_int)(struct dw_i2c_dev *dev); | 268 | void (*disable_int)(struct dw_i2c_dev *dev); |
@@ -322,8 +319,6 @@ static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; } | |||
322 | 319 | ||
323 | #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) | 320 | #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) |
324 | extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev); | 321 | extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev); |
325 | extern void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev); | ||
326 | #else | 322 | #else |
327 | static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; } | 323 | static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; } |
328 | static inline void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) {} | ||
329 | #endif | 324 | #endif |
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 997bbb3d925f..9eaac3be1f63 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c | |||
@@ -418,8 +418,6 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) | |||
418 | if (!IS_ERR_OR_NULL(dev->rst)) | 418 | if (!IS_ERR_OR_NULL(dev->rst)) |
419 | reset_control_assert(dev->rst); | 419 | reset_control_assert(dev->rst); |
420 | 420 | ||
421 | i2c_dw_remove_lock_support(dev); | ||
422 | |||
423 | return 0; | 421 | return 0; |
424 | } | 422 | } |
425 | 423 | ||