xref: /aosp_15_r20/external/flashrom/amd_imc.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2013 Rudolf Marek <[email protected]>
5  * Copyright (C) 2013 Stefan Tauner
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17 
18 #include "flash.h"
19 #include "programmer.h"
20 #include "hwaccess_x86_io.h"
21 #include "spi.h"
22 #include "platform/pci.h"
23 
24 /* same as serverengines */
enter_conf_mode_ec(uint16_t port)25 static void enter_conf_mode_ec(uint16_t port)
26 {
27 	OUTB(0x5a, port);
28 }
29 
exit_conf_mode_ec(uint16_t port)30 static void exit_conf_mode_ec(uint16_t port)
31 {
32 	OUTB(0xa5, port);
33 }
34 
get_sio_port(struct pci_dev * dev)35 static uint16_t get_sio_port(struct pci_dev *dev)
36 {
37 	uint16_t ec_port;
38 
39 	if (!dev) {
40 		return 0;
41 	}
42 
43 	ec_port = pci_read_word(dev, 0xa4);
44 
45 	/* EcPortActive? */
46 	if (!(ec_port & 0x1))
47 		return 0;
48 
49 	ec_port &= ~0x1;
50 
51 	return ec_port;
52 }
53 
54 /* Wait for up to 10 ms for a response. */
mbox_wait_ack(uint16_t mbox_port)55 static int mbox_wait_ack(uint16_t mbox_port)
56 {
57 	int i = 10;
58 	while (sio_read(mbox_port, 0x82) != 0xfa) {
59 		if (--i == 0) {
60 			msg_pwarn("IMC MBOX: Timeout!\n");
61 			return 1;
62 		}
63 		default_delay(1000);
64 	}
65 	return 0;
66 }
67 
mbox_get_port(uint16_t sio_port)68 static uint16_t mbox_get_port(uint16_t sio_port)
69 {
70 	uint16_t mbox_port;
71 
72 	enter_conf_mode_ec(sio_port);
73 
74 	/* Go to LDN 9, mailbox */
75 	sio_write(sio_port, 7, 9);
76 
77 	/* MBOX inactive? */
78 	if ((sio_read(sio_port, 0x30) & 1) == 0) {
79 		exit_conf_mode_ec(sio_port);
80 		return 0;
81 	}
82 
83 	mbox_port = sio_read(sio_port, 0x60) << 8;
84 	mbox_port |= sio_read(sio_port, 0x61);
85 
86 	exit_conf_mode_ec(sio_port);
87 	return mbox_port;
88 }
89 
90 /* Returns negative values when IMC is inactive, positive values on errors */
imc_send_cmd(struct pci_dev * dev,uint8_t cmd)91 static int imc_send_cmd(struct pci_dev *dev, uint8_t cmd)
92 {
93 	uint16_t sio_port;
94 	uint16_t mbox_port;
95 
96 	/* IntegratedEcPresent? */
97 	if (!(pci_read_byte(dev, 0x40) & (1 << 7)))
98 		return -1;
99 
100 	sio_port = get_sio_port(dev);
101 	if (!sio_port)
102 		return -1;
103 
104 	msg_pdbg2("IMC SIO is at 0x%x.\n", sio_port);
105 	mbox_port = mbox_get_port(sio_port);
106 	if (!mbox_port)
107 		return -1;
108 	msg_pdbg2("IMC MBOX is at 0x%x.\n", mbox_port);
109 
110 	sio_write(mbox_port, 0x82, 0x0);
111 	sio_write(mbox_port, 0x83, cmd);
112 	sio_write(mbox_port, 0x84, 0x0);
113 	/* trigger transfer 0x96 with subcommand cmd */
114 	sio_write(mbox_port, 0x80, 0x96);
115 
116 	return mbox_wait_ack(mbox_port);
117 }
118 
imc_resume(void * data)119 static int imc_resume(void *data)
120 {
121 	struct pci_dev *dev = data;
122 	int ret = imc_send_cmd(dev, 0xb5);
123 
124 	if (ret != 0)
125 		msg_pinfo("Resuming IMC failed.\n");
126 	else
127 		msg_pdbg2("IMC resumed.\n");
128 	return ret;
129 }
130 
amd_imc_shutdown(struct pci_dev * dev)131 int amd_imc_shutdown(struct pci_dev *dev)
132 {
133 	/* Try to put IMC to sleep */
134 	int ret = imc_send_cmd(dev, 0xb4);
135 
136 	/* No IMC activity detectable, assume we are fine */
137 	if (ret < 0) {
138 		msg_pdbg2("No IMC found.\n");
139 		return 0;
140 	}
141 
142 	if (ret != 0) {
143 		msg_perr("Shutting down IMC failed.\n");
144 		return ret;
145 	}
146 	msg_pdbg2("Shutting down IMC successful.\n");
147 
148 	if (register_shutdown(imc_resume, dev))
149 		return 1;
150 
151 	return ret;
152 }
153