kinetis: fix "SF1" parts to limit FlexRAM usage
[openocd.git] / src / flash / nor / kinetis.c
index e0bb5c20ba59784c1faf5c221ce8069bdf0b2025..fe18451c92710280f0bff4e27728eed4eb4821cb 100644 (file)
@@ -95,6 +95,24 @@ const struct {
        { 4<<10, 4<<10, 4 }
 };
 
+/* Addressess */
+#define FLEXRAM                0x14000000
+#define FTFx_FSTAT     0x40020000
+#define FTFx_FCNFG     0x40020001
+#define FTFx_FCCOB3    0x40020004
+#define FTFx_FPROT3    0x40020010
+#define SIM_SDID       0x40048024
+#define SIM_FCFG1      0x4004804c
+#define SIM_FCFG2      0x40048050
+
+/* Commands */
+#define FTFx_CMD_BLOCKSTAT 0x00
+#define FTFx_CMD_SECTSTAT 0x01
+#define FTFx_CMD_LWORDPROG 0x06
+#define FTFx_CMD_SECTERASE 0x09
+#define FTFx_CMD_SECTWRITE 0x0b
+#define FTFx_CMD_SETFLEXRAM 0x81
+
 struct kinetis_flash_bank {
        unsigned granularity;
        unsigned bank_ordinal;
@@ -160,8 +178,8 @@ static int kinetis_protect_check(struct flash_bank *bank)
                uint32_t fprot, psec;
                int i, b;
 
-               /* read protection register FTFx_FPROT */
-               result = target_read_memory(bank->target, 0x40020010, 1, 4, buffer);
+               /* read protection register */
+               result = target_read_memory(bank->target, FTFx_FPROT3, 1, 4, buffer);
 
                if (result != ERROR_OK)
                        return result;
@@ -195,54 +213,55 @@ static int kinetis_protect_check(struct flash_bank *bank)
        return ERROR_OK;
 }
 
-static int kinetis_ftfx_command(struct flash_bank *bank, uint32_t w0,
-                               uint32_t w1, uint32_t w2, uint8_t *ftfx_fstat)
+static int kinetis_ftfx_command(struct flash_bank *bank, uint8_t fcmd, uint32_t faddr,
+                               uint8_t fccob4, uint8_t fccob5, uint8_t fccob6, uint8_t fccob7,
+                               uint8_t fccob8, uint8_t fccob9, uint8_t fccoba, uint8_t fccobb,
+                               uint8_t *ftfx_fstat)
 {
-       uint8_t buffer[12];
+       uint8_t command[12] = {faddr & 0xff, (faddr >> 8) & 0xff, (faddr >> 16) & 0xff, fcmd,
+                              fccob7, fccob6, fccob5, fccob4,
+                              fccobb, fccoba, fccob9, fccob8};
        int result, i;
+       uint8_t buffer;
 
        /* wait for done */
        for (i = 0; i < 50; i++) {
                result =
-                       target_read_memory(bank->target, 0x40020000, 1, 1, buffer);
+                       target_read_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer);
 
                if (result != ERROR_OK)
                        return result;
 
-               if (buffer[0] & 0x80)
+               if (buffer & 0x80)
                        break;
 
-               buffer[0] = 0x00;
+               buffer = 0x00;
        }
 
-       if (buffer[0] != 0x80) {
+       if (buffer != 0x80) {
                /* reset error flags */
-               buffer[0] = 0x30;
+               buffer = 0x30;
                result =
-                       target_write_memory(bank->target, 0x40020000, 1, 1, buffer);
+                       target_write_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer);
                if (result != ERROR_OK)
                        return result;
        }
 
-       target_buffer_set_u32(bank->target, buffer, w0);
-       target_buffer_set_u32(bank->target, buffer + 4, w1);
-       target_buffer_set_u32(bank->target, buffer + 8, w2);
-
-       result = target_write_memory(bank->target, 0x40020004, 4, 3, buffer);
+       result = target_write_memory(bank->target, FTFx_FCCOB3, 4, 3, command);
 
        if (result != ERROR_OK)
                return result;
 
        /* start command */
-       buffer[0] = 0x80;
-       result = target_write_memory(bank->target, 0x40020000, 1, 1, buffer);
+       buffer = 0x80;
+       result = target_write_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer);
        if (result != ERROR_OK)
                return result;
 
        /* wait for done */
        for (i = 0; i < 50; i++) {
                result =
-                       target_read_memory(bank->target, 0x40020000, 1, 1, ftfx_fstat);
+                       target_read_memory(bank->target, FTFx_FSTAT, 1, 1, ftfx_fstat);
 
                if (result != ERROR_OK)
                        return result;
@@ -253,9 +272,10 @@ static int kinetis_ftfx_command(struct flash_bank *bank, uint32_t w0,
 
        if ((*ftfx_fstat & 0xf0) != 0x80) {
                LOG_ERROR
-                       ("ftfx command failed FSTAT: %02X W0: %08X W1: %08X W2: %08X",
-                        *ftfx_fstat, w0, w1, w2);
-
+                       ("ftfx command failed FSTAT: %02X FCCOB: %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
+                        *ftfx_fstat, command[3], command[2], command[1], command[0],
+                                     command[7], command[6], command[5], command[4],
+                                     command[11], command[10], command[9], command[8]);
                return ERROR_FLASH_OPERATION_FAILED;
        }
 
@@ -265,7 +285,6 @@ static int kinetis_ftfx_command(struct flash_bank *bank, uint32_t w0,
 static int kinetis_erase(struct flash_bank *bank, int first, int last)
 {
        int result, i;
-       uint32_t w0 = 0, w1 = 0, w2 = 0;
 
        if (bank->target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
@@ -283,9 +302,8 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
        for (i = first; i <= last; i++) {
                uint8_t ftfx_fstat;
                /* set command and sector address */
-               w0 = (0x09 << 24) | (bank->base + bank->sectors[i].offset);
-
-               result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+               result = kinetis_ftfx_command(bank, FTFx_CMD_SECTERASE, bank->base + bank->sectors[i].offset,
+                                             0, 0, 0, 0,  0, 0, 0, 0,  &ftfx_fstat);
 
                if (result != ERROR_OK) {
                        LOG_WARNING("erase sector %d failed", i);
@@ -308,7 +326,7 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
 {
        unsigned int i, result, fallback = 0;
        uint8_t buf[8];
-       uint32_t wc, w0 = 0, w1 = 0, w2 = 0;
+       uint32_t wc;
        struct kinetis_flash_bank *kinfo = bank->driver_priv;
 
        if (bank->target->state != TARGET_HALTED) {
@@ -322,15 +340,13 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
                LOG_DEBUG("flash write into FlexNVM @%08X", offset);
 
                /* make flex ram available */
-               w0 = (0x81 << 24) | 0x00ff0000;
-
-               result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+               result = kinetis_ftfx_command(bank, FTFx_CMD_SETFLEXRAM, 0x00ff0000, 0, 0, 0, 0,  0, 0, 0, 0,  &ftfx_fstat);
 
                if (result != ERROR_OK)
                        return ERROR_FLASH_OPERATION_FAILED;
 
                /* check if ram ready */
-               result = target_read_memory(bank->target, 0x40020001, 1, 1, buf);
+               result = target_read_memory(bank->target, FTFx_FCNFG, 1, 1, buf);
 
                if (result != ERROR_OK)
                        return result;
@@ -349,36 +365,82 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
 
        /* program section command */
        if (fallback == 0) {
-               unsigned prog_section_bytes = kinfo->sector_size >> 8;
-               for (i = 0; i < count; i += kinfo->sector_size) {
+               /*
+                * Kinetis uses different terms for the granularity of
+                * sector writes, e.g. "phrase" or "128 bits".  We use
+                * the generic term "chunk". The largest possible
+                * Kinetis "chunk" is 16 bytes (128 bits).
+                */
+               unsigned prog_section_chunk_bytes = kinfo->sector_size >> 8;
+               /* assume the NVM sector size is half the FlexRAM size */
+               unsigned prog_size_bytes = MIN(kinfo->sector_size,
+                                              kinetis_flash_params[kinfo->granularity].nvm_sector_size_bytes);
+               for (i = 0; i < count; i += prog_size_bytes) {
+                       uint8_t residual_buffer[16];
                        uint8_t ftfx_fstat;
-
-                       wc = kinfo->sector_size / 4;
-
-                       if ((count - i) < kinfo->sector_size) {
-                               wc = count - i;
-                               wc /= 4;
+                       uint32_t section_count = prog_size_bytes / prog_section_chunk_bytes;
+                       uint32_t residual_wc = 0;
+
+                       /*
+                        * Assume the word count covers an entire
+                        * sector.
+                        */
+                       wc = prog_size_bytes / 4;
+
+                       /*
+                        * If bytes to be programmed are less than the
+                        * full sector, then determine the number of
+                        * full-words to program, and put together the
+                        * residual buffer so that a full "section"
+                        * may always be programmed.
+                        */
+                       if ((count - i) < prog_size_bytes) {
+                               /* number of bytes to program beyond full section */
+                               unsigned residual_bc = (count-i) % prog_section_chunk_bytes;
+
+                               /* number of complete words to copy directly from buffer */
+                               wc = (count - i) / 4;
+
+                               /* number of total sections to write, including residual */
+                               section_count = DIV_ROUND_UP((count-i), prog_section_chunk_bytes);
+
+                               /* any residual bytes delivers a whole residual section */
+                               residual_wc = (residual_bc ? prog_section_chunk_bytes : 0)/4;
+
+                               /* clear residual buffer then populate residual bytes */
+                               (void) memset(residual_buffer, 0xff, prog_section_chunk_bytes);
+                               (void) memcpy(residual_buffer, &buffer[i+4*wc], residual_bc);
                        }
 
-                       LOG_DEBUG("write section @ %08X with length %d",
-                                 offset + i, wc * 4);
+                       LOG_DEBUG("write section @ %08X with length %d bytes",
+                                 offset + i, wc*4);
 
-                       /* write data to flexram */
-                       result =
-                               target_write_memory(bank->target, 0x14000000, 4, wc,
-                                                   buffer + i);
+                       /* write data to flexram as whole-words */
+                       result = target_write_memory(bank->target, FLEXRAM, 4, wc,
+                                                    buffer + i);
 
                        if (result != ERROR_OK) {
                                LOG_ERROR("target_write_memory failed");
-
                                return result;
                        }
 
-                       /* execute section command */
-                       w0 = (0x0b << 24) | (bank->base + offset + i);
-                       w1 = ((wc * 4 / prog_section_bytes) << 16);
+                       /* write the residual words to the flexram */
+                       if (residual_wc) {
+                               result = target_write_memory(bank->target,
+                                                            FLEXRAM+4*wc,
+                                                            4, residual_wc,
+                                                            residual_buffer);
 
-                       result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+                               if (result != ERROR_OK) {
+                                       LOG_ERROR("target_write_memory failed");
+                                       return result;
+                               }
+                       }
+
+                       /* execute section-write command */
+                       result = kinetis_ftfx_command(bank, FTFx_CMD_SECTWRITE, bank->base + offset + i,
+                                                     section_count>>8, section_count, 0, 0,
+                                                     0, 0, 0, 0,  &ftfx_fstat);
 
                        if (result != ERROR_OK)
                                return ERROR_FLASH_OPERATION_FAILED;
@@ -391,10 +453,11 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
 
                        LOG_DEBUG("write longword @ %08X", offset + i);
 
-                       w0 = (0x06 << 24) | (bank->base + offset + i);
-                       w1 = buf_get_u32(buffer + offset + i, 0, 32);
-
-                       result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+                       uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
+                       memcpy(padding, buffer + i, MIN(4, count-i));
+                       result = kinetis_ftfx_command(bank, FTFx_CMD_LWORDPROG, bank->base + offset + i,
+                                                     padding[3], padding[2], padding[1], padding[0],
+                                                     0, 0, 0, 0,  &ftfx_fstat);
 
                        if (result != ERROR_OK)
                                return ERROR_FLASH_OPERATION_FAILED;
@@ -418,16 +481,18 @@ static int kinetis_read_part_info(struct flash_bank *bank)
                first_nvm_bank = 0, reassign = 0;
        struct kinetis_flash_bank *kinfo = bank->driver_priv;
 
-       result = target_read_memory(bank->target, 0x40048024, 1, 4, buf);
+       result = target_read_memory(bank->target, SIM_SDID, 1, 4, buf);
        if (result != ERROR_OK)
                return result;
        kinfo->sim_sdid = target_buffer_get_u32(bank->target, buf);
        granularity = (kinfo->sim_sdid >> 7) & 0x03;
-       result = target_read_memory(bank->target, 0x4004804c, 1, 4, buf);
+
+       result = target_read_memory(bank->target, SIM_FCFG1, 1, 4, buf);
        if (result != ERROR_OK)
                return result;
        kinfo->sim_fcfg1 = target_buffer_get_u32(bank->target, buf);
-       result = target_read_memory(bank->target, 0x40048050, 1, 4, buf);
+
+       result = target_read_memory(bank->target, SIM_FCFG2, 1, 4, buf);
        if (result != ERROR_OK)
                return result;
        kinfo->sim_fcfg2 = target_buffer_get_u32(bank->target, buf);
@@ -576,7 +641,7 @@ static int kinetis_read_part_info(struct flash_bank *bank)
                                } else if (bank->size != ee_size) {
                                        LOG_WARNING("FlexRAM size mismatch");
                                        reassign = 1;
-                               } else if (bank->base != 0x14000000) {
+                               } else if (bank->base != FLEXRAM) {
                                        LOG_WARNING("FlexRAM address mismatch");
                                        reassign = 1;
                                } else if (kinfo->sector_size !=
@@ -695,14 +760,10 @@ static int kinetis_blank_check(struct flash_bank *bank)
 
        if (kinfo->flash_class == FC_PFLASH) {
                int result;
-               uint32_t w0 = 0, w1 = 0, w2 = 0;
                uint8_t ftfx_fstat;
 
                /* check if whole bank is blank */
-               w0 = (0x00 << 24) | bank->base;
-               w1 = 0; /* "normal margin" */
-
-               result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+               result = kinetis_ftfx_command(bank, FTFx_CMD_BLOCKSTAT, bank->base, 0, 0, 0, 0,  0, 0, 0, 0, &ftfx_fstat);
 
                if (result != ERROR_OK)
                        return result;
@@ -711,10 +772,9 @@ static int kinetis_blank_check(struct flash_bank *bank)
                        /* the whole bank is not erased, check sector-by-sector */
                        int i;
                        for (i = 0; i < bank->num_sectors; i++) {
-                               w0 = (0x01 << 24) | (bank->base + bank->sectors[i].offset);
-                               w1 = (0x100 << 16) | 0; /* normal margin */
-
-                               result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
+                               /* normal margin */
+                               result = kinetis_ftfx_command(bank, FTFx_CMD_SECTSTAT, bank->base + bank->sectors[i].offset,
+                                               1, 0, 0, 0,  0, 0, 0, 0, &ftfx_fstat);
 
                                if (result == ERROR_OK) {
                                        bank->sectors[i].is_erased = !(ftfx_fstat & 0x01);

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)