diff options
| -rw-r--r-- | drivers/platform/x86/intel_pmc_ipc.c | 398 |
1 files changed, 139 insertions, 259 deletions
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index e03fa31446ca..e36144c337cd 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
| 23 | #include <linux/mfd/core.h> | ||
| 23 | #include <linux/pm.h> | 24 | #include <linux/pm.h> |
| 24 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
| 25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
| @@ -88,6 +89,7 @@ | |||
| 88 | #define PLAT_RESOURCE_ISP_IFACE_INDEX 5 | 89 | #define PLAT_RESOURCE_ISP_IFACE_INDEX 5 |
| 89 | #define PLAT_RESOURCE_GTD_DATA_INDEX 6 | 90 | #define PLAT_RESOURCE_GTD_DATA_INDEX 6 |
| 90 | #define PLAT_RESOURCE_GTD_IFACE_INDEX 7 | 91 | #define PLAT_RESOURCE_GTD_IFACE_INDEX 7 |
| 92 | #define PLAT_RESOURCE_MEM_MAX_INDEX 8 | ||
| 91 | #define PLAT_RESOURCE_ACPI_IO_INDEX 0 | 93 | #define PLAT_RESOURCE_ACPI_IO_INDEX 0 |
| 92 | 94 | ||
| 93 | /* | 95 | /* |
| @@ -106,8 +108,6 @@ | |||
| 106 | #define TELEM_SSRAM_SIZE 240 | 108 | #define TELEM_SSRAM_SIZE 240 |
| 107 | #define TELEM_PMC_SSRAM_OFFSET 0x1B00 | 109 | #define TELEM_PMC_SSRAM_OFFSET 0x1B00 |
| 108 | #define TELEM_PUNIT_SSRAM_OFFSET 0x1A00 | 110 | #define TELEM_PUNIT_SSRAM_OFFSET 0x1A00 |
| 109 | #define TCO_PMC_OFFSET 0x8 | ||
| 110 | #define TCO_PMC_SIZE 0x4 | ||
| 111 | 111 | ||
| 112 | /* PMC register bit definitions */ | 112 | /* PMC register bit definitions */ |
| 113 | 113 | ||
| @@ -124,26 +124,10 @@ static struct intel_pmc_ipc_dev { | |||
| 124 | int cmd; | 124 | int cmd; |
| 125 | struct completion cmd_complete; | 125 | struct completion cmd_complete; |
| 126 | 126 | ||
| 127 | /* The following PMC BARs share the same ACPI device with the IPC */ | ||
| 128 | resource_size_t acpi_io_base; | ||
| 129 | int acpi_io_size; | ||
| 130 | struct platform_device *tco_dev; | ||
| 131 | |||
| 132 | /* gcr */ | 127 | /* gcr */ |
| 133 | void __iomem *gcr_mem_base; | 128 | void __iomem *gcr_mem_base; |
| 134 | bool has_gcr_regs; | 129 | bool has_gcr_regs; |
| 135 | spinlock_t gcr_lock; | 130 | spinlock_t gcr_lock; |
| 136 | |||
| 137 | /* punit */ | ||
| 138 | struct platform_device *punit_dev; | ||
| 139 | |||
| 140 | /* Telemetry */ | ||
| 141 | resource_size_t telem_pmc_ssram_base; | ||
| 142 | resource_size_t telem_punit_ssram_base; | ||
| 143 | int telem_pmc_ssram_size; | ||
| 144 | int telem_punit_ssram_size; | ||
| 145 | u8 telem_res_inval; | ||
| 146 | struct platform_device *telemetry_dev; | ||
| 147 | } ipcdev; | 131 | } ipcdev; |
| 148 | 132 | ||
| 149 | static char *ipc_err_sources[] = { | 133 | static char *ipc_err_sources[] = { |
| @@ -508,7 +492,7 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 508 | ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc", | 492 | ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc", |
| 509 | pmc); | 493 | pmc); |
| 510 | if (ret) { | 494 | if (ret) { |
| 511 | dev_err(&pdev->dev, "Failed to request irq\n"); | 495 | dev_err(&pdev->dev, "Failed to request IRQ\n"); |
| 512 | return ret; | 496 | return ret; |
| 513 | } | 497 | } |
| 514 | 498 | ||
| @@ -593,44 +577,6 @@ static const struct attribute_group intel_ipc_group = { | |||
| 593 | .attrs = intel_ipc_attrs, | 577 | .attrs = intel_ipc_attrs, |
| 594 | }; | 578 | }; |
| 595 | 579 | ||
| 596 | static struct resource punit_res_array[] = { | ||
| 597 | /* Punit BIOS */ | ||
| 598 | { | ||
| 599 | .flags = IORESOURCE_MEM, | ||
| 600 | }, | ||
| 601 | { | ||
| 602 | .flags = IORESOURCE_MEM, | ||
| 603 | }, | ||
| 604 | /* Punit ISP */ | ||
| 605 | { | ||
| 606 | .flags = IORESOURCE_MEM, | ||
| 607 | }, | ||
| 608 | { | ||
| 609 | .flags = IORESOURCE_MEM, | ||
| 610 | }, | ||
| 611 | /* Punit GTD */ | ||
| 612 | { | ||
| 613 | .flags = IORESOURCE_MEM, | ||
| 614 | }, | ||
| 615 | { | ||
| 616 | .flags = IORESOURCE_MEM, | ||
| 617 | }, | ||
| 618 | }; | ||
| 619 | |||
| 620 | #define TCO_RESOURCE_ACPI_IO 0 | ||
| 621 | #define TCO_RESOURCE_SMI_EN_IO 1 | ||
| 622 | #define TCO_RESOURCE_GCR_MEM 2 | ||
| 623 | static struct resource tco_res[] = { | ||
| 624 | /* ACPI - TCO */ | ||
| 625 | { | ||
| 626 | .flags = IORESOURCE_IO, | ||
| 627 | }, | ||
| 628 | /* ACPI - SMI */ | ||
| 629 | { | ||
| 630 | .flags = IORESOURCE_IO, | ||
| 631 | }, | ||
| 632 | }; | ||
| 633 | |||
| 634 | static struct itco_wdt_platform_data tco_info = { | 580 | static struct itco_wdt_platform_data tco_info = { |
| 635 | .name = "Apollo Lake SoC", | 581 | .name = "Apollo Lake SoC", |
| 636 | .version = 5, | 582 | .version = 5, |
| @@ -638,234 +584,177 @@ static struct itco_wdt_platform_data tco_info = { | |||
| 638 | .update_no_reboot_bit = update_no_reboot_bit, | 584 | .update_no_reboot_bit = update_no_reboot_bit, |
| 639 | }; | 585 | }; |
| 640 | 586 | ||
| 641 | #define TELEMETRY_RESOURCE_PUNIT_SSRAM 0 | 587 | static int ipc_create_punit_device(struct platform_device *pdev) |
| 642 | #define TELEMETRY_RESOURCE_PMC_SSRAM 1 | ||
| 643 | static struct resource telemetry_res[] = { | ||
| 644 | /*Telemetry*/ | ||
| 645 | { | ||
| 646 | .flags = IORESOURCE_MEM, | ||
| 647 | }, | ||
| 648 | { | ||
| 649 | .flags = IORESOURCE_MEM, | ||
| 650 | }, | ||
| 651 | }; | ||
| 652 | |||
| 653 | static int ipc_create_punit_device(void) | ||
| 654 | { | 588 | { |
| 655 | struct platform_device *pdev; | 589 | struct resource punit_res[PLAT_RESOURCE_MEM_MAX_INDEX]; |
| 656 | const struct platform_device_info pdevinfo = { | 590 | struct mfd_cell punit_cell; |
| 657 | .parent = ipcdev.dev, | 591 | struct resource *res; |
| 658 | .name = PUNIT_DEVICE_NAME, | 592 | int mindex, pindex = 0; |
| 659 | .id = -1, | 593 | |
| 660 | .res = punit_res_array, | 594 | for (mindex = 0; mindex <= PLAT_RESOURCE_MEM_MAX_INDEX; mindex++) { |
| 661 | .num_res = ARRAY_SIZE(punit_res_array), | 595 | |
| 596 | res = platform_get_resource(pdev, IORESOURCE_MEM, mindex); | ||
| 597 | |||
| 598 | switch (mindex) { | ||
| 599 | /* Get PUNIT resources */ | ||
| 600 | case PLAT_RESOURCE_BIOS_DATA_INDEX: | ||
| 601 | case PLAT_RESOURCE_BIOS_IFACE_INDEX: | ||
| 602 | /* BIOS resources are required, so return error if not | ||
| 603 | * available | ||
| 604 | */ | ||
| 605 | if (!res) { | ||
| 606 | dev_err(&pdev->dev, | ||
| 607 | "Failed to get PUNIT MEM resource %d\n", | ||
| 608 | pindex); | ||
| 609 | return -ENXIO; | ||
| 610 | } | ||
| 611 | case PLAT_RESOURCE_ISP_DATA_INDEX: | ||
| 612 | case PLAT_RESOURCE_ISP_IFACE_INDEX: | ||
| 613 | case PLAT_RESOURCE_GTD_DATA_INDEX: | ||
| 614 | case PLAT_RESOURCE_GTD_IFACE_INDEX: | ||
| 615 | /* if valid resource found, copy the resource to PUNIT | ||
| 616 | * resource | ||
| 617 | */ | ||
| 618 | if (res) | ||
| 619 | memcpy(&punit_res[pindex], res, sizeof(*res)); | ||
| 620 | punit_res[pindex].flags = IORESOURCE_MEM; | ||
| 621 | dev_dbg(&pdev->dev, "PUNIT memory res: %pR\n", | ||
| 622 | &punit_res[pindex]); | ||
| 623 | pindex++; | ||
| 624 | break; | ||
| 662 | }; | 625 | }; |
| 626 | } | ||
| 663 | 627 | ||
| 664 | pdev = platform_device_register_full(&pdevinfo); | 628 | /* Create PUNIT IPC MFD cell */ |
| 665 | if (IS_ERR(pdev)) | 629 | punit_cell.name = PUNIT_DEVICE_NAME; |
| 666 | return PTR_ERR(pdev); | 630 | punit_cell.num_resources = ARRAY_SIZE(punit_res); |
| 667 | 631 | punit_cell.resources = punit_res; | |
| 668 | ipcdev.punit_dev = pdev; | 632 | punit_cell.ignore_resource_conflicts = 1; |
| 669 | 633 | ||
| 670 | return 0; | 634 | return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, |
| 635 | &punit_cell, 1, NULL, 0, NULL); | ||
| 671 | } | 636 | } |
| 672 | 637 | ||
| 673 | static int ipc_create_tco_device(void) | 638 | static int ipc_create_wdt_device(struct platform_device *pdev) |
| 674 | { | 639 | { |
| 675 | struct platform_device *pdev; | 640 | static struct resource wdt_ipc_res[2]; |
| 676 | struct resource *res; | 641 | struct resource *res; |
| 677 | const struct platform_device_info pdevinfo = { | 642 | static struct mfd_cell wdt_cell; |
| 678 | .parent = ipcdev.dev, | ||
| 679 | .name = TCO_DEVICE_NAME, | ||
| 680 | .id = -1, | ||
| 681 | .res = tco_res, | ||
| 682 | .num_res = ARRAY_SIZE(tco_res), | ||
| 683 | .data = &tco_info, | ||
| 684 | .size_data = sizeof(tco_info), | ||
| 685 | }; | ||
| 686 | 643 | ||
| 687 | res = tco_res + TCO_RESOURCE_ACPI_IO; | 644 | /* If we have ACPI based watchdog use that instead, othewise create |
| 688 | res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET; | 645 | * a MFD cell for iTCO watchdog |
| 689 | res->end = res->start + TCO_REGS_SIZE - 1; | 646 | */ |
| 647 | if (acpi_has_watchdog()) | ||
| 648 | return 0; | ||
| 690 | 649 | ||
| 691 | res = tco_res + TCO_RESOURCE_SMI_EN_IO; | 650 | /* Get iTCO watchdog resources */ |
| 692 | res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET; | 651 | res = platform_get_resource(pdev, IORESOURCE_IO, |
| 693 | res->end = res->start + SMI_EN_SIZE - 1; | 652 | PLAT_RESOURCE_ACPI_IO_INDEX); |
| 653 | if (!res) { | ||
| 654 | dev_err(&pdev->dev, "Failed to get WDT resource\n"); | ||
| 655 | return -ENXIO; | ||
| 656 | } | ||
| 694 | 657 | ||
| 695 | pdev = platform_device_register_full(&pdevinfo); | 658 | wdt_ipc_res[0].start = res->start + TCO_BASE_OFFSET; |
| 696 | if (IS_ERR(pdev)) | 659 | wdt_ipc_res[0].end = res->start + |
| 697 | return PTR_ERR(pdev); | 660 | TCO_BASE_OFFSET + TCO_REGS_SIZE - 1; |
| 661 | wdt_ipc_res[0].flags = IORESOURCE_IO; | ||
| 662 | wdt_ipc_res[1].start = res->start + SMI_EN_OFFSET; | ||
| 663 | wdt_ipc_res[1].end = res->start + | ||
| 664 | SMI_EN_OFFSET + SMI_EN_SIZE - 1; | ||
| 665 | wdt_ipc_res[1].flags = IORESOURCE_IO; | ||
| 698 | 666 | ||
| 699 | ipcdev.tco_dev = pdev; | 667 | dev_dbg(&pdev->dev, "watchdog res 0: %pR\n", &wdt_ipc_res[0]); |
| 668 | dev_dbg(&pdev->dev, "watchdog res 1: %pR\n", &wdt_ipc_res[1]); | ||
| 700 | 669 | ||
| 701 | return 0; | 670 | wdt_cell.name = TCO_DEVICE_NAME; |
| 671 | wdt_cell.platform_data = &tco_info; | ||
| 672 | wdt_cell.pdata_size = sizeof(tco_info); | ||
| 673 | wdt_cell.num_resources = ARRAY_SIZE(wdt_ipc_res); | ||
| 674 | wdt_cell.resources = wdt_ipc_res; | ||
| 675 | wdt_cell.ignore_resource_conflicts = 1; | ||
| 676 | |||
| 677 | return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, | ||
| 678 | &wdt_cell, 1, NULL, 0, NULL); | ||
| 702 | } | 679 | } |
| 703 | 680 | ||
| 704 | static int ipc_create_telemetry_device(void) | 681 | static int ipc_create_telemetry_device(struct platform_device *pdev) |
| 705 | { | 682 | { |
| 706 | struct platform_device *pdev; | 683 | struct resource telemetry_ipc_res[2]; |
| 684 | struct mfd_cell telemetry_cell; | ||
| 707 | struct resource *res; | 685 | struct resource *res; |
| 708 | const struct platform_device_info pdevinfo = { | ||
| 709 | .parent = ipcdev.dev, | ||
| 710 | .name = TELEMETRY_DEVICE_NAME, | ||
| 711 | .id = -1, | ||
| 712 | .res = telemetry_res, | ||
| 713 | .num_res = ARRAY_SIZE(telemetry_res), | ||
| 714 | }; | ||
| 715 | 686 | ||
| 716 | res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM; | 687 | /* Get telemetry resources */ |
| 717 | res->start = ipcdev.telem_punit_ssram_base; | 688 | res = platform_get_resource(pdev, IORESOURCE_MEM, |
| 718 | res->end = res->start + ipcdev.telem_punit_ssram_size - 1; | 689 | PLAT_RESOURCE_TELEM_SSRAM_INDEX); |
| 690 | if (!res) { | ||
| 691 | dev_err(&pdev->dev, "Failed to get telemetry resource\n"); | ||
| 692 | return -ENXIO; | ||
| 693 | } | ||
| 719 | 694 | ||
| 720 | res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM; | 695 | telemetry_ipc_res[0].start = res->start + TELEM_PUNIT_SSRAM_OFFSET; |
| 721 | res->start = ipcdev.telem_pmc_ssram_base; | 696 | telemetry_ipc_res[0].end = res->start + |
| 722 | res->end = res->start + ipcdev.telem_pmc_ssram_size - 1; | 697 | TELEM_PUNIT_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1; |
| 698 | telemetry_ipc_res[0].flags = IORESOURCE_MEM; | ||
| 699 | telemetry_ipc_res[1].start = res->start + TELEM_PMC_SSRAM_OFFSET; | ||
| 700 | telemetry_ipc_res[1].end = res->start + | ||
| 701 | TELEM_PMC_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1; | ||
| 702 | telemetry_ipc_res[1].flags = IORESOURCE_MEM; | ||
| 723 | 703 | ||
| 724 | pdev = platform_device_register_full(&pdevinfo); | 704 | dev_dbg(&pdev->dev, "Telemetry res 0: %pR\n", &telemetry_ipc_res[0]); |
| 725 | if (IS_ERR(pdev)) | 705 | dev_dbg(&pdev->dev, "Telemetry res 1: %pR\n", &telemetry_ipc_res[1]); |
| 726 | return PTR_ERR(pdev); | ||
| 727 | 706 | ||
| 728 | ipcdev.telemetry_dev = pdev; | 707 | telemetry_cell.name = TELEMETRY_DEVICE_NAME; |
| 708 | telemetry_cell.num_resources = ARRAY_SIZE(telemetry_ipc_res); | ||
| 709 | telemetry_cell.resources = telemetry_ipc_res; | ||
| 710 | telemetry_cell.ignore_resource_conflicts = 1; | ||
| 729 | 711 | ||
| 730 | return 0; | 712 | return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, |
| 713 | &telemetry_cell, 1, NULL, 0, NULL); | ||
| 731 | } | 714 | } |
| 732 | 715 | ||
| 733 | static int ipc_create_pmc_devices(void) | 716 | static int ipc_create_pmc_devices(struct platform_device *pdev) |
| 734 | { | 717 | { |
| 735 | int ret; | 718 | int ret; |
| 736 | 719 | ||
| 737 | /* If we have ACPI based watchdog use that instead */ | 720 | ret = ipc_create_punit_device(pdev); |
| 738 | if (!acpi_has_watchdog()) { | 721 | if (ret < 0) |
| 739 | ret = ipc_create_tco_device(); | 722 | return ret; |
| 740 | if (ret) { | ||
| 741 | dev_err(ipcdev.dev, "Failed to add tco platform device\n"); | ||
| 742 | return ret; | ||
| 743 | } | ||
| 744 | } | ||
| 745 | 723 | ||
| 746 | ret = ipc_create_punit_device(); | 724 | ret = ipc_create_wdt_device(pdev); |
| 747 | if (ret) { | 725 | if (ret < 0) |
| 748 | dev_err(ipcdev.dev, "Failed to add punit platform device\n"); | 726 | return ret; |
| 749 | platform_device_unregister(ipcdev.tco_dev); | ||
| 750 | } | ||
| 751 | 727 | ||
| 752 | if (!ipcdev.telem_res_inval) { | 728 | ret = ipc_create_telemetry_device(pdev); |
| 753 | ret = ipc_create_telemetry_device(); | 729 | if (ret < 0) |
| 754 | if (ret) | 730 | return ret; |
| 755 | dev_warn(ipcdev.dev, | ||
| 756 | "Failed to add telemetry platform device\n"); | ||
| 757 | } | ||
| 758 | 731 | ||
| 759 | return ret; | 732 | return 0; |
| 760 | } | 733 | } |
| 761 | 734 | ||
| 762 | static int ipc_plat_get_res(struct platform_device *pdev) | 735 | static int ipc_plat_get_res(struct platform_device *pdev) |
| 763 | { | 736 | { |
| 764 | struct resource *res, *punit_res; | 737 | struct resource *res; |
| 765 | void __iomem *addr; | 738 | void __iomem *addr; |
| 766 | int size; | ||
| 767 | |||
| 768 | res = platform_get_resource(pdev, IORESOURCE_IO, | ||
| 769 | PLAT_RESOURCE_ACPI_IO_INDEX); | ||
| 770 | if (!res) { | ||
| 771 | dev_err(&pdev->dev, "Failed to get io resource\n"); | ||
| 772 | return -ENXIO; | ||
| 773 | } | ||
| 774 | size = resource_size(res); | ||
| 775 | ipcdev.acpi_io_base = res->start; | ||
| 776 | ipcdev.acpi_io_size = size; | ||
| 777 | dev_info(&pdev->dev, "io res: %pR\n", res); | ||
| 778 | |||
| 779 | punit_res = punit_res_array; | ||
| 780 | /* This is index 0 to cover BIOS data register */ | ||
| 781 | res = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 782 | PLAT_RESOURCE_BIOS_DATA_INDEX); | ||
| 783 | if (!res) { | ||
| 784 | dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n"); | ||
| 785 | return -ENXIO; | ||
| 786 | } | ||
| 787 | *punit_res = *res; | ||
| 788 | dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res); | ||
| 789 | |||
| 790 | /* This is index 1 to cover BIOS interface register */ | ||
| 791 | res = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 792 | PLAT_RESOURCE_BIOS_IFACE_INDEX); | ||
| 793 | if (!res) { | ||
| 794 | dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n"); | ||
| 795 | return -ENXIO; | ||
| 796 | } | ||
| 797 | *++punit_res = *res; | ||
| 798 | dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res); | ||
| 799 | |||
| 800 | /* This is index 2 to cover ISP data register, optional */ | ||
| 801 | res = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 802 | PLAT_RESOURCE_ISP_DATA_INDEX); | ||
| 803 | ++punit_res; | ||
| 804 | if (res) { | ||
| 805 | *punit_res = *res; | ||
| 806 | dev_info(&pdev->dev, "punit ISP data res: %pR\n", res); | ||
| 807 | } | ||
| 808 | |||
| 809 | /* This is index 3 to cover ISP interface register, optional */ | ||
| 810 | res = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 811 | PLAT_RESOURCE_ISP_IFACE_INDEX); | ||
| 812 | ++punit_res; | ||
| 813 | if (res) { | ||
| 814 | *punit_res = *res; | ||
| 815 | dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res); | ||
| 816 | } | ||
| 817 | |||
| 818 | /* This is index 4 to cover GTD data register, optional */ | ||
| 819 | res = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 820 | PLAT_RESOURCE_GTD_DATA_INDEX); | ||
| 821 | ++punit_res; | ||
| 822 | if (res) { | ||
| 823 | *punit_res = *res; | ||
| 824 | dev_info(&pdev->dev, "punit GTD data res: %pR\n", res); | ||
| 825 | } | ||
| 826 | |||
| 827 | /* This is index 5 to cover GTD interface register, optional */ | ||
| 828 | res = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 829 | PLAT_RESOURCE_GTD_IFACE_INDEX); | ||
| 830 | ++punit_res; | ||
| 831 | if (res) { | ||
| 832 | *punit_res = *res; | ||
| 833 | dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res); | ||
| 834 | } | ||
| 835 | 739 | ||
| 740 | /* Get IPC resources */ | ||
| 836 | res = platform_get_resource(pdev, IORESOURCE_MEM, | 741 | res = platform_get_resource(pdev, IORESOURCE_MEM, |
| 837 | PLAT_RESOURCE_IPC_INDEX); | 742 | PLAT_RESOURCE_IPC_INDEX); |
| 838 | if (!res) { | 743 | if (!res) { |
| 839 | dev_err(&pdev->dev, "Failed to get ipc resource\n"); | 744 | dev_err(&pdev->dev, "Failed to get IPC resources\n"); |
| 840 | return -ENXIO; | 745 | return -ENXIO; |
| 841 | } | 746 | } |
| 842 | size = PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE; | 747 | |
| 843 | res->end = res->start + size - 1; | 748 | res->end = res->start + |
| 749 | PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE - 1; | ||
| 844 | 750 | ||
| 845 | addr = devm_ioremap_resource(&pdev->dev, res); | 751 | addr = devm_ioremap_resource(&pdev->dev, res); |
| 846 | if (IS_ERR(addr)) | 752 | if (IS_ERR(addr)) |
| 847 | return PTR_ERR(addr); | 753 | return PTR_ERR(addr); |
| 848 | 754 | ||
| 849 | ipcdev.ipc_base = addr; | 755 | ipcdev.ipc_base = addr; |
| 850 | |||
| 851 | ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET; | 756 | ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET; |
| 852 | dev_info(&pdev->dev, "ipc res: %pR\n", res); | 757 | dev_dbg(&pdev->dev, "PMC IPC resource %pR\n", res); |
| 853 | |||
| 854 | ipcdev.telem_res_inval = 0; | ||
| 855 | res = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 856 | PLAT_RESOURCE_TELEM_SSRAM_INDEX); | ||
| 857 | if (!res) { | ||
| 858 | dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n"); | ||
| 859 | ipcdev.telem_res_inval = 1; | ||
| 860 | } else { | ||
| 861 | ipcdev.telem_punit_ssram_base = res->start + | ||
| 862 | TELEM_PUNIT_SSRAM_OFFSET; | ||
| 863 | ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE; | ||
| 864 | ipcdev.telem_pmc_ssram_base = res->start + | ||
| 865 | TELEM_PMC_SSRAM_OFFSET; | ||
| 866 | ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE; | ||
| 867 | dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res); | ||
| 868 | } | ||
| 869 | 758 | ||
| 870 | return 0; | 759 | return 0; |
| 871 | } | 760 | } |
| @@ -911,7 +800,7 @@ static int ipc_plat_probe(struct platform_device *pdev) | |||
| 911 | 800 | ||
| 912 | ipcdev.irq = platform_get_irq(pdev, 0); | 801 | ipcdev.irq = platform_get_irq(pdev, 0); |
| 913 | if (ipcdev.irq < 0) { | 802 | if (ipcdev.irq < 0) { |
| 914 | dev_err(&pdev->dev, "Failed to get irq\n"); | 803 | dev_err(&pdev->dev, "Failed to get IRQ\n"); |
| 915 | return -EINVAL; | 804 | return -EINVAL; |
| 916 | } | 805 | } |
| 917 | 806 | ||
| @@ -921,47 +810,38 @@ static int ipc_plat_probe(struct platform_device *pdev) | |||
| 921 | return ret; | 810 | return ret; |
| 922 | } | 811 | } |
| 923 | 812 | ||
| 924 | ret = ipc_create_pmc_devices(); | 813 | ret = ipc_create_pmc_devices(pdev); |
| 925 | if (ret) { | 814 | if (ret) { |
| 926 | dev_err(&pdev->dev, "Failed to create pmc devices\n"); | 815 | dev_err(&pdev->dev, "Failed to create PMC devices\n"); |
| 927 | return ret; | 816 | return ret; |
| 928 | } | 817 | } |
| 929 | 818 | ||
| 930 | if (devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND, | 819 | ret = devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND, |
| 931 | "intel_pmc_ipc", &ipcdev)) { | 820 | "intel_pmc_ipc", &ipcdev); |
| 932 | dev_err(&pdev->dev, "Failed to request irq\n"); | 821 | if (ret) { |
| 933 | ret = -EBUSY; | 822 | dev_err(&pdev->dev, "Failed to request IRQ\n"); |
| 934 | goto err_irq; | 823 | return ret; |
| 935 | } | 824 | } |
| 936 | 825 | ||
| 937 | ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group); | 826 | ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group); |
| 938 | if (ret) { | 827 | if (ret) { |
| 939 | dev_err(&pdev->dev, "Failed to create sysfs group %d\n", | 828 | dev_err(&pdev->dev, "Failed to create sysfs group %d\n", |
| 940 | ret); | 829 | ret); |
| 941 | goto err_sys; | 830 | devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev); |
| 831 | return ret; | ||
| 942 | } | 832 | } |
| 943 | 833 | ||
| 944 | ipcdev.has_gcr_regs = true; | 834 | ipcdev.has_gcr_regs = true; |
| 945 | 835 | ||
| 946 | return 0; | 836 | return 0; |
| 947 | err_sys: | ||
| 948 | devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev); | ||
| 949 | err_irq: | ||
| 950 | platform_device_unregister(ipcdev.tco_dev); | ||
| 951 | platform_device_unregister(ipcdev.punit_dev); | ||
| 952 | platform_device_unregister(ipcdev.telemetry_dev); | ||
| 953 | |||
| 954 | return ret; | ||
| 955 | } | 837 | } |
| 956 | 838 | ||
| 957 | static int ipc_plat_remove(struct platform_device *pdev) | 839 | static int ipc_plat_remove(struct platform_device *pdev) |
| 958 | { | 840 | { |
| 959 | sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group); | 841 | sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group); |
| 960 | devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev); | 842 | devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev); |
| 961 | platform_device_unregister(ipcdev.tco_dev); | ||
| 962 | platform_device_unregister(ipcdev.punit_dev); | ||
| 963 | platform_device_unregister(ipcdev.telemetry_dev); | ||
| 964 | ipcdev.dev = NULL; | 843 | ipcdev.dev = NULL; |
| 844 | |||
| 965 | return 0; | 845 | return 0; |
| 966 | } | 846 | } |
| 967 | 847 | ||
| @@ -980,12 +860,12 @@ static int __init intel_pmc_ipc_init(void) | |||
| 980 | 860 | ||
| 981 | ret = platform_driver_register(&ipc_plat_driver); | 861 | ret = platform_driver_register(&ipc_plat_driver); |
| 982 | if (ret) { | 862 | if (ret) { |
| 983 | pr_err("Failed to register PMC ipc platform driver\n"); | 863 | pr_err("Failed to register PMC IPC platform driver\n"); |
| 984 | return ret; | 864 | return ret; |
| 985 | } | 865 | } |
| 986 | ret = pci_register_driver(&ipc_pci_driver); | 866 | ret = pci_register_driver(&ipc_pci_driver); |
| 987 | if (ret) { | 867 | if (ret) { |
| 988 | pr_err("Failed to register PMC ipc pci driver\n"); | 868 | pr_err("Failed to register PMC IPC PCI driver\n"); |
| 989 | platform_driver_unregister(&ipc_plat_driver); | 869 | platform_driver_unregister(&ipc_plat_driver); |
| 990 | return ret; | 870 | return ret; |
| 991 | } | 871 | } |
