===================================================================
@@ -29,6 +29,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
+#include <stdarg.h>
#ifdef _WIN32
#include <windows.h>
#undef min
@@ -40,6 +41,7 @@
/* Error codes */
#define ERROR_OOM -100
#define TIMEOUT_ERROR -101
+struct flashctx;
/* TODO: check using code for correct usage of types */
typedef uintptr_t chipaddr;
@@ -53,10 +55,15 @@
#define PRIxCHIPADDR "06"PRIx32
#define PRIuCHIPSIZE PRIu32
+enum highlevel_cmd {
+ HL_ID_TOGGLE_READY_JEDEC = 1
+};
+
int register_shutdown(int (*function) (void *data), void *data);
void *programmer_map_flash_region(const char *descr, uintptr_t phys_addr, size_t len);
void programmer_unmap_flash_region(void *virt_addr, size_t len);
void programmer_delay(int usecs);
+int programmer_highlevel(const struct flashctx *flash, enum highlevel_cmd id, ...);
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -120,7 +127,6 @@
#define FEATURE_OTP (1 << 8)
#define FEATURE_QPI (1 << 9)
-struct flashctx;
typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
struct flashchip {
===================================================================
@@ -22,6 +22,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdlib.h>
#include "flash.h"
#define MAX_REFLASH_TRIES 0x10
@@ -43,6 +44,8 @@
unsigned int i = 0;
uint8_t tmp1, tmp2;
+ if (programmer_highlevel(flash, HL_ID_TOGGLE_READY_JEDEC, dst, delay)) return;
+
tmp1 = chip_readb(flash, dst) & 0x40;
while (i++ < 0xFFFFFFF) {
===================================================================
@@ -886,6 +886,47 @@
sp_prev_was_write = 0;
}
+int serprog_highlevel(const struct flashctx *flash, enum highlevel_cmd id, va_list ap)
+{
+ switch (id) {
+ default: /* Any new ids, by default not handled. */
+ return 0;
+ case HL_ID_TOGGLE_READY_JEDEC:
+ if (sp_check_commandavail(S_CMD_O_TOGGLERDY)) {
+
+ uint8_t buf[7];
+ if ((sp_max_write_n) && (sp_write_n_bytes))
+ sp_pass_writen();
+ sp_check_opbuf_usage(8);
+ unsigned int addr = va_arg(ap,unsigned int);
+ int usecs = va_arg(ap,int);
+ buf[0] = ((usecs >> 0) & 0xFF);
+ buf[1] = ((usecs >> 8) & 0xFF);
+ buf[2] = ((usecs >> 16) & 0xFF);
+ buf[3] = ((usecs >> 24) & 0xFF);
+ buf[4] = ((addr >> 0) & 0xFF);
+ buf[5] = ((addr >> 8) & 0xFF);
+ buf[6] = ((addr >> 16) & 0xFF);
+ sp_stream_buffer_op(S_CMD_O_TOGGLERDY, 7, buf);
+ sp_opbuf_usage += 8;
+ sp_prev_was_write = 0;
+ msg_pspew(MSGHEADER "highlevel toggle ready dly=%d addr=0x%x\n",
+ usecs,addr);
+ if (sp_opbuf_usage > (sp_device_opbuf_size/3)) {
+ /* Since this was previously a natural exec point,
+ execute if we have more than 33% of opbuf in use. */
+ /* FIXME: Return error. */
+ sp_execute_opbuf_noflush();
+ }
+ return 1; /* Handled by programmer. */
+ }
+ return 0;
+
+ }
+ /* If you accidentally fall here, not handled. */
+ return 0;
+}
+
static int serprog_spi_send_command(struct flashctx *flash,
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr,
===================================================================
@@ -23,3 +23,4 @@
#define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */
#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */
#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */
+#define S_CMD_O_TOGGLERDY 0x16 /* Write to opbuf: Wait Jedec Toggle */
===================================================================
@@ -35,6 +35,8 @@
+ slen bytes of data
0x14 Set SPI clock frequency in Hz 32-bit requested frequency ACK + 32-bit set frequency / NAK
0x15 Toggle flash chip pin drivers 8-bit (0 disable, else enable) ACK / NAK
+0x16 Write to opbuf: Toggle Ready 32-bit delay + 24-bit addr ACK / NAK (NOTE: 8 bytes in opbuf)
+ JEDEC
0x?? unimplemented command - invalid.
===================================================================
@@ -194,6 +194,7 @@
.map_flash_region = fallback_map,
.unmap_flash_region = fallback_unmap,
.delay = serprog_delay,
+ .highlevel = serprog_highlevel,
},
#endif
@@ -490,6 +491,17 @@
programmer_table[programmer].delay(usecs);
}
+int programmer_highlevel(const struct flashctx *flash, enum highlevel_cmd id, ...)
+{
+ int rv = 0;
+ va_list ap;
+ va_start(ap,id);
+ if (programmer_table[programmer].highlevel)
+ rv = programmer_table[programmer].highlevel(flash,id,ap);
+ va_end(ap);
+ return rv;
+}
+
void map_flash_registers(struct flashctx *flash)
{
size_t size = flash->chip->total_size * 1024;
===================================================================
@@ -121,6 +121,8 @@
void (*unmap_flash_region) (void *virt_addr, size_t len);
void (*delay) (int usecs);
+
+ int (*highlevel) (const struct flashctx *flash, enum highlevel_cmd id, va_list ap);
};
extern const struct programmer_entry programmer_table[];
@@ -655,6 +657,7 @@
#if CONFIG_SERPROG == 1
int serprog_init(void);
void serprog_delay(int usecs);
+int serprog_highlevel(const struct flashctx *flash, enum highlevel_cmd id, va_list ap);
#endif
/* serial.c */
Hi, Add mechanism to allow the external programmer to take over a higher level operation than previously. As an useful first example jedec toggle ready on serprog is included. Signed-off-by: Urja Rannikko <urjaman@gmail.com> ----- I dont have much to say about this, except that there is one more patch following this to make proper use of the speed improvement this allows to write_jedec_1, and that serprog LPC support still depends on http://patchwork.coreboot.org/patch/3465/ or something similar. What do you think? Oh and there is an example of the device code for this added serprog operation here: https://github.com/urjaman/frser-atmega644