packaging: minor amendments
[profile/ivi/flashrom.git] / nic3com.c
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
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  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #if defined(__i386__) || defined(__x86_64__)
22
23 #include <stdlib.h>
24 #include "flash.h"
25 #include "programmer.h"
26 #include "hwaccess.h"
27
28 #define BIOS_ROM_ADDR           0x04
29 #define BIOS_ROM_DATA           0x08
30 #define INT_STATUS              0x0e
31 #define INTERNAL_CONFIG         0x00
32 #define SELECT_REG_WINDOW       0x800
33
34 #define PCI_VENDOR_ID_3COM      0x10b7
35
36 static uint32_t internal_conf;
37 static uint16_t id;
38
39 const struct pcidev_status nics_3com[] = {
40         /* 3C90xB */
41         {0x10b7, 0x9055, OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"},
42         {0x10b7, 0x9001, NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" },
43         {0x10b7, 0x9004, OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" },
44         {0x10b7, 0x9005, NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" },
45         {0x10b7, 0x9006, NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" },
46         {0x10b7, 0x900a, NT, "3COM", "3C90xB: PCI 10BASE-FL" },
47         {0x10b7, 0x905a, NT, "3COM", "3C90xB: PCI 10BASE-FX" },
48         {0x10b7, 0x9058, OK, "3COM", "3C905B: Cyclone 10/100/BNC" },
49
50         /* 3C905C */
51         {0x10b7, 0x9200, OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" },
52
53         /* 3C980C */
54         {0x10b7, 0x9805, NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" },
55
56         {},
57 };
58
59 static void nic3com_chip_writeb(const struct flashctx *flash, uint8_t val,
60                                 chipaddr addr);
61 static uint8_t nic3com_chip_readb(const struct flashctx *flash,
62                                   const chipaddr addr);
63 static const struct par_programmer par_programmer_nic3com = {
64                 .chip_readb             = nic3com_chip_readb,
65                 .chip_readw             = fallback_chip_readw,
66                 .chip_readl             = fallback_chip_readl,
67                 .chip_readn             = fallback_chip_readn,
68                 .chip_writeb            = nic3com_chip_writeb,
69                 .chip_writew            = fallback_chip_writew,
70                 .chip_writel            = fallback_chip_writel,
71                 .chip_writen            = fallback_chip_writen,
72 };
73
74 static int nic3com_shutdown(void *data)
75 {
76         /* 3COM 3C90xB cards need a special fixup. */
77         if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
78             || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
79                 /* Select register window 3 and restore the receiver status. */
80                 OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
81                 OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG);
82         }
83
84         pci_cleanup(pacc);
85         return 0;
86 }
87
88 int nic3com_init(void)
89 {
90         if (rget_io_perms())
91                 return 1;
92
93         io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_3com);
94
95         id = pcidev_dev->device_id;
96
97         /* 3COM 3C90xB cards need a special fixup. */
98         if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
99             || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
100                 /* Select register window 3 and save the receiver status. */
101                 OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
102                 internal_conf = INL(io_base_addr + INTERNAL_CONFIG);
103
104                 /* Set receiver type to MII for full BIOS ROM access. */
105                 OUTL((internal_conf & 0xf00fffff) | 0x00600000, io_base_addr);
106         }
107
108         /*
109          * The lowest 16 bytes of the I/O mapped register space of (most) 3COM
110          * cards form a 'register window' into one of multiple (usually 8)
111          * register banks. For 3C90xB/3C90xC we need register window/bank 0.
112          */
113         OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS);
114
115         if (register_shutdown(nic3com_shutdown, NULL))
116                 return 1;
117
118         max_rom_decode.parallel = 128 * 1024;
119         register_par_programmer(&par_programmer_nic3com, BUS_PARALLEL);
120
121         return 0;
122 }
123
124 static void nic3com_chip_writeb(const struct flashctx *flash, uint8_t val,
125                                 chipaddr addr)
126 {
127         OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
128         OUTB(val, io_base_addr + BIOS_ROM_DATA);
129 }
130
131 static uint8_t nic3com_chip_readb(const struct flashctx *flash,
132                                   const chipaddr addr)
133 {
134         OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
135         return INB(io_base_addr + BIOS_ROM_DATA);
136 }
137
138 #else
139 #error PCI port I/O access is not supported on this architecture yet.
140 #endif