aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-07-05 13:54:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-07-05 13:54:09 -0400
commita585d2b738bfa26326b3f1f40f0f1eda0c067ccf (patch)
treedcf3289b576b1c8697f2a2d46909d36104208ba3
parent1dc51b8288007753ad7cd7d08bb8fa930fc8bb10 (diff)
parent0a8b83530b6f67b9a50bd7937d57a5deea187b5b (diff)
Merge tag 'platform-drivers-x86-v4.2-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull late x86 platform driver updates from Darren Hart: "The following came in a bit later and I wanted them to bake in next a few more days before submitting, thus the second pull. A new intel_pmc_ipc driver, a symmetrical allocation and free fix in dell-laptop, a couple minor fixes, and some updated documentation in the dell-laptop comments. intel_pmc_ipc: - Add Intel Apollo Lake PMC IPC driver tc1100-wmi: - Delete an unnecessary check before the function call "kfree" dell-laptop: - Fix allocating & freeing SMI buffer page - Show info about WiGig and UWB in debugfs - Update information about wireless control" * tag 'platform-drivers-x86-v4.2-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: intel_pmc_ipc: Add Intel Apollo Lake PMC IPC driver tc1100-wmi: Delete an unnecessary check before the function call "kfree" dell-laptop: Fix allocating & freeing SMI buffer page dell-laptop: Show info about WiGig and UWB in debugfs dell-laptop: Update information about wireless control
-rw-r--r--MAINTAINERS7
-rw-r--r--arch/x86/include/asm/intel_pmc_ipc.h82
-rw-r--r--drivers/platform/x86/Kconfig7
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/dell-laptop.c183
-rw-r--r--drivers/platform/x86/intel_pmc_ipc.c767
-rw-r--r--drivers/platform/x86/tc1100-wmi.c2
7 files changed, 1004 insertions, 45 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index bbb6aeb78b52..8133cefb6b6e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5470,6 +5470,13 @@ F: include/linux/mei_cl_bus.h
5470F: drivers/misc/mei/* 5470F: drivers/misc/mei/*
5471F: Documentation/misc-devices/mei/* 5471F: Documentation/misc-devices/mei/*
5472 5472
5473INTEL PMC IPC DRIVER
5474M: Zha Qipeng<qipeng.zha@intel.com>
5475L: platform-driver-x86@vger.kernel.org
5476S: Maintained
5477F: drivers/platform/x86/intel_pmc_ipc.c
5478F: arch/x86/include/asm/intel_pmc_ipc.h
5479
5473IOC3 ETHERNET DRIVER 5480IOC3 ETHERNET DRIVER
5474M: Ralf Baechle <ralf@linux-mips.org> 5481M: Ralf Baechle <ralf@linux-mips.org>
5475L: linux-mips@linux-mips.org 5482L: linux-mips@linux-mips.org
diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h
new file mode 100644
index 000000000000..200ec2e7821d
--- /dev/null
+++ b/arch/x86/include/asm/intel_pmc_ipc.h
@@ -0,0 +1,82 @@
1#ifndef _ASM_X86_INTEL_PMC_IPC_H_
2#define _ASM_X86_INTEL_PMC_IPC_H_
3
4/* Commands */
5#define PMC_IPC_PMIC_ACCESS 0xFF
6#define PMC_IPC_PMIC_ACCESS_READ 0x0
7#define PMC_IPC_PMIC_ACCESS_WRITE 0x1
8#define PMC_IPC_USB_PWR_CTRL 0xF0
9#define PMC_IPC_PMIC_BLACKLIST_SEL 0xEF
10#define PMC_IPC_PHY_CONFIG 0xEE
11#define PMC_IPC_NORTHPEAK_CTRL 0xED
12#define PMC_IPC_PM_DEBUG 0xEC
13#define PMC_IPC_PMC_TELEMTRY 0xEB
14#define PMC_IPC_PMC_FW_MSG_CTRL 0xEA
15
16/* IPC return code */
17#define IPC_ERR_NONE 0
18#define IPC_ERR_CMD_NOT_SUPPORTED 1
19#define IPC_ERR_CMD_NOT_SERVICED 2
20#define IPC_ERR_UNABLE_TO_SERVICE 3
21#define IPC_ERR_CMD_INVALID 4
22#define IPC_ERR_CMD_FAILED 5
23#define IPC_ERR_EMSECURITY 6
24#define IPC_ERR_UNSIGNEDKERNEL 7
25
26#if IS_ENABLED(CONFIG_INTEL_PMC_IPC)
27
28/*
29 * intel_pmc_ipc_simple_command
30 * @cmd: command
31 * @sub: sub type
32 */
33int intel_pmc_ipc_simple_command(int cmd, int sub);
34
35/*
36 * intel_pmc_ipc_raw_cmd
37 * @cmd: command
38 * @sub: sub type
39 * @in: input data
40 * @inlen: input length in bytes
41 * @out: output data
42 * @outlen: output length in dwords
43 * @sptr: data writing to SPTR register
44 * @dptr: data writing to DPTR register
45 */
46int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
47 u32 *out, u32 outlen, u32 dptr, u32 sptr);
48
49/*
50 * intel_pmc_ipc_command
51 * @cmd: command
52 * @sub: sub type
53 * @in: input data
54 * @inlen: input length in bytes
55 * @out: output data
56 * @outlen: output length in dwords
57 */
58int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
59 u32 *out, u32 outlen);
60
61#else
62
63static inline int intel_pmc_ipc_simple_command(int cmd, int sub)
64{
65 return -EINVAL;
66}
67
68static inline int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
69 u32 *out, u32 outlen, u32 dptr, u32 sptr)
70{
71 return -EINVAL;
72}
73
74static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
75 u32 *out, u32 outlen)
76{
77 return -EINVAL;
78}
79
80#endif /*CONFIG_INTEL_PMC_IPC*/
81
82#endif
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 1e2f57f6d297..6dc13e4de396 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -912,4 +912,11 @@ config PVPANIC
912 a paravirtualized device provided by QEMU; it lets a virtual machine 912 a paravirtualized device provided by QEMU; it lets a virtual machine
913 (guest) communicate panic events to the host. 913 (guest) communicate panic events to the host.
914 914
915config INTEL_PMC_IPC
916 tristate "Intel PMC IPC Driver"
917 ---help---
918 This driver provides support for PMC control on some Intel platforms.
919 The PMC is an ARC processor which defines IPC commands for communication
920 with other entities in the CPU.
921
915endif # X86_PLATFORM_DEVICES 922endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index b3e54ed863c3..dda95a985321 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
59 59
60obj-$(CONFIG_PVPANIC) += pvpanic.o 60obj-$(CONFIG_PVPANIC) += pvpanic.o
61obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o 61obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
62obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 35de903cb506..ed317ccac4a2 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -307,7 +307,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
307}; 307};
308 308
309static struct calling_interface_buffer *buffer; 309static struct calling_interface_buffer *buffer;
310static struct page *bufferpage;
311static DEFINE_MUTEX(buffer_mutex); 310static DEFINE_MUTEX(buffer_mutex);
312 311
313static int hwswitch_state; 312static int hwswitch_state;
@@ -424,45 +423,125 @@ static inline int dell_smi_error(int value)
424 } 423 }
425} 424}
426 425
427/* Derived from information in DellWirelessCtl.cpp: 426/*
428 Class 17, select 11 is radio control. It returns an array of 32-bit values. 427 * Derived from information in smbios-wireless-ctl:
429 428 *
430 Input byte 0 = 0: Wireless information 429 * cbSelect 17, Value 11
431 430 *
432 result[0]: return code 431 * Return Wireless Info
433 result[1]: 432 * cbArg1, byte0 = 0x00
434 Bit 0: Hardware switch supported 433 *
435 Bit 1: Wifi locator supported 434 * cbRes1 Standard return codes (0, -1, -2)
436 Bit 2: Wifi is supported 435 * cbRes2 Info bit flags:
437 Bit 3: Bluetooth is supported 436 *
438 Bit 4: WWAN is supported 437 * 0 Hardware switch supported (1)
439 Bit 5: Wireless keyboard supported 438 * 1 WiFi locator supported (1)
440 Bits 6-7: Reserved 439 * 2 WLAN supported (1)
441 Bit 8: Wifi is installed 440 * 3 Bluetooth (BT) supported (1)
442 Bit 9: Bluetooth is installed 441 * 4 WWAN supported (1)
443 Bit 10: WWAN is installed 442 * 5 Wireless KBD supported (1)
444 Bits 11-15: Reserved 443 * 6 Uw b supported (1)
445 Bit 16: Hardware switch is on 444 * 7 WiGig supported (1)
446 Bit 17: Wifi is blocked 445 * 8 WLAN installed (1)
447 Bit 18: Bluetooth is blocked 446 * 9 BT installed (1)
448 Bit 19: WWAN is blocked 447 * 10 WWAN installed (1)
449 Bits 20-31: Reserved 448 * 11 Uw b installed (1)
450 result[2]: NVRAM size in bytes 449 * 12 WiGig installed (1)
451 result[3]: NVRAM format version number 450 * 13-15 Reserved (0)
452 451 * 16 Hardware (HW) switch is On (1)
453 Input byte 0 = 2: Wireless switch configuration 452 * 17 WLAN disabled (1)
454 result[0]: return code 453 * 18 BT disabled (1)
455 result[1]: 454 * 19 WWAN disabled (1)
456 Bit 0: Wifi controlled by switch 455 * 20 Uw b disabled (1)
457 Bit 1: Bluetooth controlled by switch 456 * 21 WiGig disabled (1)
458 Bit 2: WWAN controlled by switch 457 * 20-31 Reserved (0)
459 Bits 3-6: Reserved 458 *
460 Bit 7: Wireless switch config locked 459 * cbRes3 NVRAM size in bytes
461 Bit 8: Wifi locator enabled 460 * cbRes4, byte 0 NVRAM format version number
462 Bits 9-14: Reserved 461 *
463 Bit 15: Wifi locator setting locked 462 *
464 Bits 16-31: Reserved 463 * Set QuickSet Radio Disable Flag
465*/ 464 * cbArg1, byte0 = 0x01
465 * cbArg1, byte1
466 * Radio ID value:
467 * 0 Radio Status
468 * 1 WLAN ID
469 * 2 BT ID
470 * 3 WWAN ID
471 * 4 UWB ID
472 * 5 WIGIG ID
473 * cbArg1, byte2 Flag bits:
474 * 0 QuickSet disables radio (1)
475 * 1-7 Reserved (0)
476 *
477 * cbRes1 Standard return codes (0, -1, -2)
478 * cbRes2 QuickSet (QS) radio disable bit map:
479 * 0 QS disables WLAN
480 * 1 QS disables BT
481 * 2 QS disables WWAN
482 * 3 QS disables UWB
483 * 4 QS disables WIGIG
484 * 5-31 Reserved (0)
485 *
486 * Wireless Switch Configuration
487 * cbArg1, byte0 = 0x02
488 *
489 * cbArg1, byte1
490 * Subcommand:
491 * 0 Get config
492 * 1 Set config
493 * 2 Set WiFi locator enable/disable
494 * cbArg1,byte2
495 * Switch settings (if byte 1==1):
496 * 0 WLAN sw itch control (1)
497 * 1 BT sw itch control (1)
498 * 2 WWAN sw itch control (1)
499 * 3 UWB sw itch control (1)
500 * 4 WiGig sw itch control (1)
501 * 5-7 Reserved (0)
502 * cbArg1, byte2 Enable bits (if byte 1==2):
503 * 0 Enable WiFi locator (1)
504 *
505 * cbRes1 Standard return codes (0, -1, -2)
506 * cbRes2 QuickSet radio disable bit map:
507 * 0 WLAN controlled by sw itch (1)
508 * 1 BT controlled by sw itch (1)
509 * 2 WWAN controlled by sw itch (1)
510 * 3 UWB controlled by sw itch (1)
511 * 4 WiGig controlled by sw itch (1)
512 * 5-6 Reserved (0)
513 * 7 Wireless sw itch config locked (1)
514 * 8 WiFi locator enabled (1)
515 * 9-14 Reserved (0)
516 * 15 WiFi locator setting locked (1)
517 * 16-31 Reserved (0)
518 *
519 * Read Local Config Data (LCD)
520 * cbArg1, byte0 = 0x10
521 * cbArg1, byte1 NVRAM index low byte
522 * cbArg1, byte2 NVRAM index high byte
523 * cbRes1 Standard return codes (0, -1, -2)
524 * cbRes2 4 bytes read from LCD[index]
525 * cbRes3 4 bytes read from LCD[index+4]
526 * cbRes4 4 bytes read from LCD[index+8]
527 *
528 * Write Local Config Data (LCD)
529 * cbArg1, byte0 = 0x11
530 * cbArg1, byte1 NVRAM index low byte
531 * cbArg1, byte2 NVRAM index high byte
532 * cbArg2 4 bytes to w rite at LCD[index]
533 * cbArg3 4 bytes to w rite at LCD[index+4]
534 * cbArg4 4 bytes to w rite at LCD[index+8]
535 * cbRes1 Standard return codes (0, -1, -2)
536 *
537 * Populate Local Config Data from NVRAM
538 * cbArg1, byte0 = 0x12
539 * cbRes1 Standard return codes (0, -1, -2)
540 *
541 * Commit Local Config Data to NVRAM
542 * cbArg1, byte0 = 0x13
543 * cbRes1 Standard return codes (0, -1, -2)
544 */
466 545
467static int dell_rfkill_set(void *data, bool blocked) 546static int dell_rfkill_set(void *data, bool blocked)
468{ 547{
@@ -550,12 +629,21 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
550 (status & BIT(4)) >> 4); 629 (status & BIT(4)) >> 4);
551 seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n", 630 seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n",
552 (status & BIT(5)) >> 5); 631 (status & BIT(5)) >> 5);
632 seq_printf(s, "Bit 6 : UWB supported: %lu\n",
633 (status & BIT(6)) >> 6);
634 seq_printf(s, "Bit 7 : WiGig supported: %lu\n",
635 (status & BIT(7)) >> 7);
553 seq_printf(s, "Bit 8 : Wifi is installed: %lu\n", 636 seq_printf(s, "Bit 8 : Wifi is installed: %lu\n",
554 (status & BIT(8)) >> 8); 637 (status & BIT(8)) >> 8);
555 seq_printf(s, "Bit 9 : Bluetooth is installed: %lu\n", 638 seq_printf(s, "Bit 9 : Bluetooth is installed: %lu\n",
556 (status & BIT(9)) >> 9); 639 (status & BIT(9)) >> 9);
557 seq_printf(s, "Bit 10: WWAN is installed: %lu\n", 640 seq_printf(s, "Bit 10: WWAN is installed: %lu\n",
558 (status & BIT(10)) >> 10); 641 (status & BIT(10)) >> 10);
642 seq_printf(s, "Bit 11: UWB installed: %lu\n",
643 (status & BIT(11)) >> 11);
644 seq_printf(s, "Bit 12: WiGig installed: %lu\n",
645 (status & BIT(12)) >> 12);
646
559 seq_printf(s, "Bit 16: Hardware switch is on: %lu\n", 647 seq_printf(s, "Bit 16: Hardware switch is on: %lu\n",
560 (status & BIT(16)) >> 16); 648 (status & BIT(16)) >> 16);
561 seq_printf(s, "Bit 17: Wifi is blocked: %lu\n", 649 seq_printf(s, "Bit 17: Wifi is blocked: %lu\n",
@@ -564,6 +652,10 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
564 (status & BIT(18)) >> 18); 652 (status & BIT(18)) >> 18);
565 seq_printf(s, "Bit 19: WWAN is blocked: %lu\n", 653 seq_printf(s, "Bit 19: WWAN is blocked: %lu\n",
566 (status & BIT(19)) >> 19); 654 (status & BIT(19)) >> 19);
655 seq_printf(s, "Bit 20: UWB is blocked: %lu\n",
656 (status & BIT(20)) >> 20);
657 seq_printf(s, "Bit 21: WiGig is blocked: %lu\n",
658 (status & BIT(21)) >> 21);
567 659
568 seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state); 660 seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state);
569 seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n", 661 seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n",
@@ -572,6 +664,10 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
572 (hwswitch_state & BIT(1)) >> 1); 664 (hwswitch_state & BIT(1)) >> 1);
573 seq_printf(s, "Bit 2 : WWAN controlled by switch: %lu\n", 665 seq_printf(s, "Bit 2 : WWAN controlled by switch: %lu\n",
574 (hwswitch_state & BIT(2)) >> 2); 666 (hwswitch_state & BIT(2)) >> 2);
667 seq_printf(s, "Bit 3 : UWB controlled by switch: %lu\n",
668 (hwswitch_state & BIT(3)) >> 3);
669 seq_printf(s, "Bit 4 : WiGig controlled by switch: %lu\n",
670 (hwswitch_state & BIT(4)) >> 4);
575 seq_printf(s, "Bit 7 : Wireless switch config locked: %lu\n", 671 seq_printf(s, "Bit 7 : Wireless switch config locked: %lu\n",
576 (hwswitch_state & BIT(7)) >> 7); 672 (hwswitch_state & BIT(7)) >> 7);
577 seq_printf(s, "Bit 8 : Wifi locator enabled: %lu\n", 673 seq_printf(s, "Bit 8 : Wifi locator enabled: %lu\n",
@@ -1972,12 +2068,11 @@ static int __init dell_init(void)
1972 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr 2068 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
1973 * is passed to SMI handler. 2069 * is passed to SMI handler.
1974 */ 2070 */
1975 bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32); 2071 buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
1976 if (!bufferpage) { 2072 if (!buffer) {
1977 ret = -ENOMEM; 2073 ret = -ENOMEM;
1978 goto fail_buffer; 2074 goto fail_buffer;
1979 } 2075 }
1980 buffer = page_address(bufferpage);
1981 2076
1982 ret = dell_setup_rfkill(); 2077 ret = dell_setup_rfkill();
1983 2078
@@ -2034,7 +2129,7 @@ static int __init dell_init(void)
2034fail_backlight: 2129fail_backlight:
2035 dell_cleanup_rfkill(); 2130 dell_cleanup_rfkill();
2036fail_rfkill: 2131fail_rfkill:
2037 free_page((unsigned long)bufferpage); 2132 free_page((unsigned long)buffer);
2038fail_buffer: 2133fail_buffer:
2039 platform_device_del(platform_device); 2134 platform_device_del(platform_device);
2040fail_platform_device2: 2135fail_platform_device2:
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
new file mode 100644
index 000000000000..d734763dab69
--- /dev/null
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -0,0 +1,767 @@
1/*
2 * intel_pmc_ipc.c: Driver for the Intel PMC IPC mechanism
3 *
4 * (C) Copyright 2014-2015 Intel Corporation
5 *
6 * This driver is based on Intel SCU IPC driver(intel_scu_opc.c) by
7 * Sreedhara DS <sreedhara.ds@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
12 * of the License.
13 *
14 * PMC running in ARC processor communicates with other entity running in IA
15 * core through IPC mechanism which in turn messaging between IA core ad PMC.
16 */
17
18#include <linux/module.h>
19#include <linux/delay.h>
20#include <linux/errno.h>
21#include <linux/init.h>
22#include <linux/device.h>
23#include <linux/pm.h>
24#include <linux/pci.h>
25#include <linux/platform_device.h>
26#include <linux/interrupt.h>
27#include <linux/pm_qos.h>
28#include <linux/kernel.h>
29#include <linux/bitops.h>
30#include <linux/sched.h>
31#include <linux/atomic.h>
32#include <linux/notifier.h>
33#include <linux/suspend.h>
34#include <linux/acpi.h>
35#include <asm/intel_pmc_ipc.h>
36#include <linux/mfd/lpc_ich.h>
37
38/*
39 * IPC registers
40 * The IA write to IPC_CMD command register triggers an interrupt to the ARC,
41 * The ARC handles the interrupt and services it, writing optional data to
42 * the IPC1 registers, updates the IPC_STS response register with the status.
43 */
44#define IPC_CMD 0x0
45#define IPC_CMD_MSI 0x100
46#define IPC_CMD_SIZE 16
47#define IPC_CMD_SUBCMD 12
48#define IPC_STATUS 0x04
49#define IPC_STATUS_IRQ 0x4
50#define IPC_STATUS_ERR 0x2
51#define IPC_STATUS_BUSY 0x1
52#define IPC_SPTR 0x08
53#define IPC_DPTR 0x0C
54#define IPC_WRITE_BUFFER 0x80
55#define IPC_READ_BUFFER 0x90
56
57/*
58 * 16-byte buffer for sending data associated with IPC command.
59 */
60#define IPC_DATA_BUFFER_SIZE 16
61
62#define IPC_LOOP_CNT 3000000
63#define IPC_MAX_SEC 3
64
65#define IPC_TRIGGER_MODE_IRQ true
66
67/* exported resources from IFWI */
68#define PLAT_RESOURCE_IPC_INDEX 0
69#define PLAT_RESOURCE_IPC_SIZE 0x1000
70#define PLAT_RESOURCE_GCR_SIZE 0x1000
71#define PLAT_RESOURCE_PUNIT_DATA_INDEX 1
72#define PLAT_RESOURCE_PUNIT_INTER_INDEX 2
73#define PLAT_RESOURCE_ACPI_IO_INDEX 0
74
75/*
76 * BIOS does not create an ACPI device for each PMC function,
77 * but exports multiple resources from one ACPI device(IPC) for
78 * multiple functions. This driver is responsible to create a
79 * platform device and to export resources for those functions.
80 */
81#define TCO_DEVICE_NAME "iTCO_wdt"
82#define SMI_EN_OFFSET 0x30
83#define SMI_EN_SIZE 4
84#define TCO_BASE_OFFSET 0x60
85#define TCO_REGS_SIZE 16
86#define PUNIT_DEVICE_NAME "intel_punit_ipc"
87
88static const int iTCO_version = 3;
89
90static struct intel_pmc_ipc_dev {
91 struct device *dev;
92 void __iomem *ipc_base;
93 bool irq_mode;
94 int irq;
95 int cmd;
96 struct completion cmd_complete;
97
98 /* The following PMC BARs share the same ACPI device with the IPC */
99 void *acpi_io_base;
100 int acpi_io_size;
101 struct platform_device *tco_dev;
102
103 /* gcr */
104 void *gcr_base;
105 int gcr_size;
106
107 /* punit */
108 void *punit_base;
109 int punit_size;
110 void *punit_base2;
111 int punit_size2;
112 struct platform_device *punit_dev;
113} ipcdev;
114
115static char *ipc_err_sources[] = {
116 [IPC_ERR_NONE] =
117 "no error",
118 [IPC_ERR_CMD_NOT_SUPPORTED] =
119 "command not supported",
120 [IPC_ERR_CMD_NOT_SERVICED] =
121 "command not serviced",
122 [IPC_ERR_UNABLE_TO_SERVICE] =
123 "unable to service",
124 [IPC_ERR_CMD_INVALID] =
125 "command invalid",
126 [IPC_ERR_CMD_FAILED] =
127 "command failed",
128 [IPC_ERR_EMSECURITY] =
129 "Invalid Battery",
130 [IPC_ERR_UNSIGNEDKERNEL] =
131 "Unsigned kernel",
132};
133
134/* Prevent concurrent calls to the PMC */
135static DEFINE_MUTEX(ipclock);
136
137static inline void ipc_send_command(u32 cmd)
138{
139 ipcdev.cmd = cmd;
140 if (ipcdev.irq_mode) {
141 reinit_completion(&ipcdev.cmd_complete);
142 cmd |= IPC_CMD_MSI;
143 }
144 writel(cmd, ipcdev.ipc_base + IPC_CMD);
145}
146
147static inline u32 ipc_read_status(void)
148{
149 return readl(ipcdev.ipc_base + IPC_STATUS);
150}
151
152static inline void ipc_data_writel(u32 data, u32 offset)
153{
154 writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset);
155}
156
157static inline u8 ipc_data_readb(u32 offset)
158{
159 return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
160}
161
162static inline u32 ipc_data_readl(u32 offset)
163{
164 return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
165}
166
167static int intel_pmc_ipc_check_status(void)
168{
169 int status;
170 int ret = 0;
171
172 if (ipcdev.irq_mode) {
173 if (0 == wait_for_completion_timeout(
174 &ipcdev.cmd_complete, IPC_MAX_SEC * HZ))
175 ret = -ETIMEDOUT;
176 } else {
177 int loop_count = IPC_LOOP_CNT;
178
179 while ((ipc_read_status() & IPC_STATUS_BUSY) && --loop_count)
180 udelay(1);
181 if (loop_count == 0)
182 ret = -ETIMEDOUT;
183 }
184
185 status = ipc_read_status();
186 if (ret == -ETIMEDOUT) {
187 dev_err(ipcdev.dev,
188 "IPC timed out, TS=0x%x, CMD=0x%x\n",
189 status, ipcdev.cmd);
190 return ret;
191 }
192
193 if (status & IPC_STATUS_ERR) {
194 int i;
195
196 ret = -EIO;
197 i = (status >> IPC_CMD_SIZE) & 0xFF;
198 if (i < ARRAY_SIZE(ipc_err_sources))
199 dev_err(ipcdev.dev,
200 "IPC failed: %s, STS=0x%x, CMD=0x%x\n",
201 ipc_err_sources[i], status, ipcdev.cmd);
202 else
203 dev_err(ipcdev.dev,
204 "IPC failed: unknown, STS=0x%x, CMD=0x%x\n",
205 status, ipcdev.cmd);
206 if ((i == IPC_ERR_UNSIGNEDKERNEL) || (i == IPC_ERR_EMSECURITY))
207 ret = -EACCES;
208 }
209
210 return ret;
211}
212
213/*
214 * intel_pmc_ipc_simple_command
215 * @cmd: command
216 * @sub: sub type
217 */
218int intel_pmc_ipc_simple_command(int cmd, int sub)
219{
220 int ret;
221
222 mutex_lock(&ipclock);
223 if (ipcdev.dev == NULL) {
224 mutex_unlock(&ipclock);
225 return -ENODEV;
226 }
227 ipc_send_command(sub << IPC_CMD_SUBCMD | cmd);
228 ret = intel_pmc_ipc_check_status();
229 mutex_unlock(&ipclock);
230
231 return ret;
232}
233EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command);
234
235/*
236 * intel_pmc_ipc_raw_cmd
237 * @cmd: command
238 * @sub: sub type
239 * @in: input data
240 * @inlen: input length in bytes
241 * @out: output data
242 * @outlen: output length in dwords
243 * @sptr: data writing to SPTR register
244 * @dptr: data writing to DPTR register
245 */
246int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
247 u32 outlen, u32 dptr, u32 sptr)
248{
249 u32 wbuf[4] = { 0 };
250 int ret;
251 int i;
252
253 if (inlen > IPC_DATA_BUFFER_SIZE || outlen > IPC_DATA_BUFFER_SIZE / 4)
254 return -EINVAL;
255
256 mutex_lock(&ipclock);
257 if (ipcdev.dev == NULL) {
258 mutex_unlock(&ipclock);
259 return -ENODEV;
260 }
261 memcpy(wbuf, in, inlen);
262 writel(dptr, ipcdev.ipc_base + IPC_DPTR);
263 writel(sptr, ipcdev.ipc_base + IPC_SPTR);
264 /* The input data register is 32bit register and inlen is in Byte */
265 for (i = 0; i < ((inlen + 3) / 4); i++)
266 ipc_data_writel(wbuf[i], 4 * i);
267 ipc_send_command((inlen << IPC_CMD_SIZE) |
268 (sub << IPC_CMD_SUBCMD) | cmd);
269 ret = intel_pmc_ipc_check_status();
270 if (!ret) {
271 /* out is read from 32bit register and outlen is in 32bit */
272 for (i = 0; i < outlen; i++)
273 *out++ = ipc_data_readl(4 * i);
274 }
275 mutex_unlock(&ipclock);
276
277 return ret;
278}
279EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd);
280
281/*
282 * intel_pmc_ipc_command
283 * @cmd: command
284 * @sub: sub type
285 * @in: input data
286 * @inlen: input length in bytes
287 * @out: output data
288 * @outlen: output length in dwords
289 */
290int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
291 u32 *out, u32 outlen)
292{
293 return intel_pmc_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0);
294}
295EXPORT_SYMBOL_GPL(intel_pmc_ipc_command);
296
297static irqreturn_t ioc(int irq, void *dev_id)
298{
299 int status;
300
301 if (ipcdev.irq_mode) {
302 status = ipc_read_status();
303 writel(status | IPC_STATUS_IRQ, ipcdev.ipc_base + IPC_STATUS);
304 }
305 complete(&ipcdev.cmd_complete);
306
307 return IRQ_HANDLED;
308}
309
310static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
311{
312 resource_size_t pci_resource;
313 int ret;
314 int len;
315
316 ipcdev.dev = &pci_dev_get(pdev)->dev;
317 ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ;
318
319 ret = pci_enable_device(pdev);
320 if (ret)
321 return ret;
322
323 ret = pci_request_regions(pdev, "intel_pmc_ipc");
324 if (ret)
325 return ret;
326
327 pci_resource = pci_resource_start(pdev, 0);
328 len = pci_resource_len(pdev, 0);
329 if (!pci_resource || !len) {
330 dev_err(&pdev->dev, "Failed to get resource\n");
331 return -ENOMEM;
332 }
333
334 init_completion(&ipcdev.cmd_complete);
335
336 if (request_irq(pdev->irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) {
337 dev_err(&pdev->dev, "Failed to request irq\n");
338 return -EBUSY;
339 }
340
341 ipcdev.ipc_base = ioremap_nocache(pci_resource, len);
342 if (!ipcdev.ipc_base) {
343 dev_err(&pdev->dev, "Failed to ioremap ipc base\n");
344 free_irq(pdev->irq, &ipcdev);
345 ret = -ENOMEM;
346 }
347
348 return ret;
349}
350
351static void ipc_pci_remove(struct pci_dev *pdev)
352{
353 free_irq(pdev->irq, &ipcdev);
354 pci_release_regions(pdev);
355 pci_dev_put(pdev);
356 iounmap(ipcdev.ipc_base);
357 ipcdev.dev = NULL;
358}
359
360static const struct pci_device_id ipc_pci_ids[] = {
361 {PCI_VDEVICE(INTEL, 0x0a94), 0},
362 {PCI_VDEVICE(INTEL, 0x1a94), 0},
363 { 0,}
364};
365MODULE_DEVICE_TABLE(pci, ipc_pci_ids);
366
367static struct pci_driver ipc_pci_driver = {
368 .name = "intel_pmc_ipc",
369 .id_table = ipc_pci_ids,
370 .probe = ipc_pci_probe,
371 .remove = ipc_pci_remove,
372};
373
374static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev,
375 struct device_attribute *attr,
376 const char *buf, size_t count)
377{
378 int subcmd;
379 int cmd;
380 int ret;
381
382 ret = sscanf(buf, "%d %d", &cmd, &subcmd);
383 if (ret != 2) {
384 dev_err(dev, "Error args\n");
385 return -EINVAL;
386 }
387
388 ret = intel_pmc_ipc_simple_command(cmd, subcmd);
389 if (ret) {
390 dev_err(dev, "command %d error with %d\n", cmd, ret);
391 return ret;
392 }
393 return (ssize_t)count;
394}
395
396static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev,
397 struct device_attribute *attr,
398 const char *buf, size_t count)
399{
400 unsigned long val;
401 int subcmd;
402 int ret;
403
404 if (kstrtoul(buf, 0, &val))
405 return -EINVAL;
406
407 if (val)
408 subcmd = 1;
409 else
410 subcmd = 0;
411 ret = intel_pmc_ipc_simple_command(PMC_IPC_NORTHPEAK_CTRL, subcmd);
412 if (ret) {
413 dev_err(dev, "command north %d error with %d\n", subcmd, ret);
414 return ret;
415 }
416 return (ssize_t)count;
417}
418
419static DEVICE_ATTR(simplecmd, S_IWUSR,
420 NULL, intel_pmc_ipc_simple_cmd_store);
421static DEVICE_ATTR(northpeak, S_IWUSR,
422 NULL, intel_pmc_ipc_northpeak_store);
423
424static struct attribute *intel_ipc_attrs[] = {
425 &dev_attr_northpeak.attr,
426 &dev_attr_simplecmd.attr,
427 NULL
428};
429
430static const struct attribute_group intel_ipc_group = {
431 .attrs = intel_ipc_attrs,
432};
433
434#define PUNIT_RESOURCE_INTER 1
435static struct resource punit_res[] = {
436 /* Punit */
437 {
438 .flags = IORESOURCE_MEM,
439 },
440 {
441 .flags = IORESOURCE_MEM,
442 },
443};
444
445#define TCO_RESOURCE_ACPI_IO 0
446#define TCO_RESOURCE_SMI_EN_IO 1
447#define TCO_RESOURCE_GCR_MEM 2
448static struct resource tco_res[] = {
449 /* ACPI - TCO */
450 {
451 .flags = IORESOURCE_IO,
452 },
453 /* ACPI - SMI */
454 {
455 .flags = IORESOURCE_IO,
456 },
457 /* GCS */
458 {
459 .flags = IORESOURCE_MEM,
460 },
461};
462
463static struct lpc_ich_info tco_info = {
464 .name = "Apollo Lake SoC",
465 .iTCO_version = 3,
466};
467
468static int ipc_create_punit_device(void)
469{
470 struct platform_device *pdev;
471 struct resource *res;
472 int ret;
473
474 pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1);
475 if (!pdev) {
476 dev_err(ipcdev.dev, "Failed to alloc punit platform device\n");
477 return -ENOMEM;
478 }
479
480 pdev->dev.parent = ipcdev.dev;
481
482 res = punit_res;
483 res->start = (resource_size_t)ipcdev.punit_base;
484 res->end = res->start + ipcdev.punit_size - 1;
485
486 res = punit_res + PUNIT_RESOURCE_INTER;
487 res->start = (resource_size_t)ipcdev.punit_base2;
488 res->end = res->start + ipcdev.punit_size2 - 1;
489
490 ret = platform_device_add_resources(pdev, punit_res,
491 ARRAY_SIZE(punit_res));
492 if (ret) {
493 dev_err(ipcdev.dev, "Failed to add platform punit resources\n");
494 goto err;
495 }
496
497 ret = platform_device_add(pdev);
498 if (ret) {
499 dev_err(ipcdev.dev, "Failed to add punit platform device\n");
500 goto err;
501 }
502 ipcdev.punit_dev = pdev;
503
504 return 0;
505err:
506 platform_device_put(pdev);
507 return ret;
508}
509
510static int ipc_create_tco_device(void)
511{
512 struct platform_device *pdev;
513 struct resource *res;
514 int ret;
515
516 pdev = platform_device_alloc(TCO_DEVICE_NAME, -1);
517 if (!pdev) {
518 dev_err(ipcdev.dev, "Failed to alloc tco platform device\n");
519 return -ENOMEM;
520 }
521
522 pdev->dev.parent = ipcdev.dev;
523
524 res = tco_res + TCO_RESOURCE_ACPI_IO;
525 res->start = (resource_size_t)ipcdev.acpi_io_base + TCO_BASE_OFFSET;
526 res->end = res->start + TCO_REGS_SIZE - 1;
527
528 res = tco_res + TCO_RESOURCE_SMI_EN_IO;
529 res->start = (resource_size_t)ipcdev.acpi_io_base + SMI_EN_OFFSET;
530 res->end = res->start + SMI_EN_SIZE - 1;
531
532 res = tco_res + TCO_RESOURCE_GCR_MEM;
533 res->start = (resource_size_t)ipcdev.gcr_base;
534 res->end = res->start + ipcdev.gcr_size - 1;
535
536 ret = platform_device_add_resources(pdev, tco_res, ARRAY_SIZE(tco_res));
537 if (ret) {
538 dev_err(ipcdev.dev, "Failed to add tco platform resources\n");
539 goto err;
540 }
541
542 ret = platform_device_add_data(pdev, &tco_info,
543 sizeof(struct lpc_ich_info));
544 if (ret) {
545 dev_err(ipcdev.dev, "Failed to add tco platform data\n");
546 goto err;
547 }
548
549 ret = platform_device_add(pdev);
550 if (ret) {
551 dev_err(ipcdev.dev, "Failed to add tco platform device\n");
552 goto err;
553 }
554 ipcdev.tco_dev = pdev;
555
556 return 0;
557err:
558 platform_device_put(pdev);
559 return ret;
560}
561
562static int ipc_create_pmc_devices(void)
563{
564 int ret;
565
566 ret = ipc_create_tco_device();
567 if (ret) {
568 dev_err(ipcdev.dev, "Failed to add tco platform device\n");
569 return ret;
570 }
571 ret = ipc_create_punit_device();
572 if (ret) {
573 dev_err(ipcdev.dev, "Failed to add punit platform device\n");
574 platform_device_unregister(ipcdev.tco_dev);
575 }
576 return ret;
577}
578
579static int ipc_plat_get_res(struct platform_device *pdev)
580{
581 struct resource *res;
582 void __iomem *addr;
583 int size;
584
585 res = platform_get_resource(pdev, IORESOURCE_IO,
586 PLAT_RESOURCE_ACPI_IO_INDEX);
587 if (!res) {
588 dev_err(&pdev->dev, "Failed to get io resource\n");
589 return -ENXIO;
590 }
591 size = resource_size(res);
592 ipcdev.acpi_io_base = (void *)res->start;
593 ipcdev.acpi_io_size = size;
594 dev_info(&pdev->dev, "io res: %llx %x\n",
595 (long long)res->start, (int)resource_size(res));
596
597 res = platform_get_resource(pdev, IORESOURCE_MEM,
598 PLAT_RESOURCE_PUNIT_DATA_INDEX);
599 if (!res) {
600 dev_err(&pdev->dev, "Failed to get punit resource\n");
601 return -ENXIO;
602 }
603 size = resource_size(res);
604 ipcdev.punit_base = (void *)res->start;
605 ipcdev.punit_size = size;
606 dev_info(&pdev->dev, "punit data res: %llx %x\n",
607 (long long)res->start, (int)resource_size(res));
608
609 res = platform_get_resource(pdev, IORESOURCE_MEM,
610 PLAT_RESOURCE_PUNIT_INTER_INDEX);
611 if (!res) {
612 dev_err(&pdev->dev, "Failed to get punit inter resource\n");
613 return -ENXIO;
614 }
615 size = resource_size(res);
616 ipcdev.punit_base2 = (void *)res->start;
617 ipcdev.punit_size2 = size;
618 dev_info(&pdev->dev, "punit interface res: %llx %x\n",
619 (long long)res->start, (int)resource_size(res));
620
621 res = platform_get_resource(pdev, IORESOURCE_MEM,
622 PLAT_RESOURCE_IPC_INDEX);
623 if (!res) {
624 dev_err(&pdev->dev, "Failed to get ipc resource\n");
625 return -ENXIO;
626 }
627 size = PLAT_RESOURCE_IPC_SIZE;
628 if (!request_mem_region(res->start, size, pdev->name)) {
629 dev_err(&pdev->dev, "Failed to request ipc resource\n");
630 return -EBUSY;
631 }
632 addr = ioremap_nocache(res->start, size);
633 if (!addr) {
634 dev_err(&pdev->dev, "I/O memory remapping failed\n");
635 release_mem_region(res->start, size);
636 return -ENOMEM;
637 }
638 ipcdev.ipc_base = addr;
639
640 ipcdev.gcr_base = (void *)(res->start + size);
641 ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE;
642 dev_info(&pdev->dev, "ipc res: %llx %x\n",
643 (long long)res->start, (int)resource_size(res));
644
645 return 0;
646}
647
648#ifdef CONFIG_ACPI
649static const struct acpi_device_id ipc_acpi_ids[] = {
650 { "INT34D2", 0},
651 { }
652};
653MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids);
654#endif
655
656static int ipc_plat_probe(struct platform_device *pdev)
657{
658 struct resource *res;
659 int ret;
660
661 ipcdev.dev = &pdev->dev;
662 ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ;
663 init_completion(&ipcdev.cmd_complete);
664
665 ipcdev.irq = platform_get_irq(pdev, 0);
666 if (ipcdev.irq < 0) {
667 dev_err(&pdev->dev, "Failed to get irq\n");
668 return -EINVAL;
669 }
670
671 ret = ipc_plat_get_res(pdev);
672 if (ret) {
673 dev_err(&pdev->dev, "Failed to request resource\n");
674 return ret;
675 }
676
677 ret = ipc_create_pmc_devices();
678 if (ret) {
679 dev_err(&pdev->dev, "Failed to create pmc devices\n");
680 goto err_device;
681 }
682
683 if (request_irq(ipcdev.irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) {
684 dev_err(&pdev->dev, "Failed to request irq\n");
685 ret = -EBUSY;
686 goto err_irq;
687 }
688
689 ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
690 if (ret) {
691 dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
692 ret);
693 goto err_sys;
694 }
695
696 return 0;
697err_sys:
698 free_irq(ipcdev.irq, &ipcdev);
699err_irq:
700 platform_device_unregister(ipcdev.tco_dev);
701 platform_device_unregister(ipcdev.punit_dev);
702err_device:
703 iounmap(ipcdev.ipc_base);
704 res = platform_get_resource(pdev, IORESOURCE_MEM,
705 PLAT_RESOURCE_IPC_INDEX);
706 if (res)
707 release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE);
708 return ret;
709}
710
711static int ipc_plat_remove(struct platform_device *pdev)
712{
713 struct resource *res;
714
715 sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
716 free_irq(ipcdev.irq, &ipcdev);
717 platform_device_unregister(ipcdev.tco_dev);
718 platform_device_unregister(ipcdev.punit_dev);
719 iounmap(ipcdev.ipc_base);
720 res = platform_get_resource(pdev, IORESOURCE_MEM,
721 PLAT_RESOURCE_IPC_INDEX);
722 if (res)
723 release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE);
724 ipcdev.dev = NULL;
725 return 0;
726}
727
728static struct platform_driver ipc_plat_driver = {
729 .remove = ipc_plat_remove,
730 .probe = ipc_plat_probe,
731 .driver = {
732 .name = "pmc-ipc-plat",
733 .acpi_match_table = ACPI_PTR(ipc_acpi_ids),
734 },
735};
736
737static int __init intel_pmc_ipc_init(void)
738{
739 int ret;
740
741 ret = platform_driver_register(&ipc_plat_driver);
742 if (ret) {
743 pr_err("Failed to register PMC ipc platform driver\n");
744 return ret;
745 }
746 ret = pci_register_driver(&ipc_pci_driver);
747 if (ret) {
748 pr_err("Failed to register PMC ipc pci driver\n");
749 platform_driver_unregister(&ipc_plat_driver);
750 return ret;
751 }
752 return ret;
753}
754
755static void __exit intel_pmc_ipc_exit(void)
756{
757 pci_unregister_driver(&ipc_pci_driver);
758 platform_driver_unregister(&ipc_plat_driver);
759}
760
761MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>");
762MODULE_DESCRIPTION("Intel PMC IPC driver");
763MODULE_LICENSE("GPL");
764
765/* Some modules are dependent on this, so init earlier */
766fs_initcall(intel_pmc_ipc_init);
767module_exit(intel_pmc_ipc_exit);
diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c
index e36542564131..89aa976f0ab2 100644
--- a/drivers/platform/x86/tc1100-wmi.c
+++ b/drivers/platform/x86/tc1100-wmi.c
@@ -82,7 +82,7 @@ static int get_state(u32 *out, u8 instance)
82 tmp = 0; 82 tmp = 0;
83 } 83 }
84 84
85 if (result.length > 0 && result.pointer) 85 if (result.length > 0)
86 kfree(result.pointer); 86 kfree(result.pointer);
87 87
88 switch (instance) { 88 switch (instance) {