dvnixload/ubl copy as of pre 0.2.6 svn
This commit is contained in:
commit
4b779cf0d2
|
@ -0,0 +1,18 @@
|
|||
v0.2.3
|
||||
Mini-DAS: Enable DSP1 & DSP2 power.
|
||||
|
||||
v0.2.4
|
||||
Mini-DAS: Enable DSP1 & DSP2 power.
|
||||
Deactivate DSP1 & DSP2 reset lines.
|
||||
|
||||
|
||||
v0.2.5
|
||||
Mini-DAS: Enable all power supplys and deactivate
|
||||
all peripheral reset lines.
|
||||
|
||||
v0.2.6
|
||||
Mini-DAS: Add delay after applying DSP power and
|
||||
before releasing DSP reset lines.
|
||||
|
||||
v0.2.7
|
||||
Mini-DAS: Open-drain output for CAMERA RESET.
|
|
@ -0,0 +1,201 @@
|
|||
#
|
||||
# Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.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; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
ifndef CROSS_COMPILE
|
||||
CROSS_COMPILE=arm-linux-
|
||||
endif
|
||||
|
||||
.PHONY : clean check
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
LD=$(CROSS_COMPILE)ld
|
||||
|
||||
CFLAGS := -c -Os -Wall
|
||||
LDFLAGS := -Map ubl.map -nostdlib
|
||||
|
||||
SOURCES := davinci.c uart.c uartboot.c ubl.c util.c gpio.c crc.c gunzip.c
|
||||
|
||||
# Boards setup
|
||||
ifeq ($(BOARD),dvevm)
|
||||
# EVM for DM6446
|
||||
PLATFORM := DM644x
|
||||
FLASH_TYPE := FLASH_TYPE_NAND
|
||||
DDR_TYPE := MICRON_MT47H64M16BT_3_162MHZ
|
||||
DDR_SIZE := 0x10000000 # 256MB
|
||||
endif
|
||||
ifeq ($(BOARD),sffsdr)
|
||||
PLATFORM := DM644x
|
||||
FLASH_TYPE := FLASH_TYPE_NAND
|
||||
DDR_TYPE := MICRON_MT47H32M16BN_3_162MHZ
|
||||
DDR_SIZE := 0x08000000 # 128MB
|
||||
endif
|
||||
ifeq ($(BOARD),das)
|
||||
PLATFORM := DM644x
|
||||
FLASH_TYPE := FLASH_TYPE_NAND
|
||||
DDR_TYPE := MICRON_MT47H64M16HR_3_162MHZ
|
||||
DDR_SIZE := 0x10000000 # 256MB
|
||||
endif
|
||||
ifeq ($(BOARD),minidas)
|
||||
PLATFORM := DM35x
|
||||
FLASH_TYPE := FLASH_TYPE_NAND
|
||||
DDR_TYPE := MICRON_MT47H128M16HG_3IT_171MHZ
|
||||
DDR_SIZE := 0x10000000 # 256MB
|
||||
endif
|
||||
ifeq ($(BOARD),afeusb)
|
||||
PLATFORM := DM35x
|
||||
FLASH_TYPE := FLASH_TYPE_NAND
|
||||
DDR_TYPE := MICRON_MT47H32M16BN_3_171MHZ
|
||||
DDR_SIZE := 0x04000000 # 64MB
|
||||
endif
|
||||
ifeq ($(BOARD),dm355evm)
|
||||
PLATFORM := DM35x
|
||||
FLASH_TYPE := FLASH_TYPE_NAND
|
||||
DDR_TYPE := MICRON_MT47H64M16BT_37E_171MHZ
|
||||
DDR_SIZE := 0x08000000 # 128MB
|
||||
endif
|
||||
ifeq ($(BOARD),nor)
|
||||
# Only for testing NOR flash compilation
|
||||
PLATFORM := DM35x
|
||||
FLASH_TYPE := FLASH_TYPE_NOR
|
||||
DDR_TYPE := MICRON_MT47H64M16BT_37E_171MHZ
|
||||
DDR_SIZE := 0x08000000 # 128MB
|
||||
endif
|
||||
|
||||
# Generate a config.h file based on the board selected.
|
||||
# Only update this file if the selected board is different.
|
||||
OLDBOARD = $(shell cat config.h 2> /dev/null | grep "$(BOARD)")
|
||||
ifneq ($(OLDBOARD),$(BOARD))
|
||||
$(shell echo "$(BOARD)" > config.h)
|
||||
endif
|
||||
|
||||
CFLAGS += -D${PLATFORM} -D${FLASH_TYPE} -D$(DDR_TYPE) -Dboard_$(BOARD)
|
||||
|
||||
# Processor type setup
|
||||
# The Instruction and Data accesses are differentiated via accessing different
|
||||
# memory map regions. The instruction region at 0x0000 and data region at
|
||||
# 0x8000 (0x10000 for DM35x) map to the same physical TCM RAM.
|
||||
ifeq ($(PLATFORM),DM644x)
|
||||
SOURCES += dm644x.c
|
||||
IRAM_SIZE := 0x00004000
|
||||
DRAM_START := 0x00008000
|
||||
DRAM_SIZE := 0x00004000
|
||||
endif
|
||||
ifeq ($(PLATFORM),DM35x)
|
||||
SOURCES += dm35x.c
|
||||
IRAM_SIZE := 0x00008000
|
||||
DRAM_START := 0x00010000
|
||||
DRAM_SIZE := 0x00008000
|
||||
endif
|
||||
|
||||
LDFLAGS += --defsym __DDR_SIZE=$(DDR_SIZE) \
|
||||
--defsym __IRAM_SIZE=$(IRAM_SIZE) \
|
||||
--defsym __DRAM_START=$(DRAM_START) \
|
||||
--defsym __DRAM_SIZE=$(DRAM_SIZE) \
|
||||
-T ubl.lds
|
||||
|
||||
# NAND flash setup
|
||||
ifeq ($(FLASH_TYPE),FLASH_TYPE_NAND)
|
||||
SOURCES += nandboot.c nand.c
|
||||
endif
|
||||
ifeq ($(FLASH_TYPE),FLASH_TYPE_NOR)
|
||||
SOURCES += norboot.c nor.c
|
||||
endif
|
||||
|
||||
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
|
||||
EXECUTABLE := ubl.elf
|
||||
BINARY := $(EXECUTABLE)
|
||||
|
||||
DEPS_DIR := .deps
|
||||
# Creation of the dependencies directory
|
||||
$(shell mkdir -p $(DEPS_DIR))
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifndef BOARD
|
||||
all:
|
||||
@echo "You must select a board."
|
||||
@echo "List of supported boards: evmdm6446 sffsdr das minidas afeusb evmdm355"
|
||||
@echo "Example:"
|
||||
@echo " make BOARD=sffsdr"; exit 1
|
||||
else
|
||||
ifndef PLATFORM
|
||||
all:
|
||||
@echo "Invalid board"; exit 1
|
||||
else
|
||||
all: $(BINARY)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Including the dependency files (except during clean rules, so Make won't
|
||||
# create them only to immediately remove them again). Each one of them will
|
||||
# become a target in this Makefile (that is why the 'include' command must be
|
||||
# placed after the 'all' target). If a dependency file is not found or is out
|
||||
# of date, it is built or updated.
|
||||
# If any have actually been changed, Make restarts with a clean state and
|
||||
# reads all the dependency makefiles over again.
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq "$(SOURCES)" ""
|
||||
ifdef BOARD
|
||||
-include $(patsubst %.c,$(DEPS_DIR)/%.d,$(SOURCES))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
clean:
|
||||
-@rm -f -v *.o $(EXECUTABLE)
|
||||
-@rm -f -v *.map
|
||||
-@rm -f -v *~
|
||||
-@rm -f -v config.h
|
||||
-@rm -f -r $(DEPS_DIR)
|
||||
|
||||
check:
|
||||
-@checkpatch.pl --no-tree --file *.c *.h | more
|
||||
|
||||
$(EXECUTABLE): $(OBJECTS)
|
||||
$(LD) $(LDFLAGS) $(OBJECTS) -o $@
|
||||
|
||||
# Any source files depend on automatically generated config.h.
|
||||
# This is necessary to recompile everything when we change boards.
|
||||
*.o: config.h $(LINKERSCRIPT)
|
||||
|
||||
# The preprocessor of the compiler is used to generate a string representing
|
||||
# the dependencies of the input file. This is done invoking the compiler with
|
||||
# the -MM option (like -M but omit system header files). The purpose of the
|
||||
# sed script is to add the name of the dependency file (.d) to the string
|
||||
# returned by the preprocessor, like in the following example:
|
||||
# "main.o: main.c main.h" would become "main.o main.d: main.c main.h"
|
||||
# The MAKE '$*' automatic variable represents the stem with which an implicit
|
||||
# rule match. This would be 'main' in the above example.
|
||||
#
|
||||
# Use of the $(SHELL) function: Double quotes must be used to surround the
|
||||
# command.
|
||||
#
|
||||
# In MAKE, using '$$' will produce a single dollar sign. When using only '$',
|
||||
# MAKE tries to expand the variable following the dollar sign. Additionally,
|
||||
# and for an obscure reason, '$1' must be preceded by a backslash on the
|
||||
# command line. This is why '\$$1' is used in the command line of the shell to
|
||||
# be seen as '$1' by the PERL script.
|
||||
#
|
||||
# The `-e' flag to the shell makes it exit immediately if the $(CC) command
|
||||
# fails (exits with a nonzero status). Normally the shell exits with the
|
||||
# status of the last command in the pipeline (sed in this case), so make would
|
||||
# not notice a nonzero status from the compiler.
|
||||
$(DEPS_DIR)/%.d: %.c
|
||||
@echo "Generating dependencies for $<"
|
||||
@$(SHELL) -ec '$(CC) -MM $(CPPFLAGS) $< | \
|
||||
sed '\''s/\($*\)\.o[ :]*/\1.o $(DEPS_DIR)\/$*.d : /g'\'' > $@; \
|
||||
[ -s $@ ] || rm -f $@'
|
|
@ -0,0 +1,21 @@
|
|||
README for HVUBL
|
||||
|
||||
This UBL can be used for flashing itself and a 2nd stage bootloader (usually
|
||||
U-boot) in flash memory.
|
||||
|
||||
It can also be used to flash an arbitrary data image into flash, without
|
||||
a header.
|
||||
|
||||
It can also be used to run DDR RAM memory testing.
|
||||
|
||||
To compile HVUBL for the sffsdr board, for example, run:
|
||||
$> make BOARD=sffsdr
|
||||
|
||||
The Makefile honors the CROSS_COMPILE environment variable to specify the prefix
|
||||
of your ARM gcc toolchain. If it is not set, it defaults to:
|
||||
CROSS_COMPILE=arm-linux-
|
||||
|
||||
You can override it like this, for example:
|
||||
$> make CROSS_COMPILE=arm-angstrom-linux-gnueabi- BOARD=sffsdr
|
||||
|
||||
The output file, in ARM ELF format, will be named <ubl.elf>
|
|
@ -0,0 +1,7 @@
|
|||
TODO
|
||||
|
||||
-Define DDR bus width and number of banks for each board.
|
||||
-NAND write & read page: do bound checking on
|
||||
block number < maximum number of blocks.
|
||||
-When writing something other than UBL, use
|
||||
Linux and U-Boot standard ECC layout.
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* board.h - board definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
|
||||
#if defined(board_dvevm)
|
||||
# define PINMUX1_DEFAULT PINMUX1_UART0
|
||||
|
||||
#elif defined(board_sffsdr)
|
||||
# define PINMUX1_DEFAULT PINMUX1_UART0 | PINMUX1_UART1 | PINMUX1_I2C | \
|
||||
PINMUX1_ASP
|
||||
|
||||
#elif defined(board_das)
|
||||
# define PINMUX0_DEFAULT PINMUX0_VLYNQEN | VLYNQ_WIDTH_4
|
||||
# define PINMUX1_DEFAULT PINMUX1_UART0 | PINMUX1_UART2 | PINMUX1_I2C | \
|
||||
PINMUX1_SPI
|
||||
|
||||
#elif defined(board_dm355evm)
|
||||
# define PINMUX0_DEFAULT 0x00007F55 /* All Video Inputs */
|
||||
# define PINMUX1_DEFAULT 0x00145555 /* All Video Outputs */
|
||||
# define PINMUX2_DEFAULT 0x00000004 /* EMIFA */
|
||||
# define PINMUX3_DEFAULT 0x1BFF55FF /* SPI0, SPI1, UART1, I2C, SD0, SD1,
|
||||
* ASP0, CLKOUTs */
|
||||
# define PINMUX4_DEFAULT 0x00000000 /* MMC/SD0 instead of MS, SPI0 */
|
||||
|
||||
#elif defined(board_minidas)
|
||||
# define PINMUX0_DEFAULT 0x00005C00 /* 8-bits video input, rest is GPIOs. */
|
||||
# define PINMUX1_DEFAULT 0x00430000 /* All GPIOs (temporary: no PWM1 for buzzer) */
|
||||
# define PINMUX2_DEFAULT 0x00000C0A /* EMIF A3:13, CE0 & CE1. */
|
||||
# define PINMUX3_DEFAULT 0x0B7BAAC0 /* SPI0, SPI1, UART1, UART2, I2C, SD0,
|
||||
* CLKOUT1, CLKOUT2 */
|
||||
# define PINMUX4_DEFAULT 0x00000001 /* MMC/SD0 + SPI0_SDI */
|
||||
|
||||
/* Optional GPIO used as a status LED. Make sure to enable the corresponding
|
||||
* PINMUX bit. */
|
||||
#define STATUS_LED GPIO(71)
|
||||
#define DSP1_PWR_ENA GPIO(95)
|
||||
#define DSP2_PWR_ENA GPIO(94)
|
||||
#define HDD_ENA GPIO(96)
|
||||
#define FULL_ENA GPIO(68)
|
||||
#define ALCOHOL_ENA GPIO(73)
|
||||
#define CAMERA_RESETn GPIO(72)
|
||||
#define FAN GPIO(81)
|
||||
#define BUZZER GPIO(80)
|
||||
#define WIFI_RESETn GPIO(79)
|
||||
#define GPS_RESETn GPIO(78)
|
||||
#define CAN_RESETn GPIO(77)
|
||||
#define ATA_RESETn GPIO(76)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _BOARD_H_ */
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* common.h - common definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h> /* For size_t */
|
||||
|
||||
#include "board.h"
|
||||
|
||||
/* Return types */
|
||||
#define E_PASS 0
|
||||
#define E_FAIL 1
|
||||
#define E_TIMEOUT 2
|
||||
|
||||
/* Define this to have more verbose NAND debug messages */
|
||||
/* #define NAND_DEBUG 1 */
|
||||
|
||||
/* Define this to write a RAMP into NAND for debugging. */
|
||||
/* #define NAND_DEBUG_WRITE_RAMP 1 */
|
||||
|
||||
#define UBL_VERSION_STR "HV-UBL v0.2.11"
|
||||
|
||||
/* Define this for bypassing the ECC check when reading from the NAND.
|
||||
* This is useful for debugging or during development. */
|
||||
#define NAND_BYPASS_READ_PAGE_ECC_CHECK 1
|
||||
|
||||
#define MAGIC_NUMBER_MASK 0xFFFFFF00
|
||||
#define MAGIC_NUMBER_VALID 0xA1ACED00
|
||||
|
||||
/* RBL magic numbers */
|
||||
#define RBL_MAGIC_SAFE 0xA1ACED00 /* Describes UBL flash image type for
|
||||
* RBL. */
|
||||
|
||||
/* UBL magic numbers */
|
||||
#define UBL_MAGIC_BIN_IMG 0xA1ACED66 /* Describes binary flash image type
|
||||
* for UBL. */
|
||||
#define UBL_MAGIC_GZIP_IMG 0xA1ACED77 /* Describes gzipped binary flash
|
||||
* image type for UBL. */
|
||||
|
||||
/* UBL commands */
|
||||
#define UBL_CMD_FLASH_UBL_APP 0xA1ACEDCC /* Download UBL & application via
|
||||
* UART and burn in flash. */
|
||||
#define UBL_CMD_FLASH_DATA 0xA1ACEDCD /* Download data via UART and
|
||||
* burn in flash (no header in flash). */
|
||||
#define UBL_CMD_FLASH_ERASE 0xA1ACEDCE /* Erase the whole flash. */
|
||||
#define UBL_CMD_RUN_APP 0xA1ACEDDD /* Load and run application via UART. */
|
||||
#define UBL_CMD_DDR_TEST 0xA1ACEDEE /* Test DDR2 memory. */
|
||||
|
||||
/* Define maximum downloadable image size */
|
||||
#define MAX_IMAGE_SIZE 0xC00000 /* 12 Mbytes */
|
||||
|
||||
struct nor_boot_t {
|
||||
uint32_t magicNum;
|
||||
uint32_t entryPoint;
|
||||
uint32_t appSize;
|
||||
uint32_t ldAddress; /* Starting RAM address where image is to copied - XIP Mode */
|
||||
};
|
||||
|
||||
enum bootmode_t {
|
||||
NON_SECURE_NAND = 0, /* Non-secure NAND mode */
|
||||
NON_SECURE_NOR, /* Non-secure NOR mode */
|
||||
UNKNOWN_MODE, /* Unknown mode */
|
||||
NON_SECURE_UART /* Non-secure UART mode */
|
||||
};
|
||||
|
||||
#define ENDIAN_SWAP(a) (((a&0xFF)<<24)|((a&0xFF0000)>>8)|((a&0xFF00)<<8)|((a&0xFF000000)>>24))
|
||||
|
||||
/* Log functions */
|
||||
#define log_fail(_x_) uart_send_str_lf(_x_)
|
||||
#define log_info(_x_) uart_send_str_lf(_x_)
|
||||
#define log_debug(_x_) uart_send_str_lf(_x_)
|
||||
|
||||
#define host_msg(_x_) uart_send_str_lf(_x_)
|
||||
|
||||
#endif /* _COMMON_H_ */
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* crc.h -- CRC routines
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on dv-boot, original copyright follows:
|
||||
* Copyright (c) 2007 Sergey Kubushin <ksi@koi8.net>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* For size_t */
|
||||
|
||||
#define CRC_TABLE_ELEMENTS 256
|
||||
#define DAVINCI_CRC_POLY 0x04C11DB7
|
||||
|
||||
static uint32_t crc32_table[CRC_TABLE_ELEMENTS];
|
||||
|
||||
static uint32_t
|
||||
reflect_num(uint32_t in_val, uint32_t num)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t out_val = 0x0;
|
||||
|
||||
for (i = 1; i < (num + 1); i++) {
|
||||
out_val |= (uint32_t)(((in_val & 0x1)) << (num - i));
|
||||
in_val >>= 1;
|
||||
}
|
||||
|
||||
return out_val;
|
||||
}
|
||||
|
||||
/* Build a reflected CRC-32 table (for standard CRC-32 algorithm) */
|
||||
void
|
||||
crc32_dv_build_table(void)
|
||||
{
|
||||
uint32_t i, j, crc_accum;
|
||||
|
||||
for (i = 0; i < CRC_TABLE_ELEMENTS; i++) {
|
||||
crc_accum = reflect_num(i, 8) << (32 - 8);
|
||||
for (j = 0; j < 8; j++) {
|
||||
if ((crc_accum & 0x80000000) != 0x00000000)
|
||||
crc_accum = (crc_accum << 1) ^ DAVINCI_CRC_POLY;
|
||||
else
|
||||
crc_accum = (crc_accum << 1);
|
||||
|
||||
crc32_table[i] = reflect_num(crc_accum, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute CRC32 checksum */
|
||||
uint32_t
|
||||
crc32_dv_compute(uint8_t *data, size_t size)
|
||||
{
|
||||
uint32_t crc32 = 0xFFFFFFFF;
|
||||
|
||||
while (size-- > 0)
|
||||
crc32 = crc32_table[(crc32 ^ *data++) & 0xFF] ^ (crc32 >> 8);
|
||||
|
||||
return crc32;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* crc.h -- CRC definitions.
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef CRC_H
|
||||
#define CRC_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* For size_t, memcpy, memset */
|
||||
|
||||
/* Build a reflected CRC-32 table (for standard CRC-32 algorithm) */
|
||||
void crc32_dv_build_table(void);
|
||||
|
||||
/* Compute non-standard CRC32 */
|
||||
uint32_t
|
||||
crc32_dv_compute(uint8_t *data, size_t size);
|
||||
|
||||
#endif /* CRC_H */
|
|
@ -0,0 +1,528 @@
|
|||
/*
|
||||
* davinci.c - common DaVinci platform initialization
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
#include "ddr.h"
|
||||
#include "util.h"
|
||||
#include "uart.h"
|
||||
#include "gpio.h"
|
||||
|
||||
extern enum bootmode_t bootmode;
|
||||
extern const int8_t lpsc_en_list[];
|
||||
extern const int8_t lpsc_emurstie_list[];
|
||||
extern const size_t lpsc_en_list_len;
|
||||
extern const size_t lpsc_emurstie_list_len;
|
||||
|
||||
/* Symbol from linker script */
|
||||
extern uint32_t __DDR_START;
|
||||
|
||||
static void
|
||||
pinmuxControl(uint32_t regOffset, uint32_t mask, uint32_t value)
|
||||
{
|
||||
SYSTEM->PINMUX[regOffset] &= ~mask;
|
||||
SYSTEM->PINMUX[regOffset] |= (mask & value);
|
||||
}
|
||||
|
||||
static void
|
||||
lpsc_tansition(uint8_t module, uint8_t domain, uint8_t state)
|
||||
{
|
||||
/* Wait for any outstanding transition to complete */
|
||||
while ((PSC->PTSTAT) & (0x00000001 << domain))
|
||||
;
|
||||
|
||||
/* If we are already in that state, just return */
|
||||
if (((PSC->MDSTAT[module]) & 0x1F) == state)
|
||||
return;
|
||||
|
||||
/* Perform transition */
|
||||
PSC->MDCTL[module] = ((PSC->MDCTL[module]) & (0xFFFFFFE0)) | (state);
|
||||
PSC->PTCMD |= (0x00000001 << domain);
|
||||
|
||||
/* Wait for transition to complete */
|
||||
while ((PSC->PTSTAT) & (0x00000001 << domain))
|
||||
;
|
||||
|
||||
/* Wait and verify the state */
|
||||
while (((PSC->MDSTAT[module]) & 0x1F) != state)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
ivt_init(void)
|
||||
{
|
||||
volatile uint32_t *ivect;
|
||||
extern uint32_t __IVT;
|
||||
|
||||
if (bootmode == NON_SECURE_NOR) {
|
||||
ivect = &(__IVT);
|
||||
*ivect++ = 0xEAFFFFFE; /* Reset @ 0x00*/
|
||||
} else
|
||||
ivect = &(__IVT) + 4;
|
||||
|
||||
*ivect++ = 0xEAFFFFFE; /* Undefined Address @ 0x04 */
|
||||
*ivect++ = 0xEAFFFFFE; /* Software Interrupt @0x08 */
|
||||
*ivect++ = 0xEAFFFFFE; /* Pre-Fetch Abort @ 0x0C */
|
||||
*ivect++ = 0xEAFFFFFE; /* Data Abort @ 0x10 */
|
||||
*ivect++ = 0xEAFFFFFE; /* Reserved @ 0x14 */
|
||||
*ivect++ = 0xEAFFFFFE; /* IRQ @ 0x18 */
|
||||
*ivect = 0xEAFFFFFE; /* FIQ @ 0x1C */
|
||||
}
|
||||
|
||||
static int
|
||||
timer0_init(void)
|
||||
{
|
||||
TIMER0->TGCR = 0x00000000; /* Reset timer */
|
||||
TIMER0->TCR = 0x00000000; /* Disable timer */
|
||||
TIMER0->TIM12 = 0x00000000; /* Reset timer count to zero */
|
||||
|
||||
/* Set timer period (5 seconds timeout) */
|
||||
TIMER0->PRD12 = SYSTEM_CLK_HZ * 5;
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
void
|
||||
timer0_start(void)
|
||||
{
|
||||
AINTC->IRQ1 |= 0x00000001; /* Clear interrupt */
|
||||
TIMER0->TGCR = 0x00000000; /* Reset timer */
|
||||
TIMER0->TIM12 = 0x00000000; /* Reset timer count to zero */
|
||||
TIMER0->TCR = 0x00000040; /* Setup for one-shot mode */
|
||||
TIMER0->TGCR = 0x00000005; /* Start TIMER12 in 32-bits mode. */
|
||||
}
|
||||
|
||||
uint32_t
|
||||
timer0_status(void)
|
||||
{
|
||||
return AINTC->IRQ1 & 0x1;
|
||||
}
|
||||
|
||||
static int
|
||||
uart0_init(void)
|
||||
{
|
||||
UART0->PWREMU_MGNT = 0; /* Reset UART TX & RX components */
|
||||
waitloop(100);
|
||||
|
||||
/* Set DLAB bit - allows setting of clock divisors */
|
||||
UART0->LCR |= 0x80;
|
||||
|
||||
/*
|
||||
* Compute divisor value. Normally, we should simply return:
|
||||
* SYSTEM_CLK_HZ / (16 * baudrate)
|
||||
* but we need to round that value by adding 0.5.
|
||||
* Rounding is especially important at high baud rates.
|
||||
*/
|
||||
UART0->DLL = (SYSTEM_CLK_HZ + (UART_BAUDRATE * (UART_BCLK_RATIO / 2))) /
|
||||
(UART_BCLK_RATIO * UART_BAUDRATE);
|
||||
UART0->DLH = 0x00;
|
||||
|
||||
UART0->FCR = 0x0007; /* Clear UART TX & RX FIFOs */
|
||||
UART0->MCR = 0x0000; /* RTS & CTS disabled,
|
||||
* Loopback mode disabled,
|
||||
* Autoflow disabled
|
||||
*/
|
||||
|
||||
UART0->LCR = 0x0003; /* Clear DLAB bit
|
||||
* 8-bit words,
|
||||
* 1 STOP bit generated,
|
||||
* No Parity, No Stick paritiy,
|
||||
* No Break control
|
||||
*/
|
||||
|
||||
/* Enable receiver, transmitter, set to run. */
|
||||
UART0->PWREMU_MGNT |= 0x6001;
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
static int
|
||||
pll_init(volatile struct pll_regs_t *pll, int pll_mult, int plldiv_ratio[5])
|
||||
{
|
||||
int k;
|
||||
volatile uint32_t *plldiv_reg[5];
|
||||
int pll_is_powered_up =
|
||||
(pll->PLLCTL & DEVICE_PLLCTL_PLLPWRDN_MASK) >> 1;
|
||||
|
||||
plldiv_reg[0] = &pll->PLLDIV1;
|
||||
plldiv_reg[1] = &pll->PLLDIV2;
|
||||
plldiv_reg[2] = &pll->PLLDIV3;
|
||||
plldiv_reg[3] = &pll->PLLDIV4;
|
||||
plldiv_reg[4] = &pll->PLLDIV5;
|
||||
|
||||
/* Set PLL clock input to internal osc. */
|
||||
pll->PLLCTL &= ~(DEVICE_PLLCTL_CLKMODE_MASK);
|
||||
|
||||
/* Set PLL to bypass, then wait for PLL to stabilize */
|
||||
pll->PLLCTL &= ~(DEVICE_PLLCTL_PLLENSRC_MASK |
|
||||
DEVICE_PLLCTL_PLLEN_MASK);
|
||||
waitloop(150);
|
||||
|
||||
/* Reset PLL: Warning, bit state is inverted for DM644x vs DM35x. */
|
||||
#if defined(DM644x)
|
||||
pll->PLLCTL &= ~DEVICE_PLLCTL_PLLRST_MASK;
|
||||
#elif defined(DM35x)
|
||||
pll->PLLCTL |= DEVICE_PLLCTL_PLLRST_MASK;
|
||||
#endif
|
||||
|
||||
if (pll_is_powered_up) {
|
||||
/* Disable PLL */
|
||||
pll->PLLCTL |= DEVICE_PLLCTL_PLLDIS_MASK;
|
||||
|
||||
/* Powerup PLL */
|
||||
pll->PLLCTL &= ~(DEVICE_PLLCTL_PLLPWRDN_MASK);
|
||||
}
|
||||
|
||||
/* Enable PLL */
|
||||
pll->PLLCTL &= ~(DEVICE_PLLCTL_PLLDIS_MASK);
|
||||
|
||||
/* Wait for PLL to stabilize */
|
||||
waitloop(150);
|
||||
|
||||
/* Load PLL multiplier. */
|
||||
pll->PLLM = (pll_mult - 1) & 0xff;
|
||||
|
||||
/* Set and enable dividers as needed. */
|
||||
for (k = 0; k < 5; k++) {
|
||||
if (plldiv_ratio[k] > 0)
|
||||
*(plldiv_reg[k]) |= DEVICE_PLLDIV_EN_MASK |
|
||||
(plldiv_ratio[k] - 1);
|
||||
}
|
||||
|
||||
#if defined(DM35x)
|
||||
/* Set the processor AIM wait state and PLL1 post-divider to to 1 */
|
||||
SYSTEM->MISC &= ~(DEVICE_MISC_PLL1POSTDIV_MASK |
|
||||
DEVICE_MISC_AIMWAITST_MASK);
|
||||
#endif
|
||||
|
||||
/* Initiate a new divider transition. */
|
||||
pll->PLLCMD |= DEVICE_PLLCMD_GOSET_MASK;
|
||||
|
||||
/* Wait for completion of phase alignment. */
|
||||
while ((pll->PLLSTAT & DEVICE_PLLSTAT_GOSTAT_MASK))
|
||||
;
|
||||
|
||||
/* Wait for PLL to reset ( ~5 usec ) */
|
||||
waitloop(5000);
|
||||
|
||||
/* Release PLL from reset */
|
||||
|
||||
/* Reset PLL: Warning, bit state is inverted for DM644x vs DM35x. */
|
||||
#if defined(DM644x)
|
||||
pll->PLLCTL |= DEVICE_PLLCTL_PLLRST_MASK;
|
||||
#elif defined(DM35x)
|
||||
pll->PLLCTL &= ~DEVICE_PLLCTL_PLLRST_MASK;
|
||||
#endif
|
||||
|
||||
/* Wait for PLL to re-lock:
|
||||
* DM644z: 2000P
|
||||
* DM35x: 8000P
|
||||
*/
|
||||
waitloop(8000);
|
||||
|
||||
/* Switch out of BYPASS mode */
|
||||
pll->PLLCTL |= DEVICE_PLLCTL_PLLEN_MASK;
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
static int
|
||||
pll1_init(void)
|
||||
{
|
||||
int plldiv_ratio[5];
|
||||
|
||||
#if defined(DM644x)
|
||||
plldiv_ratio[0] = 1; /* PLLDIV1 fixed */
|
||||
plldiv_ratio[1] = 2; /* PLLDIV2 fixed */
|
||||
plldiv_ratio[2] = 3; /* PLLDIV3 fixed */
|
||||
plldiv_ratio[3] = -1; /* PLLDIV4 not used */
|
||||
plldiv_ratio[4] = 6; /* PLLDIV5 fixed */
|
||||
#elif defined(DM35x)
|
||||
plldiv_ratio[0] = 2; /* PLLDIV1 fixed */
|
||||
plldiv_ratio[1] = 4; /* PLLDIV2 fixed */
|
||||
|
||||
/* Calculate PLL divider ratio for divider 3 (feeds VPBE) */
|
||||
plldiv_ratio[2] = 0;
|
||||
while ((plldiv_ratio[2] * VPBE_CLK_HZ) <
|
||||
(SYSTEM_CLK_HZ * (PLL1_Mult >> 3)))
|
||||
plldiv_ratio[2]++;
|
||||
|
||||
/* Check to make sure we can supply accurate VPBE clock */
|
||||
if ((plldiv_ratio[2] * VPBE_CLK_HZ) !=
|
||||
(SYSTEM_CLK_HZ * (PLL1_Mult >> 3)))
|
||||
return E_FAIL;
|
||||
|
||||
/* See the device datasheet for more info (must be 2 or 4) */
|
||||
plldiv_ratio[3] = 4;
|
||||
plldiv_ratio[4] = -1; /* PLLDIV5 not used */
|
||||
#endif
|
||||
|
||||
return pll_init(PLL1, PLL1_Mult, plldiv_ratio);
|
||||
}
|
||||
|
||||
static int
|
||||
pll2_init(void)
|
||||
{
|
||||
int plldiv_ratio[5];
|
||||
|
||||
plldiv_ratio[0] = PLL2_Div1;
|
||||
plldiv_ratio[1] = PLL2_Div2;
|
||||
plldiv_ratio[2] = -1; /* PLLDIV3 not used */
|
||||
plldiv_ratio[3] = -1; /* PLLDIV4 not used */
|
||||
plldiv_ratio[4] = -1; /* PLLDIV5 not used */
|
||||
|
||||
return pll_init(PLL2, PLL2_Mult, plldiv_ratio);
|
||||
}
|
||||
|
||||
static void
|
||||
ddr_timing_setup(void)
|
||||
{
|
||||
/* The configuration of DDRPHYCR is not dependent on the DDR2 device
|
||||
* specification but rather on the board layout.
|
||||
* Setup the read latency and clear DLLPWRDN */
|
||||
DDR->DDRPHYCR = DDRPHYCR_DEFAULT |
|
||||
(DDR_READ_Latency & DDRPHYCR_READLAT_MASK);
|
||||
|
||||
/*
|
||||
* Set the PR_OLD_COUNT bits in the Bus Burst Priority Register (PBBPR)
|
||||
* as suggested in TMS320DM6446 errata 2.1.2:
|
||||
*
|
||||
* On DM6446 Silicon Revision 2.1 and earlier, under certain conditions
|
||||
* low priority modules can occupy the bus and prevent high priority
|
||||
* modules like the VPSS from getting the required DDR2 throughput.
|
||||
*/
|
||||
DDR->PBBPR = DDR_PBBPR_PR_OLD_COUNT;
|
||||
|
||||
/* TIMUNLOCK (unlocked), CAS Latency, number of banks and page size */
|
||||
DDR->SDBCR = SDBCR_DEFAULT |
|
||||
SDBCR_TIMUNLOCK |
|
||||
(DDR_NM << 14) |
|
||||
(DDR_CL << 9) |
|
||||
(DDR_IBANK << 4) |
|
||||
(DDR_PAGESIZE << 0);
|
||||
|
||||
/* Program timing registers */
|
||||
DDR->SDTIMR = (DDR_T_RFC << 25) |
|
||||
(DDR_T_RP << 22) |
|
||||
(DDR_T_RCD << 19) |
|
||||
(DDR_T_WR << 16) |
|
||||
(DDR_T_RAS << 11) |
|
||||
(DDR_T_RC << 6) |
|
||||
(DDR_T_RRD << 3) |
|
||||
(DDR_T_WTR << 0);
|
||||
|
||||
DDR->SDTIMR2 = (DDR_T_XSNR << 16) |
|
||||
(DDR_T_XSRD << 8) |
|
||||
(DDR_T_RTP << 5) |
|
||||
(DDR_T_CKE << 0);
|
||||
#if defined(DM35x)
|
||||
DDR->SDTIMR2 |= (DDR_T_RASMAX << 27) |
|
||||
(DDR_T_XP << 25);
|
||||
#endif
|
||||
|
||||
/* Clear the TIMUNLOCK bit (locked) */
|
||||
DDR->SDBCR &= ~SDBCR_TIMUNLOCK;
|
||||
|
||||
/* Set the refresh rate */
|
||||
DDR->SDRCR = DDR_RR;
|
||||
}
|
||||
|
||||
static void
|
||||
ddr_reset(void)
|
||||
{
|
||||
/* Perform a soft reset to the DDR2 memory controller:
|
||||
* Put in SYNCRESET and enable it again. */
|
||||
lpsc_tansition(LPSC_DDR2, PD0, PSC_SYNCRESET);
|
||||
lpsc_tansition(LPSC_DDR2, PD0, PSC_ENABLE);
|
||||
}
|
||||
|
||||
static int
|
||||
ddr_init(void)
|
||||
{
|
||||
volatile uint32_t *ddr_start = &__DDR_START;
|
||||
/* For reading/writing dummy value in order to apply timing settings */
|
||||
volatile uint32_t ddr_dummy_read;
|
||||
|
||||
/* Enable DDR2 module. */
|
||||
lpsc_tansition(LPSC_DDR2, PD0, PSC_ENABLE);
|
||||
|
||||
#if defined(DM35x)
|
||||
ddr_vtp_calibration();
|
||||
ddr_reset();
|
||||
#endif
|
||||
|
||||
ddr_timing_setup();
|
||||
|
||||
/* Dummy read to apply timing settings */
|
||||
ddr_dummy_read = ddr_start[0];
|
||||
|
||||
#if defined(DM644x)
|
||||
ddr_reset();
|
||||
ddr_vtp_calibration();
|
||||
#endif
|
||||
|
||||
/* Verify correct initialization. */
|
||||
ddr_start[0] = DDR_TEST_PATTERN;
|
||||
if (ddr_start[0] != DDR_TEST_PATTERN) {
|
||||
log_fail("DDR init failed");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
static void
|
||||
psc_init(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
#if defined(DM35x)
|
||||
/* Do always on power domain transitions */
|
||||
while ((PSC->PTSTAT) & 0x00000001);
|
||||
#elif defined(DM644x)
|
||||
/*
|
||||
* Workaround for TMS320DM6446 errata 1.3.22
|
||||
* (Revision(s) Affected: 1.3 and earlier):
|
||||
* PSC: PTSTAT Register Does Not Clear After Warm/Maximum Reset.
|
||||
* Clear the reserved location at address 0x01C41A20
|
||||
*/
|
||||
PSC_PTSTAT_WORKAROUND_REG = 0;
|
||||
|
||||
/* Put the C64x+ Core into reset (if it's on) */
|
||||
PSC->MDCTL[LPSC_DSP] &= (~0x00000100);
|
||||
PSC->PTCMD |= 0x00000002;
|
||||
while ((PSC->PTSTAT) & (0x00000002));
|
||||
while ((PSC->MDSTAT[LPSC_DSP]) & (0x00000100));
|
||||
#endif
|
||||
|
||||
/* Enable selected modules */
|
||||
for (i = 0; i < lpsc_en_list_len; i++) {
|
||||
int8_t k = lpsc_en_list[i];
|
||||
|
||||
PSC->MDCTL[k] = (PSC->MDCTL[k] & 0xFFFFFFE0) | PSC_ENABLE;
|
||||
}
|
||||
|
||||
/* Set EMURSTIE on selected modules */
|
||||
for (i = 0; i < lpsc_emurstie_list_len; i++) {
|
||||
int8_t k = lpsc_emurstie_list[i];
|
||||
|
||||
PSC->MDCTL[k] |= EMURSTIE_MASK;
|
||||
}
|
||||
|
||||
/* Do Always-On Power Domain Transitions */
|
||||
PSC->PTCMD |= 0x00000001;
|
||||
while ((PSC->PTSTAT) & 0x00000001);
|
||||
|
||||
#if defined(DM644x)
|
||||
/* DO DSP Power Domain Transitions */
|
||||
PSC->PTCMD |= 0x00000002;
|
||||
while ((PSC->PTSTAT) & (0x00000002));
|
||||
#endif
|
||||
|
||||
/* Clear EMURSTIE on selected modules */
|
||||
for (i = 0; i < lpsc_emurstie_list_len; i++) {
|
||||
int8_t k = lpsc_emurstie_list[i];
|
||||
|
||||
PSC->MDCTL[k] &= (~EMURSTIE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
davinci_platform_init(char *version)
|
||||
{
|
||||
int status = E_PASS;
|
||||
|
||||
psc_init();
|
||||
|
||||
/* Disable ARM interrupts */
|
||||
AINTC->INTCTL = 0x4;
|
||||
AINTC->EABASE = 0x0;
|
||||
AINTC->EINT0 = 0x0;
|
||||
AINTC->EINT1 = 0x0;
|
||||
|
||||
AINTC->FIQ0 = 0xFFFFFFFF;
|
||||
AINTC->FIQ1 = 0xFFFFFFFF;
|
||||
AINTC->IRQ0 = 0xFFFFFFFF;
|
||||
AINTC->IRQ1 = 0xFFFFFFFF;
|
||||
|
||||
#ifdef PINMUX0_DEFAULT
|
||||
pinmuxControl(0, 0xFFFFFFFF, PINMUX0_DEFAULT);
|
||||
#endif
|
||||
#ifdef PINMUX1_DEFAULT
|
||||
pinmuxControl(1, 0xFFFFFFFF, PINMUX1_DEFAULT);
|
||||
#endif
|
||||
/* The folowing are only available on DM35x */
|
||||
#ifdef PINMUX2_DEFAULT
|
||||
pinmuxControl(2, 0xFFFFFFFF, PINMUX2_DEFAULT);
|
||||
#endif
|
||||
#ifdef PINMUX3_DEFAULT
|
||||
pinmuxControl(3, 0xFFFFFFFF, PINMUX3_DEFAULT);
|
||||
#endif
|
||||
#ifdef PINMUX4_DEFAULT
|
||||
pinmuxControl(4, 0xFFFFFFFF, PINMUX4_DEFAULT);
|
||||
#endif
|
||||
|
||||
if (status == E_PASS)
|
||||
status |= pll1_init();
|
||||
|
||||
if (status == E_PASS)
|
||||
status |= uart0_init();
|
||||
|
||||
if (status == E_PASS)
|
||||
status |= timer0_init();
|
||||
|
||||
uart_send_lf();
|
||||
log_info(version);
|
||||
|
||||
if (status == E_PASS)
|
||||
status |= pll2_init();
|
||||
|
||||
if (status == E_PASS)
|
||||
status |= ddr_init();
|
||||
|
||||
#ifdef STATUS_LED
|
||||
gpio_direction_out(STATUS_LED, 1);
|
||||
#endif /* STATUS_LED */
|
||||
|
||||
#ifdef board_minidas
|
||||
gpio_direction_out(FAN, 0);
|
||||
gpio_direction_out(BUZZER, 0);
|
||||
|
||||
/* Put all peripherals in RESET state */
|
||||
gpio_direction_out(DSP1_PWR_ENA, 0);
|
||||
gpio_direction_out(DSP2_PWR_ENA, 0);
|
||||
gpio_direction_out(WIFI_RESETn, 0);
|
||||
gpio_direction_out(GPS_RESETn, 0);
|
||||
gpio_direction_out(CAN_RESETn, 0);
|
||||
gpio_direction_out(ATA_RESETn, 0);
|
||||
gpio_direction_out(CAMERA_RESETn, 0);
|
||||
|
||||
/* Enable power for hard disk */
|
||||
gpio_direction_out(HDD_ENA, 1);
|
||||
#endif
|
||||
|
||||
/* IRQ Vector Table Setup */
|
||||
ivt_init();
|
||||
|
||||
return status;
|
||||
}
|
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
* davinci.h - common DaVinci platform definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DAVINCI_H_
|
||||
#define _DAVINCI_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(DM644x)
|
||||
#include "dm644x.h"
|
||||
#elif defined(DM35x)
|
||||
#include "dm35x.h"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* System Control Module register structure - See sprue14.pdf, Chapter 10 *
|
||||
* for more details. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct sys_module_regs_t {
|
||||
#if defined(DM644x)
|
||||
uint32_t PINMUX[2]; //0x00
|
||||
uint32_t DSPBOOTADDR; //0x08
|
||||
uint32_t SUSPSRC; //0x0C
|
||||
uint32_t INTGEN; //0x10
|
||||
#elif defined(DM35x)
|
||||
uint32_t PINMUX[5]; //0x00
|
||||
#endif
|
||||
uint32_t BOOTCFG; //0x14
|
||||
uint32_t ARM_INTMUX; //0x18 - ONLY ON DM35x
|
||||
uint32_t EDMA_EVTMUX; //0x1C - ONLY ON DM35x
|
||||
uint32_t DDR_SLEW; //0x20 - ONLY ON DM35x
|
||||
uint32_t CLKOUT; //0x24 - ONLY ON DM35x
|
||||
uint32_t DEVICE_ID; //0x28
|
||||
uint32_t VDAC_CONFIG; //0x2C - ONLY ON DM35x
|
||||
uint32_t TIMER64_CTL; //0x30 - ONLY ON DM35x
|
||||
uint32_t USBPHY_CTL; //0x34
|
||||
#if defined(DM644x)
|
||||
uint32_t CHP_SHRTSW; //0x38
|
||||
#elif defined(DM35x)
|
||||
uint32_t MISC; //0x38
|
||||
#endif
|
||||
uint32_t MSTPRI[2]; //0x3C
|
||||
uint32_t VPSS_CLKCTL; //0x44
|
||||
#if defined(DM644x)
|
||||
uint32_t VDD3P3V_PWDN; //0x48
|
||||
uint32_t DDRVTPER; //0x4C
|
||||
uint32_t RSVD2[8]; //0x50
|
||||
#elif defined(DM35x)
|
||||
uint32_t DEEPSLEEP; //0x48
|
||||
uint32_t RSVD0; //0x4C
|
||||
uint32_t DEBOUNCE[8]; //0x50
|
||||
uint32_t VTPIOCR; //0x70
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SYSTEM ((volatile struct sys_module_regs_t *) 0x01C40000)
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* ARM Interrupt Controller register structure - See sprue26.pdf for more *
|
||||
* details. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct aintc_regs_t {
|
||||
uint32_t FIQ0;
|
||||
uint32_t FIQ1;
|
||||
uint32_t IRQ0;
|
||||
uint32_t IRQ1;
|
||||
uint32_t FIQENTRY;
|
||||
uint32_t IRQENTRY;
|
||||
uint32_t EINT0;
|
||||
uint32_t EINT1;
|
||||
uint32_t INTCTL;
|
||||
uint32_t EABASE;
|
||||
uint32_t RSVD0[2];
|
||||
uint32_t INTPRI0;
|
||||
uint32_t INTPRI1;
|
||||
uint32_t INTPRI2;
|
||||
uint32_t INTPRI3;
|
||||
uint32_t INTPRI4;
|
||||
uint32_t INTPRI5;
|
||||
uint32_t INTPRI6;
|
||||
uint32_t INTPRI7;
|
||||
};
|
||||
|
||||
#define AINTC ((volatile struct aintc_regs_t *) 0x01C48000)
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* PLL Register structure - See sprue14.pdf, Chapter 6 for more details. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct pll_regs_t {
|
||||
uint32_t PID;
|
||||
uint32_t RSVD0[56];
|
||||
uint32_t RSTYPE; /* 0x0E4 */
|
||||
uint32_t RSVD1[6];
|
||||
uint32_t PLLCTL; /* 0x100 */
|
||||
uint32_t RSVD2[3];
|
||||
uint32_t PLLM; /* 0x110 */
|
||||
uint32_t RSVD3;
|
||||
uint32_t PLLDIV1; /* 0x118 */
|
||||
uint32_t PLLDIV2;
|
||||
uint32_t PLLDIV3;
|
||||
uint32_t RSVD4;
|
||||
uint32_t POSTDIV; /* 0x128 */
|
||||
uint32_t BPDIV;
|
||||
uint32_t RSVD5[2];
|
||||
uint32_t PLLCMD; /* 0x138 */
|
||||
uint32_t PLLSTAT;
|
||||
uint32_t ALNCTL;
|
||||
uint32_t DCHANGE;
|
||||
uint32_t CKEN;
|
||||
uint32_t CKSTAT;
|
||||
uint32_t SYSTAT;
|
||||
uint32_t RSVD6[3];
|
||||
uint32_t PLLDIV4; /* 0x160 - Only on DM35x */
|
||||
uint32_t PLLDIV5; /* 0x164 - Only on DM644x */
|
||||
};
|
||||
|
||||
#define PLL1 ((volatile struct pll_regs_t *) 0x01C40800)
|
||||
#define PLL2 ((volatile struct pll_regs_t *) 0x01C40C00)
|
||||
|
||||
#define DEVICE_PLLCTL_CLKMODE_MASK 0x00000100
|
||||
#define DEVICE_PLLCTL_PLLEN_MASK 0x00000001
|
||||
#define DEVICE_PLLCTL_PLLPWRDN_MASK 0x00000002
|
||||
#define DEVICE_PLLCTL_PLLRST_MASK 0x00000008
|
||||
#define DEVICE_PLLCTL_PLLDIS_MASK 0x00000010
|
||||
#define DEVICE_PLLCTL_PLLENSRC_MASK 0x00000020
|
||||
|
||||
#define DEVICE_PLLCMD_GOSET_MASK 0x00000001
|
||||
#define DEVICE_PLLSTAT_GOSTAT_MASK 0x00000001
|
||||
#define DEVICE_PLLDIV_EN_MASK 0x00008000
|
||||
#define DEVICE_PLLSTAT_LOCK_MASK 0x00000002
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* Power/Sleep Ctrl Register structure - See sprue14.pdf, Chapter 7 *
|
||||
* for more details. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct psc_regs_t {
|
||||
uint32_t PID; // 0x000
|
||||
uint32_t RSVD0[3]; // 0x004
|
||||
uint32_t GBLCTL; // 0x010 - NOT ON DM35x
|
||||
uint32_t RSVD1; // 0x014
|
||||
uint32_t INTEVAL; // 0x018
|
||||
uint32_t RSVD2[9]; // 0x01C
|
||||
uint32_t MERRPR0; // 0x040
|
||||
uint32_t MERRPR1; // 0x044
|
||||
uint32_t RSVD3[2]; // 0x048
|
||||
uint32_t MERRCR0; // 0x050
|
||||
uint32_t MERRCR1; // 0x054
|
||||
uint32_t RSVD4[2]; // 0x058
|
||||
uint32_t PERRPR; // 0x060
|
||||
uint32_t RSVD5; // 0x064
|
||||
uint32_t PERRCR; // 0x068
|
||||
uint32_t RSVD6; // 0x06C
|
||||
uint32_t EPCPR; // 0x070
|
||||
uint32_t RSVD7; // 0x074
|
||||
uint32_t EPCCR; // 0x078
|
||||
uint32_t RSVD8[33]; // 0x07C
|
||||
uint32_t RAILSTAT; // 0x100 - NOT ON DM35x
|
||||
uint32_t RAILCTL; // 0x104 - NOT ON DM35x
|
||||
uint32_t RAILSEL; // 0x108 - NOT ON DM35x
|
||||
uint32_t RSVD9[5]; // 0x10C
|
||||
uint32_t PTCMD; // 0x120
|
||||
uint32_t RSVD10; // 0x124
|
||||
uint32_t PTSTAT; // 0x128
|
||||
uint32_t RSVD11[53]; // 0x12C
|
||||
uint32_t PDSTAT0; // 0x200
|
||||
uint32_t PDSTAT1; // 0x204
|
||||
uint32_t RSVD12[62]; // 0x208
|
||||
uint32_t PDCTL0; // 0x300
|
||||
uint32_t PDCTL1; // 0x304
|
||||
uint32_t RSVD13[134]; // 0x308
|
||||
uint32_t MCKOUT0; // 0x520
|
||||
uint32_t MCKOUT1; // 0x524
|
||||
uint32_t RSVD14[182]; // 0x528
|
||||
uint32_t MDSTAT[41]; // 0x800
|
||||
uint32_t RSVD15[87]; // 0x8A4
|
||||
uint32_t MDCTL[41]; // 0xA00
|
||||
};
|
||||
|
||||
#define PSC ((volatile struct psc_regs_t*) 0x01C41000)
|
||||
|
||||
#if defined(DM644x)
|
||||
/* See TMS320DM6446 errata 1.3.22 */
|
||||
#define PSC_PTSTAT_WORKAROUND_REG (*((volatile uint32_t*) 0x01C41A20))
|
||||
#endif
|
||||
|
||||
#define PD0 0
|
||||
|
||||
/* PSC constants */
|
||||
#define LPSC_VPSS_MAST 0
|
||||
#define LPSC_VPSS_SLV 1
|
||||
#define LPSC_EDMACC 2
|
||||
#define LPSC_EDMATC0 3
|
||||
#define LPSC_EDMATC1 4
|
||||
#if defined(DM644x)
|
||||
#define LPSC_EMAC 5
|
||||
#define LPSC_EMAC_MEM_CTL 6
|
||||
#define LPSC_MDIO 7
|
||||
#define LPSC_RESERVED0 8
|
||||
#elif defined(DM35x)
|
||||
#define LPSC_TIMER3 5
|
||||
#define LPSC_SPI1 6
|
||||
#define LPSC_MMC_SD1 7
|
||||
#define LPSC_ASP1 8
|
||||
#endif
|
||||
#define LPSC_USB 9
|
||||
#if defined(DM644x)
|
||||
#define LPSC_ATA 10
|
||||
#define LPSC_VLYNQ 11
|
||||
#define LPSC_HPI 12
|
||||
#elif defined(DM35x)
|
||||
#define LPSC_PWM3 10
|
||||
#define LPSC_SPI2 11
|
||||
#define LPSC_RTO 12
|
||||
#endif
|
||||
#define LPSC_DDR2 13
|
||||
#define LPSC_AEMIF 14
|
||||
#define LPSC_MMC_SD0 15
|
||||
#if defined(DM644x)
|
||||
#define LPSC_RESERVED1 16
|
||||
#elif defined(DM35x)
|
||||
#define LPSC_MEMSTK 16
|
||||
#endif
|
||||
#define LPSC_ASP0 17
|
||||
#define LPSC_I2C 18
|
||||
#define LPSC_UART0 19
|
||||
#if defined(DM35x)
|
||||
#define LPSC_UART1 20
|
||||
#define LPSC_UART2 21
|
||||
#define LPSC_SPIO 22
|
||||
#define LPSC_PWM0 23
|
||||
#define LPSC_PWM1 24
|
||||
#define LPSC_PWM2 25
|
||||
#endif
|
||||
#define LPSC_GPIO 26
|
||||
#define LPSC_TIMER0 27
|
||||
#define LPSC_TIMER1 28
|
||||
#if defined(DM35x)
|
||||
#define LPSC_TIMER2 29
|
||||
#define LPSC_SYSMOD 30
|
||||
#endif
|
||||
#define LPSC_ARM 31
|
||||
#if defined(DM644x)
|
||||
#define LPSC_DSP 39
|
||||
#define LPSC_IMCOP 40
|
||||
#elif defined(DM35x)
|
||||
#define LPSC_VPSS_DAC 40
|
||||
#endif
|
||||
|
||||
#define EMURSTIE_MASK 0x00000200
|
||||
|
||||
#define PSC_ENABLE 0x3
|
||||
#define PSC_DISABLE 0x2
|
||||
#define PSC_SYNCRESET 0x1
|
||||
#define PSC_SWRSTDISABLE 0x0
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* DDR2 Memory Ctrl Register structure - See sprue22b.pdf for more details.*
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct ddr_mem_ctl_regs_t {
|
||||
uint32_t RSVD0;
|
||||
uint32_t SDRSTAT;
|
||||
uint32_t SDBCR;
|
||||
uint32_t SDRCR;
|
||||
uint32_t SDTIMR;
|
||||
uint32_t SDTIMR2;
|
||||
#if defined(DM644x)
|
||||
uint32_t RSVD1[2];
|
||||
#elif defined(DM35x)
|
||||
uint32_t RSVD1;
|
||||
uint32_t SDBCR2;
|
||||
#endif
|
||||
uint32_t PBBPR; /* 0x20 */
|
||||
uint32_t RSVD2[39];
|
||||
uint32_t IRR; /* 0xC0 */
|
||||
uint32_t IMR;
|
||||
uint32_t IMSR;
|
||||
uint32_t IMCR;
|
||||
uint32_t RSVD3[5];
|
||||
uint32_t DDRPHYCR;
|
||||
uint32_t RSVD4[2];
|
||||
#if defined(DM644x)
|
||||
uint32_t VTPIOCR; /* 0xF0 - In system control module for DM35x */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define DDR ((volatile struct ddr_mem_ctl_regs_t *) 0x20000000)
|
||||
|
||||
#define DDR_TEST_PATTERN 0xA55AA55A
|
||||
|
||||
#define SDBCR_TIMUNLOCK (1 << 15)
|
||||
|
||||
#if defined(DM644x)
|
||||
|
||||
#define DDRVTPR (*((volatile uint32_t*) 0x01C42030))
|
||||
|
||||
#define DDRPHYCR_DEFAULT 0x50006400 /* Default value with reserved fields */
|
||||
#define DDRPHYCR_READLAT_MASK (0x7 << 0)
|
||||
#define SDBCR_DEFAULT 0x00130000 /* Default value with reserved fields */
|
||||
|
||||
#elif defined(DM35x)
|
||||
#define DDRPHYCR_DEFAULT 0x28006400 /* Default value with reserved fields */
|
||||
#define DDRPHYCR_READLAT_MASK (0xF << 0)
|
||||
#define SDBCR_DEFAULT 0x00170000 /* Default value with reserved fields */
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* AEMIF Register structure - See sprue20a.pdf for more details. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct emif_regs_t {
|
||||
uint32_t ERCSR; // 0x00
|
||||
uint32_t AWCCR; // 0x04
|
||||
uint32_t SDBCR; // 0x08 - NOT ON DM35x
|
||||
uint32_t SDRCR; // 0x0C - NOT ON DM35x
|
||||
uint32_t A1CR; // 0x10
|
||||
uint32_t A2CR; // 0x14
|
||||
uint32_t A3CR; // 0x18 - NOT ON DM35x
|
||||
uint32_t A4CR; // 0x1C - NOT ON DM35x
|
||||
uint32_t SDTIMR; // 0x20 - NOT ON DM35x
|
||||
uint32_t DDRSR; // 0x24 - NOT ON DM35x
|
||||
uint32_t DDRPHYCR; // 0x28 - NOT ON DM35x
|
||||
uint32_t DDRPHYSR; // 0x2C - NOT ON DM35x
|
||||
uint32_t TOTAR; // 0x30 - NOT ON DM35x
|
||||
uint32_t TOTACTR; // 0x34 - NOT ON DM35x
|
||||
uint32_t DDRPHYID_REV; // 0x38 - NOT ON DM35x
|
||||
uint32_t SDSRETR; // 0x3C - NOT ON DM35x
|
||||
uint32_t EIRR; // 0x40
|
||||
uint32_t EIMR;
|
||||
uint32_t EIMSR;
|
||||
uint32_t EIMCR;
|
||||
uint32_t IOCTRLR; // 0x50 - NOT ON DM35x
|
||||
uint32_t IOSTATR; // 0x54 - NOT ON DM35x
|
||||
uint32_t RSVD0;
|
||||
uint32_t ONENANDCTL; // 0x5C - ONLY ON DM35x
|
||||
uint32_t NANDFCR; // 0x60
|
||||
uint32_t NANDFSR; // 0x64
|
||||
uint32_t RSVD1[2];
|
||||
uint32_t NANDF1ECC; // 0x70
|
||||
uint32_t NANDF2ECC; // 0x74
|
||||
uint32_t NANDF3ECC; // 0x78 - NOT ON DM35x
|
||||
uint32_t NANDF4ECC; // 0x7C - NOT ON DM35x
|
||||
uint32_t RSVD2; // 0x80
|
||||
uint32_t IODFTECR;
|
||||
uint32_t IODFTGCR;
|
||||
uint32_t RSVD3;
|
||||
uint32_t IODFTMRLR; // 0x90
|
||||
uint32_t IODFTMRMR; // 0x94
|
||||
uint32_t IODFTMRMSBR; // 0x98
|
||||
uint32_t RSVD4[5];
|
||||
uint32_t MODRNR; // 0xB0
|
||||
uint32_t RSVD5[2];
|
||||
uint32_t NAND4BITECCLOAD; // 0xBC - ONLY ON DM35x
|
||||
uint32_t NAND4BITECC1; // 0xC0 - ONLY ON DM35x
|
||||
uint32_t NAND4BITECC2; // 0xC4 - ONLY ON DM35x
|
||||
uint32_t NAND4BITECC3; // 0xC8 - ONLY ON DM35x
|
||||
uint32_t NAND4BITECC4; // 0xCC - ONLY ON DM35x
|
||||
uint32_t NANDERRADD1; // 0xD0 - ONLY ON DM35x
|
||||
uint32_t NANDERRADD2; // 0xD4 - ONLY ON DM35x
|
||||
uint32_t NANDERRVAL1; // 0xD8 - ONLY ON DM35x
|
||||
uint32_t NANDERRVAL2; // 0xDC - ONLY ON DM35x
|
||||
};
|
||||
|
||||
#if defined(DM644x)
|
||||
#define AEMIF ((volatile struct emif_regs_t *) 0x01E00000)
|
||||
#elif defined(DM35x)
|
||||
#define AEMIF ((volatile struct emif_regs_t *) 0x01E10000)
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* UART Register structure - See sprue33.pdf for more details. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct uart_regs_t {
|
||||
uint32_t RBR;
|
||||
uint32_t IER;
|
||||
uint32_t IIR;
|
||||
uint32_t LCR;
|
||||
uint32_t MCR;
|
||||
uint32_t LSR;
|
||||
uint32_t MSR; /* NOT ON DM35x */
|
||||
uint32_t SCR; /* NOT ON DM35x */
|
||||
uint32_t DLL;
|
||||
uint32_t DLH;
|
||||
uint32_t PID1;
|
||||
uint32_t PID2;
|
||||
uint32_t PWREMU_MGNT;
|
||||
};
|
||||
|
||||
#define THR RBR
|
||||
#define FCR IIR
|
||||
|
||||
#define UART0 ((volatile struct uart_regs_t *) 0x01C20000)
|
||||
|
||||
#define UART_BCLK_RATIO 16 /* BCLK is 16 times the baudrate */
|
||||
#define UART_BAUDRATE 115200
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* Timer Register structure - See sprue26.pdf for more details. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
struct timer_regs_t {
|
||||
uint32_t PID12;
|
||||
uint32_t EMUMGT_CLKSPD;
|
||||
uint32_t GPINT_GPEN; // NOT ON DM35x
|
||||
uint32_t GPTDAT_GPDIR; // NOT ON DM35x
|
||||
uint32_t TIM12;
|
||||
uint32_t TIM34;
|
||||
uint32_t PRD12;
|
||||
uint32_t PRD34;
|
||||
uint32_t TCR;
|
||||
uint32_t TGCR;
|
||||
uint32_t WDTCR;
|
||||
uint32_t RSVD1[3]; // 0x2C - ONLY ON DM35x
|
||||
uint32_t REL12; // 0x34 - ONLY ON DM35x
|
||||
uint32_t REL34; // 0x38 - ONLY ON DM35x
|
||||
uint32_t CAP12; // 0x3C - ONLY ON DM35x
|
||||
uint32_t CAP34; // 0x40 - ONLY ON DM35x
|
||||
uint32_t INTCTL_STAT; // 0x44 - ONLY ON DM35x
|
||||
};
|
||||
|
||||
#define TIMER0 ((volatile struct timer_regs_t *) 0x01C21400)
|
||||
|
||||
struct gpio_controller {
|
||||
uint32_t dir;
|
||||
uint32_t out_data;
|
||||
uint32_t set_data;
|
||||
uint32_t clr_data;
|
||||
uint32_t in_data;
|
||||
uint32_t set_rising;
|
||||
uint32_t clr_rising;
|
||||
uint32_t set_falling;
|
||||
uint32_t clr_falling;
|
||||
uint32_t intstat;
|
||||
};
|
||||
|
||||
#define DAVINCI_GPIO_BASE 0x01C67000
|
||||
|
||||
#define GPIOC ((volatile struct gpio_controller *) DAVINCI_GPIO_BASE)
|
||||
|
||||
int davinci_platform_init(char *version);
|
||||
void ddr_vtp_calibration(void);
|
||||
|
||||
void timer0_start(void);
|
||||
uint32_t timer0_status(void);
|
||||
|
||||
#endif /* _DAVINCI_H_ */
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* ddr.h - DDR devices parameters
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DDDR_H_
|
||||
#define _DDDR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(MICRON_MT47H32M16BN_3_171MHZ)
|
||||
/* Micron MT47H32M16BN-3 @ 171 MHz settings:
|
||||
* TCK = 5.85 nS -> 1 / 171MHz
|
||||
* T_REF = 7.8 uS (varies with commercial vs industrial)
|
||||
* T_RFC = 105 nS (varies with capacity)
|
||||
* T_RP = 15 nS
|
||||
* T_RCD = 15 nS
|
||||
* T_WR = 15 nS
|
||||
* T_RAS = 40 nS
|
||||
* T_RASMAX = 70 uS
|
||||
* T_RTP = 7.5 nS
|
||||
* T_RC = 55 nS
|
||||
* T_RRD = 10 nS
|
||||
* T_WTR = 7.5 nS
|
||||
* T_XSRD = 200 nS
|
||||
* T_XSNR = 115 nS -> T_RFC(MIN) + 10
|
||||
* T_CKE = 3 TCK
|
||||
* T_XP = 2 TCK
|
||||
*/
|
||||
static const uint8_t DDR_IBANK = 2; /* 4 banks. */
|
||||
static const uint16_t DDR_RR = 1336; /* DDRCLK * T_REF */
|
||||
static const uint8_t DDR_CL = 3;
|
||||
static const uint8_t DDR_T_RFC = 17; /* (T_RFC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RP = 2; /* (T_RP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RCD = 2; /* (T_RCD * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_WR = 2; /* (T_WR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RAS = 6; /* (T_RAS * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RC = 9; /* (T_RC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RRD = 1; /* [((4 * T_RRD) + (2 * TCK)) / (4 * TCK)] - 1 */
|
||||
/*
|
||||
* Only for 8 bank DDR2/mDDR memories. When interfacing to DDR2/mDDR memories
|
||||
* with less than 8 banks the T_RRD field should be calculated using:
|
||||
* (T_RRD * DDRCLK) - 1.
|
||||
*/
|
||||
static const uint8_t DDR_T_WTR = 1; /* (T_WTR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RASMAX = 8; /*
|
||||
* (T_RASMAX(uS) / T_REF) - 1
|
||||
* Should be 17 but max. value
|
||||
* is 15 (4 bits)
|
||||
*/
|
||||
static const uint8_t DDR_T_XP = 2; /*
|
||||
* If T_XP > T_CKE then
|
||||
* T_XP = T_XP - 1
|
||||
* else
|
||||
* T_XP = T_CKE - 1
|
||||
*/
|
||||
static const uint8_t DDR_T_XSNR = 19; /* (T_XSNR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_XSRD = 199; /* T_XSRD - 1 */
|
||||
static const uint8_t DDR_T_RTP = 1; /* (T_RTP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_CKE = 2; /* T_CKE - 1 */
|
||||
static const uint8_t DDR_READ_Latency = 4; /* Board specific */
|
||||
|
||||
#elif defined(MICRON_MT47H32M16BN_3_162MHZ) /* SFFSDR */
|
||||
/* Micron MT47H32M16BN-3 @ 162 MHz settings:
|
||||
* TCK = 6.17 nS -> 1 / 162 MHz
|
||||
* T_REF = 7.8 uS (varies with commercial vs industrial)
|
||||
* T_RFC = 105 nS (varies with capacity)
|
||||
* T_RP = 15 nS
|
||||
* T_RCD = 15 nS
|
||||
* T_WR = 15 nS
|
||||
* T_RAS = 40 nS
|
||||
* T_RASMAX = 70 uS
|
||||
* T_RTP = 7.5 nS
|
||||
* T_RC = 55 nS
|
||||
* T_RRD = 10 nS
|
||||
* T_WTR = 7.5 nS
|
||||
* T_XSRD = 200 nS
|
||||
* T_XSNR = 115 nS -> T_RFC(MIN) + 10
|
||||
* T_CKE = 3 TCK
|
||||
* T_XP = 2 TCK
|
||||
*/
|
||||
static const uint8_t DDR_IBANK = 2; /* 4 banks. */
|
||||
static const uint16_t DDR_RR = 1265; /* DDRCLK * T_REF */
|
||||
static const uint8_t DDR_CL = 3;
|
||||
static const uint8_t DDR_T_RFC = 16; /* (T_RFC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RP = 2; /* (T_RP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RCD = 2; /* (T_RCD * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_WR = 2; /* (T_WR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RAS = 6; /* (T_RAS * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RC = 8; /* (T_RC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RRD = 1; /* [((4 * T_RRD) + (2 * TCK)) / (4 * TCK)] - 1 */
|
||||
/*
|
||||
* Only for 8 bank DDR2/mDDR memories. When interfacing to DDR2/mDDR memories
|
||||
* with less than 8 banks the T_RRD field should be calculated using:
|
||||
* (T_RRD * DDRCLK) - 1.
|
||||
*/
|
||||
static const uint8_t DDR_T_WTR = 1; /* (T_WTR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RASMAX = 8; /*
|
||||
* (T_RASMAX(uS) / T_REF) - 1
|
||||
* Should be 17 but max. value
|
||||
* is 15 (4 bits)
|
||||
*/
|
||||
static const uint8_t DDR_T_XP = 2; /*
|
||||
* If T_XP > T_CKE then
|
||||
* T_XP = T_XP - 1
|
||||
* else
|
||||
* T_XP = T_CKE - 1
|
||||
*/
|
||||
static const uint8_t DDR_T_XSNR = 18; /* (T_XSNR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_XSRD = 199; /* T_XSRD - 1 */
|
||||
static const uint8_t DDR_T_RTP = 1; /* (T_RTP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_CKE = 2; /* T_CKE - 1 */
|
||||
static const uint8_t DDR_READ_Latency = 4; /* Board specific */
|
||||
|
||||
#elif defined(MICRON_MT47H64M16BT_37E_171MHZ) /* EVM DM355 */
|
||||
/* Micron MT47H64M16BT-37E @ 171 MHz */
|
||||
static const uint8_t DDR_IBANK = 3; /* 8 banks. */
|
||||
static const uint16_t DDR_RR = 1336;
|
||||
static const uint8_t DDR_CL = 3;
|
||||
static const uint8_t DDR_T_RFC = 21;
|
||||
static const uint8_t DDR_T_RP = 2;
|
||||
static const uint8_t DDR_T_RCD = 2;
|
||||
static const uint8_t DDR_T_WR = 2;
|
||||
static const uint8_t DDR_T_RAS = 6;
|
||||
static const uint8_t DDR_T_RC = 9;
|
||||
static const uint8_t DDR_T_RRD = 1;
|
||||
static const uint8_t DDR_T_WTR = 1;
|
||||
static const uint8_t DDR_T_RASMAX = 7;
|
||||
static const uint8_t DDR_T_XP = 2;
|
||||
static const uint8_t DDR_T_XSNR = 23;
|
||||
static const uint8_t DDR_T_XSRD = 199;
|
||||
static const uint8_t DDR_T_RTP = 3;
|
||||
static const uint8_t DDR_T_CKE = 3;
|
||||
static const uint8_t DDR_READ_Latency = 4; /* Board specific */
|
||||
|
||||
#elif defined(MICRON_MT47H64M16HR_3_162MHZ) /* DAS Commercial */
|
||||
/* Micron MT47H64M16HR-3 @ 162 MHz settings:
|
||||
* TCK = 6.17 nS -> 1 / 162 MHz
|
||||
* T_REF = 7.8 uS (varies with commercial vs industrial)
|
||||
* T_RFC = 127.5 nS (varies with capacity)
|
||||
* T_RP = 15 nS
|
||||
* T_RCD = 15 nS
|
||||
* T_WR = 15 nS
|
||||
* T_RAS = 40 nS
|
||||
* T_RASMAX = 70 uS
|
||||
* T_RTP = 7.5 nS
|
||||
* T_RC = 55 nS
|
||||
* T_RRD = 10 nS
|
||||
* T_WTR = 7.5 nS
|
||||
* T_XSRD = 200 nS
|
||||
* T_XSNR = 138 nS -> T_RFC(MIN) + 10
|
||||
* T_CKE = 3 TCK
|
||||
* T_XP = 2 TCK
|
||||
*/
|
||||
static const uint8_t DDR_IBANK = 3; /* 8 banks. */
|
||||
static const uint16_t DDR_RR = 1265; /* DDRCLK * T_REF */
|
||||
static const uint8_t DDR_CL = 3;
|
||||
static const uint8_t DDR_T_RFC = 20; /* (T_RFC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RP = 2; /* (T_RP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RCD = 2; /* (T_RCD * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_WR = 2; /* (T_WR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RAS = 6; /* (T_RAS * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RC = 8; /* (T_RC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RRD = 2; /* [((4 * T_RRD) + (2 * TCK)) / (4 * TCK)] - 1 */
|
||||
/*
|
||||
* Only for 8 bank DDR2/mDDR memories. When interfacing to DDR2/mDDR memories
|
||||
* with less than 8 banks the T_RRD field should be calculated using:
|
||||
* (T_RRD * DDRCLK) - 1.
|
||||
*/
|
||||
static const uint8_t DDR_T_WTR = 1; /* (T_WTR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RASMAX = 8; /*
|
||||
* (T_RASMAX(uS) / T_REF) - 1
|
||||
* Should be 17 but max. value
|
||||
* is 15 (4 bits)
|
||||
*/
|
||||
static const uint8_t DDR_T_XP = 2; /*
|
||||
* If T_XP > T_CKE then
|
||||
* T_XP = T_XP - 1
|
||||
* else
|
||||
* T_XP = T_CKE - 1
|
||||
*/
|
||||
static const uint8_t DDR_T_XSNR = 21; /* (T_XSNR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_XSRD = 199; /* T_XSRD - 1 */
|
||||
static const uint8_t DDR_T_RTP = 1; /* (T_RTP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_CKE = 2; /* T_CKE - 1 */
|
||||
static const uint8_t DDR_READ_Latency = 4; /* Board specific */
|
||||
|
||||
#elif defined(MICRON_MT47H64M16HR_3IT_162MHZ) /* DAS industrial */
|
||||
/* Micron MT47H64M16HR-3IT @ 162 MHz settings:
|
||||
* TCK = 6.17 nS -> 1 / 162 MHz
|
||||
* T_REF = 3.9 uS (varies with commercial vs industrial)
|
||||
* T_RFC = 127.5 nS (varies with capacity)
|
||||
* T_RP = 15 nS
|
||||
* T_RCD = 15 nS
|
||||
* T_WR = 15 nS
|
||||
* T_RAS = 40 nS
|
||||
* T_RASMAX = 70 uS
|
||||
* T_RTP = 7.5 nS
|
||||
* T_RC = 55 nS
|
||||
* T_RRD = 10 nS
|
||||
* T_WTR = 7.5 nS
|
||||
* T_XSRD = 200 nS
|
||||
* T_XSNR = 138 nS -> T_RFC(MIN) + 10
|
||||
* T_CKE = 3 TCK
|
||||
* T_XP = 2 TCK
|
||||
*/
|
||||
static const uint8_t DDR_IBANK = 3; /* 8 banks. */
|
||||
static const uint16_t DDR_RR = 635; /* DDRCLK * T_REF */
|
||||
static const uint8_t DDR_CL = 3;
|
||||
static const uint8_t DDR_T_RFC = 20; /* (T_RFC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RP = 2; /* (T_RP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RCD = 2; /* (T_RCD * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_WR = 2; /* (T_WR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RAS = 6; /* (T_RAS * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RC = 8; /* (T_RC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RRD = 2; /* [((4 * T_RRD) + (2 * TCK)) / (4 * TCK)] - 1 */
|
||||
/*
|
||||
* Only for 8 bank DDR2/mDDR memories. When interfacing to DDR2/mDDR memories
|
||||
* with less than 8 banks the T_RRD field should be calculated using:
|
||||
* (T_RRD * DDRCLK) - 1.
|
||||
*/
|
||||
static const uint8_t DDR_T_WTR = 1; /* (T_WTR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RASMAX = 15; /*
|
||||
* (T_RASMAX(uS) / T_REF) - 1
|
||||
* Should be 17 but max. value
|
||||
* is 15 (4 bits)
|
||||
*/
|
||||
static const uint8_t DDR_T_XP = 2; /*
|
||||
* If T_XP > T_CKE then
|
||||
* T_XP = T_XP - 1
|
||||
* else
|
||||
* T_XP = T_CKE - 1
|
||||
*/
|
||||
static const uint8_t DDR_T_XSNR = 21; /* (T_XSNR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_XSRD = 199; /* T_XSRD - 1 */
|
||||
static const uint8_t DDR_T_RTP = 1; /* (T_RTP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_CKE = 2; /* T_CKE - 1 */
|
||||
static const uint8_t DDR_READ_Latency = 4; /* Board specific */
|
||||
|
||||
#elif defined(MICRON_MT47H64M16BT_3_162MHZ)
|
||||
/* Micron MT47H64M16HR-3IT @ 162 MHz settings:
|
||||
* TCK = 5.85 nS -> 1 / 162 MHz
|
||||
* T_REF = 3.9 uS (varies with commercial vs industrial)
|
||||
* T_RFC = 198 nS (varies with capacity)
|
||||
* T_RP = 15 nS
|
||||
* T_RCD = 15 nS
|
||||
* T_WR = 15 nS
|
||||
* T_RAS = 40 nS
|
||||
* T_RASMAX = 70 uS
|
||||
* T_RTP = 7.5 nS
|
||||
* T_RC = 55 nS
|
||||
* T_RRD = 10 nS
|
||||
* T_WTR = 7.5 nS
|
||||
* T_XSRD = 200 nS
|
||||
* T_XSNR = 208 nS -> T_RFC(MIN) + 10
|
||||
* T_CKE = 3 TCK
|
||||
* T_XP = 2 TCK
|
||||
*/
|
||||
static const uint8_t DDR_IBANK = 3; /* 8 banks. */
|
||||
static const uint16_t DDR_RR = 667; /* DDRCLK * T_REF */
|
||||
static const uint8_t DDR_CL = 3;
|
||||
static const uint8_t DDR_T_RFC = 33; /* (T_RFC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RP = 2; /* (T_RP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RCD = 2; /* (T_RCD * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_WR = 2; /* (T_WR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RAS = 6; /* (T_RAS * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RC = 9; /* (T_RC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RRD = 1; /* [((4 * T_RRD) + (2 * TCK)) / (4 * TCK)] - 1 */
|
||||
/*
|
||||
* Only for 8 bank DDR2/mDDR memories. When interfacing to DDR2/mDDR memories
|
||||
* with less than 8 banks the T_RRD field should be calculated using:
|
||||
* (T_RRD * DDRCLK) - 1.
|
||||
*/
|
||||
static const uint8_t DDR_T_WTR = 1; /* (T_WTR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RASMAX = 15; /*
|
||||
* (T_RASMAX(uS) / T_REF) - 1
|
||||
* Should be 17 but max. value
|
||||
* is 15 (4 bits)
|
||||
*/
|
||||
static const uint8_t DDR_T_XP = 2; /*
|
||||
* If T_XP > T_CKE then
|
||||
* T_XP = T_XP - 1
|
||||
* else
|
||||
* T_XP = T_CKE - 1
|
||||
*/
|
||||
static const uint8_t DDR_T_XSNR = 34; /* (T_XSNR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_XSRD = 199; /* T_XSRD - 1 */
|
||||
static const uint8_t DDR_T_RTP = 1; /* (T_RTP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_CKE = 2; /* T_CKE - 1 */
|
||||
static const uint8_t DDR_READ_Latency = 4; /* Board specific */
|
||||
|
||||
#elif defined(MICRON_MT47H128M16HG_3IT_171MHZ)
|
||||
/* Micron MT47H128M16HG-3IT @ 171 MHz settings:
|
||||
* TCK = 5.85 nS -> 1 / 171MHz
|
||||
* T_REF = 3.9 uS (varies with commercial vs industrial)
|
||||
* T_RFC = 198 nS (varies with capacity)
|
||||
* T_RP = 15 nS
|
||||
* T_RCD = 15 nS
|
||||
* T_WR = 15 nS
|
||||
* T_RAS = 40 nS
|
||||
* T_RASMAX = 70 uS
|
||||
* T_RTP = 7.5 nS
|
||||
* T_RC = 55 nS
|
||||
* T_RRD = 10 nS
|
||||
* T_WTR = 7.5 nS
|
||||
* T_XSRD = 200 nS
|
||||
* T_XSNR = 208 nS -> T_RFC(MIN) + 10
|
||||
* T_CKE = 3 TCK
|
||||
* T_XP = 2 TCK
|
||||
*/
|
||||
static const uint8_t DDR_IBANK = 3; /* 8 banks. */
|
||||
static const uint16_t DDR_RR = 667; /* DDRCLK * T_REF */
|
||||
static const uint8_t DDR_CL = 3;
|
||||
static const uint8_t DDR_T_RFC = 33; /* (T_RFC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RP = 2; /* (T_RP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RCD = 2; /* (T_RCD * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_WR = 2; /* (T_WR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RAS = 6; /* (T_RAS * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RC = 9; /* (T_RC * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RRD = 1; /* [((4 * T_RRD) + (2 * TCK)) / (4 * TCK)] - 1 */
|
||||
/*
|
||||
* Only for 8 bank DDR2/mDDR memories. When interfacing to DDR2/mDDR memories
|
||||
* with less than 8 banks the T_RRD field should be calculated using:
|
||||
* (T_RRD * DDRCLK) - 1.
|
||||
*/
|
||||
static const uint8_t DDR_T_WTR = 1; /* (T_WTR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_RASMAX = 15; /*
|
||||
* (T_RASMAX(uS) / T_REF) - 1
|
||||
* Should be 17 but max. value
|
||||
* is 15 (4 bits)
|
||||
*/
|
||||
static const uint8_t DDR_T_XP = 2; /*
|
||||
* If T_XP > T_CKE then
|
||||
* T_XP = T_XP - 1
|
||||
* else
|
||||
* T_XP = T_CKE - 1
|
||||
*/
|
||||
static const uint8_t DDR_T_XSNR = 34; /* (T_XSNR * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_XSRD = 199; /* T_XSRD - 1 */
|
||||
static const uint8_t DDR_T_RTP = 1; /* (T_RTP * DDRCLK) - 1 */
|
||||
static const uint8_t DDR_T_CKE = 2; /* T_CKE - 1 */
|
||||
static const uint8_t DDR_READ_Latency = 4; /* Board specific */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _DDDR_H_ */
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* dm35x.c - DM35x specific platform initialization
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "davinci.h"
|
||||
#include "util.h"
|
||||
|
||||
#define DEVICE_VTPIOCR_PWRDN_MASK (0x00000040)
|
||||
#define DEVICE_VTPIOCR_LOCK_MASK (0x00000080)
|
||||
#define DEVICE_VTPIOCR_PWRSAVE_MASK (0x00000100)
|
||||
#define DEVICE_VTPIOCR_CLR_MASK (0x00002000)
|
||||
#define DEVICE_VTPIOCR_VTPIOREADY_MASK (0x00004000)
|
||||
#define DEVICE_VTPIOCR_READY_MASK (0x00008000)
|
||||
|
||||
/* List of modules to enable in the PSC */
|
||||
const int8_t lpsc_en_list[] = {
|
||||
LPSC_VPSS_MAST,
|
||||
LPSC_VPSS_SLV,
|
||||
LPSC_EDMACC,
|
||||
LPSC_EDMATC0,
|
||||
LPSC_EDMATC1,
|
||||
LPSC_TIMER3,
|
||||
LPSC_SPI1,
|
||||
LPSC_MMC_SD1,
|
||||
LPSC_ASP1,
|
||||
LPSC_USB,
|
||||
LPSC_PWM3,
|
||||
LPSC_SPI2,
|
||||
LPSC_RTO,
|
||||
LPSC_DDR2,
|
||||
LPSC_AEMIF,
|
||||
LPSC_MMC_SD0,
|
||||
LPSC_MEMSTK,
|
||||
LPSC_ASP0,
|
||||
LPSC_I2C,
|
||||
LPSC_UART0,
|
||||
LPSC_UART1,
|
||||
LPSC_UART2,
|
||||
LPSC_SPIO,
|
||||
LPSC_PWM0,
|
||||
LPSC_PWM1,
|
||||
LPSC_PWM2,
|
||||
LPSC_GPIO,
|
||||
LPSC_TIMER0,
|
||||
LPSC_TIMER1,
|
||||
LPSC_TIMER2,
|
||||
LPSC_SYSMOD,
|
||||
LPSC_ARM,
|
||||
LPSC_VPSS_DAC,
|
||||
};
|
||||
|
||||
const size_t lpsc_en_list_len = sizeof(lpsc_en_list) /
|
||||
sizeof(lpsc_en_list[0]);
|
||||
|
||||
/* List of modules for which to control EMURSTIE */
|
||||
const int8_t lpsc_emurstie_list[] = {
|
||||
LPSC_VPSS_MAST,
|
||||
LPSC_VPSS_SLV,
|
||||
LPSC_TIMER3,
|
||||
LPSC_SPI1,
|
||||
LPSC_USB,
|
||||
LPSC_PWM3,
|
||||
LPSC_DDR2,
|
||||
LPSC_AEMIF,
|
||||
LPSC_MMC_SD0,
|
||||
LPSC_ASP0,
|
||||
LPSC_GPIO,
|
||||
LPSC_VPSS_DAC,
|
||||
};
|
||||
|
||||
const size_t lpsc_emurstie_list_len = sizeof(lpsc_emurstie_list) /
|
||||
sizeof(lpsc_emurstie_list[0]);
|
||||
|
||||
/* DDR2 VTP Calibration */
|
||||
void
|
||||
ddr_vtp_calibration(void)
|
||||
{
|
||||
/* DO VTP calibration:
|
||||
* Clear CLR & PWRDN & LOCK bits */
|
||||
SYSTEM->VTPIOCR &= ~(DEVICE_VTPIOCR_PWRDN_MASK |
|
||||
DEVICE_VTPIOCR_LOCK_MASK |
|
||||
DEVICE_VTPIOCR_CLR_MASK);
|
||||
|
||||
/* Un-clear VTP */
|
||||
SYSTEM->VTPIOCR |= DEVICE_VTPIOCR_CLR_MASK;
|
||||
|
||||
/* Wait for ready */
|
||||
while (!(SYSTEM->VTPIOCR & DEVICE_VTPIOCR_READY_MASK));
|
||||
|
||||
/* Set bit VTP_IO_READY */
|
||||
SYSTEM->VTPIOCR |= DEVICE_VTPIOCR_VTPIOREADY_MASK;
|
||||
|
||||
/* Enable power save mode and lock impedance */
|
||||
SYSTEM->VTPIOCR |= (DEVICE_VTPIOCR_PWRSAVE_MASK |
|
||||
DEVICE_VTPIOCR_LOCK_MASK);
|
||||
|
||||
/* Powerdown VTP as it is locked */
|
||||
SYSTEM->VTPIOCR |= DEVICE_VTPIOCR_PWRDN_MASK;
|
||||
|
||||
/* Wait for calibration to complete */
|
||||
waitloop(150);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* dm35x.h - DM35x specific platform definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DM35X_H_
|
||||
#define _DM35X_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SYSTEM_CLK_HZ 24000000
|
||||
|
||||
#define VPBE_CLK_HZ 27000000
|
||||
|
||||
#define PLL1_Mult 144 /* 216 MHz */
|
||||
|
||||
#define PLL2_Mult 114
|
||||
#define PLL2_Div1 2 /* Fixed */
|
||||
#define PLL2_Div2 -1 /* PLLDIV2 not used */
|
||||
|
||||
#define DEVICE_MISC_PLL1POSTDIV_MASK 0x00000002
|
||||
#define DEVICE_MISC_AIMWAITST_MASK 0x00000001
|
||||
#define DEVICE_MISC_TIMER2WDT_MASK 0x00000010
|
||||
|
||||
#define UBL_IMAGE_SIZE 0x7800 /* 30 kB UBL (2Kb reserved for RBL stack) */
|
||||
|
||||
/* Global Memory Timing and PLL Settings */
|
||||
static const uint8_t DDR_NM = 1; /* 16-bit bus width only on DM35x. */
|
||||
static const uint8_t DDR_PAGESIZE = 2; /* 1024-word page size. */
|
||||
|
||||
#define DDR_PBBPR_PR_OLD_COUNT 0x000000FE;
|
||||
|
||||
/* PINMUX2 register bit values */
|
||||
#define PINMUX2_EM_CLK (1 << 11)
|
||||
#define PINMUX2_EM_AVD (1 << 10)
|
||||
#define PINMUX2_EM_WAIT (1 << 9)
|
||||
#define PINMUX2_EM_WE_OE (1 << 8)
|
||||
#define PINMUX2_EM_CE1 (1 << 7)
|
||||
#define PINMUX2_EM_CE0 (1 << 6)
|
||||
#define PINMUX2_EM_D7_0 (1 << 5)
|
||||
#define PINMUX2_EM_D15_8 (1 << 4)
|
||||
#define PINMUX2_EM_BA0 (1 << 2)
|
||||
#define PINMUX2_EM_A0_BA1 (1 << 1)
|
||||
#define PINMUX2_EM_A13_3 (1 << 0)
|
||||
|
||||
#endif /* _DM35X_H_ */
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* dm644x.c - DM644x specific platform initialization
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "davinci.h"
|
||||
#include "util.h"
|
||||
|
||||
#define VTPIOCR_EN_MASK (1 << 13)
|
||||
#define VTPIOCR_RECAL_MASK (1 << 15)
|
||||
|
||||
#define DDRVTPER_EN_MASK (1 << 0)
|
||||
|
||||
#define DDRVTPR_CAL_DATA_MASK 0x03FF
|
||||
|
||||
/* List of modules to enable in the PSC */
|
||||
const int8_t lpsc_en_list[] = {
|
||||
LPSC_VPSS_MAST,
|
||||
LPSC_VPSS_SLV,
|
||||
LPSC_EDMACC,
|
||||
LPSC_EDMATC0,
|
||||
LPSC_EDMATC1,
|
||||
LPSC_EMAC,
|
||||
LPSC_EMAC_MEM_CTL,
|
||||
LPSC_MDIO,
|
||||
LPSC_USB,
|
||||
LPSC_ATA,
|
||||
LPSC_VLYNQ,
|
||||
LPSC_HPI,
|
||||
LPSC_DDR2,
|
||||
LPSC_AEMIF,
|
||||
LPSC_MMC_SD0,
|
||||
LPSC_ASP0,
|
||||
LPSC_I2C,
|
||||
LPSC_UART0,
|
||||
LPSC_GPIO,
|
||||
LPSC_TIMER0,
|
||||
LPSC_ARM,
|
||||
LPSC_IMCOP,
|
||||
};
|
||||
|
||||
const size_t lpsc_en_list_len = sizeof(lpsc_en_list) /
|
||||
sizeof(lpsc_en_list[0]);
|
||||
|
||||
/* List of modules for which to control EMURSTIE */
|
||||
const int8_t lpsc_emurstie_list[] = {
|
||||
LPSC_VPSS_SLV,
|
||||
LPSC_EMAC,
|
||||
LPSC_EMAC_MEM_CTL,
|
||||
LPSC_MDIO,
|
||||
LPSC_USB,
|
||||
LPSC_ATA,
|
||||
LPSC_VLYNQ,
|
||||
LPSC_HPI,
|
||||
LPSC_DDR2,
|
||||
LPSC_AEMIF,
|
||||
LPSC_MMC_SD0,
|
||||
LPSC_ASP0,
|
||||
LPSC_GPIO,
|
||||
LPSC_IMCOP,
|
||||
};
|
||||
|
||||
const size_t lpsc_emurstie_list_len = sizeof(lpsc_emurstie_list) /
|
||||
sizeof(lpsc_emurstie_list[0]);
|
||||
|
||||
/* DDR2 VTP Calibration */
|
||||
void
|
||||
ddr_vtp_calibration(void)
|
||||
{
|
||||
int32_t cal_data;
|
||||
|
||||
/* Enable VTP IO calibration bit (not started) */
|
||||
DDR->VTPIOCR = 0x0000001F | VTPIOCR_EN_MASK;
|
||||
|
||||
/* Start VTP IO calibration */
|
||||
DDR->VTPIOCR |= VTPIOCR_RECAL_MASK;
|
||||
|
||||
/* Wait for calibration to complete */
|
||||
waitloop(11*33);
|
||||
|
||||
/* Enable access to DDRVTPR */
|
||||
SYSTEM->DDRVTPER = DDRVTPER_EN_MASK;
|
||||
|
||||
cal_data = DDRVTPR & DDRVTPR_CAL_DATA_MASK; /* Read calibration data */
|
||||
|
||||
/* Write calibration data to VTP Control register */
|
||||
DDR->VTPIOCR &= ~DDRVTPR_CAL_DATA_MASK;
|
||||
DDR->VTPIOCR |= cal_data;
|
||||
|
||||
/* Disable VTP IO calibration bit */
|
||||
DDR->VTPIOCR &= ~VTPIOCR_EN_MASK;
|
||||
|
||||
/* Disable access to DDRVTPR */
|
||||
SYSTEM->DDRVTPER = 0;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* dm644x.h - DM644x specific platform definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DM644X_H_
|
||||
#define _DM644X_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SYSTEM_CLK_HZ 27000000
|
||||
|
||||
#define PLL1_Mult 22 /* DSP=594 MHz ARM=297 MHz */
|
||||
|
||||
#define PLL2_Mult 24 /* DDRPHY=324 MHz DDRCLK=162 MHz */
|
||||
#define PLL2_Div1 12
|
||||
#define PLL2_Div2 2
|
||||
|
||||
#define UBL_IMAGE_SIZE 0x3800 /* 14 kB UBL (2Kb reserved for RBL stack) */
|
||||
|
||||
/* Global Memory Timing and PLL Settings */
|
||||
static const uint8_t DDR_NM = 0; /* 32-bit bus width by default. */
|
||||
static const uint8_t DDR_PAGESIZE = 2; /* 1024-word page size. */
|
||||
|
||||
/*
|
||||
* See TMS320DM6446 errata 2.1.2:
|
||||
* A value of $20 should provide a good ARM (cache enabled)
|
||||
* performance and still allow good utilization by the VPSS or other
|
||||
* modules.
|
||||
*/
|
||||
#define DDR_PBBPR_PR_OLD_COUNT 0x00000020;
|
||||
|
||||
/* PINMUX0 register bit values */
|
||||
#define PINMUX0_EMACEN (1 << 31)
|
||||
#define PINMUX0_HPIEN (1 << 29)
|
||||
#define PINMUX0_CFLDEN (1 << 27)
|
||||
#define PINMUX0_CWE (1 << 26)
|
||||
#define PINMUX0_LFLDEN (1 << 25)
|
||||
#define PINMUX0_LOEEN (1 << 24)
|
||||
#define PINMUX0_RGB888 (1 << 23)
|
||||
#define PINMUX0_RGB666 (1 << 22)
|
||||
#define PINMUX0_ATAEN (1 << 17)
|
||||
#define PINMUX0_HDIREN (1 << 16)
|
||||
#define PINMUX0_VLYNQEN (1 << 15)
|
||||
#define PINMUX0_VLSCREN (1 << 14)
|
||||
#define PINMUX0_VLYNQWD1 (1 << 13)
|
||||
#define PINMUX0_VLYNQWD0 (1 << 12)
|
||||
|
||||
#define VLYNQ_WIDTH_1 (0 << 12)
|
||||
#define VLYNQ_WIDTH_2 (1 << 12)
|
||||
#define VLYNQ_WIDTH_3 (3 << 12) /* See TI SPRUE26A document. */
|
||||
#define VLYNQ_WIDTH_4 (2 << 12) /* See TI SPRUE26A document. */
|
||||
|
||||
/* PINMUX1 register bit values */
|
||||
#define PINMUX1_TIMIN (1 << 18)
|
||||
#define PINMUX1_CLK1 (1 << 17)
|
||||
#define PINMUX1_CLK0 (1 << 16)
|
||||
#define PINMUX1_ASP (1 << 10)
|
||||
#define PINMUX1_SPI (1 << 8)
|
||||
#define PINMUX1_I2C (1 << 7)
|
||||
#define PINMUX1_PWM2 (1 << 6)
|
||||
#define PINMUX1_PWM1 (1 << 5)
|
||||
#define PINMUX1_PWM0 (1 << 4)
|
||||
#define PINMUX1_U2FLO (1 << 3)
|
||||
#define PINMUX1_UART2 (1 << 2)
|
||||
#define PINMUX1_UART1 (1 << 1)
|
||||
#define PINMUX1_UART0 (1 << 0)
|
||||
|
||||
#endif /* _DM644X_H_ */
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* gpio.c - GPIO handling
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on davinci gpio code from the Linux kernel, original copyright follows:
|
||||
* Copyright (c) 2006-2007 David Brownell
|
||||
* Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
#include "gpio.h"
|
||||
|
||||
static struct gpio_controller *
|
||||
gpio_to_controller(unsigned gpio)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (gpio < 32 * 1)
|
||||
ptr = (void *) DAVINCI_GPIO_BASE + 0x10;
|
||||
else if (gpio < 32 * 2)
|
||||
ptr = (void *) DAVINCI_GPIO_BASE + 0x38;
|
||||
else if (gpio < 32 * 3)
|
||||
ptr = (void *) DAVINCI_GPIO_BASE + 0x60;
|
||||
else if (gpio < 32 * 4)
|
||||
ptr = (void *) DAVINCI_GPIO_BASE + 0x88;
|
||||
else
|
||||
ptr = NULL;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
gpio_mask(unsigned gpio)
|
||||
{
|
||||
return 1 << (gpio % 32);
|
||||
}
|
||||
|
||||
int
|
||||
gpio_direction_in(unsigned gpio)
|
||||
{
|
||||
volatile struct gpio_controller *g = gpio_to_controller(gpio);
|
||||
uint32_t mask = gpio_mask(gpio);
|
||||
|
||||
g->dir |= mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gpio_direction_out(unsigned gpio, int initial_value)
|
||||
{
|
||||
volatile struct gpio_controller *g = gpio_to_controller(gpio);
|
||||
uint32_t mask = gpio_mask(gpio);
|
||||
|
||||
if (initial_value)
|
||||
g->set_data = mask;
|
||||
else
|
||||
g->clr_data = mask;
|
||||
|
||||
g->dir &= ~mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gpio_set(unsigned gpio, int state)
|
||||
{
|
||||
volatile struct gpio_controller *g = gpio_to_controller(gpio);
|
||||
uint32_t mask = gpio_mask(gpio);
|
||||
|
||||
if (state)
|
||||
g->set_data = mask;
|
||||
else
|
||||
g->clr_data = mask;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* gpio.h - Gpio specific platform definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _GPIO_H_
|
||||
#define _GPIO_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define GPIO(X) (X) /* 0 <= X <= (DAVINCI_N_GPIO - 1) */
|
||||
|
||||
int
|
||||
gpio_direction_in(unsigned gpio);
|
||||
|
||||
int
|
||||
gpio_direction_out(unsigned gpio, int initial_value);
|
||||
|
||||
void
|
||||
gpio_set(unsigned gpio, int state);
|
||||
|
||||
#endif /* _GPIO_H_ */
|
|
@ -0,0 +1,868 @@
|
|||
/* gunzip.c - puff implementation
|
||||
*
|
||||
* Copyright (C) 2002-2004 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in puff.h
|
||||
* version 1.8, 9 Jan 2004
|
||||
*
|
||||
* puff.c is a simple inflate written to be an unambiguous way to specify the
|
||||
* deflate format. It is not written for speed but rather simplicity. As a
|
||||
* side benefit, this code might actually be useful when small code is more
|
||||
* important than speed, such as bootstrap applications. For typical deflate
|
||||
* data, zlib's inflate() is about four times as fast as puff(). zlib's
|
||||
* inflate compiles to around 20K on my machine, whereas puff.c compiles to
|
||||
* around 4K on my machine (a PowerPC using GNU cc). If the faster decode()
|
||||
* function here is used, then puff() is only twice as slow as zlib's
|
||||
* inflate().
|
||||
*
|
||||
* All dynamically allocated memory comes from the stack. The stack required
|
||||
* is less than 2K bytes. This code is compatible with 16-bit int's and
|
||||
* assumes that long's are at least 32 bits. puff.c uses the short data type,
|
||||
* assumed to be 16 bits, for arrays in order to to conserve memory. The code
|
||||
* works whether integers are stored big endian or little endian.
|
||||
*
|
||||
* In the comments below are "Format notes" that describe the inflate process
|
||||
* and document some of the less obvious aspects of the format. This source
|
||||
* code is meant to supplement RFC 1951, which formally describes the deflate
|
||||
* format:
|
||||
*
|
||||
* http://www.zlib.org/rfc-deflate.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Change history:
|
||||
*
|
||||
* 1.0 10 Feb 2002 - First version
|
||||
* 1.1 17 Feb 2002 - Clarifications of some comments and notes
|
||||
* - Update puff() dest and source pointers on negative
|
||||
* errors to facilitate debugging deflators
|
||||
* - Remove longest from struct huffman -- not needed
|
||||
* - Simplify offs[] index in construct()
|
||||
* - Add input size and checking, using longjmp() to
|
||||
* maintain easy readability
|
||||
* - Use short data type for large arrays
|
||||
* - Use pointers instead of long to specify source and
|
||||
* destination sizes to avoid arbitrary 4 GB limits
|
||||
* 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!),
|
||||
* but leave simple version for readabilty
|
||||
* - Make sure invalid distances detected if pointers
|
||||
* are 16 bits
|
||||
* - Fix fixed codes table error
|
||||
* - Provide a scanning mode for determining size of
|
||||
* uncompressed data
|
||||
* 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup]
|
||||
* - Add a puff.h file for the interface
|
||||
* - Add braces in puff() for else do [Jean-loup]
|
||||
* - Use indexes instead of pointers for readability
|
||||
* 1.4 31 Mar 2002 - Simplify construct() code set check
|
||||
* - Fix some comments
|
||||
* - Add FIXLCODES #define
|
||||
* 1.5 6 Apr 2002 - Minor comment fixes
|
||||
* 1.6 7 Aug 2002 - Minor format changes
|
||||
* 1.7 3 Mar 2003 - Added test code for distribution
|
||||
* - Added zlib-like license
|
||||
* 1.8 9 Jan 2004 - Added some comments on no distance codes case
|
||||
* 1.9 20 Feb 2009 - Hugo villeneuve: changed puff function name to gunzip
|
||||
*/
|
||||
|
||||
#include "uart.h"
|
||||
|
||||
#define NIL ((unsigned char *)0) /* for no output option */
|
||||
|
||||
/*
|
||||
* Maximums for allocations and loops. It is not useful to change these --
|
||||
* they are fixed by the deflate format.
|
||||
*/
|
||||
#define MAXBITS 15 /* maximum bits in a code */
|
||||
#define MAXLCODES 286 /* maximum number of literal/length codes */
|
||||
#define MAXDCODES 30 /* maximum number of distance codes */
|
||||
#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
|
||||
#define FIXLCODES 288 /* number of fixed literal/length codes */
|
||||
|
||||
/* input and output state */
|
||||
struct state {
|
||||
/* output state */
|
||||
unsigned char *out; /* output buffer */
|
||||
unsigned long outlen; /* available space at out */
|
||||
unsigned long outcnt; /* bytes written to out so far */
|
||||
|
||||
/* input state */
|
||||
unsigned char *in; /* input buffer */
|
||||
unsigned long inlen; /* available input at in */
|
||||
unsigned long incnt; /* bytes read so far */
|
||||
int bitbuf; /* bit buffer */
|
||||
int bitcnt; /* number of bits in bit buffer */
|
||||
};
|
||||
|
||||
static int pufferror;
|
||||
|
||||
/*
|
||||
* Moved those variables from internal stack to DDR.
|
||||
* They were using too much internal stack and corrupted data.
|
||||
*/
|
||||
short distcnt[MAXBITS+1] __attribute__((section(".ddrram"))); /* distcode memory */
|
||||
short distsym[MAXDCODES] __attribute__((section(".ddrram"))); /* distcode memory */
|
||||
short lencnt[MAXBITS+1] __attribute__((section(".ddrram"))); /* lencode memory */
|
||||
short dyn_lengths[MAXCODES] __attribute__((section(".ddrram"))); /* descriptor code lengths */
|
||||
short lensym[FIXLCODES] __attribute__((section(".ddrram")));
|
||||
|
||||
/*
|
||||
* Return need bits from the input stream. This always leaves less than
|
||||
* eight bits in the buffer. bits() works properly for need == 0.
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - Bits are stored in bytes from the least significant bit to the most
|
||||
* significant bit. Therefore bits are dropped from the bottom of the bit
|
||||
* buffer, using shift right, and new bytes are appended to the top of the
|
||||
* bit buffer, using shift left.
|
||||
*/
|
||||
static int
|
||||
bits(struct state *s, int need)
|
||||
{
|
||||
long val; /* bit accumulator (can use up to 20 bits) */
|
||||
|
||||
/* load at least need bits into val */
|
||||
val = s->bitbuf;
|
||||
|
||||
while (s->bitcnt < need) {
|
||||
if (s->incnt == s->inlen) {
|
||||
pufferror = -1;
|
||||
return 0; /* out of input */
|
||||
}
|
||||
|
||||
/* load eight bits */
|
||||
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
|
||||
s->bitcnt += 8;
|
||||
}
|
||||
|
||||
/* drop need bits and update buffer, always zero to seven bits left */
|
||||
s->bitbuf = (int)(val >> need);
|
||||
|
||||
s->bitcnt -= need;
|
||||
|
||||
/* return need bits, zeroing the bits above that */
|
||||
return (int)(val & ((1L << need) - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a stored block.
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - After the two-bit stored block type (00), the stored block length and
|
||||
* stored bytes are byte-aligned for fast copying. Therefore any leftover
|
||||
* bits in the byte that has the last bit of the type, as many as seven, are
|
||||
* discarded. The value of the discarded bits are not defined and should not
|
||||
* be checked against any expectation.
|
||||
*
|
||||
* - The second inverted copy of the stored block length does not have to be
|
||||
* checked, but it's probably a good idea to do so anyway.
|
||||
*
|
||||
* - A stored block can have zero length. This is sometimes used to byte-align
|
||||
* subsets of the compressed data for random access or partial recovery.
|
||||
*/
|
||||
static int
|
||||
stored(struct state *s)
|
||||
{
|
||||
unsigned len; /* length of stored block */
|
||||
|
||||
/* discard leftover bits from current byte (assumes s->bitcnt < 8) */
|
||||
s->bitbuf = 0;
|
||||
s->bitcnt = 0;
|
||||
|
||||
/* get length and check against its one's complement */
|
||||
if (s->incnt + 4 > s->inlen)
|
||||
return 2; /* not enough input */
|
||||
len = s->in[s->incnt++];
|
||||
len |= s->in[s->incnt++] << 8;
|
||||
if (s->in[s->incnt++] != (~len & 0xff) ||
|
||||
s->in[s->incnt++] != ((~len >> 8) & 0xff))
|
||||
return -2; /* didn't match complement! */
|
||||
|
||||
/* copy len bytes from in to out */
|
||||
if (s->incnt + len > s->inlen)
|
||||
return 2; /* not enough input */
|
||||
if (s->out != NIL) {
|
||||
if (s->outcnt + len > s->outlen)
|
||||
return 1; /* not enough output space */
|
||||
while (len--)
|
||||
s->out[s->outcnt++] = s->in[s->incnt++];
|
||||
} else { /* just scanning */
|
||||
s->outcnt += len;
|
||||
s->incnt += len;
|
||||
}
|
||||
|
||||
/* done with a valid stored block */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
|
||||
* each length, which for a canonical code are stepped through in order.
|
||||
* symbol[] are the symbol values in canonical order, where the number of
|
||||
* entries is the sum of the counts in count[]. The decoding process can be
|
||||
* seen in the function decode() below.
|
||||
*/
|
||||
struct huffman {
|
||||
short *count; /* number of symbols of each length */
|
||||
short *symbol; /* canonically ordered symbols */
|
||||
};
|
||||
|
||||
/*
|
||||
* Decode a code from the stream s using huffman table h. Return the symbol or
|
||||
* a negative value if there is an error. If all of the lengths are zero, i.e.
|
||||
* an empty code, or if the code is incomplete and an invalid code is received,
|
||||
* then -9 is returned after reading MAXBITS bits.
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - The codes as stored in the compressed data are bit-reversed relative to
|
||||
* a simple integer ordering of codes of the same lengths. Hence below the
|
||||
* bits are pulled from the compressed data one at a time and used to
|
||||
* build the code value reversed from what is in the stream in order to
|
||||
* permit simple integer comparisons for decoding. A table-based decoding
|
||||
* scheme (as used in zlib) does not need to do this reversal.
|
||||
*
|
||||
* - The first code for the shortest length is all zeros. Subsequent codes of
|
||||
* the same length are simply integer increments of the previous code. When
|
||||
* moving up a length, a zero bit is appended to the code. For a complete
|
||||
* code, the last code of the longest length will be all ones.
|
||||
*
|
||||
* - Incomplete codes are handled by this decoder, since they are permitted
|
||||
* in the deflate format. See the format notes for fixed() and dynamic().
|
||||
*/
|
||||
#ifdef SLOW
|
||||
static int
|
||||
decode(struct state *s, struct huffman *h)
|
||||
{
|
||||
int len; /* current number of bits in code */
|
||||
int code; /* len bits being decoded */
|
||||
int first; /* first code of length len */
|
||||
int count; /* number of codes of length len */
|
||||
int index; /* index of first code of length len in symbol table */
|
||||
|
||||
code = first = index = 0;
|
||||
for (len = 1; len <= MAXBITS; len++) {
|
||||
code |= bits(s, 1); /* get next bit */
|
||||
if (pufferror)
|
||||
return -1;
|
||||
|
||||
count = h->count[len];
|
||||
if (code < first + count) /* if length len, return symbol */
|
||||
return h->symbol[index + (code - first)];
|
||||
index += count; /* else update for next length */
|
||||
first += count;
|
||||
first <<= 1;
|
||||
code <<= 1;
|
||||
}
|
||||
return -9; /* ran out of codes */
|
||||
}
|
||||
|
||||
/*
|
||||
* A faster version of decode() for real applications of this code. It's not
|
||||
* as readable, but it makes puff() twice as fast. And it only makes the code
|
||||
* a few percent larger.
|
||||
*/
|
||||
#else /* !SLOW */
|
||||
static int
|
||||
decode(struct state *s, struct huffman *h)
|
||||
{
|
||||
int len; /* current number of bits in code */
|
||||
int code; /* len bits being decoded */
|
||||
int first; /* first code of length len */
|
||||
int count; /* number of codes of length len */
|
||||
int index; /* index of first code of length len in symbol table */
|
||||
int bitbuf; /* bits from stream */
|
||||
int left; /* bits left in next or left to process */
|
||||
short *next; /* next number of codes */
|
||||
|
||||
bitbuf = s->bitbuf;
|
||||
left = s->bitcnt;
|
||||
code = first = index = 0;
|
||||
len = 1;
|
||||
next = h->count + 1;
|
||||
while (1) {
|
||||
while (left--) {
|
||||
code |= bitbuf & 1;
|
||||
bitbuf >>= 1;
|
||||
count = *next++;
|
||||
if (code < first + count) {
|
||||
/* if length len, return symbol */
|
||||
s->bitbuf = bitbuf;
|
||||
s->bitcnt = (s->bitcnt - len) & 7;
|
||||
return h->symbol[index + (code - first)];
|
||||
}
|
||||
index += count; /* else update for next length */
|
||||
first += count;
|
||||
first <<= 1;
|
||||
code <<= 1;
|
||||
len++;
|
||||
}
|
||||
left = (MAXBITS+1) - len;
|
||||
if (left == 0)
|
||||
break;
|
||||
if (s->incnt == s->inlen) {
|
||||
pufferror = -1; /* out of input */
|
||||
return -1;
|
||||
}
|
||||
|
||||
bitbuf = s->in[s->incnt++];
|
||||
if (left > 8)
|
||||
left = 8;
|
||||
}
|
||||
return -9; /* ran out of codes */
|
||||
}
|
||||
#endif /* SLOW */
|
||||
|
||||
/*
|
||||
* Given the list of code lengths length[0..n-1] representing a canonical
|
||||
* Huffman code for n symbols, construct the tables required to decode those
|
||||
* codes. Those tables are the number of codes of each length, and the symbols
|
||||
* sorted by length, retaining their original order within each length. The
|
||||
* return value is zero for a complete code set, negative for an over-
|
||||
* subscribed code set, and positive for an incomplete code set. The tables
|
||||
* can be used if the return value is zero or positive, but they cannot be used
|
||||
* if the return value is negative. If the return value is zero, it is not
|
||||
* possible for decode() using that table to return an error--any stream of
|
||||
* enough bits will resolve to a symbol. If the return value is positive, then
|
||||
* it is possible for decode() using that table to return an error for received
|
||||
* codes past the end of the incomplete lengths.
|
||||
*
|
||||
* Not used by decode(), but used for error checking, h->count[0] is the number
|
||||
* of the n symbols not in the code. So n - h->count[0] is the number of
|
||||
* codes. This is useful for checking for incomplete codes that have more than
|
||||
* one symbol, which is an error in a dynamic block.
|
||||
*
|
||||
* Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS
|
||||
* This is assured by the construction of the length arrays in dynamic() and
|
||||
* fixed() and is not verified by construct().
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - Permitted and expected examples of incomplete codes are one of the fixed
|
||||
* codes and any code with a single symbol which in deflate is coded as one
|
||||
* bit instead of zero bits. See the format notes for fixed() and dynamic().
|
||||
*
|
||||
* - Within a given code length, the symbols are kept in ascending order for
|
||||
* the code bits definition.
|
||||
*/
|
||||
static int
|
||||
construct(struct huffman *h, short *length, int n)
|
||||
{
|
||||
int symbol; /* current symbol when stepping through length[] */
|
||||
int len; /* current length when stepping through h->count[] */
|
||||
int left; /* number of possible codes left of current length */
|
||||
short offs[MAXBITS+1]; /* offsets in symbol table for each length */
|
||||
|
||||
/* count number of codes of each length */
|
||||
for (len = 0; len <= MAXBITS; len++)
|
||||
h->count[len] = 0;
|
||||
|
||||
/* assumes lengths are within bounds */
|
||||
for (symbol = 0; symbol < n; symbol++)
|
||||
(h->count[length[symbol]])++;
|
||||
if (h->count[0] == n) /* no codes! */
|
||||
return 0; /* complete, but decode() will fail */
|
||||
|
||||
/* check for an over-subscribed or incomplete set of lengths */
|
||||
left = 1; /* one possible code of zero length */
|
||||
for (len = 1; len <= MAXBITS; len++) {
|
||||
left <<= 1; /* one more bit, double codes left */
|
||||
left -= h->count[len]; /* deduct count from possible codes */
|
||||
if (left < 0)
|
||||
return left; /* over-subscribed--return negative */
|
||||
} /* left > 0 means incomplete */
|
||||
|
||||
/* generate offsets into symbol table for each length for sorting */
|
||||
offs[1] = 0;
|
||||
for (len = 1; len < MAXBITS; len++)
|
||||
offs[len + 1] = offs[len] + h->count[len];
|
||||
|
||||
/*
|
||||
* put symbols in table sorted by length, by symbol order within each
|
||||
* length
|
||||
*/
|
||||
for (symbol = 0; symbol < n; symbol++)
|
||||
if (length[symbol] != 0)
|
||||
h->symbol[offs[length[symbol]]++] = symbol;
|
||||
|
||||
/* return zero for complete set, positive for incomplete set */
|
||||
return left;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode literal/length and distance codes until an end-of-block code.
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - Compressed data that is after the block type if fixed or after the code
|
||||
* description if dynamic is a combination of literals and length/distance
|
||||
* pairs terminated by and end-of-block code. Literals are simply Huffman
|
||||
* coded bytes. A length/distance pair is a coded length followed by a
|
||||
* coded distance to represent a string that occurs earlier in the
|
||||
* uncompressed data that occurs again at the current location.
|
||||
*
|
||||
* - Literals, lengths, and the end-of-block code are combined into a single
|
||||
* code of up to 286 symbols. They are 256 literals (0..255), 29 length
|
||||
* symbols (257..285), and the end-of-block symbol (256).
|
||||
*
|
||||
* - There are 256 possible lengths (3..258), and so 29 symbols are not enough
|
||||
* to represent all of those. Lengths 3..10 and 258 are in fact represented
|
||||
* by just a length symbol. Lengths 11..257 are represented as a symbol and
|
||||
* some number of extra bits that are added as an integer to the base length
|
||||
* of the length symbol. The number of extra bits is determined by the base
|
||||
* length symbol. These are in the static arrays below, lens[] for the base
|
||||
* lengths and lext[] for the corresponding number of extra bits.
|
||||
*
|
||||
* - The reason that 258 gets its own symbol is that the longest length is used
|
||||
* often in highly redundant files. Note that 258 can also be coded as the
|
||||
* base value 227 plus the maximum extra value of 31. While a good deflate
|
||||
* should never do this, it is not an error, and should be decoded properly.
|
||||
*
|
||||
* - If a length is decoded, including its extra bits if any, then it is
|
||||
* followed a distance code. There are up to 30 distance symbols. Again
|
||||
* there are many more possible distances (1..32768), so extra bits are added
|
||||
* to a base value represented by the symbol. The distances 1..4 get their
|
||||
* own symbol, but the rest require extra bits. The base distances and
|
||||
* corresponding number of extra bits are below in the static arrays dist[]
|
||||
* and dext[].
|
||||
*
|
||||
* - Literal bytes are simply written to the output. A length/distance pair is
|
||||
* an instruction to copy previously uncompressed bytes to the output. The
|
||||
* copy is from distance bytes back in the output stream, copying for length
|
||||
* bytes.
|
||||
*
|
||||
* - Distances pointing before the beginning of the output data are not
|
||||
* permitted.
|
||||
*
|
||||
* - Overlapped copies, where the length is greater than the distance, are
|
||||
* allowed and common. For example, a distance of one and a length of 258
|
||||
* simply copies the last byte 258 times. A distance of four and a length of
|
||||
* twelve copies the last four bytes three times. A simple forward copy
|
||||
* ignoring whether the length is greater than the distance or not implements
|
||||
* this correctly. You should not use memcpy() since its behavior is not
|
||||
* defined for overlapped arrays. You should not use memmove() or bcopy()
|
||||
* since though their behavior -is- defined for overlapping arrays, it is
|
||||
* defined to do the wrong thing in this case.
|
||||
*/
|
||||
static int
|
||||
codes(struct state *s,
|
||||
struct huffman *lencode,
|
||||
struct huffman *distcode)
|
||||
{
|
||||
int symbol; /* decoded symbol */
|
||||
int len; /* length for copy */
|
||||
unsigned dist; /* distance for copy */
|
||||
/* Size base for length codes 257-285 */
|
||||
static const short lens[29] = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
|
||||
/* Extra bits for length codes 257-285 */
|
||||
static const short lext[29] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
|
||||
/* Offset base for distance codes 0-29 */
|
||||
static const short dists[30] = {
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||
8193, 12289, 16385, 24577};
|
||||
/* Extra bits for distance codes 0-29 */
|
||||
static const short dext[30] = {
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||
12, 12, 13, 13};
|
||||
|
||||
/* decode literals and length/distance pairs */
|
||||
do {
|
||||
symbol = decode(s, lencode);
|
||||
if (symbol < 0)
|
||||
return symbol; /* invalid symbol */
|
||||
if (symbol < 256) { /* literal: symbol is the byte */
|
||||
/* write out the literal */
|
||||
if (s->out != NIL) {
|
||||
if (s->outcnt == s->outlen)
|
||||
return 1;
|
||||
s->out[s->outcnt] = symbol;
|
||||
}
|
||||
s->outcnt++;
|
||||
} else if (symbol > 256) { /* length */
|
||||
/* get and compute length */
|
||||
symbol -= 257;
|
||||
if (symbol >= 29)
|
||||
return -9; /* invalid fixed code */
|
||||
len = lens[symbol] + bits(s, lext[symbol]);
|
||||
if (pufferror)
|
||||
return -1;
|
||||
|
||||
/* get and check distance */
|
||||
symbol = decode(s, distcode);
|
||||
if (symbol < 0)
|
||||
return symbol; /* invalid symbol */
|
||||
dist = dists[symbol] + bits(s, dext[symbol]);
|
||||
if (pufferror)
|
||||
return -1;
|
||||
|
||||
if (dist > s->outcnt)
|
||||
return -10; /* distance too far back */
|
||||
|
||||
/* copy length bytes from distance bytes back */
|
||||
if (s->out != NIL) {
|
||||
if (s->outcnt + len > s->outlen)
|
||||
return 1;
|
||||
while (len--) {
|
||||
s->out[s->outcnt] =
|
||||
s->out[s->outcnt - dist];
|
||||
s->outcnt++;
|
||||
}
|
||||
} else
|
||||
s->outcnt += len;
|
||||
}
|
||||
} while (symbol != 256); /* end of block symbol */
|
||||
|
||||
/* done with a valid fixed or dynamic block */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a fixed codes block.
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - This block type can be useful for compressing small amounts of data for
|
||||
* which the size of the code descriptions in a dynamic block exceeds the
|
||||
* benefit of custom codes for that block. For fixed codes, no bits are
|
||||
* spent on code descriptions. Instead the code lengths for literal/length
|
||||
* codes and distance codes are fixed. The specific lengths for each symbol
|
||||
* can be seen in the "for" loops below.
|
||||
*
|
||||
* - The literal/length code is complete, but has two symbols that are invalid
|
||||
* and should result in an error if received. This cannot be implemented
|
||||
* simply as an incomplete code since those two symbols are in the "middle"
|
||||
* of the code. They are eight bits long and the longest literal/length\
|
||||
* code is nine bits. Therefore the code must be constructed with those
|
||||
* symbols, and the invalid symbols must be detected after decoding.
|
||||
*
|
||||
* - The fixed distance codes also have two invalid symbols that should result
|
||||
* in an error if received. Since all of the distance codes are the same
|
||||
* length, this can be implemented as an incomplete code. Then the invalid
|
||||
* codes are detected while decoding.
|
||||
*/
|
||||
static int
|
||||
fixed(struct state *s)
|
||||
{
|
||||
static int virgin = 1;
|
||||
//////////////static short lencnt[MAXBITS+1];
|
||||
//////static short lensym[FIXLCODES];
|
||||
///////////////////static short distcnt[MAXBITS+1], distsym[MAXDCODES];
|
||||
static struct huffman lencode = {lencnt, lensym};
|
||||
static struct huffman distcode = {distcnt, distsym};
|
||||
|
||||
/* build fixed huffman tables if first call (may not be thread safe) */
|
||||
if (virgin) {
|
||||
int symbol;
|
||||
short lengths[FIXLCODES];
|
||||
|
||||
/* literal/length table */
|
||||
for (symbol = 0; symbol < 144; symbol++)
|
||||
lengths[symbol] = 8;
|
||||
for (; symbol < 256; symbol++)
|
||||
lengths[symbol] = 9;
|
||||
for (; symbol < 280; symbol++)
|
||||
lengths[symbol] = 7;
|
||||
for (; symbol < FIXLCODES; symbol++)
|
||||
lengths[symbol] = 8;
|
||||
construct(&lencode, lengths, FIXLCODES);
|
||||
|
||||
/* distance table */
|
||||
for (symbol = 0; symbol < MAXDCODES; symbol++)
|
||||
lengths[symbol] = 5;
|
||||
construct(&distcode, lengths, MAXDCODES);
|
||||
|
||||
/* do this just once */
|
||||
virgin = 0;
|
||||
}
|
||||
|
||||
/* decode data until end-of-block code */
|
||||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a dynamic codes block.
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - A dynamic block starts with a description of the literal/length and
|
||||
* distance codes for that block. New dynamic blocks allow the compressor to
|
||||
* rapidly adapt to changing data with new codes optimized for that data.
|
||||
*
|
||||
* - The codes used by the deflate format are "canonical", which means that
|
||||
* the actual bits of the codes are generated in an unambiguous way simply
|
||||
* from the number of bits in each code. Therefore the code descriptions
|
||||
* are simply a list of code lengths for each symbol.
|
||||
*
|
||||
* - The code lengths are stored in order for the symbols, so lengths are
|
||||
* provided for each of the literal/length symbols, and for each of the
|
||||
* distance symbols.
|
||||
*
|
||||
* - If a symbol is not used in the block, this is represented by a zero as
|
||||
* as the code length. This does not mean a zero-length code, but rather
|
||||
* that no code should be created for this symbol. There is no way in the
|
||||
* deflate format to represent a zero-length code.
|
||||
*
|
||||
* - The maximum number of bits in a code is 15, so the possible lengths for
|
||||
* any code are 1..15.
|
||||
*
|
||||
* - The fact that a length of zero is not permitted for a code has an
|
||||
* interesting consequence. Normally if only one symbol is used for a given
|
||||
* code, then in fact that code could be represented with zero bits. However
|
||||
* in deflate, that code has to be at least one bit. So for example, if
|
||||
* only a single distance base symbol appears in a block, then it will be
|
||||
* represented by a single code of length one, in particular one 0 bit. This
|
||||
* is an incomplete code, since if a 1 bit is received, it has no meaning,
|
||||
* and should result in an error. So incomplete distance codes of one symbol
|
||||
* should be permitted, and the receipt of invalid codes should be handled.
|
||||
*
|
||||
* - It is also possible to have a single literal/length code, but that code
|
||||
* must be the end-of-block code, since every dynamic block has one. This
|
||||
* is not the most efficient way to create an empty block (an empty fixed
|
||||
* block is fewer bits), but it is allowed by the format. So incomplete
|
||||
* literal/length codes of one symbol should also be permitted.
|
||||
*
|
||||
* - If there are only literal codes and no lengths, then there are no distance
|
||||
* codes. This is represented by one distance code with zero bits.
|
||||
*
|
||||
* - The list of up to 286 length/literal lengths and up to 30 distance lengths
|
||||
* are themselves compressed using Huffman codes and run-length encoding. In
|
||||
* the list of code lengths, a 0 symbol means no code, a 1..15 symbol means
|
||||
* that length, and the symbols 16, 17, and 18 are run-length instructions.
|
||||
* Each of 16, 17, and 18 are follwed by extra bits to define the length of
|
||||
* the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10
|
||||
* zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols
|
||||
* are common, hence the special coding for zero lengths.
|
||||
*
|
||||
* - The symbols for 0..18 are Huffman coded, and so that code must be
|
||||
* described first. This is simply a sequence of up to 19 three-bit values
|
||||
* representing no code (0) or the code length for that symbol (1..7).
|
||||
*
|
||||
* - A dynamic block starts with three fixed-size counts from which is computed
|
||||
* the number of literal/length code lengths, the number of distance code
|
||||
* lengths, and the number of code length code lengths (ok, you come up with
|
||||
* a better name!) in the code descriptions. For the literal/length and
|
||||
* distance codes, lengths after those provided are considered zero, i.e. no
|
||||
* code. The code length code lengths are received in a permuted order (see
|
||||
* the order[] array below) to make a short code length code length list more
|
||||
* likely. As it turns out, very short and very long codes are less likely
|
||||
* to be seen in a dynamic code description, hence what may appear initially
|
||||
* to be a peculiar ordering.
|
||||
*
|
||||
* - Given the number of literal/length code lengths (nlen) and distance code
|
||||
* lengths (ndist), then they are treated as one long list of nlen + ndist
|
||||
* code lengths. Therefore run-length coding can and often does cross the
|
||||
* boundary between the two sets of lengths.
|
||||
*
|
||||
* - So to summarize, the code description at the start of a dynamic block is
|
||||
* three counts for the number of code lengths for the literal/length codes,
|
||||
* the distance codes, and the code length codes. This is followed by the
|
||||
* code length code lengths, three bits each. This is used to construct the
|
||||
* code length code which is used to read the remainder of the lengths. Then
|
||||
* the literal/length code lengths and distance lengths are read as a single
|
||||
* set of lengths using the code length codes. Codes are constructed from
|
||||
* the resulting two sets of lengths, and then finally you can start
|
||||
* decoding actual compressed data in the block.
|
||||
*
|
||||
* - For reference, a "typical" size for the code description in a dynamic
|
||||
* block is around 80 bytes.
|
||||
*/
|
||||
static int
|
||||
dynamic(struct state *s)
|
||||
{
|
||||
int nlen, ndist, ncode; /* number of dyn_lengths in descriptor */
|
||||
int index; /* index of dyn_lengths[] */
|
||||
int err; /* construct() return value */
|
||||
//////////////short lensym[MAXLCODES]; /* lencode memory */
|
||||
struct huffman lencode = {lencnt, lensym}; /* length code */
|
||||
struct huffman distcode = {distcnt, distsym}; /* distance code */
|
||||
static const short order[19] = /* permutation of code length codes */
|
||||
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14,
|
||||
1, 15};
|
||||
|
||||
/* get number of dyn_lengths in each table, check dyn_lengths */
|
||||
nlen = bits(s, 5) + 257;
|
||||
ndist = bits(s, 5) + 1;
|
||||
ncode = bits(s, 4) + 4;
|
||||
if (pufferror)
|
||||
return -1;
|
||||
|
||||
if (nlen > MAXLCODES || ndist > MAXDCODES)
|
||||
return -3; /* bad counts */
|
||||
|
||||
/* read code length code dyn_lengths (really), missing dyn_lengths are zero */
|
||||
for (index = 0; index < ncode; index++) {
|
||||
dyn_lengths[order[index]] = bits(s, 3);
|
||||
if (pufferror)
|
||||
return -1;
|
||||
}
|
||||
for (; index < 19; index++)
|
||||
dyn_lengths[order[index]] = 0;
|
||||
|
||||
/* build huffman table for code dyn_lengths codes (use lencode
|
||||
* temporarily) */
|
||||
err = construct(&lencode, dyn_lengths, 19);
|
||||
if (err != 0)
|
||||
return -4; /* require complete code set here */
|
||||
|
||||
/* read length/literal and distance code length tables */
|
||||
index = 0;
|
||||
while (index < nlen + ndist) {
|
||||
int symbol; /* decoded value */
|
||||
int len; /* last length to repeat */
|
||||
|
||||
symbol = decode(s, &lencode);
|
||||
if (symbol < 16) /* length in 0..15 */
|
||||
dyn_lengths[index++] = symbol;
|
||||
else { /* repeat instruction */
|
||||
len = 0; /* assume repeating zeros */
|
||||
if (symbol == 16) { /* repeat last length 3..6 times */
|
||||
if (index == 0)
|
||||
return -5; /* no last length! */
|
||||
len = dyn_lengths[index - 1]; /* last length */
|
||||
symbol = 3 + bits(s, 2);
|
||||
if (pufferror)
|
||||
return -1;
|
||||
} else if (symbol == 17) { /* repeat zero 3..10 times */
|
||||
symbol = 3 + bits(s, 3);
|
||||
if (pufferror)
|
||||
return -1;
|
||||
} else { /* == 18, repeat zero 11..138 times */
|
||||
symbol = 11 + bits(s, 7);
|
||||
if (pufferror)
|
||||
return -1;
|
||||
}
|
||||
if (index + symbol > nlen + ndist)
|
||||
return -6; /* too many dyn_lengths! */
|
||||
while (symbol--) /* repeat last or zero symbol times */
|
||||
dyn_lengths[index++] = len;
|
||||
}
|
||||
}
|
||||
|
||||
/* build huffman table for literal/length codes */
|
||||
err = construct(&lencode, dyn_lengths, nlen);
|
||||
if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
|
||||
return -7; /* only allow incomplete codes if just one code */
|
||||
|
||||
/* build huffman table for distance codes */
|
||||
err = construct(&distcode, dyn_lengths + nlen, ndist);
|
||||
if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
|
||||
return -8; /* only allow incomplete codes if just one code */
|
||||
|
||||
/* decode data until end-of-block code */
|
||||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inflate source to dest. On return, destlen and sourcelen are updated to the
|
||||
* size of the uncompressed data and the size of the deflate data respectively.
|
||||
* On success, the return value of puff() is zero. If there is an error in the
|
||||
* source data, i.e. it is not in the deflate format, then a negative value is
|
||||
* returned. If there is not enough input available or there is not enough
|
||||
* output space, then a positive error is returned. In that case, destlen and
|
||||
* sourcelen are not updated to facilitate retrying from the beginning with the
|
||||
* provision of more input data or more output space. In the case of invalid
|
||||
* inflate data (a negative error), the dest and source pointers are updated to
|
||||
* facilitate the debugging of deflators.
|
||||
*
|
||||
* puff() also has a mode to determine the size of the uncompressed output with
|
||||
* no output written. For this dest must be (unsigned char *)0. In this case,
|
||||
* the input value of *destlen is ignored, and on return *destlen is set to the
|
||||
* size of the uncompressed output.
|
||||
*
|
||||
* The return codes are:
|
||||
*
|
||||
* 2: available inflate data did not terminate
|
||||
* 1: output space exhausted before completing inflate
|
||||
* 0: successful inflate
|
||||
* -1: invalid block type (type == 3)
|
||||
* -2: stored block length did not match one's complement
|
||||
* -3: dynamic block code description: too many length or distance codes
|
||||
* -4: dynamic block code description: code lengths codes incomplete
|
||||
* -5: dynamic block code description: repeat lengths with no first length
|
||||
* -6: dynamic block code description: repeat more than specified lengths
|
||||
* -7: dynamic block code description: invalid literal/length code lengths
|
||||
* -8: dynamic block code description: invalid distance code lengths
|
||||
* -9: invalid literal/length or distance code in fixed or dynamic block
|
||||
* -10: distance is too far back in fixed or dynamic block
|
||||
*
|
||||
* Format notes:
|
||||
*
|
||||
* - Three bits are read for each block to determine the kind of block and
|
||||
* whether or not it is the last block. Then the block is decoded and the
|
||||
* process repeated if it was not the last block.
|
||||
*
|
||||
* - The leftover bits in the last byte of the deflate data after the last
|
||||
* block (if it was a fixed or dynamic block) are undefined and have no
|
||||
* expected values to check.
|
||||
*/
|
||||
int
|
||||
gunzip(unsigned char *dest, /* destination pointer */
|
||||
unsigned long *destlen, /* amount of output space */
|
||||
unsigned char *source, /* source data pointer */
|
||||
unsigned long *sourcelen) /* amount of input available */
|
||||
{
|
||||
struct state s; /* input/output state */
|
||||
int last, type; /* block information */
|
||||
int err; /* return value */
|
||||
|
||||
pufferror = 0;
|
||||
|
||||
/* initialize output state */
|
||||
s.out = dest;
|
||||
s.outlen = *destlen; /* ignored if dest is NIL */
|
||||
s.outcnt = 0;
|
||||
|
||||
/* initialize input state */
|
||||
s.in = source;
|
||||
s.inlen = *sourcelen;
|
||||
s.incnt = 0;
|
||||
s.bitbuf = 0;
|
||||
s.bitcnt = 0;
|
||||
|
||||
/* process blocks until last block or error */
|
||||
do {
|
||||
last = bits(&s, 1); /* one if last block */
|
||||
if (pufferror)
|
||||
return 2;
|
||||
|
||||
type = bits(&s, 2); /* block type 0..3 */
|
||||
if (pufferror)
|
||||
return 2;
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
err = stored(&s);
|
||||
break;
|
||||
case 1:
|
||||
err = fixed(&s);
|
||||
break;
|
||||
case 2:
|
||||
err = dynamic(&s);
|
||||
break;
|
||||
default:
|
||||
err = -1; /* Invalid */
|
||||
break;
|
||||
}
|
||||
|
||||
if (pufferror)
|
||||
return 2;
|
||||
|
||||
if (err != 0)
|
||||
break; /* return with error */
|
||||
} while (!last);
|
||||
|
||||
/* update the lengths and return */
|
||||
if (err <= 0) {
|
||||
*destlen = s.outcnt;
|
||||
*sourcelen = s.incnt;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/* gunzip.h
|
||||
Copyright (C) 2002, 2003 Mark Adler, all rights reserved
|
||||
version 1.7, 3 Mar 2002
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Mark Adler madler@alumni.caltech.edu
|
||||
*/
|
||||
|
||||
#define GUNZIP_COMP_BLOCK_OFFSET 0x0A /* Offset of compressed block when no
|
||||
* flags are set in the GZIP file. */
|
||||
|
||||
int gunzip(unsigned char *dest, /* destination pointer */
|
||||
unsigned long *destlen, /* amount of output space */
|
||||
unsigned char *source, /* source data pointer */
|
||||
unsigned long *sourcelen); /* amount of input available */
|
|
@ -0,0 +1,975 @@
|
|||
/*
|
||||
* nand.c - NAND flash functions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
#include "util.h"
|
||||
#include "uart.h"
|
||||
#include "nand.h"
|
||||
|
||||
/* BUS width defines */
|
||||
#define BUS_8BIT 0x01
|
||||
#define BUS_16BIT 0x02
|
||||
#define BUS_32BIT 0x04
|
||||
|
||||
/* NAND flash addresses */
|
||||
#define NAND_DATA_OFFSET 0x00
|
||||
#define NAND_ALE_OFFSET 0x08
|
||||
#define NAND_CLE_OFFSET 0x10
|
||||
|
||||
#define NAND_TIMEOUT 20480
|
||||
|
||||
/* NAND flash commands */
|
||||
#define NAND_LO_PAGE 0x00
|
||||
#define NAND_HI_PAGE 0x01
|
||||
#define NAND_LOCK 0x2A
|
||||
#define NAND_UNLOCK_START 0x23
|
||||
#define NAND_UNLOCK_END 0x24
|
||||
#define NAND_READ_30H 0x30
|
||||
#define NAND_EXTRA_PAGE 0x50
|
||||
#define NAND_RDID 0x90
|
||||
#define NAND_RDIDADD 0x00
|
||||
#define NAND_RESET 0xFF
|
||||
#define NAND_PGRM_START 0x80
|
||||
#define NAND_PGRM_END 0x10
|
||||
#define NAND_RDY 0x40
|
||||
#define NAND_PGM_FAIL 0x01
|
||||
#define NAND_BERASEC1 0x60
|
||||
#define NAND_BERASEC2 0xD0
|
||||
#define NAND_STATUS 0x70
|
||||
|
||||
/* Status output */
|
||||
#define NAND_NANDFSR_READY 0x01
|
||||
#define NAND_STATUS_WRITEREADY 0xC0
|
||||
#define NAND_STATUS_ERROR 0x01
|
||||
#define NAND_STATUS_BUSY 0x40
|
||||
|
||||
#define UNKNOWN_NAND 0xFF /* Unknown device id */
|
||||
|
||||
/* Gives the page size in bytes without the spare bytes */
|
||||
#define NANDFLASH_PAGESIZE(x) ((x >> 8) << 8)
|
||||
|
||||
union flash_data {
|
||||
uint8_t c;
|
||||
uint16_t w;
|
||||
uint32_t l;
|
||||
};
|
||||
|
||||
union flash_ptr {
|
||||
volatile uint8_t *cp;
|
||||
volatile uint16_t *wp;
|
||||
volatile uint32_t *lp;
|
||||
};
|
||||
|
||||
struct nand_dev_infos_t {
|
||||
uint8_t id; /* Device ID */
|
||||
uint16_t num_blocks; /* Number of blocks */
|
||||
uint8_t pages_per_block; /* Number of pages per block */
|
||||
uint16_t bytes_per_page; /* Number of bytes per page (with spare) */
|
||||
};
|
||||
|
||||
struct nand_info_t {
|
||||
uint32_t base_addr; /* Base address of NAND CS memory space. */
|
||||
int bus_width; /* Bus width: 0 = 8 bits, 1 = 16 bits */
|
||||
int id; /* Index into nand_dev_infos_t array. */
|
||||
int num_blocks; /* Number of blocks */
|
||||
int pages_per_block; /* Number of pages per block */
|
||||
int bytes_per_page; /* Number of bytes per page (with spare) */
|
||||
int num_cab; /* Number of Column address cycles */
|
||||
int num_rab; /* Number of Row address cycles */
|
||||
uint32_t ecc_mask; /* Mask for ECC register */
|
||||
int large_page; /* True if page size >= 2048 bytes */
|
||||
int ecc_index; /* ECC position is different for small and
|
||||
* large page devices. */
|
||||
int chunk_size; /* Always read/write in 512 bytes chunk max.
|
||||
* This will be set based on page size. */
|
||||
int spare_bytes; /* Number of spare area bytes per page. */
|
||||
int blk_addr_shift; /* Number of bits by which to shift block address */
|
||||
int page_addr_shift; /* Number of bits by which to shift page address */
|
||||
int cs_offset; /*
|
||||
* Chip-select offset:
|
||||
* 0 = CS2 space
|
||||
* 1 = CS3 space
|
||||
* 2 = CS4 space
|
||||
* 3 = CS5 space
|
||||
*/
|
||||
};
|
||||
|
||||
/* Buffer for storing data read from NAND flash */
|
||||
static uint8_t read_buf[MAX_PAGE_SIZE] __attribute__((section(".ddrram")));
|
||||
|
||||
/* Symbol from linker script */
|
||||
extern uint32_t __NANDFlash;
|
||||
|
||||
/* structure for holding details about the NAND device itself */
|
||||
static volatile struct nand_info_t nand_info;
|
||||
|
||||
/* Table of ROM supported NAND devices */
|
||||
static const struct nand_dev_infos_t nand_dev_infos[] = {
|
||||
/* id, num_blocks, pages_per_block, bytes_per_page */
|
||||
{0x6E, 256, 16, 256+8}, /* 1 MB */
|
||||
{0x68, 256, 16, 256+8}, /* 1 MB */
|
||||
{0xEC, 256, 16, 256+8}, /* 1 MB */
|
||||
{0xE8, 256, 16, 256+8}, /* 1 MB */
|
||||
{0xEA, 512, 16, 256+8}, /* 2 MB */
|
||||
{0xE3, 512, 16, 512+16}, /* 4 MB */
|
||||
{0xE5, 512, 16, 512+16}, /* 4 MB */
|
||||
{0xE6, 1024, 16, 512+16}, /* 8 MB */
|
||||
|
||||
{0x39, 1024, 16, 512+16}, /* 8 MB */
|
||||
{0x6B, 1024, 16, 512+16}, /* 8 MB */
|
||||
{0x73, 1024, 32, 512+16}, /* 16 MB */
|
||||
{0x33, 1024, 32, 512+16}, /* 16 MB */
|
||||
{0x75, 2048, 32, 512+16}, /* 32 MB */
|
||||
{0x35, 2048, 32, 512+16}, /* 32 MB */
|
||||
|
||||
{0x43, 1024, 32, 512+16}, /* 16 MB 0x1243 */
|
||||
{0x45, 2048, 32, 512+16}, /* 32 MB 0x1245 */
|
||||
{0x53, 1024, 32, 512+16}, /* 16 MB 0x1253 */
|
||||
{0x55, 2048, 32, 512+16}, /* 32 MB 0x1255 */
|
||||
{0x36, 4096, 32, 512+16}, /* 64 MB */
|
||||
{0x46, 4096, 32, 512+16}, /* 64 MB 0x1346 */
|
||||
{0x56, 4096, 32, 512+16}, /* 64 MB 0x1356 */
|
||||
|
||||
{0x76, 4096, 32, 512+16}, /* 64 MB */
|
||||
|
||||
{0x74, 8192, 32, 512+16}, /* 128 MB 0x1374 */
|
||||
{0x79, 8192, 32, 512+16}, /* 128 MB */
|
||||
{0x71, 16384, 32, 512+16}, /* 256 MB */
|
||||
{0xF1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
|
||||
{0xA1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
|
||||
{0xAA, 2048, 64, 2048+64}, /* 256 MB - Big Block */
|
||||
{0xDA, 2048, 64, 2048+64}, /* 256 MB - Big Block */
|
||||
{0xDC, 4096, 64, 2048+64}, /* 512 MB - Big Block */
|
||||
{0xAC, 4096, 64, 2048+64}, /* 512 MB - Big Block */
|
||||
{0xB1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
|
||||
{0xC1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
|
||||
{0xD3, 4096, 64, 2048+64}, /* 512 MB - Big Block */
|
||||
{0x00, 0, 0, 0} /* Indicate end of table */
|
||||
};
|
||||
|
||||
static volatile uint8_t *
|
||||
flash_make_addr(uint32_t baseAddr, uint32_t offset)
|
||||
{
|
||||
return (volatile uint8_t *) (baseAddr + offset);
|
||||
}
|
||||
|
||||
static void
|
||||
flash_write_data(uint32_t offset, uint32_t data)
|
||||
{
|
||||
volatile union flash_ptr addr;
|
||||
union flash_data dataword;
|
||||
dataword.l = data;
|
||||
|
||||
addr.cp = flash_make_addr(nand_info.base_addr, offset);
|
||||
switch (nand_info.bus_width) {
|
||||
case BUS_8BIT:
|
||||
*addr.cp = dataword.c;
|
||||
break;
|
||||
case BUS_16BIT:
|
||||
*addr.wp = dataword.w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
flash_write_cmd(uint32_t cmd)
|
||||
{
|
||||
flash_write_data(NAND_CLE_OFFSET, cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
flash_write_addr(uint32_t addr)
|
||||
{
|
||||
flash_write_data(NAND_ALE_OFFSET, addr);
|
||||
}
|
||||
|
||||
static void
|
||||
flash_write_bytes(const uint8_t *src, uint32_t numBytes)
|
||||
{
|
||||
volatile union flash_ptr destAddr, srcAddr;
|
||||
uint32_t i;
|
||||
|
||||
srcAddr.cp = (volatile uint8_t *) src;
|
||||
destAddr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET);
|
||||
switch (nand_info.bus_width) {
|
||||
case BUS_8BIT:
|
||||
for (i = 0; i < numBytes; i++)
|
||||
*destAddr.cp = *srcAddr.cp++;
|
||||
break;
|
||||
case BUS_16BIT:
|
||||
for (i = 0; i < (numBytes >> 1); i++)
|
||||
*destAddr.wp = *srcAddr.wp++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
flash_write_addr_bytes(uint32_t numAddrBytes, uint32_t addr)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < numAddrBytes; i++)
|
||||
flash_write_addr((addr >> (8*i)) & 0xff);
|
||||
}
|
||||
|
||||
static void
|
||||
flash_write_row_addr_bytes(uint32_t block, uint32_t page)
|
||||
{
|
||||
uint32_t row_addr;
|
||||
row_addr =
|
||||
(block << (nand_info.blk_addr_shift - nand_info.page_addr_shift)) | page;
|
||||
flash_write_addr_bytes(nand_info.num_rab, row_addr);
|
||||
}
|
||||
|
||||
static void
|
||||
flash_write_addr_cycles(uint32_t block, uint32_t page)
|
||||
{
|
||||
flash_write_addr_bytes(nand_info.num_cab, 0x00000000);
|
||||
flash_write_row_addr_bytes(block, page);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
flash_read_data(void)
|
||||
{
|
||||
volatile union flash_ptr addr;
|
||||
union flash_data cmdword;
|
||||
|
||||
cmdword.l = 0x0;
|
||||
addr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET);
|
||||
switch (nand_info.bus_width) {
|
||||
case BUS_8BIT:
|
||||
cmdword.c = *addr.cp;
|
||||
break;
|
||||
case BUS_16BIT:
|
||||
cmdword.w = *addr.wp;
|
||||
break;
|
||||
}
|
||||
return cmdword.l;
|
||||
}
|
||||
|
||||
static void
|
||||
flash_read_bytes(uint8_t *dest, uint32_t numBytes)
|
||||
{
|
||||
volatile union flash_ptr destAddr, srcAddr;
|
||||
uint32_t i;
|
||||
|
||||
destAddr.cp = (volatile uint8_t *) dest;
|
||||
srcAddr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET);
|
||||
switch (nand_info.bus_width) {
|
||||
case BUS_8BIT:
|
||||
for (i = 0; i < numBytes; i++)
|
||||
*destAddr.cp++ = *srcAddr.cp;
|
||||
break;
|
||||
case BUS_16BIT:
|
||||
for (i = 0; i < (numBytes >> 1); i++)
|
||||
*destAddr.wp++ = *srcAddr.wp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Poll bit of NANDFSR to indicate ready */
|
||||
static int
|
||||
nand_wait_for_ready(uint32_t timeout)
|
||||
{
|
||||
volatile uint32_t cnt = timeout;
|
||||
uint32_t ready;
|
||||
|
||||
waitloop(200);
|
||||
|
||||
do {
|
||||
ready = AEMIF->NANDFSR & NAND_NANDFSR_READY;
|
||||
cnt--;
|
||||
} while ((cnt > 0) && !ready);
|
||||
|
||||
if (cnt == 0) {
|
||||
log_info("NAND busy timeout");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* Wait for the status to be ready in NAND register
|
||||
* There were some problems reported in DM320 with Ready/Busy pin
|
||||
* not working with all NANDs. So this check has also been added.
|
||||
*/
|
||||
static int
|
||||
nand_wait_for_status(uint32_t timeout)
|
||||
{
|
||||
volatile uint32_t cnt;
|
||||
uint32_t status;
|
||||
cnt = timeout;
|
||||
|
||||
do {
|
||||
flash_write_cmd(NAND_STATUS);
|
||||
status = flash_read_data() &
|
||||
(NAND_STATUS_ERROR | NAND_STATUS_BUSY);
|
||||
cnt--;
|
||||
} while ((cnt > 0) && !status);
|
||||
|
||||
if (cnt == 0) {
|
||||
log_info("NAND status timeout");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* Read the current ECC calculation and restart process */
|
||||
static uint32_t
|
||||
nand_read_ecc(void)
|
||||
{
|
||||
uint32_t retval;
|
||||
|
||||
/* Read and mask appropriate (based on CSn space flash is in)
|
||||
* ECC register */
|
||||
retval = ((uint32_t *)(&(AEMIF->NANDF1ECC)))[nand_info.cs_offset] &
|
||||
nand_info.ecc_mask;
|
||||
|
||||
waitloop(5);
|
||||
|
||||
#ifdef NAND_DEBUG
|
||||
uart_send_str("Value read from ECC register: ");
|
||||
uart_send_hexnum(retval, 8);
|
||||
uart_send_lf();
|
||||
#endif
|
||||
|
||||
/* Write appropriate bit to start ECC calculations */
|
||||
AEMIF->NANDFCR |= (1<<(8 + (nand_info.cs_offset)));
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Get details of the NAND flash used from the id and the table of NAND
|
||||
* devices. */
|
||||
static int
|
||||
nand_get_details(void)
|
||||
{
|
||||
uint32_t deviceID, i, j;
|
||||
|
||||
/* Issue device read ID command. */
|
||||
flash_write_cmd(NAND_RDID);
|
||||
flash_write_addr(NAND_RDIDADD);
|
||||
|
||||
/* Read ID bytes */
|
||||
j = flash_read_data() & 0xFF;
|
||||
deviceID = flash_read_data() & 0xFF;
|
||||
j = flash_read_data() & 0xFF;
|
||||
j = flash_read_data() & 0xFF;
|
||||
|
||||
uart_send_str(" ID:");
|
||||
uart_send_hexnum(deviceID, 2);
|
||||
if (nand_info.bus_width == BUS_16BIT)
|
||||
uart_send_str(", 16");
|
||||
else
|
||||
uart_send_str(", 8");
|
||||
|
||||
log_info("-bit bus");
|
||||
|
||||
i = 0;
|
||||
while (nand_dev_infos[i].id != 0x00) {
|
||||
if (deviceID == nand_dev_infos[i].id) {
|
||||
nand_info.id = (uint8_t) nand_dev_infos[i].id;
|
||||
nand_info.pages_per_block =
|
||||
nand_dev_infos[i].pages_per_block;
|
||||
nand_info.num_blocks = nand_dev_infos[i].num_blocks;
|
||||
nand_info.bytes_per_page = NANDFLASH_PAGESIZE(
|
||||
nand_dev_infos[i].bytes_per_page);
|
||||
|
||||
nand_info.spare_bytes = nand_dev_infos[i].bytes_per_page -
|
||||
nand_info.bytes_per_page;
|
||||
|
||||
/* Configure small or large page device. */
|
||||
if (nand_info.bytes_per_page >= 2048) {
|
||||
/* Set the large page flag */
|
||||
nand_info.large_page = true;
|
||||
nand_info.ecc_index = 2;
|
||||
nand_info.chunk_size = 512; /* Limit to 512 bytes */
|
||||
} else {
|
||||
/* Clear the large page flag */
|
||||
nand_info.large_page = false;
|
||||
nand_info.ecc_index = 0;
|
||||
nand_info.chunk_size = nand_info.bytes_per_page;
|
||||
}
|
||||
|
||||
/* Setup address shift values */
|
||||
j = 0;
|
||||
while ((nand_info.pages_per_block >> j) > 1)
|
||||
j++;
|
||||
|
||||
nand_info.blk_addr_shift = j;
|
||||
nand_info.page_addr_shift = (nand_info.large_page) ? 16 : 8;
|
||||
|
||||
nand_info.blk_addr_shift += nand_info.page_addr_shift;
|
||||
|
||||
/* Set number of column address bytes needed */
|
||||
nand_info.num_cab = nand_info.page_addr_shift >> 3;
|
||||
|
||||
j = 0;
|
||||
while ((nand_info.num_blocks >> j) > 1)
|
||||
j++;
|
||||
|
||||
/* Set number of row address bytes needed */
|
||||
if ((nand_info.blk_addr_shift + j) <= 24)
|
||||
nand_info.num_rab = 3 -
|
||||
nand_info.num_cab;
|
||||
else if ((nand_info.blk_addr_shift + j) <= 32)
|
||||
nand_info.num_rab = 4 -
|
||||
nand_info.num_cab;
|
||||
else
|
||||
nand_info.num_rab = 5 -
|
||||
nand_info.num_cab;
|
||||
|
||||
/* Set the ECC bit mask */
|
||||
if (nand_info.bytes_per_page < 512)
|
||||
nand_info.ecc_mask = 0x07FF07FF;
|
||||
else
|
||||
nand_info.ecc_mask = 0x0FFF0FFF;
|
||||
|
||||
/* Report informations */
|
||||
uart_send_str(" Blocks: ");
|
||||
uart_send_hexnum(nand_info.num_blocks, 5);
|
||||
uart_send_str(", Pages/block: ");
|
||||
uart_send_hexnum(nand_info.pages_per_block, 3);
|
||||
uart_send_str(", Bytes per page: ");
|
||||
uart_send_hexnum(nand_info.bytes_per_page, 4);
|
||||
uart_send_lf();
|
||||
|
||||
/* Report additional debug informations */
|
||||
#ifdef NAND_DEBUG
|
||||
uart_send_str(" Page shift: ");
|
||||
uart_send_hexnum(nand_info.page_addr_shift, 2);
|
||||
uart_send_lf();
|
||||
uart_send_str(" Block shift: ");
|
||||
uart_send_hexnum(nand_info.blk_addr_shift, 2);
|
||||
uart_send_lf();
|
||||
uart_send_str(" Column address bytes: ");
|
||||
uart_send_hexnum(nand_info.num_cab, 2);
|
||||
uart_send_lf();
|
||||
uart_send_str(" Row address bytes: ");
|
||||
uart_send_hexnum(nand_info.num_rab, 2);
|
||||
uart_send_lf();
|
||||
uart_send_str(" ECC mask: ");
|
||||
uart_send_hexnum(nand_info.ecc_mask, 8);
|
||||
uart_send_lf();
|
||||
#endif
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
/* No match was found for the device ID */
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
static void
|
||||
nand_write_spare(uint32_t eccvalue)
|
||||
{
|
||||
uint32_t spare_data[4] = {
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF
|
||||
};
|
||||
|
||||
/* Place the ECC values where the RBL expects them */
|
||||
spare_data[nand_info.ecc_index] = eccvalue;
|
||||
|
||||
/* Write spare bytes infos */
|
||||
if (nand_info.bytes_per_page == 256)
|
||||
flash_write_bytes((uint8_t *) spare_data, 8);
|
||||
else
|
||||
flash_write_bytes((uint8_t *) spare_data, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* RBL-expected layout for large page NAND (ex: 2048 bytes/page):
|
||||
*
|
||||
* DM35x DM644x
|
||||
* -----------------------------
|
||||
* 512 DATA 2048 DATA
|
||||
* 16 SPARE 64 SPARE
|
||||
* 512 DATA
|
||||
* 16 SPARE
|
||||
* 512 DATA
|
||||
* 16 SPARE
|
||||
* 512 DATA
|
||||
* 16 SPARE
|
||||
*
|
||||
* So for big block NAND devices (bytes per page > 512) on the DM35x, we must
|
||||
* write 512 bytes and write the ECC immediately after that data, and repeat
|
||||
* until all the page is written.
|
||||
*/
|
||||
|
||||
/* Generic routine to write a page of data to NAND */
|
||||
static int
|
||||
nand_write_page(uint32_t block, uint32_t page, const uint8_t *src)
|
||||
{
|
||||
uint32_t hw_ecc[4]; /* Maximum of 2048 bytes/page (4 * 512 = 2048) */
|
||||
uint8_t numWrites, i;
|
||||
|
||||
numWrites = (nand_info.bytes_per_page >> 9); /* Divide by 512 */
|
||||
if (numWrites == 0)
|
||||
numWrites++;
|
||||
|
||||
/* Write program command */
|
||||
flash_write_cmd(NAND_PGRM_START);
|
||||
|
||||
/* Write address bytes */
|
||||
flash_write_addr_cycles(block, page);
|
||||
|
||||
/* Starting the ECC in the NANDFCR register for CS2 (bit no.8) */
|
||||
nand_read_ecc();
|
||||
|
||||
/* Write data */
|
||||
for (i = 0; i < numWrites; i++) {
|
||||
/* Write data to page */
|
||||
flash_write_bytes(src, nand_info.chunk_size);
|
||||
|
||||
/* Read the ECC value */
|
||||
hw_ecc[i] = nand_read_ecc();
|
||||
|
||||
/* Format ECC */
|
||||
endian_data(&(hw_ecc[i]));
|
||||
|
||||
#if defined(DM35x)
|
||||
/* Write spare area */
|
||||
nand_write_spare(hw_ecc[i]);
|
||||
#endif
|
||||
|
||||
/* Increment the pointer */
|
||||
src += nand_info.chunk_size;
|
||||
}
|
||||
|
||||
#if defined(DM644x)
|
||||
for (i = 0; i < numWrites; i++) {
|
||||
nand_write_spare(hw_ecc[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write program end command */
|
||||
flash_write_cmd(NAND_PGRM_END);
|
||||
|
||||
/* Wait for the device to be ready */
|
||||
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
/* Return status check result */
|
||||
return nand_wait_for_status(NAND_TIMEOUT);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
nand_read_spare(void)
|
||||
{
|
||||
uint32_t spare_ecc[4], spare_ecc_temp;
|
||||
|
||||
/* Read the stored ECC value(s) */
|
||||
if (nand_info.bytes_per_page == 256)
|
||||
flash_read_bytes((uint8_t *) spare_ecc, 8);
|
||||
else
|
||||
flash_read_bytes((uint8_t *) spare_ecc, 16);
|
||||
|
||||
spare_ecc_temp = spare_ecc[nand_info.ecc_index];
|
||||
|
||||
/* Format ECC */
|
||||
endian_data(&spare_ecc_temp);
|
||||
|
||||
return spare_ecc_temp;
|
||||
}
|
||||
|
||||
/* Read a page from NAND */
|
||||
int
|
||||
nand_read_page(uint32_t block, uint32_t page, uint8_t *dest)
|
||||
{
|
||||
uint32_t hw_ecc[4];
|
||||
uint32_t spare_ecc[4];
|
||||
uint8_t numReads, i;
|
||||
|
||||
numReads = (nand_info.bytes_per_page >> 9); /* Divide by 512 */
|
||||
if (numReads == 0)
|
||||
numReads++;
|
||||
|
||||
/* Write read command */
|
||||
flash_write_cmd(NAND_LO_PAGE);
|
||||
|
||||
/* Write address bytes */
|
||||
flash_write_addr_cycles(block, page);
|
||||
|
||||
/* Additional confirm command for big_block devices */
|
||||
if (nand_info.large_page)
|
||||
flash_write_cmd(NAND_READ_30H);
|
||||
|
||||
/* Wait for data to be available */
|
||||
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
/* Starting the ECC in the NANDFCR register for CS2(bit no.8) */
|
||||
nand_read_ecc();
|
||||
|
||||
/* Read the page data */
|
||||
for (i = 0; i < numReads; i++) {
|
||||
/* Read data bytes */
|
||||
flash_read_bytes(dest, nand_info.chunk_size);
|
||||
|
||||
/* Read hardware computed ECC */
|
||||
hw_ecc[i] = nand_read_ecc();
|
||||
|
||||
#if defined(DM35x)
|
||||
/* Read spare area ECC */
|
||||
spare_ecc[i] = nand_read_spare();
|
||||
#endif
|
||||
|
||||
/* Increment the pointer */
|
||||
dest += nand_info.chunk_size;
|
||||
}
|
||||
|
||||
#if defined(DM644x)
|
||||
for (i = 0; i < numReads; i++) {
|
||||
spare_ecc[i] = nand_read_spare();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NAND_BYPASS_READ_PAGE_ECC_CHECK
|
||||
for (i = 0; i < numReads; i++) {
|
||||
/* Verify ECC values */
|
||||
if (hw_ecc[i] != spare_ecc[i]) {
|
||||
log_info("NAND ECC failure:");
|
||||
uart_send_str("HW = ");
|
||||
uart_send_hexnum(hw_ecc[i], 8);
|
||||
uart_send_lf();
|
||||
uart_send_str("SPARE =");
|
||||
uart_send_hexnum(spare_ecc[i], 8);
|
||||
uart_send_lf();
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
#endif /* NAND_BYPASS_READ_PAGE_ECC_CHECK */
|
||||
|
||||
/* Return status check result */
|
||||
return nand_wait_for_status(NAND_TIMEOUT);
|
||||
}
|
||||
|
||||
/* Verify data written by reading and comparing byte for byte */
|
||||
static int
|
||||
nand_verify_page(int block, int page, const uint8_t *src)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (nand_read_page(block, page, read_buf) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
for (i = 0; i < nand_info.bytes_per_page; i++) {
|
||||
/* Check for data read errors */
|
||||
if (src[i] != read_buf[i]) {
|
||||
int k = i;
|
||||
|
||||
uart_send_str("NAND verify page failed at block ");
|
||||
uart_send_hexnum(block, 4);
|
||||
uart_send_str(", page ");
|
||||
uart_send_hexnum(page, 4);
|
||||
uart_send_str(", offset ");
|
||||
uart_send_hexnum(i, 4);
|
||||
uart_send_lf();
|
||||
|
||||
for (k = i - 8; k < (i + 20); k += 4) {
|
||||
uart_send_str("offset ");
|
||||
uart_send_hexnum(k, 4);
|
||||
uart_send_str(", ram=");
|
||||
uart_send_hexnum(*((uint32_t *) &src[k]), 8);
|
||||
uart_send_str(", nand=");
|
||||
uart_send_hexnum(*((uint32_t *) &read_buf[k]), 8);
|
||||
uart_send_lf();
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* NAND Flash unprotect command */
|
||||
static uint32_t
|
||||
nand_unprotect_blocks(uint32_t startBlkNum, uint32_t blkCnt)
|
||||
{
|
||||
uint32_t endBlkNum;
|
||||
endBlkNum = startBlkNum + blkCnt - 1;
|
||||
|
||||
uart_send_str("Unprotecting blocks ");
|
||||
uart_send_hexnum(startBlkNum, 4);
|
||||
uart_send_str(" to ");
|
||||
uart_send_hexnum(endBlkNum, 4);
|
||||
uart_send_lf();
|
||||
|
||||
/* Do bounds checking */
|
||||
if (endBlkNum >= nand_info.num_blocks) {
|
||||
log_fail("Invalid last block");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
flash_write_cmd(NAND_UNLOCK_START);
|
||||
flash_write_row_addr_bytes(startBlkNum, 0);
|
||||
|
||||
flash_write_cmd(NAND_UNLOCK_END);
|
||||
flash_write_row_addr_bytes(endBlkNum, 0);
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* NAND Flash protect command */
|
||||
static void
|
||||
nand_protect_blocks(void)
|
||||
{
|
||||
log_info("Protecting the entire NAND flash");
|
||||
flash_write_cmd(NAND_LOCK);
|
||||
}
|
||||
|
||||
/* NAND Flash erase block function */
|
||||
static uint32_t
|
||||
nand_erase_blocks(uint32_t startBlkNum, uint32_t blkCnt)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* Do bounds checking */
|
||||
if ((startBlkNum + blkCnt - 1) >= nand_info.num_blocks)
|
||||
return E_FAIL;
|
||||
|
||||
/* Output info about what we are doing */
|
||||
uart_send_str("Erasing blocks ");
|
||||
uart_send_hexnum(startBlkNum, 4);
|
||||
uart_send_str(" to ");
|
||||
uart_send_hexnum(startBlkNum + blkCnt - 1, 4);
|
||||
uart_send_lf();
|
||||
|
||||
for (i = 0; i < blkCnt; i++) {
|
||||
/* Start erase command */
|
||||
flash_write_cmd(NAND_BERASEC1);
|
||||
|
||||
/* Write the row addr bytes only */
|
||||
flash_write_row_addr_bytes(startBlkNum + i, 0);
|
||||
|
||||
/* Confirm erase command */
|
||||
flash_write_cmd(NAND_BERASEC2);
|
||||
|
||||
/* Wait for the device to be ready */
|
||||
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
/* Verify the op succeeded by reading status from flash */
|
||||
if (nand_wait_for_status(NAND_TIMEOUT) != E_PASS)
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* Initialize NAND interface and find the details of the NAND used */
|
||||
int
|
||||
nand_init(void)
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t *CSRegs;
|
||||
|
||||
log_info("Initializing NAND flash:");
|
||||
|
||||
#ifdef NAND_BYPASS_READ_PAGE_ECC_CHECK
|
||||
log_info(" Bypassing ECC checks");
|
||||
#endif /* NAND_BYPASS_READ_PAGE_ECC_CHECK */
|
||||
|
||||
/* Set NAND flash base address */
|
||||
nand_info.base_addr = (uint32_t) &__NANDFlash;
|
||||
|
||||
/* Get the cs_offset (can be 0 through 3 - corresponds with CS2 through
|
||||
* CS5) */
|
||||
nand_info.cs_offset = (nand_info.base_addr >> 25) - 1;
|
||||
|
||||
/* Setting the nand_width = 0(8 bit NAND) or 1(16 bit NAND). AEMIF CS2
|
||||
* bus Width is given by the BOOTCFG(bit no.5). */
|
||||
width = (((SYSTEM->BOOTCFG) & 0x20) >> 5);
|
||||
nand_info.bus_width = (width)?BUS_16BIT:BUS_8BIT;
|
||||
|
||||
/* Setup AEMIF registers for NAND */
|
||||
CSRegs = (uint32_t *) &(AEMIF->A1CR);
|
||||
|
||||
/* Set correct AxCR reg */
|
||||
CSRegs[nand_info.cs_offset] = 0x3FFFFFFC | width;
|
||||
|
||||
/* NAND enable for CSx. */
|
||||
AEMIF->NANDFCR |= (0x1 << (nand_info.cs_offset));
|
||||
nand_read_ecc();
|
||||
|
||||
/* Send reset command to NAND */
|
||||
flash_write_cmd(NAND_RESET);
|
||||
|
||||
if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
return nand_get_details();
|
||||
}
|
||||
|
||||
static int
|
||||
nand_write_verify_page(int block, int page, const uint8_t *src)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = nand_write_page(block, page, src);
|
||||
if (status != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
waitloop(200);
|
||||
|
||||
/* Verify the page just written */
|
||||
return nand_verify_page(block, page, src);
|
||||
}
|
||||
|
||||
int
|
||||
nand_write_prog(struct nand_image_descriptor_t *im_desc, const uint8_t *src,
|
||||
size_t size)
|
||||
{
|
||||
int num_blocks;
|
||||
int max_block_num;
|
||||
int page_num;
|
||||
uint32_t count_mask;
|
||||
|
||||
im_desc->page_num = 1; /* Always start data in page 1 */
|
||||
|
||||
/* Do some rounding based on data buffer size */
|
||||
im_desc->size_in_pages = 0;
|
||||
while ((im_desc->size_in_pages * nand_info.bytes_per_page) < size)
|
||||
im_desc->size_in_pages++;
|
||||
|
||||
/* Get total number of blocks needed */
|
||||
num_blocks = 0;
|
||||
while ((num_blocks * nand_info.pages_per_block) <
|
||||
(im_desc->size_in_pages + 1))
|
||||
num_blocks++;
|
||||
|
||||
uart_send_str("Needed blocks: ");
|
||||
uart_send_hexnum(num_blocks, 4);
|
||||
uart_send_lf();
|
||||
uart_send_str("Needed pages: ");
|
||||
uart_send_hexnum(im_desc->size_in_pages, 4);
|
||||
uart_send_lf();
|
||||
|
||||
/* Check whether writing UBL or APP (based on destination block) */
|
||||
if (im_desc->block_num == START_UBL_BLOCK_NUM)
|
||||
max_block_num = END_UBL_BLOCK_NUM;
|
||||
else
|
||||
max_block_num = nand_info.num_blocks - 1;
|
||||
|
||||
NAND_WRITE_RETRY:
|
||||
if (im_desc->block_num > max_block_num) {
|
||||
log_fail("Block > last block");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
uart_send_str("Trying block ");
|
||||
uart_send_hexnum(im_desc->block_num, 4);
|
||||
uart_send_lf();
|
||||
|
||||
/* Unprotect all needed blocks of the Flash */
|
||||
if (nand_unprotect_blocks(im_desc->block_num, num_blocks) != E_PASS) {
|
||||
im_desc->block_num++;
|
||||
log_info("Unprotect failed");
|
||||
goto NAND_WRITE_RETRY;
|
||||
}
|
||||
|
||||
/* Erase the block where the header goes and the data starts */
|
||||
if (nand_erase_blocks(im_desc->block_num, num_blocks) != E_PASS) {
|
||||
im_desc->block_num++;
|
||||
log_info("Erase failed");
|
||||
goto NAND_WRITE_RETRY;
|
||||
}
|
||||
|
||||
#ifdef NAND_DEBUG_WRITE_RAMP
|
||||
{
|
||||
int k;
|
||||
|
||||
/* Usefull for debugging NAND ECC and spare bytes errors. */
|
||||
for (k = 0; k < 512; k++)
|
||||
ptr[k] = 0xCAFE0000 | k;
|
||||
}
|
||||
#endif
|
||||
|
||||
page_num = 0; /* Start in page 0. */
|
||||
|
||||
if (im_desc->magic != UBL_CMD_FLASH_DATA) {
|
||||
/* Write the header to page 0. */
|
||||
log_info("Writing header");
|
||||
|
||||
if (nand_write_verify_page(im_desc->block_num, page_num,
|
||||
(uint8_t *) im_desc) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
/* Set starting page number for next data portion. */
|
||||
page_num = 1;
|
||||
}
|
||||
|
||||
/* The following assumes power of 2 page_cnt - *should* always be
|
||||
* valid. */
|
||||
count_mask = nand_info.pages_per_block - 1;
|
||||
log_info("Writing data");
|
||||
do {
|
||||
/* Write data on a per page basis */
|
||||
if (nand_write_verify_page(im_desc->block_num,
|
||||
page_num & count_mask, src)
|
||||
!= E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
page_num++;
|
||||
src += nand_info.bytes_per_page;
|
||||
if (!(page_num & count_mask))
|
||||
im_desc->block_num++;
|
||||
} while (page_num <= im_desc->size_in_pages);
|
||||
|
||||
nand_protect_blocks();
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
int
|
||||
nand_erase_all(void)
|
||||
{
|
||||
/* Unprotect the NAND Flash */
|
||||
nand_unprotect_blocks(0, nand_info.num_blocks - 1);
|
||||
|
||||
/* Erase all the pages */
|
||||
if (nand_erase_blocks(0, nand_info.num_blocks - 1) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
/* Protect the device */
|
||||
nand_protect_blocks();
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
int
|
||||
nand_get_pages_per_block(void)
|
||||
{
|
||||
return nand_info.pages_per_block;
|
||||
}
|
||||
|
||||
int
|
||||
nand_get_bytes_per_page(void)
|
||||
{
|
||||
return nand_info.bytes_per_page;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* nand.h - NAND flash definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _NAND_H_
|
||||
#define _NAND_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
|
||||
/* Define which blocks are valid for writing UBL and APP data */
|
||||
#define START_UBL_BLOCK_NUM 1
|
||||
#define END_UBL_BLOCK_NUM 5
|
||||
#define START_APP_BLOCK_NUM 6
|
||||
|
||||
#define MAX_PAGE_SIZE (2048+64) /* Data bytes + spare area */
|
||||
|
||||
/* NAND descriptor expected by RBL when it loads UBL image. */
|
||||
struct nand_image_descriptor_t {
|
||||
uint32_t magic;
|
||||
uint32_t entry_point;
|
||||
uint32_t size_in_pages;
|
||||
uint32_t block_num;
|
||||
uint32_t page_num;
|
||||
uint32_t load_address; /* Not used by RBL */
|
||||
};
|
||||
|
||||
|
||||
int nand_init(void);
|
||||
|
||||
int nand_erase_all(void);
|
||||
|
||||
int nand_read_page(uint32_t block, uint32_t page, uint8_t *dest);
|
||||
|
||||
int nand_write_prog(struct nand_image_descriptor_t *im_desc,
|
||||
const uint8_t *src, size_t size);
|
||||
|
||||
/* Copy Application from NAND to RAM */
|
||||
int nand_copy(uint32_t *jump_entry_point);
|
||||
|
||||
int nand_get_pages_per_block(void);
|
||||
|
||||
int nand_get_bytes_per_page(void);
|
||||
|
||||
#endif /* _NAND_H_ */
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* nandboot.c - NAND boot mode functions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "nand.h"
|
||||
#include "util.h"
|
||||
#include "uart.h"
|
||||
|
||||
static uint8_t nand_header[MAX_PAGE_SIZE] __attribute__((section(".ddrram")));
|
||||
|
||||
/*
|
||||
* Find out where the application is and copy to RAM
|
||||
* jump_entry_point: Entry point for application we are decoding out of
|
||||
* flash
|
||||
*/
|
||||
int
|
||||
nand_copy(uint32_t *jump_entry_point)
|
||||
{
|
||||
uint32_t count, start_block;
|
||||
uint32_t i;
|
||||
uint32_t magicNum;
|
||||
uint32_t block, page;
|
||||
uint32_t readError = E_FAIL;
|
||||
int failedOnceAlready = false;
|
||||
uint8_t *rxBuf; /* Temporary buffer to load header in NAND */
|
||||
struct nand_image_descriptor_t im_desc;
|
||||
int last_header_block;
|
||||
|
||||
start_block = START_APP_BLOCK_NUM;
|
||||
last_header_block = start_block + 10;
|
||||
|
||||
NAND_startAgain:
|
||||
/* Read header about application starting at START_APP_BLOCK_NUM, Page 0
|
||||
* and try 10 blocks. */
|
||||
for (count = start_block; count <= last_header_block; count++) {
|
||||
if (nand_read_page(count, 0, nand_header) != E_PASS)
|
||||
continue;
|
||||
|
||||
magicNum = *((uint32_t *) nand_header);
|
||||
|
||||
/* Valid magic number found */
|
||||
if ((magicNum & MAGIC_NUMBER_MASK) == MAGIC_NUMBER_VALID) {
|
||||
start_block = count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never found valid header. */
|
||||
if (count > last_header_block)
|
||||
return E_FAIL;
|
||||
|
||||
memcpy((void *) &im_desc, nand_header, sizeof(im_desc));
|
||||
|
||||
uart_send_str("Image infos: Magic = ");
|
||||
uart_send_hexnum(im_desc.magic, 8);
|
||||
uart_send_str(", Entry = ");
|
||||
uart_send_hexnum(im_desc.entry_point, 8);
|
||||
uart_send_str(", Pages = ");
|
||||
uart_send_hexnum(im_desc.size_in_pages, 8);
|
||||
uart_send_str(", Load = ");
|
||||
uart_send_hexnum(im_desc.load_address, 8);
|
||||
uart_send_lf();
|
||||
|
||||
rxBuf = (uint8_t *) im_desc.load_address;
|
||||
|
||||
NAND_retry:
|
||||
/* initialize block and page number to be used for read */
|
||||
block = im_desc.block_num;
|
||||
page = im_desc.page_num;
|
||||
|
||||
/* Perform the actual copying of the application from NAND to RAM */
|
||||
for (i = 0; i < im_desc.size_in_pages; i++) {
|
||||
/* if page goes beyond max number of pages increment block
|
||||
* number and reset page number */
|
||||
if (page >= nand_get_pages_per_block()) {
|
||||
page = 0;
|
||||
block++;
|
||||
}
|
||||
|
||||
/* Copy the data */
|
||||
readError =
|
||||
nand_read_page(block, page++,
|
||||
&rxBuf[i * nand_get_bytes_per_page()]);
|
||||
|
||||
/*
|
||||
* We attempt to read the app data twice. If we fail twice then
|
||||
* we go look for a new application header in the NAND flash at
|
||||
* the next block.
|
||||
*/
|
||||
if (readError != E_PASS) {
|
||||
if (failedOnceAlready) {
|
||||
start_block++;
|
||||
goto NAND_startAgain;
|
||||
} else {
|
||||
failedOnceAlready = true;
|
||||
goto NAND_retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Application was read correctly, so set entrypoint */
|
||||
*jump_entry_point = im_desc.entry_point;
|
||||
|
||||
return E_PASS;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* nor.h - NOR flash definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _NOR_H_
|
||||
#define _NOR_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
|
||||
/* Global NOR commands */
|
||||
uint32_t NOR_Init (void);
|
||||
|
||||
int nor_copy(uint32_t *jump_entry_point);
|
||||
|
||||
uint32_t NOR_WriteBytes(uint32_t writeAddress, uint32_t numBytes, uint32_t readAddress);
|
||||
uint32_t NOR_GlobalErase(void);
|
||||
uint32_t NOR_Erase(uint32_t start_address, uint32_t size);
|
||||
uint32_t DiscoverBlockInfo(uint32_t address,uint32_t* blockSize, uint32_t* blockAddr);
|
||||
|
||||
|
||||
uint32_t nor_get_flashbase(void);
|
||||
|
||||
|
||||
#endif /* _NOR_H_ */
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* norboot.c - NOR boot mode functions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "nor.h"
|
||||
#include "util.h"
|
||||
#include "uart.h"
|
||||
|
||||
extern NOR_INFO gNorInfo;
|
||||
|
||||
/* Function to find out where the Application is and copy to DRAM */
|
||||
int
|
||||
nor_copy(uint32_t *jump_entry_point)
|
||||
{
|
||||
volatile struct nor_boot_t *hdr = 0;
|
||||
volatile uint32_t *appStartAddr = 0;
|
||||
volatile uint32_t count = 0;
|
||||
volatile uint32_t *ramPtr = 0;
|
||||
uint32_t blkSize, blkAddress;
|
||||
|
||||
if (NOR_Init() != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
DiscoverBlockInfo((gNorInfo.flashBase + UBL_IMAGE_SIZE), &blkSize,
|
||||
&blkAddress);
|
||||
|
||||
hdr = (volatile struct nor_boot_t *) (blkAddress + blkSize);
|
||||
|
||||
/* Check for valid magic number. */
|
||||
if ((hdr->magicNum & 0xFFFFFF00) != MAGIC_NUMBER_VALID) {
|
||||
log_fail("No valid header found");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Set the source address for copy */
|
||||
appStartAddr = (uint32_t *)(((uint8_t*) hdr) + sizeof(struct nor_boot_t));
|
||||
|
||||
if (hdr->magicNum == UBL_MAGIC_BIN_IMG) {
|
||||
log_fail("Unsupported image format");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
ramPtr = (uint32_t *) hdr->ldAddress;
|
||||
|
||||
/* Copy data to RAM */
|
||||
memcpy(ramPtr, appStartAddr, hdr->appSize);
|
||||
|
||||
/* Application was read correctly, so set entrypoint */
|
||||
*jump_entry_point = hdr->entryPoint;
|
||||
|
||||
return E_PASS;
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
* uart.c - UART Rx and Tx functions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
#include "uart.h"
|
||||
#include "util.h"
|
||||
#include "crc.h"
|
||||
#include "gunzip.h"
|
||||
|
||||
/* Symbol from linker script */
|
||||
extern uint32_t __DDR_FREE; /* Start of free DDR memory region. */
|
||||
extern uint32_t __DDR_END; /* Last DDR memory address. */
|
||||
|
||||
/* Receive data from UART */
|
||||
static int
|
||||
uart_recv_bytes(size_t count, uint8_t *dest)
|
||||
{
|
||||
uint32_t i, status = 0;
|
||||
uint32_t timerStatus = 1;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Enable timer one time */
|
||||
timer0_start();
|
||||
do {
|
||||
status = (UART0->LSR)&(0x01);
|
||||
timerStatus = timer0_status();
|
||||
} while (!status && timerStatus);
|
||||
|
||||
if (timerStatus == 0) {
|
||||
host_msg("UART_TIMEOUT");
|
||||
return E_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Receive byte */
|
||||
dest[i] = (UART0->RBR) & 0xFF;
|
||||
|
||||
/* Check status for errors */
|
||||
if ((UART0->LSR & 0x1C) != 0) {
|
||||
host_msg("UART_RXERR");
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* Send bytes with optional null terminating character. */
|
||||
static void
|
||||
uart_send_bytes(char *string)
|
||||
{
|
||||
uint32_t status = 0;
|
||||
int32_t i, count;
|
||||
uint32_t timerStatus = 1;
|
||||
|
||||
count = strlen(string);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Enable Timer one time */
|
||||
timer0_start();
|
||||
do {
|
||||
status = (UART0->LSR)&(0x20);
|
||||
timerStatus = timer0_status();
|
||||
} while (!status && timerStatus);
|
||||
|
||||
if (timerStatus == 0)
|
||||
return; /* E_TIMEOUT */
|
||||
|
||||
/* Send byte */
|
||||
(UART0->THR) = string[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the given string is received via UART */
|
||||
static int
|
||||
uart_check_string(char *string, int include_null)
|
||||
{
|
||||
int i, count;
|
||||
|
||||
count = strlen(string);
|
||||
if (include_null != false)
|
||||
count++;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uint8_t recv;
|
||||
|
||||
/* Get one byte */
|
||||
if (uart_recv_bytes(1, &recv) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
if (recv != string[i])
|
||||
return E_FAIL;
|
||||
}
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* Receive a uint32 value in HEX form (8 bytes) */
|
||||
static int
|
||||
uart_recv_hex_uint32(uint32_t *data)
|
||||
{
|
||||
int k;
|
||||
uint8_t recv[8];
|
||||
uint32_t temp;
|
||||
int shift;
|
||||
const int num_ascii_char = 8;
|
||||
|
||||
/* Get 8 bytes from UART */
|
||||
if (uart_recv_bytes(num_ascii_char, recv) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
*data = 0;
|
||||
|
||||
/* Converting ascii to Hex */
|
||||
for (k = 0, shift = 28; k < num_ascii_char; k++, shift -= 4) {
|
||||
temp = recv[k] - 48;
|
||||
|
||||
if (temp > 22) /* Lower case a,b,c,d,e,f */
|
||||
temp -= 39;
|
||||
else if (temp > 9) /* Upper case A,B,C,D,E,F */
|
||||
temp -= 7;
|
||||
|
||||
*data |= temp << shift;
|
||||
}
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
/* Send line feed (\n) to UART. */
|
||||
void
|
||||
uart_send_lf(void)
|
||||
{
|
||||
uart_send_bytes("\r\n");
|
||||
}
|
||||
|
||||
/* Send a string to UART, without line feed. */
|
||||
void
|
||||
uart_send_str(char *string)
|
||||
{
|
||||
uart_send_bytes(string);
|
||||
}
|
||||
|
||||
/* Send a string to UART, with line feed. */
|
||||
void
|
||||
uart_send_str_lf(char *string)
|
||||
{
|
||||
uart_send_bytes(string);
|
||||
uart_send_lf();
|
||||
}
|
||||
|
||||
void
|
||||
uart_send_hexnum(uint32_t value, int digits)
|
||||
{
|
||||
char seq[9];
|
||||
uint32_t i, shift;
|
||||
uint8_t temp;
|
||||
|
||||
for (i = 0; i < digits; i++) {
|
||||
shift = ((digits - 1) - i) * 4;
|
||||
temp = (value >> shift) & 0x0F;
|
||||
if (temp > 9)
|
||||
temp += 7;
|
||||
seq[i] = temp + 48;
|
||||
}
|
||||
seq[digits] = 0;
|
||||
|
||||
uart_send_str("0x");
|
||||
uart_send_bytes(seq);
|
||||
}
|
||||
|
||||
int
|
||||
uart_get_cmd(uint32_t *boot_cmd)
|
||||
{
|
||||
if (uart_check_string(" CMD", true) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
if (uart_recv_hex_uint32(boot_cmd) != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
return E_PASS;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
uart_get_prog(struct uart_ack_header_t *uart_ack_header)
|
||||
{
|
||||
uint32_t error;
|
||||
uint32_t recv_crc, computed_crc;
|
||||
unsigned long inflate_dstbuf_len, inflate_srcbuf_len;
|
||||
uint8_t *ddr_free = (uint8_t *) &__DDR_FREE;
|
||||
|
||||
uart_ack_header->recv_buffer = ddr_free;
|
||||
uart_ack_header->inflate_dstbuf = ddr_free + MAX_IMAGE_SIZE;
|
||||
inflate_dstbuf_len = ((uint8_t *) &__DDR_END) + 1 - uart_ack_header->inflate_dstbuf;
|
||||
|
||||
/* Send ACK command */
|
||||
error = uart_check_string(" ACK", true);
|
||||
if (error != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
/* Get the ACK header elements */
|
||||
error = uart_recv_hex_uint32(&uart_ack_header->magic);
|
||||
error |= uart_recv_hex_uint32(&recv_crc);
|
||||
error |= uart_recv_hex_uint32(&uart_ack_header->size);
|
||||
error |= uart_recv_hex_uint32(&uart_ack_header->entry_point);
|
||||
error |= uart_check_string("0000", false);
|
||||
if (error != E_PASS)
|
||||
return E_FAIL;
|
||||
|
||||
uart_send_str("Magic = ");
|
||||
uart_send_hexnum(uart_ack_header->magic, 8);
|
||||
uart_send_str(", CRC = ");
|
||||
uart_send_hexnum(recv_crc, 8);
|
||||
uart_send_str(", Entry = ");
|
||||
uart_send_hexnum(uart_ack_header->entry_point, 8);
|
||||
uart_send_str(", Size = ");
|
||||
uart_send_hexnum(uart_ack_header->size, 8);
|
||||
uart_send_lf();
|
||||
|
||||
/* Verify that the file size is appropriate */
|
||||
if ((uart_ack_header->size == 0) ||
|
||||
(uart_ack_header->size > MAX_IMAGE_SIZE)) {
|
||||
host_msg("BADCNT");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Send BEGIN command */
|
||||
host_msg("BEGIN");
|
||||
|
||||
/* Receive the data over UART */
|
||||
if (uart_recv_bytes(uart_ack_header->size,
|
||||
uart_ack_header->recv_buffer)
|
||||
!= E_PASS) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Return first DONE when all data arrives */
|
||||
host_msg("DONE");
|
||||
|
||||
computed_crc = crc32_dv_compute(uart_ack_header->recv_buffer,
|
||||
uart_ack_header->size);
|
||||
if (computed_crc != recv_crc) {
|
||||
host_msg("BADCRC");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
inflate_srcbuf_len = uart_ack_header->size - GUNZIP_COMP_BLOCK_OFFSET;
|
||||
|
||||
error = gunzip(uart_ack_header->inflate_dstbuf, &inflate_dstbuf_len,
|
||||
&uart_ack_header->recv_buffer[GUNZIP_COMP_BLOCK_OFFSET],
|
||||
&inflate_srcbuf_len);
|
||||
if (error != 0) {
|
||||
uart_send_str("gzip error = ");
|
||||
uart_send_hexnum(error, 8);
|
||||
uart_send_lf();
|
||||
host_msg("GZIPERR");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
uart_send_str("Deflated data size = ");
|
||||
uart_send_hexnum(inflate_dstbuf_len, 8);
|
||||
uart_send_lf();
|
||||
|
||||
uart_ack_header->recv_buffer = uart_ack_header->inflate_dstbuf;
|
||||
uart_ack_header->size = inflate_dstbuf_len;
|
||||
|
||||
/* Return DONE when all data is validated */
|
||||
host_msg("DONE");
|
||||
|
||||
return E_PASS;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* uart.h - UART Rx and Tx definitions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _UART_H_
|
||||
#define _UART_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct uart_ack_header_t {
|
||||
uint32_t magic;
|
||||
uint32_t entry_point;
|
||||
uint32_t size;
|
||||
uint8_t *recv_buffer;
|
||||
uint8_t *inflate_dstbuf;
|
||||
};
|
||||
|
||||
void uart_boot(uint32_t *jump_entry_point);
|
||||
|
||||
void uart_send_lf(void);
|
||||
void uart_send_str(char *string);
|
||||
void uart_send_str_lf(char *string);
|
||||
void uart_send_hexnum(uint32_t value, int digits);
|
||||
|
||||
int uart_get_cmd(uint32_t *boot_cmd);
|
||||
|
||||
uint32_t uart_get_prog(struct uart_ack_header_t *uart_ack_header);
|
||||
|
||||
#endif /* _UART_H_ */
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* uartboot.c - UART boot mode
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
#include "uart.h"
|
||||
#include "util.h"
|
||||
#include "crc.h"
|
||||
#if defined(FLASH_TYPE_NOR)
|
||||
#include "nor.h"
|
||||
#elif defined(FLASH_TYPE_NAND)
|
||||
#include "nand.h"
|
||||
#endif
|
||||
|
||||
/* Symbols from linker script */
|
||||
extern uint32_t __DDR_START;
|
||||
extern uint32_t __DDR_SIZE;
|
||||
|
||||
static int
|
||||
ddr_memory_test(void)
|
||||
{
|
||||
int k;
|
||||
volatile uint32_t *ddr_start = &__DDR_START;
|
||||
const uint32_t ddr_size32 = ((uint32_t) &__DDR_SIZE) / 4;
|
||||
uint32_t read32;
|
||||
|
||||
log_info("DDR tests");
|
||||
|
||||
log_info("1. RAMP test:");
|
||||
for (k = 0; k < ddr_size32; k++)
|
||||
ddr_start[k] = k; /* Write */
|
||||
|
||||
for (k = 0; k < ddr_size32; k++) {
|
||||
read32 = ddr_start[k]; /* Read */
|
||||
if (read32 != k)
|
||||
goto error;
|
||||
}
|
||||
log_info(" Success");
|
||||
|
||||
log_info("2. PATTERN test:");
|
||||
for (k = 0; k < ddr_size32; k++)
|
||||
ddr_start[k] = DDR_TEST_PATTERN; /* Write */
|
||||
|
||||
for (k = 0; k < ddr_size32; k++) {
|
||||
read32 = ddr_start[k]; /* Read */
|
||||
if (read32 != DDR_TEST_PATTERN)
|
||||
goto error;
|
||||
}
|
||||
log_info(" Success");
|
||||
|
||||
host_msg("DDRTEST_SUCCESS");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uart_send_str("Failed at address: ");
|
||||
uart_send_hexnum(k * 4, 8);
|
||||
uart_send_str(", Expected: ");
|
||||
uart_send_hexnum(k, 8);
|
||||
uart_send_str(", Read: ");
|
||||
uart_send_hexnum(read32, 8);
|
||||
uart_send_lf();
|
||||
host_msg("DDRTEST_FAILURE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
uart_boot(uint32_t *jump_entry_point)
|
||||
{
|
||||
#if defined(FLASH_TYPE_NAND)
|
||||
struct nand_image_descriptor_t im_desc;
|
||||
#elif defined(FLASH_TYPE_NOR)
|
||||
struct nor_boot_t norBoot;
|
||||
uint32_t blkAddress, blkSize, baseAddress;
|
||||
#endif
|
||||
struct uart_ack_header_t uart_ack_header;
|
||||
uint32_t boot_cmd;
|
||||
|
||||
crc32_dv_build_table();
|
||||
log_info("Starting UART Boot");
|
||||
host_msg("BOOTPSP");
|
||||
|
||||
/* Get the BOOT command */
|
||||
if (uart_get_cmd(&boot_cmd) != E_PASS)
|
||||
goto uartboot_error;
|
||||
|
||||
/* Set the entry point to reset by default */
|
||||
*jump_entry_point = 0x0;
|
||||
|
||||
switch (boot_cmd) {
|
||||
case UBL_CMD_DDR_TEST:
|
||||
/* Perform DDR memory testing. */
|
||||
ddr_memory_test();
|
||||
break;
|
||||
|
||||
/* Download via UART UBL and APP and burn to flash. */
|
||||
case UBL_CMD_FLASH_UBL_APP:
|
||||
host_msg("SENDUBL");
|
||||
|
||||
/* Download UBL into GZIP format */
|
||||
if (uart_get_prog(&uart_ack_header) != E_PASS)
|
||||
goto uartboot_error;
|
||||
|
||||
log_info("Writing UBL");
|
||||
|
||||
#if defined(FLASH_TYPE_NOR)
|
||||
NOR_Erase(nor_get_flashbase(), uart_ack_header.size);
|
||||
|
||||
/* Write binary UBL to NOR flash. */
|
||||
NOR_WriteBytes(nor_get_flashbase(), uart_ack_header.size,
|
||||
(uint32_t) uart_ack_header.recv_buffer);
|
||||
#elif defined(FLASH_TYPE_NAND)
|
||||
im_desc.magic = uart_ack_header.magic;
|
||||
im_desc.entry_point = uart_ack_header.entry_point;
|
||||
im_desc.block_num = START_UBL_BLOCK_NUM;
|
||||
im_desc.load_address = 0; /* Load address not used by RBL */
|
||||
|
||||
if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer,
|
||||
uart_ack_header.size) != E_PASS)
|
||||
goto uartboot_error;
|
||||
#endif
|
||||
|
||||
/* Indicate that UBL flashing was successfull. */
|
||||
host_msg("DONE");
|
||||
|
||||
host_msg("SENDAPP");
|
||||
|
||||
/* Get the application header and data */
|
||||
if (uart_get_prog(&uart_ack_header) != E_PASS)
|
||||
goto uartboot_error;
|
||||
|
||||
log_info("Writing APP");
|
||||
|
||||
#if defined(FLASH_TYPE_NOR)
|
||||
/* Erase the NOR flash where header and data will go */
|
||||
DiscoverBlockInfo((nor_get_flashbase() + UBL_IMAGE_SIZE),
|
||||
&blkSize, &blkAddress);
|
||||
baseAddress = blkAddress + blkSize;
|
||||
NOR_Erase(baseAddress, uart_ack_header.size + sizeof(norBoot));
|
||||
|
||||
/* MagicFlag for Application (binary or safe) */
|
||||
norBoot.magicNum = uart_ack_header.magic;
|
||||
|
||||
/* Bytes of application (either srec or binary) */
|
||||
norBoot.appSize = uart_ack_header.size;
|
||||
|
||||
/* Value from ACK header */
|
||||
norBoot.entryPoint = uart_ack_header.entry_point;
|
||||
|
||||
/* Semi-hardcoded load address to entry point. FIXME */
|
||||
norBoot.ldAddress = uart_ack_header.entry_point;
|
||||
|
||||
/* Write the struct nor_boot_t header to the flash */
|
||||
NOR_WriteBytes(baseAddress, sizeof(norBoot),
|
||||
(uint32_t) &norBoot);
|
||||
|
||||
/* Write the application data to the flash */
|
||||
NOR_WriteBytes((baseAddress + sizeof(norBoot)),
|
||||
uart_ack_header.size,
|
||||
(uint32_t) uart_ack_header.recv_buffer);
|
||||
|
||||
/* Semi-hardcoded load address to entry point. FIXME */
|
||||
if (nor_write_prog(&nor_boot, uart_ack_header.recv_buffer,
|
||||
uart_ack_header.size,
|
||||
baseAddress + sizeof(norBoot),
|
||||
uart_ack_header.magic,
|
||||
uart_ack_header.entry_point,
|
||||
uart_ack_header.entry_point) != E_PASS)
|
||||
goto uartboot_error;
|
||||
#elif defined(FLASH_TYPE_NAND)
|
||||
im_desc.magic = uart_ack_header.magic;
|
||||
im_desc.entry_point = uart_ack_header.entry_point;
|
||||
im_desc.block_num = START_APP_BLOCK_NUM;
|
||||
/* Assuming load address is identical to entry point. */
|
||||
im_desc.load_address = uart_ack_header.entry_point;
|
||||
|
||||
if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer,
|
||||
uart_ack_header.size) != E_PASS)
|
||||
goto uartboot_error;
|
||||
#endif
|
||||
|
||||
/* Indicate that APP flashing was successfull. */
|
||||
host_msg("DONE");
|
||||
|
||||
break;
|
||||
|
||||
case UBL_CMD_FLASH_DATA:
|
||||
host_msg("SENDDATA");
|
||||
|
||||
/* Get the data block infos and actual bytes */
|
||||
if (uart_get_prog(&uart_ack_header) != E_PASS)
|
||||
goto uartboot_error;
|
||||
|
||||
log_info("Writing DATA");
|
||||
|
||||
im_desc.magic = uart_ack_header.magic;
|
||||
im_desc.block_num = uart_ack_header.entry_point; /* Block in flash */
|
||||
|
||||
if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer,
|
||||
uart_ack_header.size) != E_PASS)
|
||||
goto uartboot_error;
|
||||
|
||||
/* Indicate that APP flashing was successfull. */
|
||||
host_msg("DONE");
|
||||
|
||||
break;
|
||||
|
||||
case UBL_CMD_FLASH_ERASE:
|
||||
log_info("Erasing whole flash");
|
||||
|
||||
#if defined(FLASH_TYPE_NOR)
|
||||
if (NOR_GlobalErase() != E_PASS) {
|
||||
log_info("Erase failed");
|
||||
goto uartboot_error;
|
||||
}
|
||||
#elif defined(FLASH_TYPE_NAND)
|
||||
if (nand_erase_all() != E_PASS) {
|
||||
log_info("Erase failed");
|
||||
goto uartboot_error;
|
||||
}
|
||||
#endif
|
||||
|
||||
log_info("Erase successfull");
|
||||
|
||||
break;
|
||||
default:
|
||||
/* Load and run application */
|
||||
host_msg("SENDAPP");
|
||||
|
||||
if (uart_get_prog(&uart_ack_header) != E_PASS)
|
||||
goto uartboot_error;
|
||||
|
||||
*jump_entry_point = uart_ack_header.entry_point;
|
||||
break;
|
||||
} /* end switch statement */
|
||||
|
||||
return;
|
||||
|
||||
uartboot_error:
|
||||
/* Set the entry point to reset. */
|
||||
*jump_entry_point = 0x0;
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* ubl.c - main file
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "davinci.h"
|
||||
#include "uart.h"
|
||||
#include "util.h"
|
||||
#if defined(FLASH_TYPE_NOR)
|
||||
#include "nor.h"
|
||||
#elif defined(FLASH_TYPE_NAND)
|
||||
#include "nand.h"
|
||||
#endif
|
||||
|
||||
#define C1_IC (1 << 12) /* icache off/on */
|
||||
|
||||
static uint32_t jump_entry_point;
|
||||
|
||||
enum bootmode_t bootmode;
|
||||
|
||||
/* read co-processor 15, register #1 (control register) */
|
||||
static uint32_t
|
||||
read_p15_c1(void)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrc p15, 0, %0, c1, c0, 0 @ read control reg\n"
|
||||
: "=r" (value)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* write to co-processor 15, register #1 (control register) */
|
||||
static void
|
||||
write_p15_c1(uint32_t value)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"mcr p15, 0, %0, c1, c0, 0 @ write it back\n"
|
||||
:
|
||||
: "r" (value)
|
||||
: "memory");
|
||||
|
||||
read_p15_c1();
|
||||
}
|
||||
|
||||
static void
|
||||
cp_delay(void)
|
||||
{
|
||||
volatile int i;
|
||||
|
||||
/* copro seems to need some delay between reading and writing */
|
||||
for (i = 0; i < 100; i++)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
icache_enable(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = read_p15_c1(); /* get control reg. */
|
||||
cp_delay();
|
||||
write_p15_c1(reg | C1_IC);
|
||||
}
|
||||
|
||||
static int
|
||||
ubl_main(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Read boot mode */
|
||||
bootmode = (enum bootmode_t) (((SYSTEM->BOOTCFG) & 0xC0) >> 6);
|
||||
|
||||
/* Wait until the RBL is done using the UART. */
|
||||
if (bootmode == NON_SECURE_UART)
|
||||
while ((UART0->LSR & 0x40) == 0);
|
||||
|
||||
status = davinci_platform_init(UBL_VERSION_STR);
|
||||
if (status != E_PASS)
|
||||
goto error;
|
||||
|
||||
#if defined(FLASH_TYPE_NOR)
|
||||
status = NOR_Init();
|
||||
#elif defined(FLASH_TYPE_NAND)
|
||||
status = nand_init();
|
||||
#endif
|
||||
if (status != E_PASS) {
|
||||
uart_send_str("flash init failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
uart_send_str("BootMode = ");
|
||||
|
||||
/* Select Boot Mode */
|
||||
switch (bootmode) {
|
||||
#if defined(FLASH_TYPE_NAND)
|
||||
case NON_SECURE_NAND:
|
||||
log_info("NAND"); /* Report boot mode to host */
|
||||
|
||||
/* Copy binary application data from NAND to DDRAM */
|
||||
if (nand_copy(&jump_entry_point) != E_PASS) {
|
||||
log_info("Boot failed.");
|
||||
goto UARTBOOT;
|
||||
}
|
||||
break;
|
||||
#elif defined(FLASH_TYPE_NOR)
|
||||
case NON_SECURE_NOR:
|
||||
log_info("NOR"); /* Report boot mode to host */
|
||||
|
||||
/* Copy binary application data from NOR to DDRAM */
|
||||
if (nor_copy() != E_PASS) {
|
||||
log_info("Boot failed.");
|
||||
goto UARTBOOT;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case NON_SECURE_UART:
|
||||
log_info("UART"); /* Report boot mode to host */
|
||||
goto UARTBOOT;
|
||||
break;
|
||||
default:
|
||||
UARTBOOT:
|
||||
uart_boot(&jump_entry_point);
|
||||
break;
|
||||
}
|
||||
|
||||
waitloop(10000);
|
||||
|
||||
/* Disabling UART timeout timer */
|
||||
while ((UART0->LSR & 0x40) == 0)
|
||||
;
|
||||
TIMER0->TCR = 0x00000000;
|
||||
|
||||
return E_PASS;
|
||||
|
||||
error:
|
||||
jump_entry_point = 0; /* Reset */
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* boot() has naked attribute (doesn't save registers since it is the entry
|
||||
* point out of boot and it doesn't have an exit point). This setup requires
|
||||
* that the gnu compiler uses the -nostdlib option.
|
||||
*/
|
||||
__attribute__((naked, section(".boot"))) void boot(void);
|
||||
|
||||
void
|
||||
boot(void)
|
||||
{
|
||||
void (*app_entry_function)(void);
|
||||
extern uint32_t __topstack; /* symbol defined in linker script */
|
||||
register uint32_t *stackpointer asm("sp");
|
||||
|
||||
asm(" MRS r0, cpsr");
|
||||
asm(" BIC r0, r0, #0x1F"); /* Clear MODES */
|
||||
asm(" ORR r0, r0, #0x13"); /* Set SUPERVISOR mode */
|
||||
asm(" ORR r0, r0, #0xC0"); /* Disable FIQ and IRQ */
|
||||
asm(" MSR cpsr, r0");
|
||||
|
||||
/* Set the IVT to low memory, leave MMU & caches disabled */
|
||||
asm(" MRC p15, 0, r1, c1, c0, 0");
|
||||
asm(" BIC r0,r0,#0x00002000");
|
||||
asm(" MCR p15, 0, r1, c1, c0, 0");
|
||||
|
||||
/* Stack setup */
|
||||
stackpointer = &(__topstack);
|
||||
|
||||
icache_enable();
|
||||
|
||||
/* Call to main code */
|
||||
ubl_main();
|
||||
|
||||
uart_send_str("Starting app at: ");
|
||||
uart_send_hexnum((uint32_t) jump_entry_point, 8);
|
||||
uart_send_lf();
|
||||
|
||||
/* Jump to entry point */
|
||||
app_entry_function = (void *) jump_entry_point;
|
||||
(*app_entry_function)();
|
||||
}
|
||||
|
||||
/*
|
||||
* selfcopy() has naked attribute (doesn't save registers since it is the
|
||||
* entry point when the UBL is found at the base of the NOR Flash and then
|
||||
* goes directly to the the boot() function, which is also naked). This setup
|
||||
* requires that the gnu compiler uses the -nostdlib option.
|
||||
*/
|
||||
#if defined(FLASH_TYPE_NOR)
|
||||
__attribute__((naked, section(".selfcopy"))) void selfcopy(void);
|
||||
|
||||
void
|
||||
selfcopy(void)
|
||||
{
|
||||
volatile uint32_t *src = &(__selfcopysrc);
|
||||
volatile uint32_t *dest = &(__selfcopydest);
|
||||
volatile uint32_t *destend = &(__selfcopydestend);
|
||||
extern uint32_t __selfcopysrc, __selfcopydest, __selfcopydestend;
|
||||
|
||||
/* Enable ITCM */
|
||||
asm(" MRC p15, 0, r0, c9, c1, 1");
|
||||
asm(" MOV r0, #0x1");
|
||||
asm(" MCR p15, 0, r0, c9, c1, 1");
|
||||
|
||||
/* Enable DTCM */
|
||||
asm(" MRC p15, 0, r0, c9, c1, 0");
|
||||
asm(" MOV r0, #0x8000");
|
||||
asm(" ORR r0, r0, #0x1");
|
||||
asm(" MCR p15, 0, r0, c9, c1, 0");
|
||||
|
||||
/* Copy the words */
|
||||
while (dest < destend) {
|
||||
*dest = *src;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
|
||||
/* Jump to the normal entry point */
|
||||
boot();
|
||||
}
|
||||
|
||||
__attribute__ ((naked, section(".fakeentry"))) void fake_entry(void);
|
||||
|
||||
void
|
||||
fake_entry(void)
|
||||
{
|
||||
boot();
|
||||
}
|
||||
#endif /* FLASH_TYPE_NOR */
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* dm35x.lds - DM35x linker script file
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
ENTRY(boot)
|
||||
SECTIONS {
|
||||
/* Common definitions */
|
||||
__EMIF_START = 0x02000000;
|
||||
__EMIF_SIZE = 0x02000000;
|
||||
__IRAM_START = 0x00000000;
|
||||
__DDR_START = 0x80000000;
|
||||
|
||||
STACKStart = __DRAM_START + __DRAM_SIZE;
|
||||
__topstack = (__DRAM_START + __DRAM_SIZE) - 0x4;
|
||||
|
||||
. = __EMIF_START;
|
||||
|
||||
__CS2start = .;
|
||||
__NORFlash = .;
|
||||
__NANDFlash = .;
|
||||
|
||||
.selfcopy : AT (0x0)
|
||||
{
|
||||
*(.selfcopy)
|
||||
. = ALIGN(256);
|
||||
}
|
||||
|
||||
__selfcopysrc = .;
|
||||
__IVT = __DRAM_START;
|
||||
__selfcopydest = __DRAM_START + 0x00000020;
|
||||
|
||||
. = 0x20;
|
||||
.fakeentry : AT ( LOADADDR(.selfcopy) + SIZEOF(.selfcopy))
|
||||
{
|
||||
*(.fakeentry)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
.text : AT ( LOADADDR(.fakeentry) + SIZEOF(.fakeentry) )
|
||||
{
|
||||
*(.text)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
.boot : AT ( LOADADDR(.text) + SIZEOF(.text))
|
||||
{
|
||||
*(.boot)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
/* Move into DRAM for placing const and data sections */
|
||||
. += (__DRAM_START - __IRAM_START);
|
||||
|
||||
.rodata : AT ( LOADADDR(.boot) + SIZEOF(.boot) )
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.rodata)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
.data : AT ( LOADADDR(.rodata) + SIZEOF(.rodata) )
|
||||
{
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
__selfcopydestend = __selfcopydest + SIZEOF(.fakeentry) +
|
||||
SIZEOF(.text) + SIZEOF(.boot) +
|
||||
SIZEOF(.data) + SIZEOF(.rodata);
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.bss) *(COMMON)
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
/* DDR2 */
|
||||
. = __DDR_START;
|
||||
.ddrram (NOLOAD) :
|
||||
{
|
||||
*(.ddrram)
|
||||
}
|
||||
__DDR_FREE = .;
|
||||
__DDR_END = __DDR_START + __DDR_SIZE - 1;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* util.c - miscellaneous functions
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MAXSTRLEN 256
|
||||
|
||||
/* Endian swap */
|
||||
void
|
||||
endian_data(uint32_t *data)
|
||||
{
|
||||
uint32_t temp = *data;
|
||||
|
||||
*data = ENDIAN_SWAP(temp);
|
||||
}
|
||||
|
||||
void *
|
||||
memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
const uint8_t *src8 = src;
|
||||
uint8_t *dst8 = dest;
|
||||
|
||||
for (; n > 0; n--) {
|
||||
*dst8 = *src8;
|
||||
dst8++;
|
||||
src8++;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Get string length by finding null terminating char */
|
||||
size_t
|
||||
strlen(const char *s)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while ((s[i] != 0) && (i < MAXSTRLEN))
|
||||
i++;
|
||||
|
||||
if (i == MAXSTRLEN)
|
||||
return -1;
|
||||
else
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Simple wait loop */
|
||||
void
|
||||
waitloop(int32_t loopcnt)
|
||||
{
|
||||
for (; loopcnt > 0; loopcnt--)
|
||||
asm(" NOP");
|
||||
}
|
||||
|
||||
void
|
||||
sleep_ms(int ms)
|
||||
{
|
||||
for (; ms > 0; ms--)
|
||||
waitloop(20000);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* util.h - miscellaneous functions prototypes
|
||||
*
|
||||
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||||
*
|
||||
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||||
* Copyright 2008 Texas Instruments, Inc. <www.ti.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* For memcpy & memset prototypes */
|
||||
|
||||
void endian_data(uint32_t *data);
|
||||
|
||||
void waitloop(int32_t loopcnt);
|
||||
void sleep_ms(int ms);
|
||||
|
||||
#endif /* _UTIL_H_ */
|
Loading…
Reference in New Issue