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