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