1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <acpi/acpigen.h>
4 #include <device/mmio.h>
5 #include <console/console.h>
7 #include <intelblocks/pmclib.h>
8 #include <intelblocks/pmc_ipc.h>
9 #include <soc/pci_devs.h>
14 * WBUF register block offset 0x80..0x8f there are 4 consecutive
17 #define IPC_WBUF0 0x80
20 * RBUF registers block offset 0x90..0x9f there are 4 consecutive
23 #define IPC_RBUF0 0x90
26 * From Intel 500 Series PCH EDS vol2 s4.4
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
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))
41 static void *pmc_reg(unsigned int pmc_reg_offset
)
43 const uintptr_t pmcbase
= soc_read_pmc_base();
44 return (void *)(pmcbase
+ pmc_reg_offset
);
47 static const void *pmc_rbuf(unsigned int ix
)
49 return pmc_reg(IPC_RBUF0
+ ix
* sizeof(uint32_t));
52 static void *pmc_wbuf(unsigned int ix
)
54 return pmc_reg(IPC_WBUF0
+ ix
* sizeof(uint32_t));
57 static int check_ipc_sts(void)
62 stopwatch_init_msecs_expire(&sw
, PMC_IPC_XFER_TIMEOUT_MS
);
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
));
71 return PMC_IPC_SUCCESS
;
75 } while (!stopwatch_expired(&sw
));
77 printk(BIOS_ERR
, "PMC IPC timeout after %u ms\n", PMC_IPC_XFER_TIMEOUT_MS
);
78 return PMC_IPC_TIMEOUT
;
81 enum cb_err
pmc_send_ipc_cmd(uint32_t cmd
, const struct pmc_ipc_buffer
*wbuf
,
82 struct pmc_ipc_buffer
*rbuf
)
84 for (int i
= 0; i
< PMC_IPC_BUF_COUNT
; ++i
)
85 write32(pmc_wbuf(i
), wbuf
->buf
[i
]);
87 write32(pmc_reg(PMC_IPC_CMD_OFFSET
), cmd
);
89 if (check_ipc_sts()) {
90 printk(BIOS_ERR
, "PMC IPC command 0x%x failed\n", cmd
);
94 for (int i
= 0; i
< PMC_IPC_BUF_COUNT
; ++i
)
95 rbuf
->buf
[i
] = read32(pmc_rbuf(i
));
101 void pmc_ipc_acpi_fill_ssdt(void)
103 const struct fieldlist ipcs_fields
[] = {
104 FIELDLIST_OFFSET(PMC_IPC_CMD_OFFSET
), /* Command */
105 FIELDLIST_NAMESTR("ICMD", 32), /* Command Register */
106 FIELDLIST_OFFSET(PMC_IPC_STS_OFFSET
), /* Status */
107 FIELDLIST_NAMESTR("IBSY", 1), /* Status Busy */
108 FIELDLIST_NAMESTR("IERR", 1), /* Status Error */
109 FIELDLIST_RESERVED(14),
110 FIELDLIST_NAMESTR("IERC", 8), /* Status Error Code */
111 FIELDLIST_OFFSET(IPC_WBUF0
), /* Write Buffer */
112 FIELDLIST_NAMESTR("IWB0", 32), /* Write Buffer 0 */
113 FIELDLIST_NAMESTR("IWB1", 32), /* Write Buffer 1 */
114 FIELDLIST_NAMESTR("IWB2", 32), /* Write Buffer 2 */
115 FIELDLIST_NAMESTR("IWB3", 32), /* Write Buffer 3 */
116 FIELDLIST_OFFSET(IPC_RBUF0
), /* Read Buffer */
117 FIELDLIST_NAMESTR("IRB0", 32), /* Read Buffer 0 */
118 FIELDLIST_NAMESTR("IRB1", 32), /* Read Buffer 1 */
119 FIELDLIST_NAMESTR("IRB2", 32), /* Read Buffer 2 */
120 FIELDLIST_NAMESTR("IRB3", 32), /* Read Buffer 3 */
122 const struct opregion ipcs_opregion
= OPREGION("IPCM", SYSTEMMEMORY
,
123 soc_read_pmc_base(), 0xff);
126 /* Package with return value and read buffer. */
127 acpigen_write_name("RVAL");
128 acpigen_write_package(5);
129 for (i
= 0; i
< 5; ++i
)
130 acpigen_write_integer(0);
133 acpigen_write_method_serialized("IPCS", 7);
135 acpigen_write_opregion(&ipcs_opregion
);
136 acpigen_write_field("IPCM", ipcs_fields
, ARRAY_SIZE(ipcs_fields
),
137 FIELD_DWORDACC
| FIELD_NOLOCK
| FIELD_PRESERVE
);
139 /* Fill write buffer data registers. */
140 acpigen_write_store_op_to_namestr(ARG3_OP
, "IWB0");
141 acpigen_write_store_op_to_namestr(ARG4_OP
, "IWB1");
142 acpigen_write_store_op_to_namestr(ARG5_OP
, "IWB2");
143 acpigen_write_store_op_to_namestr(ARG6_OP
, "IWB3");
145 /* Program the command register with command and size of write data. */
146 acpigen_write_store_int_to_op(0, LOCAL0_OP
);
148 /* Local0 += (Arg0 << PMC_IPC_CMD_COMMAND_SHIFT) */
149 acpigen_emit_byte(ADD_OP
);
150 acpigen_emit_byte(LOCAL0_OP
);
151 acpigen_write_shiftleft_op_int(ARG0_OP
, PMC_IPC_CMD_COMMAND_SHIFT
);
152 acpigen_emit_byte(LOCAL0_OP
);
154 /* Local0 += (Arg1 << PMC_IPC_CMD_SUB_COMMAND_SHIFT) */
155 acpigen_emit_byte(ADD_OP
);
156 acpigen_emit_byte(LOCAL0_OP
);
157 acpigen_write_shiftleft_op_int(ARG1_OP
, PMC_IPC_CMD_SUB_COMMAND_SHIFT
);
158 acpigen_emit_byte(LOCAL0_OP
);
160 /* Local1 = PMC_IPC_CMD_NO_MSI */
161 acpigen_write_store_int_to_op(PMC_IPC_CMD_NO_MSI
, LOCAL1_OP
);
162 /* Local0 += (Local1 << PMC_IPC_CMD_MSI_SHIFT) */
163 acpigen_emit_byte(ADD_OP
);
164 acpigen_emit_byte(LOCAL0_OP
);
165 acpigen_write_shiftleft_op_int(LOCAL1_OP
, PMC_IPC_CMD_MSI_SHIFT
);
166 acpigen_emit_byte(LOCAL0_OP
);
168 /* Local0 += (Arg1 << PMC_IPC_CMD_SIZE_SHIFT) */
169 acpigen_emit_byte(ADD_OP
);
170 acpigen_emit_byte(LOCAL0_OP
);
171 acpigen_write_shiftleft_op_int(ARG2_OP
, PMC_IPC_CMD_SIZE_SHIFT
);
172 acpigen_emit_byte(LOCAL0_OP
);
174 /* Start mailbox command with one 32bit write. */
175 acpigen_write_store_op_to_namestr(LOCAL0_OP
, "ICMD");
177 /* Read status register to get busy/error status. */
178 acpigen_write_store_int_to_op(PMC_IPC_XFER_TIMEOUT_MS
, LOCAL1_OP
);
180 /* While (Local1 > 0) */
181 acpigen_emit_byte(WHILE_OP
);
182 acpigen_write_len_f();
183 acpigen_emit_byte(LGREATER_OP
);
184 acpigen_emit_byte(LOCAL1_OP
);
185 acpigen_emit_byte(ZERO_OP
);
187 /* If (IBSY == 0) { Return (SUCCESS) } */
188 acpigen_write_if_lequal_namestr_int("IBSY", 0);
189 acpigen_set_package_element_int("RVAL", 0, PMC_IPC_SUCCESS
);
190 acpigen_set_package_element_namestr("RVAL", 1, "IRB0");
191 acpigen_set_package_element_namestr("RVAL", 2, "IRB1");
192 acpigen_set_package_element_namestr("RVAL", 3, "IRB2");
193 acpigen_set_package_element_namestr("RVAL", 4, "IRB3");
194 acpigen_write_return_namestr("RVAL");
197 /* If (IERR == 1) { Return (ERROR) } */
198 acpigen_write_if_lequal_namestr_int("IERR", 1);
199 acpigen_write_debug_string("IPCS ERROR");
200 acpigen_write_debug_namestr("IERC");
201 acpigen_set_package_element_int("RVAL", 0, PMC_IPC_ERROR
);
202 acpigen_write_return_namestr("RVAL");
206 acpigen_write_sleep(1);
207 /* Decrement (Local1) */
208 acpigen_emit_byte(DECREMENT_OP
);
209 acpigen_emit_byte(LOCAL1_OP
);
210 acpigen_pop_len(); /* While */
212 /* Return (TIMEOUT) */
213 acpigen_write_debug_string("IPCS TIMEOUT");
214 acpigen_set_package_element_int("RVAL", 0, PMC_IPC_TIMEOUT
);
215 acpigen_write_return_namestr("RVAL");
217 acpigen_pop_len(); /* Method */
220 void pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp
, unsigned int clock_pin
, bool enable
)
222 const uint32_t data
[] = {
223 1 << clock_pin
, /* Clock pin to be modified */
224 (enable
? 1 : 0) << clock_pin
, /* Clock pin to set */
225 1 << pcie_rp
, /* PCIe root port to be modified */
226 (enable
? 1 : 0) << pcie_rp
, /* PCIe root port to set */
228 const char *method
= acpi_device_path_join(pcidev_path_on_root(PCH_DEVFN_PMC
), "IPCS");
231 printk(BIOS_ERR
, "%s: Unable to find PMC device IPCS method\n", __func__
);
236 * The PMC IPC mailbox method takes 7 arguments:
237 * IPCS (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3)
239 acpigen_emit_namestring(method
);
240 acpigen_write_integer(PMC_IPC_CMD_ID_SET_PCIE_CLOCK
);
241 acpigen_write_integer(0);
242 acpigen_write_integer(sizeof(data
));
243 acpigen_write_dword(data
[0]);
244 acpigen_write_dword(data
[1]);
245 acpigen_write_dword(data
[2]);
246 acpigen_write_dword(data
[3]);