blob: 71a7889bfa4044f82feab633ecc7ba927b52168a [file] [log] [blame]
Rudolf Marek70e14592013-07-25 22:58:56 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2013 Rudolf Marek <r.marek@assembler.cz>
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.
Rudolf Marek70e14592013-07-25 22:58:56 +000016 */
17
Nico Huber4d51e072023-01-29 17:56:29 +000018#include <stdlib.h>
19#include <string.h>
20
Rudolf Marek70e14592013-07-25 22:58:56 +000021#include "flash.h"
22#include "programmer.h"
Thomas Heijligena0655202021-12-14 16:36:05 +010023#include "hwaccess_x86_io.h"
Rudolf Marek70e14592013-07-25 22:58:56 +000024#include "spi.h"
Thomas Heijligend96c97c2021-11-02 21:03:00 +010025#include "platform/pci.h"
Rudolf Marek70e14592013-07-25 22:58:56 +000026
27/* same as serverengines */
28static void enter_conf_mode_ec(uint16_t port)
29{
30 OUTB(0x5a, port);
31}
32
33static void exit_conf_mode_ec(uint16_t port)
34{
35 OUTB(0xa5, port);
36}
37
38static uint16_t get_sio_port(struct pci_dev *dev)
39{
40 uint16_t ec_port;
41
42 if (!dev) {
43 return 0;
44 }
45
46 ec_port = pci_read_word(dev, 0xa4);
47
48 /* EcPortActive? */
49 if (!(ec_port & 0x1))
50 return 0;
51
52 ec_port &= ~0x1;
53
54 return ec_port;
55}
56
57/* Wait for up to 10 ms for a response. */
58static int mbox_wait_ack(uint16_t mbox_port)
59{
60 int i = 10;
61 while (sio_read(mbox_port, 0x82) != 0xfa) {
62 if (--i == 0) {
63 msg_pwarn("IMC MBOX: Timeout!\n");
64 return 1;
65 }
66 programmer_delay(1000);
67 }
68 return 0;
69}
70
71static uint16_t mbox_get_port(uint16_t sio_port)
72{
73 uint16_t mbox_port;
74
75 enter_conf_mode_ec(sio_port);
76
77 /* Go to LDN 9, mailbox */
78 sio_write(sio_port, 7, 9);
79
80 /* MBOX inactive? */
81 if ((sio_read(sio_port, 0x30) & 1) == 0) {
82 exit_conf_mode_ec(sio_port);
83 return 0;
84 }
85
86 mbox_port = sio_read(sio_port, 0x60) << 8;
87 mbox_port |= sio_read(sio_port, 0x61);
88
89 exit_conf_mode_ec(sio_port);
90 return mbox_port;
91}
92
93/* Returns negative values when IMC is inactive, positive values on errors */
94static int imc_send_cmd(struct pci_dev *dev, uint8_t cmd)
95{
96 uint16_t sio_port;
97 uint16_t mbox_port;
98
99 /* IntegratedEcPresent? */
100 if (!(pci_read_byte(dev, 0x40) & (1 << 7)))
101 return -1;
102
103 sio_port = get_sio_port(dev);
104 if (!sio_port)
105 return -1;
106
107 msg_pdbg2("IMC SIO is at 0x%x.\n", sio_port);
108 mbox_port = mbox_get_port(sio_port);
109 if (!mbox_port)
110 return -1;
111 msg_pdbg2("IMC MBOX is at 0x%x.\n", mbox_port);
112
113 sio_write(mbox_port, 0x82, 0x0);
114 sio_write(mbox_port, 0x83, cmd);
115 sio_write(mbox_port, 0x84, 0x0);
116 /* trigger transfer 0x96 with subcommand cmd */
117 sio_write(mbox_port, 0x80, 0x96);
118
119 return mbox_wait_ack(mbox_port);
120}
121
122static int imc_resume(void *data)
123{
124 struct pci_dev *dev = data;
125 int ret = imc_send_cmd(dev, 0xb5);
126
127 if (ret != 0)
Angel Pons332fdab2022-12-21 16:34:39 +0100128 msg_pinfo("Resuming IMC failed.\n");
Rudolf Marek70e14592013-07-25 22:58:56 +0000129 else
130 msg_pdbg2("IMC resumed.\n");
131 return ret;
132}
133
Nico Huber4d51e072023-01-29 17:56:29 +0000134static int amd_imc_shutdown(struct pci_dev *dev)
Rudolf Marek70e14592013-07-25 22:58:56 +0000135{
136 /* Try to put IMC to sleep */
137 int ret = imc_send_cmd(dev, 0xb4);
138
139 /* No IMC activity detectable, assume we are fine */
140 if (ret < 0) {
141 msg_pdbg2("No IMC found.\n");
142 return 0;
143 }
144
145 if (ret != 0) {
146 msg_perr("Shutting down IMC failed.\n");
147 return ret;
148 }
149 msg_pdbg2("Shutting down IMC successful.\n");
150
151 if (register_shutdown(imc_resume, dev))
152 return 1;
153
154 return ret;
155}
Nico Huber4d51e072023-01-29 17:56:29 +0000156
157int handle_imc(struct pci_dev *dev)
158{
159 bool amd_imc_force = false;
160 char *arg = extract_programmer_param("amd_imc_force");
161 if (arg && !strcmp(arg, "yes")) {
162 amd_imc_force = true;
163 msg_pspew("amd_imc_force enabled.\n");
164 } else if (arg && !strlen(arg)) {
165 msg_perr("Missing argument for amd_imc_force.\n");
166 free(arg);
167 return 1;
168 } else if (arg) {
169 msg_perr("Unknown argument for amd_imc_force: \"%s\" (not \"yes\").\n", arg);
170 free(arg);
171 return 1;
172 }
173 free(arg);
174
175 /* TODO: we should not only look at IntegratedImcPresent (LPC Dev 20, Func 3, 40h) but also at
176 * IMCEnable(Strap) and Override EcEnable(Strap) (sb8xx, sb9xx?, a50, Bolton: Misc_Reg: 80h-87h;
177 * sb7xx, sp5100: PM_Reg: B0h-B1h) etc. */
178 uint8_t reg = pci_read_byte(dev, 0x40);
179 if ((reg & (1 << 7)) == 0) {
180 msg_pdbg("IMC is not active.\n");
181 return 0;
182 }
183
184 if (!amd_imc_force)
185 programmer_may_write = false;
186 msg_pinfo("Writes have been disabled for safety reasons because the presence of the IMC\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200187 "was detected and it could interfere with accessing flash memory. Flashprog will\n"
Nico Huber4d51e072023-01-29 17:56:29 +0000188 "try to disable it temporarily but even then this might not be safe:\n"
189 "when it is re-enabled and after a reboot it expects to find working code\n"
190 "in the flash and it is unpredictable what happens if there is none.\n"
191 "\n"
192 "To be safe make sure that there is a working IMC firmware at the right\n"
193 "location in the image you intend to write and do not attempt to erase.\n"
194 "\n"
195 "You can enforce write support with the amd_imc_force programmer option.\n");
196 if (amd_imc_force)
197 msg_pinfo("Continuing with write support because the user forced us to!\n");
198
199 return amd_imc_shutdown(dev);
200}