altos/lpc: Add bits for building flash loaders
authorKeith Packard <keithp@keithp.com>
Sat, 31 Aug 2013 13:20:48 +0000 (08:20 -0500)
committerKeith Packard <keithp@keithp.com>
Sat, 31 Aug 2013 13:20:48 +0000 (08:20 -0500)
Signed-off-by: Keith Packard <keithp@keithp.com>
src/lpc/Makefile-flash.defs [new file with mode: 0644]
src/lpc/ao_flash_lpc.c [new file with mode: 0644]

diff --git a/src/lpc/Makefile-flash.defs b/src/lpc/Makefile-flash.defs
new file mode 100644 (file)
index 0000000..6bdd204
--- /dev/null
@@ -0,0 +1,92 @@
+vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/core:$(TOPDIR)/util:$(TOPDIR)
+vpath ao-make-product.5c $(TOPDIR)/util
+
+.SUFFIXES: .elf .ihx
+
+.elf.ihx:
+       objcopy -O ihex $*.elf $@
+
+CC=arm-none-eabi-gcc
+SAT=/opt/cortex
+SAT_CLIB=$(SAT)/lib/pdclib-cortex-m0.a
+SAT_CFLAGS=-I$(SAT)/include
+
+ifndef VERSION
+include $(TOPDIR)/Version
+endif
+
+AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR)
+STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS)
+
+LDFLAGS=-L$(TOPDIR)/lpc -Wl,-Taltos-loader.ld
+
+NICKLE=nickle
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf "  $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+.c.o:
+       $(call quiet,CC) -c $(CFLAGS) -o $@ $<
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_flash_pins.h \
+       ao_flash_lpc_pins.h \
+       ao_flash_task.h \
+       ao_pins.h \
+       ao_product.h \
+       Makefile
+
+#
+# Common AltOS sources
+#
+SRC = \
+       ao_interrupt.c \
+       ao_romconfig.c \
+       ao_boot_chain.c \
+       ao_boot_pin.c \
+       ao_product.c \
+       ao_notask.c \
+       ao_timer_lpc.c \
+       ao_usb_lpc.c \
+       ao_flash_lpc.c \
+       ao_flash_task.c \
+       ao_flash_loader_lpc.c
+
+OBJ=$(SRC:.c=.o)
+
+PRODUCT=AltosFlash-$(VERSION)
+PRODUCT_DEF=-DALTOS_FLASH
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os
+
+PROGNAME=altos-flash
+PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
+
+$(PROG): Makefile $(OBJ) altos-loader.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+
+ao_product.h: ao-make-product.5c $(TOPDIR)/Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+$(OBJ): $(INC)
+
+all: $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROG)
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/lpc/ao_flash_lpc.c b/src/lpc/ao_flash_lpc.c
new file mode 100644 (file)
index 0000000..5a31f39
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_flash.h>
+
+#define IAP_LOCATION 0x1fff1ff1
+
+typedef void (*iap_func)(uint32_t *in, uint32_t *out);
+
+static void
+iap(uint32_t *in, uint32_t *out)
+{
+       ao_arch_block_interrupts();
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHREG);
+       ((iap_func) IAP_LOCATION)(in, out);
+       ao_arch_release_interrupts();
+}
+
+#define LPC_IAP_PREPARE_WRITE          50
+#define LPC_IAP_COPY_RAM_TO_FLASH      51
+#define LPC_IAP_ERASE_SECTOR           52
+#define LPC_IAP_BLANK_CHECK            53
+#define LPC_IAP_READ_PART_ID           54
+#define LPC_IAP_READ_BOOT_CODE_VERSION 55
+#define LPC_IAP_COMPARE                        56
+#define LPC_IAP_REINVOKE_ISP           57
+#define LPC_IAP_READ_UID               58
+#define LPC_IAP_ERASE_PAGE             59
+#define LPC_IAP_EEPROM_WRITE           61
+#define LPC_IAP_EEPROM_READ            62
+
+#define LPC_IAP_CMD_SUCCESS            0
+#define LPC_IAP_INVALID_COMMAND                1
+#define LPC_IAP_SRC_ADDR_ERROR         2
+#define LPC_IAP_DST_ADDR_ERROR         3
+#define LPC_IAP_SRC_ADDR_NOT_MAPPED    4
+#define LPC_IAP_DST_ADDR_NOT_MAPPED    5
+#define LPC_IAP_COUNT_ERROR            6
+#define LPC_IAP_INVALID_SECTOR         7
+#define LPC_IAP_SECTOR_NOT_BLANK       8
+#define LPC_IAP_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION        9
+#define LPC_IAP_COMPARE_ERROR          10
+#define LPC_IAP_BUSY                   11
+#define LPC_IAP_PARAM_ERROR            12
+#define LPC_IAP_ADDR_ERROR             13
+#define LPC_IAP_ADDR_NOT_MAPPED                14
+#define LPC_IAP_CMD_LOCKED             15
+#define LPC_IAP_INVALID_CODE           16
+#define LPC_IAP_INVALID_BAUD_RATE      17
+#define LPC_IAP_INVALID_STOP_BIT       18
+#define LPC_IAP_CODE_READ_PROTECTION_ENABLED   19
+
+#define LPC_FLASH_BASE                 ((uint8_t *) 0x0)
+#define LPC_FLASH_SECTOR               4096
+#define LPC_FLASH_SECTOR_MASK          (LPC_FLASH_SECTOR - 1)
+#define LPC_FLASH_SECTOR_SHIFT         12
+
+static uint32_t        iap_in[5], iap_out[5];
+
+static uint32_t
+ao_lpc_addr_to_sector(uint8_t *addr)
+{
+       uint32_t        off = addr - LPC_FLASH_BASE;
+
+       return off >> LPC_FLASH_SECTOR_SHIFT;
+}
+
+static uint8_t
+ao_lpc_addr_is_sector_aligned(uint8_t *addr)
+{
+       uint32_t        off = addr - LPC_FLASH_BASE;
+       return          (off & LPC_FLASH_SECTOR_MASK) == 0;
+}
+
+static uint32_t
+ao_lpc_prepare_write(uint32_t start_sector, uint32_t end_sector)
+{
+       iap_in[0] = LPC_IAP_PREPARE_WRITE;
+       iap_in[1] = start_sector;
+       iap_in[2] = end_sector;
+       iap(iap_in,iap_out);
+       return iap_out[0];
+}
+
+static uint32_t
+ao_lpc_copy_ram_to_flash(uint8_t *dst, uint8_t *src, uint32_t len, uint32_t freq)
+{
+       iap_in[0] = LPC_IAP_COPY_RAM_TO_FLASH;
+       iap_in[1] = (uint32_t) dst;
+       iap_in[2] = (uint32_t) src;
+       iap_in[3] = len;
+       iap_in[4] = freq;
+       iap(iap_in,iap_out);
+       return iap_out[0];
+}
+
+static uint32_t
+ao_lpc_erase_sector(uint32_t start_sector, uint32_t end_sector, uint32_t freq)
+{
+       iap_in[0] = LPC_IAP_ERASE_SECTOR;
+       iap_in[1] = start_sector;
+       iap_in[2] = end_sector;
+       iap_in[3] = freq;
+       iap(iap_in,iap_out);
+       return iap_out[0];
+}
+
+uint32_t
+ao_lpc_read_part_id(void)
+{
+       iap_in[0] = LPC_IAP_READ_PART_ID;
+       iap(iap_in,iap_out);
+       return iap_out[1];
+}
+
+uint32_t
+ao_flash_erase_page(uint8_t *page)
+{
+       uint32_t        ret = LPC_IAP_CMD_SUCCESS;
+       if (ao_lpc_addr_is_sector_aligned(page)) {
+               uint32_t        sector = ao_lpc_addr_to_sector(page);
+               ret = ao_lpc_prepare_write(sector, sector);
+               if (ret == LPC_IAP_CMD_SUCCESS)
+                       ret = ao_lpc_erase_sector(sector, sector, AO_LPC_SYSCLK / 1000);
+       }
+       return ret;
+}
+
+uint32_t
+ao_flash_page(uint8_t *page, uint8_t *src)
+{
+       uint32_t        sector = ao_lpc_addr_to_sector(page);
+       uint32_t        ret;
+
+       ret = ao_flash_erase_page(page);
+       if (ret != LPC_IAP_CMD_SUCCESS)
+               return ret;
+       ret = ao_lpc_prepare_write(sector, sector);
+       if (ret != LPC_IAP_CMD_SUCCESS)
+               return ret;
+       ret = ao_lpc_copy_ram_to_flash(page, src, 256, AO_LPC_SYSCLK / 1000);
+       return ret;
+}