xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/pmc/pmc_ipc.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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 
pmc_reg(unsigned int pmc_reg_offset)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 
pmc_rbuf(unsigned int ix)47 static const void *pmc_rbuf(unsigned int ix)
48 {
49 	return pmc_reg(IPC_RBUF0 + ix * sizeof(uint32_t));
50 }
51 
pmc_wbuf(unsigned int ix)52 static void *pmc_wbuf(unsigned int ix)
53 {
54 	return pmc_reg(IPC_WBUF0 + ix * sizeof(uint32_t));
55 }
56 
check_ipc_sts(void)57 static int check_ipc_sts(void)
58 {
59 	struct stopwatch sw;
60 	uint32_t ipc_sts;
61 
62 	stopwatch_init_msecs_expire(&sw, PMC_IPC_XFER_TIMEOUT_MS);
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 
pmc_send_ipc_cmd(uint32_t cmd,const struct pmc_ipc_buffer * wbuf,struct pmc_ipc_buffer * rbuf)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 
87 	write32(pmc_reg(PMC_IPC_CMD_OFFSET), cmd);
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 
pmc_ipc_acpi_fill_ssdt(void)100 void pmc_ipc_acpi_fill_ssdt(void)
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");
127 	acpigen_write_package(5);
128 	for (i = 0; i < 5; ++i)
129 		acpigen_write_integer(0);
130 	acpigen_pop_len();
131 
132 	acpigen_write_method_serialized("IPCS", 7);
133 
134 	acpigen_write_opregion(&ipcs_opregion);
135 	acpigen_write_field("IPCM", ipcs_fields, ARRAY_SIZE(ipcs_fields),
136 			    FIELD_DWORDACC | FIELD_NOLOCK | FIELD_PRESERVE);
137 
138 	/* Fill write buffer data registers. */
139 	acpigen_write_store_op_to_namestr(ARG3_OP, "IWB0");
140 	acpigen_write_store_op_to_namestr(ARG4_OP, "IWB1");
141 	acpigen_write_store_op_to_namestr(ARG5_OP, "IWB2");
142 	acpigen_write_store_op_to_namestr(ARG6_OP, "IWB3");
143 
144 	/* Program the command register with command and size of write data. */
145 	acpigen_write_store_int_to_op(0, LOCAL0_OP);
146 
147 	/* Local0 += (Arg0 << PMC_IPC_CMD_COMMAND_SHIFT) */
148 	acpigen_emit_byte(ADD_OP);
149 	acpigen_emit_byte(LOCAL0_OP);
150 	acpigen_write_shiftleft_op_int(ARG0_OP, PMC_IPC_CMD_COMMAND_SHIFT);
151 	acpigen_emit_byte(LOCAL0_OP);
152 
153 	/* Local0 += (Arg1 << PMC_IPC_CMD_SUB_COMMAND_SHIFT) */
154 	acpigen_emit_byte(ADD_OP);
155 	acpigen_emit_byte(LOCAL0_OP);
156 	acpigen_write_shiftleft_op_int(ARG1_OP, PMC_IPC_CMD_SUB_COMMAND_SHIFT);
157 	acpigen_emit_byte(LOCAL0_OP);
158 
159 	/* Local1 = PMC_IPC_CMD_NO_MSI */
160 	acpigen_write_store_int_to_op(PMC_IPC_CMD_NO_MSI, LOCAL1_OP);
161 	/* Local0 += (Local1 << PMC_IPC_CMD_MSI_SHIFT) */
162 	acpigen_emit_byte(ADD_OP);
163 	acpigen_emit_byte(LOCAL0_OP);
164 	acpigen_write_shiftleft_op_int(LOCAL1_OP, PMC_IPC_CMD_MSI_SHIFT);
165 	acpigen_emit_byte(LOCAL0_OP);
166 
167 	/* Local0 += (Arg1 << PMC_IPC_CMD_SIZE_SHIFT) */
168 	acpigen_emit_byte(ADD_OP);
169 	acpigen_emit_byte(LOCAL0_OP);
170 	acpigen_write_shiftleft_op_int(ARG2_OP, PMC_IPC_CMD_SIZE_SHIFT);
171 	acpigen_emit_byte(LOCAL0_OP);
172 
173 	/* Start mailbox command with one 32bit write. */
174 	acpigen_write_store_op_to_namestr(LOCAL0_OP, "ICMD");
175 
176 	/* Read status register to get busy/error status. */
177 	acpigen_write_store_int_to_op(PMC_IPC_XFER_TIMEOUT_MS, LOCAL1_OP);
178 
179 	/* While (Local1 > 0) */
180 	acpigen_emit_byte(WHILE_OP);
181 	acpigen_write_len_f();
182 	acpigen_emit_byte(LGREATER_OP);
183 	acpigen_emit_byte(LOCAL1_OP);
184 	acpigen_emit_byte(ZERO_OP);
185 
186 	/* If (IBSY == 0) { Return (SUCCESS) } */
187 	acpigen_write_if_lequal_namestr_int("IBSY", 0);
188 	acpigen_set_package_element_int("RVAL", 0, PMC_IPC_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");
193 	acpigen_write_return_namestr("RVAL");
194 	acpigen_pop_len();
195 
196 	/* If (IERR == 1) { Return (ERROR) } */
197 	acpigen_write_if_lequal_namestr_int("IERR", 1);
198 	acpigen_write_debug_string("IPCS ERROR");
199 	acpigen_write_debug_namestr("IERC");
200 	acpigen_set_package_element_int("RVAL", 0, PMC_IPC_ERROR);
201 	acpigen_write_return_namestr("RVAL");
202 	acpigen_pop_len();
203 
204 	/* Sleep (1) */
205 	acpigen_write_sleep(1);
206 	/* Decrement (Local1) */
207 	acpigen_emit_byte(DECREMENT_OP);
208 	acpigen_emit_byte(LOCAL1_OP);
209 	acpigen_pop_len(); /* While */
210 
211 	/* Return (TIMEOUT) */
212 	acpigen_write_debug_string("IPCS TIMEOUT");
213 	acpigen_set_package_element_int("RVAL", 0, PMC_IPC_TIMEOUT);
214 	acpigen_write_return_namestr("RVAL");
215 
216 	acpigen_pop_len(); /* Method */
217 }
218 
pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp,unsigned int clock_pin,bool enable)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);
239 	acpigen_write_integer(PMC_IPC_CMD_ID_SET_PCIE_CLOCK);
240 	acpigen_write_integer(0);
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 }
247