Add flash support for SiFive's Freedom E platforms
[openocd.git] / contrib / loaders / flash / fespi / fespi.S
diff --git a/contrib/loaders/flash/fespi/fespi.S b/contrib/loaders/flash/fespi/fespi.S
new file mode 100644 (file)
index 0000000..d68e65e
--- /dev/null
@@ -0,0 +1,99 @@
+#define SPIFLASH_READ_STATUS   0x05 // Read Status Register
+#define SPIFLASH_BSY_BIT               0x00000001 // WIP Bit of SPI SR on SMI SR
+
+// Register offsets
+#define FESPI_REG_FMT             0x40
+#define FESPI_REG_TXFIFO          0x48
+#define FESPI_REG_RXFIFO          0x4c
+#define FESPI_REG_IP              0x74
+
+// Fields
+#define FESPI_IP_TXWM             0x1
+#define FESPI_FMT_DIR(x)          (((x) & 0x1) << 3)
+
+// To enter, jump to the start of command_table (ie. offset 0).
+//      a0 - FESPI base address
+//      a1 - start address of buffer
+
+// The buffer contains a "program" in byte sequences. The first byte in a
+// sequence determines the operation. Some operation will read more data from
+// the program, while some will not. The operation byte is the offset into
+// command_table, so eg. 4 means exit, 8 means transmit, and so on.
+
+               .global _start
+_start:
+command_table:
+               j       main            // 0
+               ebreak                  // 4
+               j       tx              // 8
+               j       txwm_wait       // 12
+               j       write_reg       // 16
+               j               wip_wait                // 20
+               j               set_dir                 // 24
+
+// Execute the program.
+main:
+               lbu     t0, 0(a1)
+               addi    a1, a1, 1
+               la      t1, command_table
+               add     t0, t0, t1
+               jr      t0
+
+// Read 1 byte the contains the number of bytes to transmit. Then read those
+// bytes from the program and transmit them one by one.
+tx:
+               lbu     t1, 0(a1)       // read number of bytes to transmit
+               addi    a1, a1, 1
+1:      lw      t0, FESPI_REG_TXFIFO(a0)        // wait for FIFO clear
+               bltz    t0, 1b
+               lbu     t0, 0(a1)       // Load byte to write
+               sw      t0, FESPI_REG_TXFIFO(a0)
+               addi    a1, a1, 1
+               addi    t1, t1, -1
+               bgtz    t1, 1b
+               j       main
+
+// Wait until TXWM is set.
+txwm_wait:
+1:      lw      t0, FESPI_REG_IP(a0)
+               andi    t0, t0, FESPI_IP_TXWM
+               beqz    t0, 1b
+               j       main
+
+// Read 1 byte that contains the offset of the register to write, and 1 byte
+// that contains the data to write.
+write_reg:
+               lbu     t0, 0(a1)       // read register to write
+               add     t0, t0, a0
+               lbu     t1, 1(a1)       // read value to write
+               addi    a1, a1, 2
+               sw      t1, 0(t0)
+               j       main
+
+wip_wait:
+               li              a2, SPIFLASH_READ_STATUS
+               jal             txrx_byte
+               // discard first result
+1:             li              a2, 0
+               jal             txrx_byte
+               andi    t0, a2, SPIFLASH_BSY_BIT
+               bnez    t0, 1b
+               j               main
+
+txrx_byte:     // transmit the byte in a2, receive a bit into a2
+               lw      t0, FESPI_REG_TXFIFO(a0)        // wait for FIFO clear
+               bltz    t0, txrx_byte
+               sw      a2, FESPI_REG_TXFIFO(a0)
+1:             lw              a2, FESPI_REG_RXFIFO(a0)
+               bltz    a2, 1b
+               ret
+
+set_dir:
+               lw              t0, FESPI_REG_FMT(a0)
+               li              t1, ~(FESPI_FMT_DIR(0xFFFFFFFF))
+               and             t0, t0, t1
+               lbu     t1, 0(a1)       // read value to OR in
+               addi    a1, a1, 1
+               or              t0, t0, t1
+               sw              t0, FESPI_REG_FMT(a0)
+               j               main

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)