diff options
| author | Keith Packard <keithp@keithp.com> | 2013-08-31 08:22:09 -0500 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2013-08-31 08:22:09 -0500 | 
| commit | 7ec1b97d278c7aec3199fb7270f0dcf9484c879f (patch) | |
| tree | 397c4dfdc148492c10d51b95b34cd1062b045ab4 | |
| parent | 017ed54ff69ef2f7740ea2578e22bf72e88deafb (diff) | |
| parent | 4188153548fca104bb49cda2d502c708fe4b49d7 (diff) | |
Merge branch 'master' into new-state
| -rw-r--r-- | src/lpc/Makefile-flash.defs | 92 | ||||
| -rw-r--r-- | src/lpc/ao_flash_lpc.c | 158 | 
2 files changed, 250 insertions, 0 deletions
| diff --git a/src/lpc/Makefile-flash.defs b/src/lpc/Makefile-flash.defs new file mode 100644 index 00000000..6bdd204c --- /dev/null +++ b/src/lpc/Makefile-flash.defs @@ -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 index 00000000..5a31f39f --- /dev/null +++ b/src/lpc/ao_flash_lpc.c @@ -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; +} | 
