coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
pmc_ipc.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpigen.h>
4 #include <device/mmio.h>
5 #include <console/console.h>
6 #include <delay.h>
7 #include <intelblocks/pmclib.h>
8 #include <intelblocks/pmc_ipc.h>
9 #include <soc/pci_devs.h>
10 #include <stdint.h>
11 #include <timer.h>
12 
13 /*
14  * WBUF register block offset 0x80..0x8f there are 4 consecutive
15  * 32 bit registers
16  */
17 #define IPC_WBUF0 0x80
18 
19 /*
20  * RBUF registers block offset 0x90..0x9f there are 4 consecutive
21  * 32 bit registers
22  */
23 #define IPC_RBUF0 0x90
24 
25 /*
26  * From Intel 500 Series PCH EDS vol2 s4.4
27  */
28 #define PMC_IPC_CMD_OFFSET 0x0
29 #define PMC_IPC_STS_OFFSET 0x4
30 #define PMC_IPC_STS_BUSY BIT(0)
31 #define PMC_IPC_STS_ERR BIT(1)
32 #define PMC_IPC_ERR_CODE_SHIFT 16
33 #define PMC_IPC_ERR_CODE_MASK 0xff
34 
35 #define PMC_IPC_XFER_TIMEOUT_MS (1 * MSECS_PER_SEC) /* max 1s */
36 #define IS_IPC_STS_BUSY(status) ((status) & PMC_IPC_STS_BUSY)
37 #define IPC_STS_HAS_ERROR(status) ((status) & PMC_IPC_STS_ERR)
38 #define IPC_STS_ERROR_CODE(sts) (((sts) >> PMC_IPC_ERR_CODE_SHIFT & \
39  PMC_IPC_ERR_CODE_MASK))
40 
41 static void *pmc_reg(unsigned int pmc_reg_offset)
42 {
43  const uintptr_t pmcbase = soc_read_pmc_base();
44  return (void *)(pmcbase + pmc_reg_offset);
45 }
46 
47 static const void *pmc_rbuf(unsigned int ix)
48 {
49  return pmc_reg(IPC_RBUF0 + ix * sizeof(uint32_t));
50 }
51 
52 static void *pmc_wbuf(unsigned int ix)
53 {
54  return pmc_reg(IPC_WBUF0 + ix * sizeof(uint32_t));
55 }
56 
57 static int check_ipc_sts(void)
58 {
59  struct stopwatch sw;
60  uint32_t ipc_sts;
61 
63  do {
64  ipc_sts = read32(pmc_reg(PMC_IPC_STS_OFFSET));
65  if (!(IS_IPC_STS_BUSY(ipc_sts))) {
66  if (IPC_STS_HAS_ERROR(ipc_sts)) {
67  printk(BIOS_ERR, "IPC_STS.error_code 0x%x\n",
68  IPC_STS_ERROR_CODE(ipc_sts));
69  return PMC_IPC_ERROR;
70  }
71  return PMC_IPC_SUCCESS;
72  }
73  udelay(50);
74 
75  } while (!stopwatch_expired(&sw));
76 
77  printk(BIOS_ERR, "PMC IPC timeout after %u ms\n", PMC_IPC_XFER_TIMEOUT_MS);
78  return PMC_IPC_TIMEOUT;
79 }
80 
81 enum cb_err pmc_send_ipc_cmd(uint32_t cmd, const struct pmc_ipc_buffer *wbuf,
82  struct pmc_ipc_buffer *rbuf)
83 {
84  for (int i = 0; i < PMC_IPC_BUF_COUNT; ++i)
85  write32(pmc_wbuf(i), wbuf->buf[i]);
86 
88 
89  if (check_ipc_sts()) {
90  printk(BIOS_ERR, "PMC IPC command 0x%x failed\n", cmd);
91  return CB_ERR;
92  }
93 
94  for (int i = 0; i < PMC_IPC_BUF_COUNT; ++i)
95  rbuf->buf[i] = read32(pmc_rbuf(i));
96 
97  return CB_SUCCESS;
98 }
99 
101 {
102  const struct fieldlist ipcs_fields[] = {
103  FIELDLIST_OFFSET(PMC_IPC_CMD_OFFSET), /* Command */
104  FIELDLIST_NAMESTR("ICMD", 32), /* Command Register */
105  FIELDLIST_OFFSET(PMC_IPC_STS_OFFSET), /* Status */
106  FIELDLIST_NAMESTR("IBSY", 1), /* Status Busy */
107  FIELDLIST_NAMESTR("IERR", 1), /* Status Error */
108  FIELDLIST_RESERVED(14),
109  FIELDLIST_NAMESTR("IERC", 8), /* Status Error Code */
110  FIELDLIST_OFFSET(IPC_WBUF0), /* Write Buffer */
111  FIELDLIST_NAMESTR("IWB0", 32), /* Write Buffer 0 */
112  FIELDLIST_NAMESTR("IWB1", 32), /* Write Buffer 1 */
113  FIELDLIST_NAMESTR("IWB2", 32), /* Write Buffer 2 */
114  FIELDLIST_NAMESTR("IWB3", 32), /* Write Buffer 3 */
115  FIELDLIST_OFFSET(IPC_RBUF0), /* Read Buffer */
116  FIELDLIST_NAMESTR("IRB0", 32), /* Read Buffer 0 */
117  FIELDLIST_NAMESTR("IRB1", 32), /* Read Buffer 1 */
118  FIELDLIST_NAMESTR("IRB2", 32), /* Read Buffer 2 */
119  FIELDLIST_NAMESTR("IRB3", 32), /* Read Buffer 3 */
120  };
121  const struct opregion ipcs_opregion = OPREGION("IPCM", SYSTEMMEMORY,
122  soc_read_pmc_base(), 0xff);
123  int i;
124 
125  /* Package with return value and read buffer. */
126  acpigen_write_name("RVAL");
128  for (i = 0; i < 5; ++i)
130  acpigen_pop_len();
131 
133 
134  acpigen_write_opregion(&ipcs_opregion);
135  acpigen_write_field("IPCM", ipcs_fields, ARRAY_SIZE(ipcs_fields),
137 
138  /* Fill write buffer data registers. */
143 
144  /* Program the command register with command and size of write data. */
146 
147  /* Local0 += (Arg0 << PMC_IPC_CMD_COMMAND_SHIFT) */
152 
153  /* Local0 += (Arg1 << PMC_IPC_CMD_SUB_COMMAND_SHIFT) */
158 
159  /* Local1 = PMC_IPC_CMD_NO_MSI */
161  /* Local0 += (Local1 << PMC_IPC_CMD_MSI_SHIFT) */
166 
167  /* Local0 += (Arg1 << PMC_IPC_CMD_SIZE_SHIFT) */
172 
173  /* Start mailbox command with one 32bit write. */
175 
176  /* Read status register to get busy/error status. */
178 
179  /* While (Local1 > 0) */
185 
186  /* If (IBSY == 0) { Return (SUCCESS) } */
189  acpigen_set_package_element_namestr("RVAL", 1, "IRB0");
190  acpigen_set_package_element_namestr("RVAL", 2, "IRB1");
191  acpigen_set_package_element_namestr("RVAL", 3, "IRB2");
192  acpigen_set_package_element_namestr("RVAL", 4, "IRB3");
194  acpigen_pop_len();
195 
196  /* If (IERR == 1) { Return (ERROR) } */
198  acpigen_write_debug_string("IPCS ERROR");
202  acpigen_pop_len();
203 
204  /* Sleep (1) */
206  /* Decrement (Local1) */
209  acpigen_pop_len(); /* While */
210 
211  /* Return (TIMEOUT) */
212  acpigen_write_debug_string("IPCS TIMEOUT");
215 
216  acpigen_pop_len(); /* Method */
217 }
218 
219 void pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable)
220 {
221  const uint32_t data[] = {
222  1 << clock_pin, /* Clock pin to be modified */
223  (enable ? 1 : 0) << clock_pin, /* Clock pin to set */
224  1 << pcie_rp, /* PCIe root port to be modified */
225  (enable ? 1 : 0) << pcie_rp, /* PCIe root port to set */
226  };
227  const char *method = acpi_device_path_join(pcidev_path_on_root(PCH_DEVFN_PMC), "IPCS");
228 
229  if (!method) {
230  printk(BIOS_ERR, "%s: Unable to find PMC device IPCS method\n", __func__);
231  return;
232  }
233 
234  /*
235  * The PMC IPC mailbox method takes 7 arguments:
236  * IPCS (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3)
237  */
238  acpigen_emit_namestring(method);
241  acpigen_write_integer(sizeof(data));
242  acpigen_write_dword(data[0]);
243  acpigen_write_dword(data[1]);
244  acpigen_write_dword(data[2]);
245  acpigen_write_dword(data[3]);
246 }
const char * acpi_device_path_join(const struct device *dev, const char *name)
Definition: device.c:172
void acpigen_write_len_f(void)
Definition: acpigen.c:28
void acpigen_write_dword(unsigned int data)
Definition: acpigen.c:108
void acpigen_emit_namestring(const char *namepath)
Definition: acpigen.c:275
void acpigen_write_integer(uint64_t data)
Definition: acpigen.c:136
void acpigen_pop_len(void)
Definition: acpigen.c:37
void acpigen_set_package_element_int(const char *package, unsigned int element, uint64_t src)
Definition: acpigen.c:368
void acpigen_write_shiftleft_op_int(uint8_t src_result, uint64_t count)
Definition: acpigen.c:1517
void acpigen_write_sleep(uint64_t sleep_ms)
Definition: acpigen.c:1327
void acpigen_write_method_serialized(const char *name, int nargs)
Definition: acpigen.c:764
char * acpigen_write_package(int nr_el)
Definition: acpigen.c:86
void acpigen_emit_byte(unsigned char b)
Definition: acpigen.c:61
void acpigen_write_field(const char *name, const struct fieldlist *l, size_t count, uint8_t flags)
Definition: acpigen.c:569
void acpigen_write_store_op_to_namestr(uint8_t src, const char *dst)
Definition: acpigen.c:1347
void acpigen_write_debug_namestr(const char *str)
Definition: acpigen.c:1430
void acpigen_write_return_namestr(const char *arg)
Definition: acpigen.c:1589
void acpigen_write_opregion(const struct opregion *opreg)
Definition: acpigen.c:447
void acpigen_set_package_element_namestr(const char *package, unsigned int element, const char *src)
Definition: acpigen.c:379
void acpigen_write_debug_string(const char *str)
Definition: acpigen.c:1406
void acpigen_write_name(const char *name)
Definition: acpigen.c:320
void acpigen_write_store_int_to_op(uint64_t src, uint8_t dst)
Definition: acpigen.c:1363
void acpigen_write_if_lequal_namestr_int(const char *namestr, uint64_t val)
Definition: acpigen.c:1486
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
#define ARRAY_SIZE(a)
Definition: helpers.h:12
cb_err
coreboot error codes
Definition: cb_err.h:15
@ CB_ERR
Generic error code.
Definition: cb_err.h:17
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
#define printk(level,...)
Definition: stdlib.h:16
DEVTREE_CONST struct device * pcidev_path_on_root(pci_devfn_t devfn)
Definition: device_const.c:255
#define FIELD_NOLOCK
Definition: acpigen.h:172
@ ARG0_OP
Definition: acpigen.h:89
@ ARG1_OP
Definition: acpigen.h:90
@ LOCAL1_OP
Definition: acpigen.h:82
@ ARG3_OP
Definition: acpigen.h:92
@ LOCAL0_OP
Definition: acpigen.h:81
@ WHILE_OP
Definition: acpigen.h:144
@ DECREMENT_OP
Definition: acpigen.h:102
@ ZERO_OP
Definition: acpigen.h:30
@ ADD_OP
Definition: acpigen.h:98
@ ARG6_OP
Definition: acpigen.h:95
@ LGREATER_OP
Definition: acpigen.h:132
@ ARG2_OP
Definition: acpigen.h:91
@ ARG5_OP
Definition: acpigen.h:94
@ ARG4_OP
Definition: acpigen.h:93
@ SYSTEMMEMORY
Definition: acpigen.h:198
#define FIELDLIST_RESERVED(X)
Definition: acpigen.h:161
#define FIELDLIST_OFFSET(X)
Definition: acpigen.h:153
#define OPREGION(rname, space, offset, len)
Definition: acpigen.h:191
#define FIELD_DWORDACC
Definition: acpigen.h:169
#define FIELDLIST_NAMESTR(X, Y)
Definition: acpigen.h:157
#define FIELD_PRESERVE
Definition: acpigen.h:174
static int stopwatch_expired(struct stopwatch *sw)
Definition: timer.h:152
static void stopwatch_init_msecs_expire(struct stopwatch *sw, long ms)
Definition: timer.h:133
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define IPC_STS_ERROR_CODE(sts)
Definition: pmc_ipc.c:38
static const void * pmc_rbuf(unsigned int ix)
Definition: pmc_ipc.c:47
static void * pmc_wbuf(unsigned int ix)
Definition: pmc_ipc.c:52
#define IPC_RBUF0
Definition: pmc_ipc.c:23
#define IS_IPC_STS_BUSY(status)
Definition: pmc_ipc.c:36
static void * pmc_reg(unsigned int pmc_reg_offset)
Definition: pmc_ipc.c:41
#define PMC_IPC_XFER_TIMEOUT_MS
Definition: pmc_ipc.c:35
void pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable)
Definition: pmc_ipc.c:219
enum cb_err pmc_send_ipc_cmd(uint32_t cmd, const struct pmc_ipc_buffer *wbuf, struct pmc_ipc_buffer *rbuf)
Definition: pmc_ipc.c:81
#define PMC_IPC_STS_OFFSET
Definition: pmc_ipc.c:29
#define IPC_WBUF0
Definition: pmc_ipc.c:17
#define IPC_STS_HAS_ERROR(status)
Definition: pmc_ipc.c:37
#define PMC_IPC_CMD_OFFSET
Definition: pmc_ipc.c:28
void pmc_ipc_acpi_fill_ssdt(void)
Definition: pmc_ipc.c:100
static int check_ipc_sts(void)
Definition: pmc_ipc.c:57
#define PMC_IPC_BUF_COUNT
Definition: pmc_ipc.h:8
#define PMC_IPC_CMD_MSI_SHIFT
Definition: pmc_ipc.h:12
#define PMC_IPC_SUCCESS
Definition: pmc_ipc.h:49
#define PMC_IPC_ERROR
Definition: pmc_ipc.h:50
#define PMC_IPC_TIMEOUT
Definition: pmc_ipc.h:51
#define PMC_IPC_CMD_NO_MSI
Definition: pmc_ipc.h:39
#define PMC_IPC_CMD_COMMAND_SHIFT
Definition: pmc_ipc.h:10
#define PMC_IPC_CMD_SIZE_SHIFT
Definition: pmc_ipc.h:16
#define PMC_IPC_CMD_ID_SET_PCIE_CLOCK
Definition: pmc_ipc.h:46
#define PMC_IPC_CMD_SUB_COMMAND_SHIFT
Definition: pmc_ipc.h:14
#define PCH_DEVFN_PMC
Definition: pci_devs.h:217
uintptr_t soc_read_pmc_base(void)
Definition: pmutil.c:147
unsigned int uint32_t
Definition: stdint.h:14
unsigned long uintptr_t
Definition: stdint.h:21
uint32_t buf[PMC_IPC_BUF_COUNT]
Definition: pmc_ipc.h:69
void udelay(uint32_t us)
Definition: udelay.c:15