aboutsummaryrefslogtreecommitdiffstats
path: root/sst_fwhub.c
blob: d688a350d948841afcb2d910fd1810a97e1f155b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
 * This file is part of the flashrom project.
 *
 * Copyright (C) 2000 Silicon Integrated System Corporation
 * Copyright (C) 2009 Kontron Modular Computers
 * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
 *
 * 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; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 */

/* Adapted from the Intel FW hub stuff for 82802ax parts. */

#include "flash.h"
#include "chipdrivers.h"

static int check_sst_fwhub_block_lock(struct flashctx *flash, unsigned int offset)
{
	chipaddr registers = flash->virtual_registers;
	uint8_t blockstatus;

	blockstatus = chip_readb(flash, registers + offset + 2);
	msg_cdbg("Lock status for 0x%06x (size 0x%06x) is %02x, ",
		     offset, flash->chip->page_size, blockstatus);
	switch (blockstatus & 0x3) {
	case 0x0:
		msg_cdbg("full access\n");
		break;
	case 0x1:
		msg_cdbg("write locked\n");
		break;
	case 0x2:
		msg_cdbg("locked open\n");
		break;
	case 0x3:
		msg_cdbg("write locked down\n");
		break;
	}
	/* Return content of the write_locked bit */
	return blockstatus & 0x1;
}

static int clear_sst_fwhub_block_lock(struct flashctx *flash, unsigned int offset)
{
	chipaddr registers = flash->virtual_registers;
	uint8_t blockstatus;

	blockstatus = check_sst_fwhub_block_lock(flash, offset);

	if (blockstatus) {
		msg_cdbg("Trying to clear lock for 0x%06x... ", offset);
		chip_writeb(flash, 0, registers + offset + 2);

		blockstatus = check_sst_fwhub_block_lock(flash, offset);
		msg_cdbg("%s\n", (blockstatus) ? "failed" : "OK");
	}

	return blockstatus;
}

int printlock_sst_fwhub(struct flashctx *flash)
{
	unsigned int i;

	for (i = 0; i < flash->chip->total_size * 1024; i += flash->chip->page_size)
		check_sst_fwhub_block_lock(flash, i);

	return 0;
}

int unlock_sst_fwhub(struct flashctx *flash)
{
	unsigned int i;
	int ret = 0;

	for (i = 0; i < flash->chip->total_size * 1024; i += flash->chip->page_size)
	{
		if (clear_sst_fwhub_block_lock(flash, i))
		{
			msg_cwarn("Warning: Unlock Failed for block 0x%06x\n", i);
			ret++;
		}
	}
	return ret;
}
class="n">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 = pci_dev_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%08x\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; } #endif