Changeset 1461 for trunk


Ignore:
Timestamp:
11/08/11 11:55:54 (7 months ago)
Author:
stefanct
Message:

ichspi: add support for Intel Hardware Sequencing

Based on the new opaque programmer framework this patch adds support
for Intel Hardware Sequencing on ICH8 and its successors.

By default (or when setting the ich_spi_mode option to auto)
the module tries to use swseq and only activates hwseq if need be:

  • if important opcodes are inaccessible due to lockdown
  • if more than one flash chip is attached.

The other options (swseq, hwseq) select the respective mode (if possible).

A general description of Hardware Sequencing can be found in this blog entry:
 http://blogs.coreboot.org/blog/2011/06/11/gsoc-2011-flashrom-part-1/

Besides adding hwseq this patch also introduces these unrelated changes:

  • Fix enable_flash_ich_dc_spi to pass ERROR_FATAL from ich_init_spi. The whole error handling looks a bit odd to me, so this patch does change very little. Also, it does not touch the tunnelcreek method, which should be refactored anyway.
  • Add null-pointer guards to find_opcode and find_preop to matches the other opcode methods better: curopcodes == NULL has some meaning and is actively used/checked in other functions.

TODO: adding real documentation when we have a directory for it

Signed-off-by: Stefan Tauner <stefan.tauner@…>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/chipset_enable.c

    r1460 r1461  
    492492                                   enum ich_chipset ich_generation) 
    493493{ 
    494         int ret; 
     494        int ret, ret_spi; 
    495495        uint8_t bbs, buc; 
    496496        uint32_t tmp, gcs; 
     
    570570 
    571571        /* This adds BUS_SPI */ 
    572         if (ich_init_spi(dev, tmp, rcrb, ich_generation) != 0) { 
    573                 if (!ret) 
    574                         ret = ERROR_NONFATAL; 
    575         } 
     572        ret_spi = ich_init_spi(dev, tmp, rcrb, ich_generation); 
     573        if (ret_spi == ERROR_FATAL) 
     574                return ret_spi; 
     575         
     576        if (ret || ret_spi) 
     577                ret = ERROR_NONFATAL; 
    576578 
    577579        return ret; 
  • trunk/flashrom.8

    r1453 r1461  
    304304report so we can diagnose the problem. 
    305305.sp 
     306If you have an Intel chipset with an ICH8 or later southbridge with SPI flash 
     307attached, and if a valid descriptor was written to it (e.g. by the vendor), the 
     308chipset provides an alternative way to access the flash chip(s) named 
     309.BR "Hardware Sequencing" . 
     310It is much simpler than the normal access method (called 
     311.BR "Software Sequencing" ")," 
     312but does not allow the software to choose the SPI commands to be sent. 
     313You can use the 
     314.sp 
     315.B "  flashrom \-p internal:ich_spi_mode=value" 
     316.sp 
     317syntax where value can be 
     318.BR auto ", " swseq " or " hwseq . 
     319By default 
     320.RB "(or when setting " ich_spi_mode=auto ) 
     321the module tries to use swseq and only activates hwseq if need be (e.g. if 
     322important opcodes are inaccessible due to lockdown; or if more than one flash 
     323chip is attached). The other options (swseq, hwseq) select the respective mode 
     324(if possible). 
     325.sp 
    306326If you have an Intel chipset with an ICH6 or later southbridge and if you want 
    307327to set specific IDSEL values for a non-default flash chip or an embedded 
  • trunk/ichspi.c

    r1460 r1461  
    424424        int a; 
    425425 
     426        if (op == NULL) { 
     427                msg_perr("\n%s: null OPCODES pointer!\n", __func__); 
     428                return -1; 
     429        } 
     430 
    426431        for (a = 0; a < 8; a++) { 
    427432                if (op->opcode[a].opcode == opcode) 
     
    435440{ 
    436441        int a; 
     442 
     443        if (op == NULL) { 
     444                msg_perr("\n%s: null OPCODES pointer!\n", __func__); 
     445                return -1; 
     446        } 
    437447 
    438448        for (a = 0; a < 2; a++) { 
     
    562572 
    563573/* 
     574 * Returns -1 if at least one mandatory opcode is inaccessible, 0 otherwise. 
     575 * FIXME: this should also check for 
     576 *   - at least one probing opcode (RDID (incl. AT25F variants?), REMS, RES?) 
     577 *   - at least one erasing opcode (lots.) 
     578 *   - at least one program opcode (BYTE_PROGRAM, AAI_WORD_PROGRAM, ...?) 
     579 *   - necessary preops? (EWSR, WREN, ...?) 
     580 */ 
     581static int ich_missing_opcodes() 
     582{ 
     583        uint8_t ops[] = { 
     584                JEDEC_READ, 
     585                JEDEC_RDSR, 
     586                0 
     587        }; 
     588        int i = 0; 
     589        while (ops[i] != 0) { 
     590                msg_pspew("checking for opcode 0x%02x\n", ops[i]); 
     591                if (find_opcode(curopcodes, ops[i]) == -1) 
     592                        return -1; 
     593                i++; 
     594        } 
     595        return 0; 
     596} 
     597 
     598/* 
    564599 * Try to set BBAR (BIOS Base Address Register), but read back the value in case 
    565600 * it didn't stick. 
     
    10671102} 
    10681103 
    1069 #if 0 
     1104static struct hwseq_data { 
     1105        uint32_t size_comp0; 
     1106        uint32_t size_comp1; 
     1107} hwseq_data; 
     1108 
    10701109/* Sets FLA in FADDR to (addr & 0x01FFFFFF) without touching other bits. */ 
    10711110static void ich_hwseq_set_addr(uint32_t addr) 
     
    11181157                addr = REGREAD32(ICH9_REG_FADDR) & 0x01FFFFFF; 
    11191158                msg_perr("Timeout error between offset 0x%08x and " 
    1120                          "0x%08x + %d (=0x%08x)!\n", 
    1121                          addr, addr, len - 1, addr + len - 1); 
    1122                 prettyprint_ich9_reg_hsfs(hsfs); 
    1123                 prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC)); 
    1124                 return 1; 
    1125         } 
    1126  
    1127         if (hsfs & HSFS_FCERR) { 
    1128                 addr = REGREAD32(ICH9_REG_FADDR) & 0x01FFFFFF; 
    1129                 msg_perr("Transaction error between offset 0x%08x and " 
    1130                          "0x%08x (=0x%08x + %d)!\n", 
     1159                         "0x%08x (= 0x%08x + %d)!\n", 
    11311160                         addr, addr + len - 1, addr, len - 1); 
    11321161                prettyprint_ich9_reg_hsfs(hsfs); 
     
    11341163                return 1; 
    11351164        } 
     1165 
     1166        if (hsfs & HSFS_FCERR) { 
     1167                addr = REGREAD32(ICH9_REG_FADDR) & 0x01FFFFFF; 
     1168                msg_perr("Transaction error between offset 0x%08x and " 
     1169                         "0x%08x (= 0x%08x + %d)!\n", 
     1170                         addr, addr + len - 1, addr, len - 1); 
     1171                prettyprint_ich9_reg_hsfs(hsfs); 
     1172                prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC)); 
     1173                return 1; 
     1174        } 
    11361175        return 0; 
    11371176} 
    1138 #endif 
     1177 
     1178int ich_hwseq_probe(struct flashchip *flash) 
     1179{ 
     1180        uint32_t total_size, boundary; 
     1181        uint32_t erase_size_low, size_low, erase_size_high, size_high; 
     1182        struct block_eraser *eraser; 
     1183 
     1184        total_size = hwseq_data.size_comp0 + hwseq_data.size_comp1; 
     1185        msg_cdbg("Found %d attached SPI flash chip", 
     1186                 (hwseq_data.size_comp1 != 0) ? 2 : 1); 
     1187        if (hwseq_data.size_comp1 != 0) 
     1188                msg_cdbg("s with a combined"); 
     1189        else 
     1190                msg_cdbg(" with a"); 
     1191        msg_cdbg(" density of %d kB.\n", total_size / 1024); 
     1192        flash->total_size = total_size / 1024; 
     1193 
     1194        eraser = &(flash->block_erasers[0]); 
     1195        boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12; 
     1196        size_high = total_size - boundary; 
     1197        erase_size_high = ich_hwseq_get_erase_block_size(boundary); 
     1198 
     1199        if (boundary == 0) { 
     1200                msg_cdbg("There is only one partition containing the whole " 
     1201                         "address space (0x%06x - 0x%06x).\n", 0, size_high-1); 
     1202                eraser->eraseblocks[0].size = erase_size_high; 
     1203                eraser->eraseblocks[0].count = size_high / erase_size_high; 
     1204                msg_cdbg("There are %d erase blocks with %d B each.\n", 
     1205                         size_high / erase_size_high, erase_size_high); 
     1206        } else { 
     1207                msg_cdbg("The flash address space (0x%06x - 0x%06x) is divided " 
     1208                         "at address 0x%06x in two partitions.\n", 
     1209                         0, size_high-1, boundary); 
     1210                size_low = total_size - size_high; 
     1211                erase_size_low = ich_hwseq_get_erase_block_size(0); 
     1212 
     1213                eraser->eraseblocks[0].size = erase_size_low; 
     1214                eraser->eraseblocks[0].count = size_low / erase_size_low; 
     1215                msg_cdbg("The first partition ranges from 0x%06x to 0x%06x.\n", 
     1216                         0, size_low-1); 
     1217                msg_cdbg("In that range are %d erase blocks with %d B each.\n", 
     1218                         size_low / erase_size_low, erase_size_low); 
     1219 
     1220                eraser->eraseblocks[1].size = erase_size_high; 
     1221                eraser->eraseblocks[1].count = size_high / erase_size_high; 
     1222                msg_cdbg("The second partition ranges from 0x%06x to 0x%06x.\n", 
     1223                         boundary, size_high-1); 
     1224                msg_cdbg("In that range are %d erase blocks with %d B each.\n", 
     1225                         size_high / erase_size_high, erase_size_high); 
     1226        } 
     1227        flash->tested = TEST_OK_PREW; 
     1228        return 1; 
     1229} 
     1230 
     1231int ich_hwseq_block_erase(struct flashchip *flash, 
     1232                          unsigned int addr, 
     1233                          unsigned int len) 
     1234{ 
     1235        uint32_t erase_block; 
     1236        uint16_t hsfc; 
     1237        uint32_t timeout = 5000 * 1000; /* 5 s for max 64 kB */ 
     1238 
     1239        erase_block = ich_hwseq_get_erase_block_size(addr); 
     1240        if (len != erase_block) { 
     1241                msg_cerr("Erase block size for address 0x%06x is %d B, " 
     1242                         "but requested erase block size is %d B. " 
     1243                         "Not erasing anything.\n", addr, erase_block, len); 
     1244                return -1; 
     1245        } 
     1246 
     1247        /* Although the hardware supports this (it would erase the whole block 
     1248         * containing the address) we play safe here. */ 
     1249        if (addr % erase_block != 0) { 
     1250                msg_cerr("Erase address 0x%06x is not aligned to the erase " 
     1251                         "block boundary (any multiple of %d). " 
     1252                         "Not erasing anything.\n", addr, erase_block); 
     1253                return -1; 
     1254        } 
     1255 
     1256        if (addr + len > flash->total_size * 1024) { 
     1257                msg_perr("Request to erase some inaccessible memory address(es)" 
     1258                         " (addr=0x%x, len=%d). " 
     1259                         "Not erasing anything.\n", addr, len); 
     1260                return -1; 
     1261        } 
     1262 
     1263        msg_pdbg("Erasing %d bytes starting at 0x%06x.\n", len, addr); 
     1264 
     1265        /* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */ 
     1266        REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); 
     1267 
     1268        hsfc = REGREAD16(ICH9_REG_HSFC); 
     1269        hsfc &= ~HSFC_FCYCLE; /* clear operation */ 
     1270        hsfc |= (0x3 << HSFC_FCYCLE_OFF); /* set erase operation */ 
     1271        hsfc |= HSFC_FGO; /* start */ 
     1272        msg_pdbg("HSFC used for block erasing: "); 
     1273        prettyprint_ich9_reg_hsfc(hsfc); 
     1274        REGWRITE16(ICH9_REG_HSFC, hsfc); 
     1275 
     1276        if (ich_hwseq_wait_for_cycle_complete(timeout, len)) 
     1277                return -1; 
     1278        return 0; 
     1279} 
     1280 
     1281int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len) 
     1282{ 
     1283        uint16_t hsfc; 
     1284        uint16_t timeout = 100 * 60; 
     1285        uint8_t block_len; 
     1286 
     1287        if (addr < 0 || addr + len > flash->total_size * 1024) { 
     1288                msg_perr("Request to read from an inaccessible memory address " 
     1289                         "(addr=0x%x, len=%d).\n", addr, len); 
     1290                return -1; 
     1291        } 
     1292 
     1293        msg_pdbg("Reading %d bytes starting at 0x%06x.\n", len, addr); 
     1294        /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */ 
     1295        REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); 
     1296 
     1297        while (len > 0) { 
     1298                block_len = min(len, opaque_programmer->max_data_read); 
     1299                ich_hwseq_set_addr(addr); 
     1300                hsfc = REGREAD16(ICH9_REG_HSFC); 
     1301                hsfc &= ~HSFC_FCYCLE; /* set read operation */ 
     1302                hsfc &= ~HSFC_FDBC; /* clear byte count */ 
     1303                /* set byte count */ 
     1304                hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC); 
     1305                hsfc |= HSFC_FGO; /* start */ 
     1306                REGWRITE16(ICH9_REG_HSFC, hsfc); 
     1307 
     1308                if (ich_hwseq_wait_for_cycle_complete(timeout, block_len)) 
     1309                        return 1; 
     1310                ich_read_data(buf, block_len, ICH9_REG_FDATA0); 
     1311                addr += block_len; 
     1312                buf += block_len; 
     1313                len -= block_len; 
     1314        } 
     1315        return 0; 
     1316} 
     1317 
     1318int ich_hwseq_write(struct flashchip *flash, uint8_t *buf, int addr, int len) 
     1319{ 
     1320        uint16_t hsfc; 
     1321        uint16_t timeout = 100 * 60; 
     1322        uint8_t block_len; 
     1323 
     1324        if (addr < 0 || addr + len > flash->total_size * 1024) { 
     1325                msg_perr("Request to write to an inaccessible memory address " 
     1326                         "(addr=0x%x, len=%d).\n", addr, len); 
     1327                return -1; 
     1328        } 
     1329 
     1330        msg_pdbg("Writing %d bytes starting at 0x%06x.\n", len, addr); 
     1331        /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */ 
     1332        REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); 
     1333 
     1334        while (len > 0) { 
     1335                ich_hwseq_set_addr(addr); 
     1336                block_len = min(len, opaque_programmer->max_data_write); 
     1337                ich_fill_data(buf, block_len, ICH9_REG_FDATA0); 
     1338                hsfc = REGREAD16(ICH9_REG_HSFC); 
     1339                hsfc &= ~HSFC_FCYCLE; /* clear operation */ 
     1340                hsfc |= (0x2 << HSFC_FCYCLE_OFF); /* set write operation */ 
     1341                hsfc &= ~HSFC_FDBC; /* clear byte count */ 
     1342                /* set byte count */ 
     1343                hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC); 
     1344                hsfc |= HSFC_FGO; /* start */ 
     1345                REGWRITE16(ICH9_REG_HSFC, hsfc); 
     1346 
     1347                if (ich_hwseq_wait_for_cycle_complete(timeout, block_len)) 
     1348                        return -1; 
     1349                addr += block_len; 
     1350                buf += block_len; 
     1351                len -= block_len; 
     1352        } 
     1353        return 0; 
     1354} 
    11391355 
    11401356static int ich_spi_send_multicommand(struct spi_command *cmds) 
     
    13011517}; 
    13021518 
     1519static const struct opaque_programmer opaque_programmer_ich_hwseq = { 
     1520        .max_data_read = 64, 
     1521        .max_data_write = 64, 
     1522        .probe = ich_hwseq_probe, 
     1523        .read = ich_hwseq_read, 
     1524        .write = ich_hwseq_write, 
     1525        .erase = ich_hwseq_block_erase, 
     1526}; 
     1527 
    13031528int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, 
    13041529                 enum ich_chipset ich_gen) 
     
    13081533        uint16_t spibar_offset, tmp2; 
    13091534        uint32_t tmp; 
     1535        char *arg; 
    13101536        int desc_valid = 0; 
     1537        struct ich_descriptors desc = {{ 0 }}; 
     1538        enum ich_spi_mode { 
     1539                ich_auto, 
     1540                ich_hwseq, 
     1541                ich_swseq 
     1542        } ich_spi_mode = ich_auto; 
    13111543 
    13121544        ich_generation = ich_gen; 
     
    13141546        switch (ich_generation) { 
    13151547        case CHIPSET_ICH_UNKNOWN: 
    1316                 return -1; 
     1548                return ERROR_FATAL; 
    13171549        case CHIPSET_ICH7: 
    13181550        case CHIPSET_ICH8: 
     
    13301562        /* Assign Virtual Address */ 
    13311563        ich_spibar = rcrb + spibar_offset; 
     1564 
     1565        ich_init_opcodes(); 
    13321566 
    13331567        switch (ich_generation) { 
     
    13701604                ich_set_bbar(0); 
    13711605                register_spi_programmer(&spi_programmer_ich7); 
    1372                 ich_init_opcodes(); 
    13731606                break; 
    13741607        case CHIPSET_ICH8: 
    13751608        default:                /* Future version might behave the same */ 
     1609                arg = extract_programmer_param("ich_spi_mode"); 
     1610                if (arg && !strcmp(arg, "hwseq")) { 
     1611                        ich_spi_mode = ich_hwseq; 
     1612                        msg_pspew("user selected hwseq\n"); 
     1613                } else if (arg && !strcmp(arg, "swseq")) { 
     1614                        ich_spi_mode = ich_swseq; 
     1615                        msg_pspew("user selected swseq\n"); 
     1616                } else if (arg && !strcmp(arg, "auto")) { 
     1617                        msg_pspew("user selected auto\n"); 
     1618                        ich_spi_mode = ich_auto; 
     1619                } else if (arg && !strlen(arg)) { 
     1620                        msg_perr("Missing argument for ich_spi_mode.\n"); 
     1621                        free(arg); 
     1622                        return ERROR_FATAL; 
     1623                } else if (arg) { 
     1624                        msg_perr("Unknown argument for ich_spi_mode: %s\n", 
     1625                                 arg); 
     1626                        free(arg); 
     1627                        return ERROR_FATAL; 
     1628                } 
     1629                free(arg); 
     1630 
    13761631                tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFS); 
    13771632                msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2); 
     
    14591714                msg_pdbg("\n"); 
    14601715                if (desc_valid) { 
    1461                         struct ich_descriptors desc = {{ 0 }}; 
    14621716                        if (read_ich_descriptors_via_fdo(ich_spibar, &desc) == 
    14631717                            ICH_RET_OK) 
    14641718                                prettyprint_ich_descriptors(CHIPSET_ICH_UNKNOWN, 
    14651719                                                            &desc); 
     1720                        /* If the descriptor is valid and indicates multiple 
     1721                         * flash devices we need to use hwseq to be able to 
     1722                         * access the second flash device. 
     1723                         */ 
     1724                        if (ich_spi_mode == ich_auto && desc.content.NC != 0) { 
     1725                                msg_pinfo("Enabling hardware sequencing due to " 
     1726                                          "multiple flash chips detected.\n"); 
     1727                                ich_spi_mode = ich_hwseq; 
     1728                        } 
    14661729                } 
    1467                 register_spi_programmer(&spi_programmer_ich9); 
    1468                 ich_init_opcodes(); 
     1730 
     1731                if (ich_spi_mode == ich_auto && ichspi_lock && 
     1732                    ich_missing_opcodes()) { 
     1733                        msg_pinfo("Enabling hardware sequencing because " 
     1734                                  "some important opcode is locked.\n"); 
     1735                        ich_spi_mode = ich_hwseq; 
     1736                } 
     1737 
     1738                if (ich_spi_mode == ich_hwseq) { 
     1739                        if (!desc_valid) { 
     1740                                msg_perr("Hardware sequencing was requested " 
     1741                                         "but the flash descriptor is not " 
     1742                                         "valid. Aborting.\n"); 
     1743                                return ERROR_FATAL; 
     1744                        } 
     1745                        hwseq_data.size_comp0 = getFCBA_component_density(&desc, 0); 
     1746                        hwseq_data.size_comp1 = getFCBA_component_density(&desc, 1); 
     1747                        register_opaque_programmer(&opaque_programmer_ich_hwseq); 
     1748                } else { 
     1749                        register_spi_programmer(&spi_programmer_ich9); 
     1750                } 
    14691751                break; 
    14701752        } 
Note: See TracChangeset for help on using the changeset viewer.