1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-26 14:42:36 +02:00
flashrom/mcp6x_spi.c
Thomas Heijligen 90286fe643 printf: Use inttype.h macros for format strings
DJGPP for compiling DOS has other sizes for the normal int types and
therefore throwing errors when using %i %d or %x with uint32_t.

Fix these warnings by using the macros created for it and provided in
inttypes.h.

Change-Id: Ia75b6df981ce60c891161fe553c7ceab8570178d
Signed-off-by: Thomas Heijligen <thomas.heijligen@secunet.com>
Reviewed-on: https://review.coreboot.org/c/flashrom/+/73040
Reviewed-by: Anastasia Klimchuk <aklm@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2023-04-27 09:36:46 +00:00

194 lines
5.3 KiB
C

/*
* This file is part of the flashrom project.
*
* Copyright (C) 2010 Carl-Daniel Hailfinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Driver for the NVIDIA MCP6x/MCP7x MCP6X_SPI controller.
* Based on clean room reverse engineered docs from
* https://flashrom.org/pipermail/flashrom/2009-December/001180.html
* created by Michael Karcher.
*/
#include <stdlib.h>
#include <ctype.h>
#include "flash.h"
#include "programmer.h"
#include "hwaccess_physmap.h"
#include "platform/pci.h"
/* Bit positions for each pin. */
#define MCP6X_SPI_CS 1
#define MCP6X_SPI_SCK 2
#define MCP6X_SPI_MOSI 3
#define MCP6X_SPI_MISO 4
#define MCP6X_SPI_REQUEST 0
#define MCP6X_SPI_GRANT 8
struct mcp6x_spi_data {
void *spibar;
/* Cached value of last GPIO state. */
uint8_t gpiostate;
};
static void mcp6x_request_spibus(void *spi_data)
{
struct mcp6x_spi_data *data = spi_data;
data->gpiostate = mmio_readb(data->spibar + 0x530);
data->gpiostate |= 1 << MCP6X_SPI_REQUEST;
mmio_writeb(data->gpiostate, data->spibar + 0x530);
/* Wait until we are allowed to use the SPI bus. */
while (!(mmio_readw(data->spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) ;
/* Update the cache. */
data->gpiostate = mmio_readb(data->spibar + 0x530);
}
static void mcp6x_release_spibus(void *spi_data)
{
struct mcp6x_spi_data *data = spi_data;
data->gpiostate &= ~(1 << MCP6X_SPI_REQUEST);
mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
static void mcp6x_bitbang_set_cs(int val, void *spi_data)
{
struct mcp6x_spi_data *data = spi_data;
data->gpiostate &= ~(1 << MCP6X_SPI_CS);
data->gpiostate |= (val << MCP6X_SPI_CS);
mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
static void mcp6x_bitbang_set_sck(int val, void *spi_data)
{
struct mcp6x_spi_data *data = spi_data;
data->gpiostate &= ~(1 << MCP6X_SPI_SCK);
data->gpiostate |= (val << MCP6X_SPI_SCK);
mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
static void mcp6x_bitbang_set_mosi(int val, void *spi_data)
{
struct mcp6x_spi_data *data = spi_data;
data->gpiostate &= ~(1 << MCP6X_SPI_MOSI);
data->gpiostate |= (val << MCP6X_SPI_MOSI);
mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
static int mcp6x_bitbang_get_miso(void *spi_data)
{
struct mcp6x_spi_data *data = spi_data;
data->gpiostate = mmio_readb(data->spibar + 0x530);
return (data->gpiostate >> MCP6X_SPI_MISO) & 0x1;
}
static const struct bitbang_spi_master bitbang_spi_master_mcp6x = {
.set_cs = mcp6x_bitbang_set_cs,
.set_sck = mcp6x_bitbang_set_sck,
.set_mosi = mcp6x_bitbang_set_mosi,
.get_miso = mcp6x_bitbang_get_miso,
.request_bus = mcp6x_request_spibus,
.release_bus = mcp6x_release_spibus,
.half_period = 0,
};
static int mcp6x_shutdown(void *spi_data)
{
free(spi_data);
return 0;
}
int mcp6x_spi_init(int want_spi)
{
uint16_t status;
uint32_t mcp6x_spibaraddr;
struct pci_dev *smbusdev;
void *mcp6x_spibar = NULL;
uint8_t mcp_gpiostate;
/* Look for the SMBus device (SMBus PCI class) */
smbusdev = pcidev_find_vendorclass(0x10de, 0x0c05);
if (!smbusdev) {
if (want_spi) {
msg_perr("ERROR: SMBus device not found. Not enabling "
"SPI.\n");
return 1;
} else {
msg_pinfo("Odd. SMBus device not found.\n");
return 0;
}
}
msg_pdbg("Found SMBus device %04x:%04x at %02x:%02x:%01x\n",
smbusdev->vendor_id, smbusdev->device_id,
smbusdev->bus, smbusdev->dev, smbusdev->func);
/* Locate the BAR where the SPI interface lives. */
mcp6x_spibaraddr = pci_read_long(smbusdev, 0x74);
/* BAR size is 64k, bits 15..4 are zero, bit 3..0 declare a
* 32-bit non-prefetchable memory BAR.
*/
mcp6x_spibaraddr &= ~0xffff;
msg_pdbg("MCP SPI BAR is at 0x%08"PRIx32"\n", mcp6x_spibaraddr);
/* Accessing a NULL pointer BAR is evil. Don't do it. */
if (!mcp6x_spibaraddr && want_spi) {
msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR is invalid.\n");
return 1;
} else if (!mcp6x_spibaraddr && !want_spi) {
msg_pdbg("MCP SPI is not used.\n");
return 0;
} else if (mcp6x_spibaraddr && !want_spi) {
msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently doesn't have SPI enabled.\n");
/* FIXME: Should we enable SPI anyway? */
return 0;
}
/* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */
mcp6x_spibar = rphysmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544);
if (mcp6x_spibar == ERROR_PTR)
return 1;
status = mmio_readw(mcp6x_spibar + 0x530);
msg_pdbg("SPI control is 0x%04x, req=%i, gnt=%i\n",
status, (status >> MCP6X_SPI_REQUEST) & 0x1,
(status >> MCP6X_SPI_GRANT) & 0x1);
mcp_gpiostate = status & 0xff;
struct mcp6x_spi_data *data = calloc(1, sizeof(*data));
if (!data) {
msg_perr("Unable to allocate space for SPI master data\n");
return 1;
}
data->spibar = mcp6x_spibar;
data->gpiostate = mcp_gpiostate;
if (register_shutdown(mcp6x_shutdown, data)) {
free(data);
return 1;
}
if (register_spi_bitbang_master(&bitbang_spi_master_mcp6x, data)) {
/* This should never happen. */
msg_perr("MCP6X bitbang SPI master init failed!\n");
return 1;
}
return 0;
}