summaryrefslogtreecommitdiffstats
path: root/nicnatsemi.c
blob: efa879a3b9fdedf55133b6a12c3c2c9a507f89a3 (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * This file is part of the flashrom project.
 *
 * Copyright (C) 2010 Andrew Morgan <ziltro@ziltro.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.
 */

#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
#include "hwaccess_x86_io.h"
#include "platform/pci.h"

#define PCI_VENDOR_ID_NATSEMI	0x100b

#define BOOT_ROM_ADDR		0x50
#define BOOT_ROM_DATA		0x54

struct nicnatsemi_data {
	uint32_t io_base_addr;
};

static const struct dev_entry nics_natsemi[] = {
	{0x100b, 0x0020, NT, "National Semiconductor", "DP83815/DP83816"},
	{0x100b, 0x0022, NT, "National Semiconductor", "DP83820"},

	{0},
};

static void nicnatsemi_chip_writeb(const struct flashctx *flash, uint8_t val,
				   chipaddr addr)
{
	const struct nicnatsemi_data *data = flash->mst->par.data;

	OUTL((uint32_t)addr & 0x0001FFFF, data->io_base_addr + BOOT_ROM_ADDR);
	/*
	 * The datasheet requires 32 bit accesses to this register, but it seems
	 * that requirement might only apply if the register is memory mapped.
	 * Bits 8-31 of this register are apparently don't care, and if this
	 * register is I/O port mapped, 8 bit accesses to the lowest byte of the
	 * register seem to work fine. Due to that, we ignore the advice in the
	 * data sheet.
	 */
	OUTB(val, data->io_base_addr + BOOT_ROM_DATA);
}

static uint8_t nicnatsemi_chip_readb(const struct flashctx *flash,
				     const chipaddr addr)
{
	const struct nicnatsemi_data *data = flash->mst->par.data;

	OUTL(((uint32_t)addr & 0x0001FFFF), data->io_base_addr + BOOT_ROM_ADDR);
	/*
	 * The datasheet requires 32 bit accesses to this register, but it seems
	 * that requirement might only apply if the register is memory mapped.
	 * Bits 8-31 of this register are apparently don't care, and if this
	 * register is I/O port mapped, 8 bit accesses to the lowest byte of the
	 * register seem to work fine. Due to that, we ignore the advice in the
	 * data sheet.
	 */
	return INB(data->io_base_addr + BOOT_ROM_DATA);
}

static int nicnatsemi_shutdown(void *par_data)
{
	free(par_data);
	return 0;
}

static const struct par_master par_master_nicnatsemi = {
	.chip_readb	= nicnatsemi_chip_readb,
	.chip_readw	= fallback_chip_readw,
	.chip_readl	= fallback_chip_readl,
	.chip_readn	= fallback_chip_readn,
	.chip_writeb	= nicnatsemi_chip_writeb,
	.chip_writew	= fallback_chip_writew,
	.chip_writel	= fallback_chip_writel,
	.chip_writen	= fallback_chip_writen,
	.shutdown	= nicnatsemi_shutdown,
};

static int nicnatsemi_init(const struct programmer_cfg *cfg)
{
	struct pci_dev *dev = NULL;
	uint32_t io_base_addr;

	if (rget_io_perms())
		return 1;

	dev = pcidev_init(cfg, nics_natsemi, PCI_BASE_ADDRESS_0);
	if (!dev)
		return 1;

	io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);
	if (!io_base_addr)
		return 1;

	struct nicnatsemi_data *data = calloc(1, sizeof(*data));
	if (!data) {
		msg_perr("Unable to allocate space for PAR master data\n");
		return 1;
	}
	data->io_base_addr = io_base_addr;

	/* The datasheet shows address lines MA0-MA16 in one place and MA0-MA15
	 * in another. My NIC has MA16 connected to A16 on the boot ROM socket
	 * so I'm assuming it is accessible. If not then next line wants to be
	 * max_rom_decode.parallel = 65536; and the mask in the read/write
	 * functions below wants to be 0x0000FFFF.
	 */
	max_rom_decode.parallel = 131072;
	return register_par_master(&par_master_nicnatsemi, BUS_PARALLEL, data);
}


const struct programmer_entry programmer_nicnatsemi = {
	.name			= "nicnatsemi",
	.type			= PCI,
	.devs.dev		= nics_natsemi,
	.init			= nicnatsemi_init,
};