| /* inteltool - dump all registers on an Intel CPU + chipset based system */ |
| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <assert.h> |
| #include <inttypes.h> |
| #include "inteltool.h" |
| #include "pcr.h" |
| |
| #include "gpio_names/apollolake.h" |
| #include "gpio_names/cannonlake.h" |
| #include "gpio_names/cannonlake_lp.h" |
| #include "gpio_names/denverton.h" |
| #include "gpio_names/geminilake.h" |
| #include "gpio_names/icelake.h" |
| #include "gpio_names/lewisburg.h" |
| #include "gpio_names/sunrise.h" |
| #include "gpio_names/tigerlake.h" |
| |
| #define SBBAR_SIZE (16 * MiB) |
| #define PCR_PORT_SIZE (64 * KiB) |
| |
| static const char *decode_pad_mode(const struct gpio_group *const group, |
| const size_t pad, const uint32_t dw0) |
| { |
| const size_t pad_mode = dw0 >> 10 & 7; |
| const char *const pad_name = |
| group->pad_names[pad * group->func_count + pad_mode]; |
| |
| if (!pad_mode) |
| return pad_name[0] == '*' ? "*GPIO" : "GPIO"; |
| else if (pad_mode < group->func_count) |
| return group->pad_names[pad * group->func_count + pad_mode]; |
| else |
| return "RESERVED"; |
| } |
| |
| static void print_gpio_group(const uint8_t pid, size_t pad_cfg, |
| const struct gpio_group *const group, |
| size_t pad_stepping) |
| { |
| size_t p; |
| |
| printf("%s\n", group->display); |
| |
| for (p = 0; p < group->pad_count; ++p, pad_cfg += pad_stepping) { |
| const uint32_t dw0 = read_pcr32(pid, pad_cfg); |
| const uint32_t dw1 = read_pcr32(pid, pad_cfg + 4); |
| const char *const pad_name = |
| group->pad_names[p * group->func_count]; |
| |
| printf("0x%04zx: 0x%016"PRIx64" %-12s %-20s\n", pad_cfg, |
| (uint64_t)dw1 << 32 | dw0, |
| pad_name[0] == '*' ? &pad_name[1] : pad_name, |
| decode_pad_mode(group, p, dw0)); |
| } |
| } |
| |
| static void print_gpio_community(const struct gpio_community *const community, |
| size_t pad_stepping) |
| { |
| size_t group, pad_count; |
| size_t pad_cfg; /* offset in bytes under this communities PCR port */ |
| |
| printf("%s\n\nPCR Port ID: 0x%06zx\n\n", |
| community->name, (size_t)community->pcr_port_id << 16); |
| |
| for (group = 0, pad_count = 0; group < community->group_count; ++group) |
| pad_count += community->groups[group]->pad_count; |
| assert(pad_count * 8 <= PCR_PORT_SIZE - 0x10); |
| |
| pad_cfg = read_pcr32(community->pcr_port_id, 0x0c); |
| if (pad_cfg + pad_count * 8 > PCR_PORT_SIZE) { |
| fprintf(stderr, "Bad Pad Base Address: 0x%08zx\n", pad_cfg); |
| return; |
| } |
| |
| for (group = 0; group < community->group_count; ++group) { |
| print_gpio_group(community->pcr_port_id, |
| pad_cfg, community->groups[group], |
| pad_stepping); |
| pad_cfg += community->groups[group]->pad_count * pad_stepping; |
| } |
| } |
| |
| const struct gpio_community *const *get_gpio_communities(struct pci_dev *const sb, |
| size_t* community_count, |
| size_t* pad_stepping) |
| { |
| *pad_stepping = 8; |
| |
| switch (sb->device_id) { |
| case PCI_DEVICE_ID_INTEL_H110: |
| case PCI_DEVICE_ID_INTEL_H170: |
| case PCI_DEVICE_ID_INTEL_Z170: |
| case PCI_DEVICE_ID_INTEL_Q170: |
| case PCI_DEVICE_ID_INTEL_Q150: |
| case PCI_DEVICE_ID_INTEL_B150: |
| case PCI_DEVICE_ID_INTEL_C236: |
| case PCI_DEVICE_ID_INTEL_C232: |
| case PCI_DEVICE_ID_INTEL_QM170: |
| case PCI_DEVICE_ID_INTEL_HM170: |
| case PCI_DEVICE_ID_INTEL_CM236: |
| case PCI_DEVICE_ID_INTEL_H270: |
| case PCI_DEVICE_ID_INTEL_Z270: |
| case PCI_DEVICE_ID_INTEL_Q270: |
| case PCI_DEVICE_ID_INTEL_Q250: |
| case PCI_DEVICE_ID_INTEL_B250: |
| case PCI_DEVICE_ID_INTEL_Z370: |
| case PCI_DEVICE_ID_INTEL_H310C: |
| case PCI_DEVICE_ID_INTEL_X299: |
| *community_count = ARRAY_SIZE(sunrise_communities); |
| return sunrise_communities; |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_PRE: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_BASE_SKL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_Y_PREM_SKL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_PREM_SKL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_BASE_KBL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_PREM_KBL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_Y_PREM_KBL: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_IHDCP_BASE: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_U_IHDCP_PREM: |
| case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_Y_IHDCP_PREM: |
| *community_count = ARRAY_SIZE(sunrise_lp_communities); |
| return sunrise_lp_communities; |
| case PCI_DEVICE_ID_INTEL_C621: |
| case PCI_DEVICE_ID_INTEL_C622: |
| case PCI_DEVICE_ID_INTEL_C624: |
| case PCI_DEVICE_ID_INTEL_C625: |
| case PCI_DEVICE_ID_INTEL_C626: |
| case PCI_DEVICE_ID_INTEL_C627: |
| case PCI_DEVICE_ID_INTEL_C628: |
| case PCI_DEVICE_ID_INTEL_C629: |
| case PCI_DEVICE_ID_INTEL_C621A: |
| case PCI_DEVICE_ID_INTEL_C627A: |
| case PCI_DEVICE_ID_INTEL_C629A: |
| case PCI_DEVICE_ID_INTEL_C624_SUPER: |
| case PCI_DEVICE_ID_INTEL_C627_SUPER_1: |
| case PCI_DEVICE_ID_INTEL_C621_SUPER: |
| case PCI_DEVICE_ID_INTEL_C627_SUPER_2: |
| case PCI_DEVICE_ID_INTEL_C628_SUPER: |
| case PCI_DEVICE_ID_INTEL_C621A_SUPER: |
| case PCI_DEVICE_ID_INTEL_C627A_SUPER: |
| case PCI_DEVICE_ID_INTEL_C629A_SUPER: |
| *community_count = ARRAY_SIZE(lewisburg_communities); |
| return lewisburg_communities; |
| case PCI_DEVICE_ID_INTEL_DNV_LPC: |
| *community_count = ARRAY_SIZE(denverton_communities); |
| return denverton_communities; |
| case PCI_DEVICE_ID_INTEL_APL_LPC: |
| *community_count = ARRAY_SIZE(apl_communities); |
| return apl_communities; |
| case PCI_DEVICE_ID_INTEL_GLK_LPC: |
| *community_count = ARRAY_SIZE(glk_communities); |
| *pad_stepping = 16; |
| return glk_communities; |
| case PCI_DEVICE_ID_INTEL_CANNONPOINT_LP_U_PREM: |
| case PCI_DEVICE_ID_INTEL_COMETPOINT_LP_U_PREM: |
| case PCI_DEVICE_ID_INTEL_COMETPOINT_LP_U_BASE: |
| *community_count = ARRAY_SIZE(cannonlake_pch_lp_communities); |
| *pad_stepping = 16; |
| return cannonlake_pch_lp_communities; |
| case PCI_DEVICE_ID_INTEL_H310: |
| case PCI_DEVICE_ID_INTEL_H370: |
| case PCI_DEVICE_ID_INTEL_Z390: |
| case PCI_DEVICE_ID_INTEL_Q370: |
| case PCI_DEVICE_ID_INTEL_B360: |
| case PCI_DEVICE_ID_INTEL_C246: |
| case PCI_DEVICE_ID_INTEL_C242: |
| case PCI_DEVICE_ID_INTEL_QM370: |
| case PCI_DEVICE_ID_INTEL_HM370: |
| case PCI_DEVICE_ID_INTEL_CM246: |
| *community_count = ARRAY_SIZE(cannonlake_pch_h_communities); |
| *pad_stepping = 16; |
| return cannonlake_pch_h_communities; |
| case PCI_DEVICE_ID_INTEL_ICELAKE_LP_U: |
| *community_count = ARRAY_SIZE(icelake_pch_h_communities); |
| *pad_stepping = 16; |
| return icelake_pch_h_communities; |
| case PCI_DEVICE_ID_INTEL_TIGERPOINT_U_SUPER: |
| case PCI_DEVICE_ID_INTEL_TIGERPOINT_U_PREM: |
| case PCI_DEVICE_ID_INTEL_TIGERPOINT_U_BASE: |
| case PCI_DEVICE_ID_INTEL_TIGERPOINT_Y_SUPER: |
| case PCI_DEVICE_ID_INTEL_TIGERPOINT_Y_PREM: |
| *community_count = ARRAY_SIZE(tigerlake_pch_lp_communities); |
| *pad_stepping = 16; |
| return tigerlake_pch_lp_communities; |
| case PCI_DEVICE_ID_INTEL_Q570: |
| case PCI_DEVICE_ID_INTEL_Z590: |
| case PCI_DEVICE_ID_INTEL_H570: |
| case PCI_DEVICE_ID_INTEL_B560: |
| case PCI_DEVICE_ID_INTEL_H510: |
| case PCI_DEVICE_ID_INTEL_WM590: |
| case PCI_DEVICE_ID_INTEL_QM580: |
| case PCI_DEVICE_ID_INTEL_HM570: |
| case PCI_DEVICE_ID_INTEL_C252: |
| case PCI_DEVICE_ID_INTEL_C256: |
| case PCI_DEVICE_ID_INTEL_W580: |
| *community_count = ARRAY_SIZE(tigerlake_pch_h_communities); |
| *pad_stepping = 16; |
| return tigerlake_pch_h_communities; |
| default: |
| return NULL; |
| } |
| } |
| |
| void print_gpio_groups(struct pci_dev *const sb) |
| { |
| size_t community_count; |
| const struct gpio_community *const *communities; |
| size_t pad_stepping; |
| |
| communities = get_gpio_communities(sb, &community_count, &pad_stepping); |
| |
| if (!communities) |
| return; |
| |
| pcr_init(sb); |
| |
| printf("\n============= GPIOS =============\n\n"); |
| |
| for (; community_count; --community_count) |
| print_gpio_community(*communities++, pad_stepping); |
| } |