flash/nor/stm32f2x: Support value line chips with trimmed flash
[fw/openocd] / src / flash / nor / nrf5.c
index f0ae203678c607e788fce52c1ab029dca9859b32..d923468fd7459e6184e229d463a2edbfe6ace68b 100644 (file)
@@ -39,13 +39,15 @@ enum nrf5_ficr_registers {
 
        NRF5_FICR_CODEPAGESIZE          = NRF5_FICR_REG(0x010),
        NRF5_FICR_CODESIZE              = NRF5_FICR_REG(0x014),
-       NRF5_FICR_CLENR0                = NRF5_FICR_REG(0x028),
-       NRF5_FICR_PPFC                  = NRF5_FICR_REG(0x02C),
-       NRF5_FICR_NUMRAMBLOCK           = NRF5_FICR_REG(0x034),
-       NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038),
-       NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C),
-       NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
-       NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
+
+       NRF51_FICR_CLENR0               = NRF5_FICR_REG(0x028),
+       NRF51_FICR_PPFC                 = NRF5_FICR_REG(0x02C),
+       NRF51_FICR_NUMRAMBLOCK          = NRF5_FICR_REG(0x034),
+       NRF51_FICR_SIZERAMBLOCK0        = NRF5_FICR_REG(0x038),
+       NRF51_FICR_SIZERAMBLOCK1        = NRF5_FICR_REG(0x03C),
+       NRF51_FICR_SIZERAMBLOCK2        = NRF5_FICR_REG(0x040),
+       NRF51_FICR_SIZERAMBLOCK3        = NRF5_FICR_REG(0x044),
+
        NRF5_FICR_CONFIGID              = NRF5_FICR_REG(0x05C),
        NRF5_FICR_DEVICEID0             = NRF5_FICR_REG(0x060),
        NRF5_FICR_DEVICEID1             = NRF5_FICR_REG(0x064),
@@ -60,17 +62,18 @@ enum nrf5_ficr_registers {
        NRF5_FICR_DEVICEADDRTYPE        = NRF5_FICR_REG(0x0A0),
        NRF5_FICR_DEVICEADDR0           = NRF5_FICR_REG(0x0A4),
        NRF5_FICR_DEVICEADDR1           = NRF5_FICR_REG(0x0A8),
-       NRF5_FICR_OVERRIDEN             = NRF5_FICR_REG(0x0AC),
-       NRF5_FICR_NRF_1MBIT0            = NRF5_FICR_REG(0x0B0),
-       NRF5_FICR_NRF_1MBIT1            = NRF5_FICR_REG(0x0B4),
-       NRF5_FICR_NRF_1MBIT2            = NRF5_FICR_REG(0x0B8),
-       NRF5_FICR_NRF_1MBIT3            = NRF5_FICR_REG(0x0BC),
-       NRF5_FICR_NRF_1MBIT4            = NRF5_FICR_REG(0x0C0),
-       NRF5_FICR_BLE_1MBIT0            = NRF5_FICR_REG(0x0EC),
-       NRF5_FICR_BLE_1MBIT1            = NRF5_FICR_REG(0x0F0),
-       NRF5_FICR_BLE_1MBIT2            = NRF5_FICR_REG(0x0F4),
-       NRF5_FICR_BLE_1MBIT3            = NRF5_FICR_REG(0x0F8),
-       NRF5_FICR_BLE_1MBIT4            = NRF5_FICR_REG(0x0FC),
+
+       NRF51_FICR_OVERRIDEN            = NRF5_FICR_REG(0x0AC),
+       NRF51_FICR_NRF_1MBIT0           = NRF5_FICR_REG(0x0B0),
+       NRF51_FICR_NRF_1MBIT1           = NRF5_FICR_REG(0x0B4),
+       NRF51_FICR_NRF_1MBIT2           = NRF5_FICR_REG(0x0B8),
+       NRF51_FICR_NRF_1MBIT3           = NRF5_FICR_REG(0x0BC),
+       NRF51_FICR_NRF_1MBIT4           = NRF5_FICR_REG(0x0C0),
+       NRF51_FICR_BLE_1MBIT0           = NRF5_FICR_REG(0x0EC),
+       NRF51_FICR_BLE_1MBIT1           = NRF5_FICR_REG(0x0F0),
+       NRF51_FICR_BLE_1MBIT2           = NRF5_FICR_REG(0x0F4),
+       NRF51_FICR_BLE_1MBIT3           = NRF5_FICR_REG(0x0F8),
+       NRF51_FICR_BLE_1MBIT4           = NRF5_FICR_REG(0x0FC),
 
        /* Following registers are available on nRF52 and on nRF51 since rev 3 */
        NRF5_FICR_INFO_PART                     = NRF5_FICR_REG(0x100),
@@ -86,10 +89,10 @@ enum nrf5_uicr_registers {
 
 #define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
 
-       NRF5_UICR_CLENR0        = NRF5_UICR_REG(0x000),
-       NRF5_UICR_RBPCONF       = NRF5_UICR_REG(0x004),
-       NRF5_UICR_XTALFREQ      = NRF5_UICR_REG(0x008),
-       NRF5_UICR_FWID          = NRF5_UICR_REG(0x010),
+       NRF51_UICR_CLENR0       = NRF5_UICR_REG(0x000),
+       NRF51_UICR_RBPCONF      = NRF5_UICR_REG(0x004),
+       NRF51_UICR_XTALFREQ     = NRF5_UICR_REG(0x008),
+       NRF51_UICR_FWID         = NRF5_UICR_REG(0x010),
 };
 
 enum nrf5_nvmc_registers {
@@ -154,6 +157,7 @@ struct nrf5_info {
        uint32_t hwid;
        enum nrf5_features features;
        unsigned int flash_size_kb;
+       unsigned int ram_size_kb;
 };
 
 #define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \
@@ -279,6 +283,8 @@ static const struct nrf5_device_package nrf5_packages_table[] = {
        { 0x2005, "CK" },
 };
 
+const struct flash_driver nrf5_flash, nrf51_flash;
+
 static int nrf5_bank_is_probed(struct flash_bank *bank)
 {
        struct nrf5_bank *nbank = bank->driver_priv;
@@ -479,7 +485,7 @@ static int nrf5_protect_check(struct flash_bank *bank)
                return ERROR_FLASH_OPER_UNSUPPORTED;
        }
 
-       res = target_read_u32(chip->target, NRF5_FICR_CLENR0,
+       res = target_read_u32(chip->target, NRF51_FICR_CLENR0,
                              &clenr0);
        if (res != ERROR_OK) {
                LOG_ERROR("Couldn't read code region 0 size[FICR]");
@@ -487,7 +493,7 @@ static int nrf5_protect_check(struct flash_bank *bank)
        }
 
        if (clenr0 == 0xFFFFFFFF) {
-               res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
+               res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
                                      &clenr0);
                if (res != ERROR_OK) {
                        LOG_ERROR("Couldn't read code region 0 size[UICR]");
@@ -526,7 +532,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
                return ERROR_FAIL;
        }
 
-       res = target_read_u32(chip->target, NRF5_FICR_PPFC,
+       res = target_read_u32(chip->target, NRF51_FICR_PPFC,
                              &ppfc);
        if (res != ERROR_OK) {
                LOG_ERROR("Couldn't read PPFC register");
@@ -538,7 +544,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
                return ERROR_FAIL;
        }
 
-       res = target_read_u32(chip->target, NRF5_UICR_CLENR0,
+       res = target_read_u32(chip->target, NRF51_UICR_CLENR0,
                              &clenr0);
        if (res != ERROR_OK) {
                LOG_ERROR("Couldn't read code region 0 size[UICR]");
@@ -546,7 +552,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last)
        }
 
        if (clenr0 == 0xFFFFFFFF) {
-               res = target_write_u32(chip->target, NRF5_UICR_CLENR0,
+               res = target_write_u32(chip->target, NRF51_UICR_CLENR0,
                                       clenr0);
                if (res != ERROR_OK) {
                        LOG_ERROR("Couldn't write code region 0 size[UICR]");
@@ -586,29 +592,31 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size)
 {
        struct nrf5_bank *nbank = bank->driver_priv;
        struct nrf5_info *chip = nbank->chip;
+       int res;
 
        if (chip->spec) {
-               snprintf(buf, buf_size,
-                               "nRF%s-%s(build code: %s) %ukB Flash",
-                               chip->spec->part, chip->spec->variant, chip->spec->build_code,
-                               chip->flash_size_kb);
+               res = snprintf(buf, buf_size,
+                               "nRF%s-%s(build code: %s)",
+                               chip->spec->part, chip->spec->variant, chip->spec->build_code);
 
        } else if (chip->ficr_info_valid) {
                char variant[5];
                nrf5_info_variant_to_str(chip->ficr_info.variant, variant);
-               snprintf(buf, buf_size,
-                               "nRF%" PRIx32 "-%s%.2s(build code: %s) %" PRIu32
-                               "kB Flash, %" PRIu32 "kB RAM",
+               res = snprintf(buf, buf_size,
+                               "nRF%" PRIx32 "-%s%.2s(build code: %s)",
                                chip->ficr_info.part,
                                nrf5_decode_info_package(chip->ficr_info.package),
-                               variant, &variant[2],
-                               chip->flash_size_kb,
-                               chip->ficr_info.ram);
+                               variant, &variant[2]);
 
        } else {
-               snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ") %ukB Flash",
-                               chip->hwid, chip->flash_size_kb);
+               res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")",
+                               chip->hwid);
        }
+       if (res <= 0)
+               return ERROR_FAIL;
+
+       snprintf(buf + res, buf_size - res, " %ukB Flash, %ukB RAM",
+                               chip->flash_size_kb, chip->ram_size_kb);
        return ERROR_OK;
 }
 
@@ -678,6 +686,39 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip)
        return ERROR_OK;
 }
 
+static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size)
+{
+       int res;
+
+       *ram_size = 0;
+
+       uint32_t numramblock;
+       res = target_read_u32(target, NRF51_FICR_NUMRAMBLOCK, &numramblock);
+       if (res != ERROR_OK) {
+               LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register");
+               return res;
+       }
+
+       if (numramblock < 1 || numramblock > 4) {
+               LOG_DEBUG("FICR NUMRAMBLOCK strange value %" PRIx32, numramblock);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       for (unsigned int i = 0; i < numramblock; i++) {
+               uint32_t sizeramblock;
+               res = target_read_u32(target, NRF51_FICR_SIZERAMBLOCK0 + sizeof(uint32_t)*i, &sizeramblock);
+               if (res != ERROR_OK) {
+                       LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register");
+                       return res;
+               }
+               if (sizeramblock < 1024 || sizeramblock > 65536)
+                       LOG_DEBUG("FICR SIZERAMBLOCK strange value %" PRIx32, sizeramblock);
+               else
+                       *ram_size += sizeramblock;
+       }
+       return res;
+}
+
 static int nrf5_probe(struct flash_bank *bank)
 {
        int res;
@@ -717,6 +758,14 @@ static int nrf5_probe(struct flash_bank *bank)
                                                PRIx32, chip->hwid, chip->ficr_info.part);
        }
 
+       if (chip->ficr_info_valid) {
+               chip->ram_size_kb = chip->ficr_info.ram;
+       } else {
+               uint32_t ram_size;
+               nrf5_get_ram_size(target, &ram_size);
+               chip->ram_size_kb = ram_size / 1024;
+       }
+
        /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
        uint32_t flash_page_size;
        res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
@@ -747,6 +796,8 @@ static int nrf5_probe(struct flash_bank *bank)
                }
        }
 
+       free(bank->sectors);
+
        if (bank->base == NRF5_FLASH_BASE) {
                /* Sanity check */
                if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb)
@@ -808,29 +859,27 @@ static int nrf5_erase_page(struct flash_bank *bank,
        int res;
 
        LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
-       if (sector->is_protected) {
-               LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
-               return ERROR_FAIL;
-       }
 
        if (bank->base == NRF5_UICR_BASE) {
-               uint32_t ppfc;
-               res = target_read_u32(chip->target, NRF5_FICR_PPFC,
+               if (chip->features & NRF5_FEATURE_SERIES_51) {
+                       uint32_t ppfc;
+                       res = target_read_u32(chip->target, NRF51_FICR_PPFC,
                                      &ppfc);
-               if (res != ERROR_OK) {
-                       LOG_ERROR("Couldn't read PPFC register");
-                       return res;
-               }
-
-               if ((ppfc & 0xFF) == 0xFF) {
-                       /* We can't erase the UICR.  Double-check to
-                          see if it's already erased before complaining. */
-                       default_flash_blank_check(bank);
-                       if (sector->is_erased == 1)
-                               return ERROR_OK;
-
-                       LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
-                       return ERROR_FAIL;
+                       if (res != ERROR_OK) {
+                               LOG_ERROR("Couldn't read PPFC register");
+                               return res;
+                       }
+
+                       if ((ppfc & 0xFF) == 0xFF) {
+                               /* We can't erase the UICR.  Double-check to
+                                  see if it's already erased before complaining. */
+                               default_flash_blank_check(bank);
+                               if (sector->is_erased == 1)
+                                       return ERROR_OK;
+
+                               LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
+                               return ERROR_FAIL;
+                       }
                }
 
                res = nrf5_nvmc_generic_erase(chip,
@@ -1014,9 +1063,31 @@ static void nrf5_free_driver_priv(struct flash_bank *bank)
        }
 }
 
+static struct nrf5_info *nrf5_get_chip(struct target *target)
+{
+       struct flash_bank *bank_iter;
+
+       /* iterate over nrf5 banks of same target */
+       for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) {
+               if (bank_iter->driver != &nrf5_flash && bank_iter->driver != &nrf51_flash)
+                       continue;
+
+               if (bank_iter->target != target)
+                       continue;
+
+               struct nrf5_bank *nbank = bank_iter->driver_priv;
+               if (!nbank)
+                       continue;
+
+               if (nbank->chip)
+                       return nbank->chip;
+       }
+       return NULL;
+}
+
 FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
 {
-       static struct nrf5_info *chip;
+       struct nrf5_info *chip;
        struct nrf5_bank *nbank = NULL;
 
        switch (bank->base) {
@@ -1028,6 +1099,7 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
                return ERROR_FAIL;
        }
 
+       chip = nrf5_get_chip(bank->target);
        if (!chip) {
                /* Create a new chip */
                chip = calloc(1, sizeof(*chip));
@@ -1074,19 +1146,20 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
        if (res != ERROR_OK)
                return res;
 
-       uint32_t ppfc;
-
-       res = target_read_u32(target, NRF5_FICR_PPFC,
+       if (chip->features & NRF5_FEATURE_SERIES_51) {
+               uint32_t ppfc;
+               res = target_read_u32(target, NRF51_FICR_PPFC,
                              &ppfc);
-       if (res != ERROR_OK) {
-               LOG_ERROR("Couldn't read PPFC register");
-               return res;
-       }
+               if (res != ERROR_OK) {
+                       LOG_ERROR("Couldn't read PPFC register");
+                       return res;
+               }
 
-       if ((ppfc & 0xFF) == 0x00) {
-               LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
-                         "mass erase command won't work.");
-               return ERROR_FAIL;
+               if ((ppfc & 0xFF) == 0x00) {
+                       LOG_ERROR("Code region 0 size was pre-programmed at the factory, "
+                                 "mass erase command won't work.");
+                       return ERROR_FAIL;
+               }
        }
 
        res = nrf5_erase_all(chip);
@@ -1133,13 +1206,13 @@ COMMAND_HANDLER(nrf5_handle_info_command)
        } ficr[] = {
                { .address = NRF5_FICR_CODEPAGESIZE     },
                { .address = NRF5_FICR_CODESIZE },
-               { .address = NRF5_FICR_CLENR0           },
-               { .address = NRF5_FICR_PPFC             },
-               { .address = NRF5_FICR_NUMRAMBLOCK      },
-               { .address = NRF5_FICR_SIZERAMBLOCK0    },
-               { .address = NRF5_FICR_SIZERAMBLOCK1    },
-               { .address = NRF5_FICR_SIZERAMBLOCK2    },
-               { .address = NRF5_FICR_SIZERAMBLOCK3    },
+               { .address = NRF51_FICR_CLENR0          },
+               { .address = NRF51_FICR_PPFC            },
+               { .address = NRF51_FICR_NUMRAMBLOCK     },
+               { .address = NRF51_FICR_SIZERAMBLOCK0   },
+               { .address = NRF51_FICR_SIZERAMBLOCK1   },
+               { .address = NRF51_FICR_SIZERAMBLOCK2   },
+               { .address = NRF51_FICR_SIZERAMBLOCK3   },
                { .address = NRF5_FICR_CONFIGID },
                { .address = NRF5_FICR_DEVICEID0        },
                { .address = NRF5_FICR_DEVICEID1        },
@@ -1154,22 +1227,22 @@ COMMAND_HANDLER(nrf5_handle_info_command)
                { .address = NRF5_FICR_DEVICEADDRTYPE   },
                { .address = NRF5_FICR_DEVICEADDR0      },
                { .address = NRF5_FICR_DEVICEADDR1      },
-               { .address = NRF5_FICR_OVERRIDEN        },
-               { .address = NRF5_FICR_NRF_1MBIT0       },
-               { .address = NRF5_FICR_NRF_1MBIT1       },
-               { .address = NRF5_FICR_NRF_1MBIT2       },
-               { .address = NRF5_FICR_NRF_1MBIT3       },
-               { .address = NRF5_FICR_NRF_1MBIT4       },
-               { .address = NRF5_FICR_BLE_1MBIT0       },
-               { .address = NRF5_FICR_BLE_1MBIT1       },
-               { .address = NRF5_FICR_BLE_1MBIT2       },
-               { .address = NRF5_FICR_BLE_1MBIT3       },
-               { .address = NRF5_FICR_BLE_1MBIT4       },
+               { .address = NRF51_FICR_OVERRIDEN       },
+               { .address = NRF51_FICR_NRF_1MBIT0      },
+               { .address = NRF51_FICR_NRF_1MBIT1      },
+               { .address = NRF51_FICR_NRF_1MBIT2      },
+               { .address = NRF51_FICR_NRF_1MBIT3      },
+               { .address = NRF51_FICR_NRF_1MBIT4      },
+               { .address = NRF51_FICR_BLE_1MBIT0      },
+               { .address = NRF51_FICR_BLE_1MBIT1      },
+               { .address = NRF51_FICR_BLE_1MBIT2      },
+               { .address = NRF51_FICR_BLE_1MBIT3      },
+               { .address = NRF51_FICR_BLE_1MBIT4      },
        }, uicr[] = {
-               { .address = NRF5_UICR_CLENR0,          },
-               { .address = NRF5_UICR_RBPCONF          },
-               { .address = NRF5_UICR_XTALFREQ },
-               { .address = NRF5_UICR_FWID             },
+               { .address = NRF51_UICR_CLENR0,         },
+               { .address = NRF51_UICR_RBPCONF         },
+               { .address = NRF51_UICR_XTALFREQ        },
+               { .address = NRF51_UICR_FWID            },
        };
 
        for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) {