xref: /aosp_15_r20/external/flashrom/nicnatsemi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2010 Andrew Morgan <[email protected]>
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; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 #include <stdlib.h>
18 #include "flash.h"
19 #include "programmer.h"
20 #include "hwaccess_x86_io.h"
21 #include "platform/pci.h"
22 
23 #define PCI_VENDOR_ID_NATSEMI	0x100b
24 
25 #define BOOT_ROM_ADDR		0x50
26 #define BOOT_ROM_DATA		0x54
27 
28 struct nicnatsemi_data {
29 	uint32_t io_base_addr;
30 };
31 
32 static const struct dev_entry nics_natsemi[] = {
33 	{0x100b, 0x0020, NT, "National Semiconductor", "DP83815/DP83816"},
34 	{0x100b, 0x0022, NT, "National Semiconductor", "DP83820"},
35 
36 	{0},
37 };
38 
nicnatsemi_chip_writeb(const struct flashctx * flash,uint8_t val,chipaddr addr)39 static void nicnatsemi_chip_writeb(const struct flashctx *flash, uint8_t val,
40 				   chipaddr addr)
41 {
42 	const struct nicnatsemi_data *data = flash->mst->par.data;
43 
44 	OUTL((uint32_t)addr & 0x0001FFFF, data->io_base_addr + BOOT_ROM_ADDR);
45 	/*
46 	 * The datasheet requires 32 bit accesses to this register, but it seems
47 	 * that requirement might only apply if the register is memory mapped.
48 	 * Bits 8-31 of this register are apparently don't care, and if this
49 	 * register is I/O port mapped, 8 bit accesses to the lowest byte of the
50 	 * register seem to work fine. Due to that, we ignore the advice in the
51 	 * data sheet.
52 	 */
53 	OUTB(val, data->io_base_addr + BOOT_ROM_DATA);
54 }
55 
nicnatsemi_chip_readb(const struct flashctx * flash,const chipaddr addr)56 static uint8_t nicnatsemi_chip_readb(const struct flashctx *flash,
57 				     const chipaddr addr)
58 {
59 	const struct nicnatsemi_data *data = flash->mst->par.data;
60 
61 	OUTL(((uint32_t)addr & 0x0001FFFF), data->io_base_addr + BOOT_ROM_ADDR);
62 	/*
63 	 * The datasheet requires 32 bit accesses to this register, but it seems
64 	 * that requirement might only apply if the register is memory mapped.
65 	 * Bits 8-31 of this register are apparently don't care, and if this
66 	 * register is I/O port mapped, 8 bit accesses to the lowest byte of the
67 	 * register seem to work fine. Due to that, we ignore the advice in the
68 	 * data sheet.
69 	 */
70 	return INB(data->io_base_addr + BOOT_ROM_DATA);
71 }
72 
nicnatsemi_shutdown(void * par_data)73 static int nicnatsemi_shutdown(void *par_data)
74 {
75 	free(par_data);
76 	return 0;
77 }
78 
79 static const struct par_master par_master_nicnatsemi = {
80 	.chip_readb	= nicnatsemi_chip_readb,
81 	.chip_writeb	= nicnatsemi_chip_writeb,
82 	.shutdown	= nicnatsemi_shutdown,
83 };
84 
nicnatsemi_init(const struct programmer_cfg * cfg)85 static int nicnatsemi_init(const struct programmer_cfg *cfg)
86 {
87 	struct pci_dev *dev = NULL;
88 	uint32_t io_base_addr;
89 
90 	if (rget_io_perms())
91 		return 1;
92 
93 	dev = pcidev_init(cfg, nics_natsemi, PCI_BASE_ADDRESS_0);
94 	if (!dev)
95 		return 1;
96 
97 	io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);
98 	if (!io_base_addr)
99 		return 1;
100 
101 	struct nicnatsemi_data *data = calloc(1, sizeof(*data));
102 	if (!data) {
103 		msg_perr("Unable to allocate space for PAR master data\n");
104 		return 1;
105 	}
106 	data->io_base_addr = io_base_addr;
107 
108 	/* The datasheet shows address lines MA0-MA16 in one place and MA0-MA15
109 	 * in another. My NIC has MA16 connected to A16 on the boot ROM socket
110 	 * so I'm assuming it is accessible. If not then next line wants to be
111 	 * max_rom_decode.parallel = 65536; and the mask in the read/write
112 	 * functions below wants to be 0x0000FFFF.
113 	 */
114 	max_rom_decode.parallel = 131072;
115 	return register_par_master(&par_master_nicnatsemi, BUS_PARALLEL, data);
116 }
117 
118 
119 const struct programmer_entry programmer_nicnatsemi = {
120 	.name			= "nicnatsemi",
121 	.type			= PCI,
122 	.devs.dev		= nics_natsemi,
123 	.init			= nicnatsemi_init,
124 };
125