1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #define __SIMPLE_DEVICE__
4
5 #include <console/console.h>
6 #include <device/pci.h>
7 #include <device/pci_ids.h>
8 #include <intelblocks/p2sb.h>
9 #include <intelblocks/p2sblib.h>
10 #include <intelblocks/pcr.h>
11 #include <soc/pci_devs.h>
12
p2sb_dev_enable_bar(pci_devfn_t dev,uint64_t bar)13 void p2sb_dev_enable_bar(pci_devfn_t dev, uint64_t bar)
14 {
15 /* Enable PCR Base addresses */
16 pci_write_config32(dev, PCI_BASE_ADDRESS_0, (uint32_t)bar);
17 pci_write_config32(dev, PCI_BASE_ADDRESS_1, (uint32_t)(bar >> 32));
18
19 /* Enable P2SB MSE */
20 pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
21 }
22
p2sb_dev_is_hidden(pci_devfn_t dev)23 bool p2sb_dev_is_hidden(pci_devfn_t dev)
24 {
25 const uint16_t pci_vid = pci_read_config16(dev, PCI_VENDOR_ID);
26
27 if (pci_vid == 0xffff)
28 return true;
29 if (pci_vid == PCI_VID_INTEL)
30 return false;
31 printk(BIOS_ERR, "P2SB PCI_VENDOR_ID is invalid, unknown if hidden\n");
32 return true;
33 }
34
p2sb_dev_set_hide_bit(pci_devfn_t dev,int hide)35 static void p2sb_dev_set_hide_bit(pci_devfn_t dev, int hide)
36 {
37 const uint16_t reg = P2SBC + 1;
38 const uint8_t mask = P2SBC_HIDE_BIT;
39 uint8_t val;
40
41 val = pci_read_config8(dev, reg);
42 val &= ~mask;
43 if (hide)
44 val |= mask;
45 pci_write_config8(dev, reg, val);
46 }
47
p2sb_dev_unhide(pci_devfn_t dev)48 void p2sb_dev_unhide(pci_devfn_t dev)
49 {
50 p2sb_dev_set_hide_bit(dev, 0);
51
52 if (p2sb_dev_is_hidden(dev))
53 die_with_post_code(POSTCODE_HW_INIT_FAILURE,
54 "Unable to unhide the P2SB device!\n");
55 }
56
p2sb_dev_hide(pci_devfn_t dev)57 void p2sb_dev_hide(pci_devfn_t dev)
58 {
59 p2sb_dev_set_hide_bit(dev, 1);
60
61 if (!p2sb_dev_is_hidden(dev))
62 die_with_post_code(POSTCODE_HW_INIT_FAILURE,
63 "Unable to hide the P2SB device!\n");
64 }
65
p2sb_send_sideband_msg(pci_devfn_t dev,uint8_t cmd,uint8_t pid,uint16_t reg,uint32_t * data)66 static void p2sb_send_sideband_msg(pci_devfn_t dev, uint8_t cmd, uint8_t pid,
67 uint16_t reg, uint32_t *data)
68 {
69 struct pcr_sbi_msg msg = {
70 .pid = pid,
71 .offset = reg,
72 .opcode = cmd,
73 .is_posted = false,
74 .fast_byte_enable = 0xF,
75 .bar = 0,
76 .fid = 0
77 };
78 uint8_t response;
79 int status;
80
81 status = pcr_execute_sideband_msg(dev, &msg, data, &response);
82 if (status || response)
83 printk(BIOS_ERR, "Fail to execute p2sb sideband access\n");
84 }
85
p2sb_execute_sbi_in_smm(pci_devfn_t dev,uint8_t cmd,uint8_t pid,uint16_t reg,uint32_t * data)86 static void p2sb_execute_sbi_in_smm(pci_devfn_t dev, uint8_t cmd, uint8_t pid,
87 uint16_t reg, uint32_t *data)
88 {
89 /* Unhide the P2SB device */
90 p2sb_dev_unhide(dev);
91
92 p2sb_send_sideband_msg(dev, cmd, pid, reg, data);
93
94 /* Hide the P2SB device */
95 p2sb_dev_hide(dev);
96 }
97
p2sb_execute_sideband_access(pci_devfn_t dev,uint8_t cmd,uint8_t pid,uint16_t reg,uint32_t * data)98 static void p2sb_execute_sideband_access(pci_devfn_t dev, uint8_t cmd, uint8_t pid,
99 uint16_t reg, uint32_t *data)
100 {
101 if (ENV_SMM)
102 /*
103 * FSP-S will hide the P2SB device. With the device hidden, we will not be
104 * able to send the sideband interface message. Therefore, we need to unhide
105 * the P2SB device which can only be done in SMM requiring that this
106 * function is called from SMM.
107 */
108 p2sb_execute_sbi_in_smm(dev, cmd, pid, reg, data);
109 else if (!p2sb_dev_is_hidden(dev))
110 p2sb_send_sideband_msg(dev, cmd, pid, reg, data);
111 else
112 printk(BIOS_WARNING, "Error: P2SB must be hidden, try calling from SMM!\n");
113 }
114
p2sb_dev_sbi_read(pci_devfn_t dev,uint8_t pid,uint16_t reg)115 uint32_t p2sb_dev_sbi_read(pci_devfn_t dev, uint8_t pid, uint16_t reg)
116 {
117 uint32_t val = 0;
118 p2sb_execute_sideband_access(dev, PCR_READ, pid, reg, &val);
119 return val;
120 }
121
p2sb_dev_sbi_write(pci_devfn_t dev,uint8_t pid,uint16_t reg,uint32_t val)122 void p2sb_dev_sbi_write(pci_devfn_t dev, uint8_t pid, uint16_t reg, uint32_t val)
123 {
124 p2sb_execute_sideband_access(dev, PCR_WRITE, pid, reg, &val);
125 }
126