| 1 | /*␊ |
| 2 | * This file is part of the flashrom project.␊ |
| 3 | *␊ |
| 4 | * Copyright (C) 2000 Silicon Integrated System Corporation␊ |
| 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 | /*␊ |
| 22 | * Datasheet:␊ |
| 23 | * - Name: Intel 82802AB/82802AC Firmware Hub (FWH)␊ |
| 24 | * - URL: http://www.intel.com/design/chipsets/datashts/290658.htm␊ |
| 25 | * - PDF: http://download.intel.com/design/chipsets/datashts/29065804.pdf␊ |
| 26 | * - Order number: 290658-004␊ |
| 27 | */␊ |
| 28 | ␊ |
| 29 | #include "flash.h"␊ |
| 30 | #include "chipdrivers.h"␊ |
| 31 | ␊ |
| 32 | void print_status_82802ab(uint8_t status)␊ |
| 33 | {␊ |
| 34 | ␉msg_cdbg("%s", status & 0x80 ? "Ready:" : "Busy:");␊ |
| 35 | ␉msg_cdbg("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");␊ |
| 36 | ␉msg_cdbg("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");␊ |
| 37 | ␉msg_cdbg("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");␊ |
| 38 | ␉msg_cdbg("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");␊ |
| 39 | ␉msg_cdbg("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");␊ |
| 40 | ␉msg_cdbg("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");␊ |
| 41 | }␊ |
| 42 | ␊ |
| 43 | int probe_82802ab(struct flashctx *flash)␊ |
| 44 | {␊ |
| 45 | ␉chipaddr bios = flash->virtual_memory;␊ |
| 46 | ␉uint8_t id1, id2, flashcontent1, flashcontent2;␊ |
| 47 | ␉int shifted = (flash->feature_bits & FEATURE_ADDR_SHIFTED) != 0;␊ |
| 48 | ␊ |
| 49 | ␉/* Reset to get a clean state */␊ |
| 50 | ␉chip_writeb(flash, 0xFF, bios);␊ |
| 51 | ␉programmer_delay(10);␊ |
| 52 | ␊ |
| 53 | ␉/* Enter ID mode */␊ |
| 54 | ␉chip_writeb(flash, 0x90, bios);␊ |
| 55 | ␉programmer_delay(10);␊ |
| 56 | ␊ |
| 57 | ␉id1 = chip_readb(flash, bios + (0x00 << shifted));␊ |
| 58 | ␉id2 = chip_readb(flash, bios + (0x01 << shifted));␊ |
| 59 | ␊ |
| 60 | ␉/* Leave ID mode */␊ |
| 61 | ␉chip_writeb(flash, 0xFF, bios);␊ |
| 62 | ␊ |
| 63 | ␉programmer_delay(10);␊ |
| 64 | ␊ |
| 65 | ␉msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2);␊ |
| 66 | ␊ |
| 67 | ␉if (!oddparity(id1))␊ |
| 68 | ␉␉msg_cdbg(", id1 parity violation");␊ |
| 69 | ␊ |
| 70 | ␉/*␊ |
| 71 | ␉ * Read the product ID location again. We should now see normal␊ |
| 72 | ␉ * flash contents.␊ |
| 73 | ␉ */␊ |
| 74 | ␉flashcontent1 = chip_readb(flash, bios + (0x00 << shifted));␊ |
| 75 | ␉flashcontent2 = chip_readb(flash, bios + (0x01 << shifted));␊ |
| 76 | ␊ |
| 77 | ␉if (id1 == flashcontent1)␊ |
| 78 | ␉␉msg_cdbg(", id1 is normal flash content");␊ |
| 79 | ␉if (id2 == flashcontent2)␊ |
| 80 | ␉␉msg_cdbg(", id2 is normal flash content");␊ |
| 81 | ␊ |
| 82 | ␉msg_cdbg("\n");␊ |
| 83 | ␉if (id1 != flash->manufacture_id || id2 != flash->model_id)␊ |
| 84 | ␉␉return 0;␊ |
| 85 | ␊ |
| 86 | ␉if (flash->feature_bits & FEATURE_REGISTERMAP)␊ |
| 87 | ␉␉map_flash_registers(flash);␊ |
| 88 | ␊ |
| 89 | ␉return 1;␊ |
| 90 | }␊ |
| 91 | ␊ |
| 92 | uint8_t wait_82802ab(struct flashctx *flash)␊ |
| 93 | {␊ |
| 94 | ␉uint8_t status;␊ |
| 95 | ␉chipaddr bios = flash->virtual_memory;␊ |
| 96 | ␊ |
| 97 | ␉chip_writeb(flash, 0x70, bios);␊ |
| 98 | ␉if ((chip_readb(flash, bios) & 0x80) == 0) {␉// it's busy␊ |
| 99 | ␉␉while ((chip_readb(flash, bios) & 0x80) == 0) ;␊ |
| 100 | ␉}␊ |
| 101 | ␊ |
| 102 | ␉status = chip_readb(flash, bios);␊ |
| 103 | ␊ |
| 104 | ␉/* Reset to get a clean state */␊ |
| 105 | ␉chip_writeb(flash, 0xFF, bios);␊ |
| 106 | ␊ |
| 107 | ␉return status;␊ |
| 108 | }␊ |
| 109 | ␊ |
| 110 | int unlock_82802ab(struct flashctx *flash)␊ |
| 111 | {␊ |
| 112 | ␉int i;␊ |
| 113 | ␉//chipaddr wrprotect = flash->virtual_registers + page + 2;␊ |
| 114 | ␊ |
| 115 | ␉for (i = 0; i < flash->total_size * 1024; i+= flash->page_size)␊ |
| 116 | ␉␉chip_writeb(flash, 0, flash->virtual_registers + i + 2);␊ |
| 117 | ␊ |
| 118 | ␉return 0;␊ |
| 119 | }␊ |
| 120 | ␊ |
| 121 | int erase_block_82802ab(struct flashctx *flash, unsigned int page,␊ |
| 122 | ␉␉␉unsigned int pagesize)␊ |
| 123 | {␊ |
| 124 | ␉chipaddr bios = flash->virtual_memory;␊ |
| 125 | ␉uint8_t status;␊ |
| 126 | ␊ |
| 127 | ␉// clear status register␊ |
| 128 | ␉chip_writeb(flash, 0x50, bios + page);␊ |
| 129 | ␊ |
| 130 | ␉// now start it␊ |
| 131 | ␉chip_writeb(flash, 0x20, bios + page);␊ |
| 132 | ␉chip_writeb(flash, 0xd0, bios + page);␊ |
| 133 | ␉programmer_delay(10);␊ |
| 134 | ␊ |
| 135 | ␉// now let's see what the register is␊ |
| 136 | ␉status = wait_82802ab(flash);␊ |
| 137 | ␉print_status_82802ab(status);␊ |
| 138 | ␊ |
| 139 | ␉/* FIXME: Check the status register for errors. */␊ |
| 140 | ␉return 0;␊ |
| 141 | }␊ |
| 142 | ␊ |
| 143 | /* chunksize is 1 */␊ |
| 144 | int write_82802ab(struct flashctx *flash, uint8_t *src, unsigned int start,␊ |
| 145 | ␉␉ unsigned int len)␊ |
| 146 | {␊ |
| 147 | ␉int i;␊ |
| 148 | ␉chipaddr dst = flash->virtual_memory + start;␊ |
| 149 | ␊ |
| 150 | ␉for (i = 0; i < len; i++) {␊ |
| 151 | ␉␉/* transfer data from source to destination */␊ |
| 152 | ␉␉chip_writeb(flash, 0x40, dst);␊ |
| 153 | ␉␉chip_writeb(flash, *src++, dst++);␊ |
| 154 | ␉␉wait_82802ab(flash);␊ |
| 155 | ␉}␊ |
| 156 | ␊ |
| 157 | ␉/* FIXME: Ignore errors for now. */␊ |
| 158 | ␉return 0;␊ |
| 159 | }␊ |
| 160 | ␊ |
| 161 | int unlock_28f004s5(struct flashctx *flash)␊ |
| 162 | {␊ |
| 163 | ␉chipaddr bios = flash->virtual_memory;␊ |
| 164 | ␉uint8_t mcfg, bcfg, need_unlock = 0, can_unlock = 0;␊ |
| 165 | ␉int i;␊ |
| 166 | ␊ |
| 167 | ␉/* Clear status register */␊ |
| 168 | ␉chip_writeb(flash, 0x50, bios);␊ |
| 169 | ␊ |
| 170 | ␉/* Read identifier codes */␊ |
| 171 | ␉chip_writeb(flash, 0x90, bios);␊ |
| 172 | ␊ |
| 173 | ␉/* Read master lock-bit */␊ |
| 174 | ␉mcfg = chip_readb(flash, bios + 0x3);␊ |
| 175 | ␉msg_cdbg("master lock is ");␊ |
| 176 | ␉if (mcfg) {␊ |
| 177 | ␉␉msg_cdbg("locked!\n");␊ |
| 178 | ␉} else {␊ |
| 179 | ␉␉msg_cdbg("unlocked!\n");␊ |
| 180 | ␉␉can_unlock = 1;␊ |
| 181 | ␉}␊ |
| 182 | ␊ |
| 183 | ␉/* Read block lock-bits */␊ |
| 184 | ␉for (i = 0; i < flash->total_size * 1024; i+= (64 * 1024)) {␊ |
| 185 | ␉␉bcfg = chip_readb(flash, bios + i + 2); // read block lock config␊ |
| 186 | ␉␉msg_cdbg("block lock at %06x is %slocked!\n", i, bcfg ? "" : "un");␊ |
| 187 | ␉␉if (bcfg) {␊ |
| 188 | ␉␉␉need_unlock = 1;␊ |
| 189 | ␉␉}␊ |
| 190 | ␉}␊ |
| 191 | ␊ |
| 192 | ␉/* Reset chip */␊ |
| 193 | ␉chip_writeb(flash, 0xFF, bios);␊ |
| 194 | ␊ |
| 195 | ␉/* Unlock: clear block lock-bits, if needed */␊ |
| 196 | ␉if (can_unlock && need_unlock) {␊ |
| 197 | ␉␉msg_cdbg("Unlock: ");␊ |
| 198 | ␉␉chip_writeb(flash, 0x60, bios);␊ |
| 199 | ␉␉chip_writeb(flash, 0xD0, bios);␊ |
| 200 | ␉␉chip_writeb(flash, 0xFF, bios);␊ |
| 201 | ␉␉msg_cdbg("Done!\n");␊ |
| 202 | ␉}␊ |
| 203 | ␊ |
| 204 | ␉/* Error: master locked or a block is locked */␊ |
| 205 | ␉if (!can_unlock && need_unlock) {␊ |
| 206 | ␉␉msg_cerr("At least one block is locked and lockdown is active!\n");␊ |
| 207 | ␉␉return -1;␊ |
| 208 | ␉}␊ |
| 209 | ␊ |
| 210 | ␉return 0;␊ |
| 211 | }␊ |
| 212 | ␊ |
| 213 | int unlock_lh28f008bjt(struct flashctx *flash)␊ |
| 214 | {␊ |
| 215 | ␉chipaddr bios = flash->virtual_memory;␊ |
| 216 | ␉uint8_t mcfg, bcfg;␊ |
| 217 | ␉uint8_t need_unlock = 0, can_unlock = 0;␊ |
| 218 | ␉int i;␊ |
| 219 | ␊ |
| 220 | ␉/* Wait if chip is busy */␊ |
| 221 | ␉wait_82802ab(flash);␊ |
| 222 | ␊ |
| 223 | ␉/* Read identifier codes */␊ |
| 224 | ␉chip_writeb(flash, 0x90, bios);␊ |
| 225 | ␊ |
| 226 | ␉/* Read master lock-bit */␊ |
| 227 | ␉mcfg = chip_readb(flash, bios + 0x3);␊ |
| 228 | ␉msg_cdbg("master lock is ");␊ |
| 229 | ␉if (mcfg) {␊ |
| 230 | ␉␉msg_cdbg("locked!\n");␊ |
| 231 | ␉} else {␊ |
| 232 | ␉␉msg_cdbg("unlocked!\n");␊ |
| 233 | ␉␉can_unlock = 1;␊ |
| 234 | ␉}␊ |
| 235 | ␊ |
| 236 | ␉/* Read block lock-bits, 8 * 8 KB + 15 * 64 KB */␊ |
| 237 | ␉for (i = 0; i < flash->total_size * 1024;␊ |
| 238 | ␉ i += (i >= (64 * 1024) ? 64 * 1024 : 8 * 1024)) {␊ |
| 239 | ␉␉bcfg = chip_readb(flash, bios + i + 2); /* read block lock config */␊ |
| 240 | ␉␉msg_cdbg("block lock at %06x is %slocked!\n", i,␊ |
| 241 | ␉␉␉ bcfg ? "" : "un");␊ |
| 242 | ␉␉if (bcfg)␊ |
| 243 | ␉␉␉need_unlock = 1;␊ |
| 244 | ␉}␊ |
| 245 | ␊ |
| 246 | ␉/* Reset chip */␊ |
| 247 | ␉chip_writeb(flash, 0xFF, bios);␊ |
| 248 | ␊ |
| 249 | ␉/* Unlock: clear block lock-bits, if needed */␊ |
| 250 | ␉if (can_unlock && need_unlock) {␊ |
| 251 | ␉␉msg_cdbg("Unlock: ");␊ |
| 252 | ␉␉chip_writeb(flash, 0x60, bios);␊ |
| 253 | ␉␉chip_writeb(flash, 0xD0, bios);␊ |
| 254 | ␉␉chip_writeb(flash, 0xFF, bios);␊ |
| 255 | ␉␉wait_82802ab(flash);␊ |
| 256 | ␉␉msg_cdbg("Done!\n");␊ |
| 257 | ␉}␊ |
| 258 | ␊ |
| 259 | ␉/* Error: master locked or a block is locked */␊ |
| 260 | ␉if (!can_unlock && need_unlock) {␊ |
| 261 | ␉␉msg_cerr("At least one block is locked and lockdown is active!\n");␊ |
| 262 | ␉␉return -1;␊ |
| 263 | ␉}␊ |
| 264 | ␊ |
| 265 | ␉return 0;␊ |
| 266 | }␊ |
| 267 | |