source: trunk/mcp6x_spi.c @ 1475

Revision 1475, 4.9 KB checked in by hailfinger, 5 months ago (diff)

Have all programmer init functions register bus masters/programmers

All programmer types (Parallel, SPI, Opaque) now register themselves
into a generic programmer list and probing is now programmer-centric
instead of chip-centric.
Registering multiple SPI/... masters at the same time is now possible
without any problems. Handling multiple flash chips is still unchanged,
but now we have the infrastructure to deal with "dual BIOS" and "one
flash behind southbridge and one flash behind EC" sanely.

A nice side effect is that this patch kills quite a few global variables
and improves the situation for libflashrom.

Hint for developers:
struct {spi,par,opaque}_programmer now have a void *data pointer to
store any additional programmer-specific data, e.g. hardware
configuration info.

Note:
flashrom -f -c FOO -r forced_read.bin
does not work anymore. We have to find an architecturally clean way to
solve this.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>
Acked-by: Michael Karcher <flashrom@…>

Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2010 Carl-Daniel Hailfinger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18 */
19
20/* Driver for the NVIDIA MCP6x/MCP7x MCP6X_SPI controller.
21 * Based on clean room reverse engineered docs from
22 * http://www.flashrom.org/pipermail/flashrom/2009-December/001180.html
23 * created by Michael Karcher.
24 */
25
26#if defined(__i386__) || defined(__x86_64__)
27
28#include <stdlib.h>
29#include <ctype.h>
30#include "flash.h"
31#include "programmer.h"
32
33/* Bit positions for each pin. */
34
35#define MCP6X_SPI_CS            1
36#define MCP6X_SPI_SCK           2
37#define MCP6X_SPI_MOSI          3
38#define MCP6X_SPI_MISO          4
39#define MCP6X_SPI_REQUEST       0
40#define MCP6X_SPI_GRANT         8
41
42void *mcp6x_spibar = NULL;
43
44/* Cached value of last GPIO state. */
45static uint8_t mcp_gpiostate;
46
47static void mcp6x_request_spibus(void)
48{
49        mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
50        mcp_gpiostate |= 1 << MCP6X_SPI_REQUEST;
51        mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
52
53        /* Wait until we are allowed to use the SPI bus. */
54        while (!(mmio_readw(mcp6x_spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) ;
55
56        /* Update the cache. */
57        mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
58}
59
60static void mcp6x_release_spibus(void)
61{
62        mcp_gpiostate &= ~(1 << MCP6X_SPI_REQUEST);
63        mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
64}
65
66static void mcp6x_bitbang_set_cs(int val)
67{
68        mcp_gpiostate &= ~(1 << MCP6X_SPI_CS);
69        mcp_gpiostate |= (val << MCP6X_SPI_CS);
70        mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
71}
72
73static void mcp6x_bitbang_set_sck(int val)
74{
75        mcp_gpiostate &= ~(1 << MCP6X_SPI_SCK);
76        mcp_gpiostate |= (val << MCP6X_SPI_SCK);
77        mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
78}
79
80static void mcp6x_bitbang_set_mosi(int val)
81{
82        mcp_gpiostate &= ~(1 << MCP6X_SPI_MOSI);
83        mcp_gpiostate |= (val << MCP6X_SPI_MOSI);
84        mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
85}
86
87static int mcp6x_bitbang_get_miso(void)
88{
89        mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
90        return (mcp_gpiostate >> MCP6X_SPI_MISO) & 0x1;
91}
92
93static const struct bitbang_spi_master bitbang_spi_master_mcp6x = {
94        .type = BITBANG_SPI_MASTER_MCP,
95        .set_cs = mcp6x_bitbang_set_cs,
96        .set_sck = mcp6x_bitbang_set_sck,
97        .set_mosi = mcp6x_bitbang_set_mosi,
98        .get_miso = mcp6x_bitbang_get_miso,
99        .request_bus = mcp6x_request_spibus,
100        .release_bus = mcp6x_release_spibus,
101        .half_period = 0,
102};
103
104int mcp6x_spi_init(int want_spi)
105{
106        uint16_t status;
107        uint32_t mcp6x_spibaraddr;
108        struct pci_dev *smbusdev;
109
110        /* Look for the SMBus device (SMBus PCI class) */
111        smbusdev = pci_dev_find_vendorclass(0x10de, 0x0c05);
112        if (!smbusdev) {
113                if (want_spi) {
114                        msg_perr("ERROR: SMBus device not found. Not enabling "
115                                 "SPI.\n");
116                        return 1;
117                } else {
118                        msg_pinfo("Odd. SMBus device not found.\n");
119                        return 0;
120                }
121        }
122        msg_pdbg("Found SMBus device %04x:%04x at %02x:%02x:%01x\n",
123                smbusdev->vendor_id, smbusdev->device_id,
124                smbusdev->bus, smbusdev->dev, smbusdev->func);
125
126
127        /* Locate the BAR where the SPI interface lives. */
128        mcp6x_spibaraddr = pci_read_long(smbusdev, 0x74);
129        /* BAR size is 64k, bits 15..4 are zero, bit 3..0 declare a
130         * 32-bit non-prefetchable memory BAR.
131         */
132        mcp6x_spibaraddr &= ~0xffff;
133        msg_pdbg("MCP SPI BAR is at 0x%08x\n", mcp6x_spibaraddr);
134
135        /* Accessing a NULL pointer BAR is evil. Don't do it. */
136        if (!mcp6x_spibaraddr && want_spi) {
137                msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR "
138                         "is invalid.\n");
139                return 1;
140        } else if (!mcp6x_spibaraddr && !want_spi) {
141                msg_pdbg("MCP SPI is not used.\n");
142                return 0;
143        } else if (mcp6x_spibaraddr && !want_spi) {
144                msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently"
145                         " doesn't have SPI enabled.\n");
146                /* FIXME: Should we enable SPI anyway? */
147                return 0;
148        }
149        /* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */
150        mcp6x_spibar = physmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544);
151
152#if 0
153        /* FIXME: Run the physunmap in a shutdown function. */
154        physunmap(mcp6x_spibar, 0x544);
155#endif
156
157        status = mmio_readw(mcp6x_spibar + 0x530);
158        msg_pdbg("SPI control is 0x%04x, req=%i, gnt=%i\n",
159                 status, (status >> MCP6X_SPI_REQUEST) & 0x1,
160                 (status >> MCP6X_SPI_GRANT) & 0x1);
161        mcp_gpiostate = status & 0xff;
162
163        if (bitbang_spi_init(&bitbang_spi_master_mcp6x)) {
164                /* This should never happen. */
165                msg_perr("MCP6X bitbang SPI master init failed!\n");
166                return 1;
167        }
168
169        return 0;
170}
171
172#endif
Note: See TracBrowser for help on using the repository browser.