diff --git a/qiboot/6410-partition-sd.sh b/qiboot/6410-partition-sd.sh new file mode 100755 index 0000000..8dd5f30 --- /dev/null +++ b/qiboot/6410-partition-sd.sh @@ -0,0 +1,283 @@ +#!/bin/sh +# 6410 SD Boot formatter +# (C) 2008 Openmoko, Inc +# Author: Andy Green + +# LAYOUT (if partition parameter is not specified) +# Partition table, then +# VFAT takes up remaining space here +# then... +# +EXT3_ROOTFS_SECTORS=$(( 256 * 1024 * 2 )) +EXT3_BACKUP_FS_SECTORS=$(( 8 * 1024 * 2 )) +QI_ALLOCATION=$(( 256 * 2 )) +# +# lastly fixed stuff: 8KByte initial boot, sig, padding +# +# ---------------------- + +echo "s3c6410 bootable SD partitioning utility" +echo "(C) Openmoko, Inc Andy Green " +echo + +# these are fixed in iROM +QI_INITIAL=$(( 8 * 2 )) +SIG=1 + + +# display usage message and exit +# any arguments are displayed as an error message +USAGE() +{ + echo + [ -z "$1" ] || echo ERROR: $* + echo + echo 'This formats a SD card for usage on SD Card boot' + echo ' on 6410 based systems' + echo + echo Usage: $(basename "$0") ' ' + echo ' device = disk device name for SD Card, e.g. sde /dev/sdf' + echo ' card = sd | sdhc' + echo ' bootloader = /path/to/qi-binary' + echo ' partition = vfat | NN | NN,NN | NN,NN,NN | NN,NN,NN,NN | no' + echo ' * vfat -> main-vfat[rest] + rootfs[256M] + backupfs[8M]' + echo ' NN -> rootfs1[NN%] + .. + rootfs4[NN%]' + echo ' NN=0 -> will skip the partition' + echo ' no -> leave partitions alone' + echo + echo 'Note: * => default action if no parameter specified' + echo ' sum(NN) must be in [1..100]' + echo + echo 'e.g. '$(basename "$0")' sdb sdhc images/qi 0,30,0,45' + echo ' will format an SDHC with partition 2 receiving 20% and partition 4' + echo ' receiving 45% of the disk capacity and the remaining 35% will be' + echo ' unused.' + echo ' Capacity is calculated after subtracting the space reserved for Qi.' + echo ' Partitions 1 and 3 will not be used.' + exit 1 +} + +[ -z "$1" -o -z "$2" -o -z "$3" ] && USAGE 'Missing arguments' + +dev="$1" +card="$2" +qi="$3" +partition="$4" + +case "${card}" in + [sS][dD][hH][cC]) + PADDING=1025 + ;; + [sS][dD]) + PADDING=1 + ;; + *) + USAGE "${card} is an unknown card type" +esac + +# the amount of space that must remain unused at the end of the disk +REAR_SECTORS=$(( $QI_ALLOCATION + $QI_INITIAL + $SIG + $PADDING )) + +# validate parameters +[ -b "${dev}" ] || dev="/dev/${dev}" +[ -b "${dev}" ] || USAGE "${dev} is not a valid block device" +[ X"${dev}" = X"${dev%%[0-9]}" ] || USAGE "${dev} is a partition, please use device: perhaps ${dev%%[0-9]}" + +echo "Checking for mounted partitions..." +grep "${dev}" /proc/mounts && USAGE "partitions on ${dev} are mounted, please unmount them" +[ -e "${qi}" ] || USAGE "bootloader file: ${qi} does not exist" + +# get size of device +bytes=$(echo p | fdisk "${dev}" 2>&1 | sed '/^Disk.*, \([0-9]*\) bytes/s//\1/p;d') +SECTORS=$(($bytes / 512)) + +[ -z "$SECTORS" ] && USAGE "could not find size for ${dev}" +[ "$SECTORS" -le 0 ] && USAGE "invalid size: '${SECTORS}' for ${dev}" + +echo "${dev} is $SECTORS 512-byte blocks" + + +# Partition and format a disk (or SD card) +# Parameters to format function are: +# +# device -> device to partition e.g. /dev/sdX +# +# Partition 1 parameters: +# +# label -> file system volume label e.g. rootfs +# sizeMB -> size of the partition in MB e.g. 256 +# fstype -> filesystem type e.g. ext2, ext3, vfat (look at /sbin/mkfs.* for others) +# +# Notes: 1. Repeat "label, sizeMB, fstype" for partitions 2..4 +# 2. Partitions 2..4 are optional +# 3. Do not repeat device parameter +# 4. To skip a partition use: 'null 0 none' for that partition + +FORMAT() +{ + local device label sizeMB fstype p partition flag skip + device="$1"; shift + ( + p=0 + flag=0 + echo o + while [ $# -gt 0 ] + do + label="$1"; shift + sizeMB="$1"; shift + fstype="$1"; shift + p=$((${p} + 1)) + skip=NO + [ ${sizeMB} -le 0 ] && skip=YES + case "${label}" in + [nN][uU][lL][lL]) + skip=YES + ;; + *) + ;; + esac + case "${skip}" in + [yY][eE][sS]|[yY]) + ;; + *) + echo n + echo p + echo ${p} + echo + echo +${sizeMB}M + case "${fstype}" in + [vV][fF][aA][tT]|[mM][sS][dD][oO][sS]) + echo t + # fdisk is "helpful" & will auto select partition if there is only one + # so do not output partition number if this is the first partition + [ "${flag}" -eq 1 ] && echo ${p} + echo 0b + ;; + *) + ;; + esac + flag=1 + ;; + esac + done + echo p + echo w + echo q + ) | fdisk "${device}" + p=0 + while [ $# -gt 0 ] + do + label="$1"; shift + sizeMB="$1"; shift + fstype="$1"; shift + p=$((${p} + 1)) + partition="${dev}${p}" + skip=NO + [ ${sizeMB} -eq 0 ] && skip=YES + case "${label}" in + [nN][uU][lL][lL]) + skip=YES + ;; + esac + + case "${skip}" in + [yY][eE][sS]|[yY]) + echo "Skipping: ${partition}" + ;; + *) + echo "Formatting: ${partition} -> ${fstype}[${sizeMB}MB]" + case "${fstype}" in + [vV][fF][aA][tT]|[mM][sS][dD][oO][sS]) + mkfs.${fstype} -n "${label}" "${partition}" + ;; + *) + mkfs.${fstype} -L "${label}" "${partition}" + ;; + esac + ;; + esac + done +} + +# format the disk +case "${partition}" in + + # this case also hadles the default case (i.e. empty string: "") + [vV][fF][aA][tT]|"") + EXT3_TOTAL_SECTORS=$(( $EXT3_ROOTFS_SECTORS + $EXT3_BACKUP_FS_SECTORS )) + FAT_SECTORS=$(( $SECTORS - $EXT3_TOTAL_SECTORS - $REAR_SECTORS )) + FAT_MB=$(( $FAT_SECTORS / 2048 )) + EXT3_ROOTFS_MB=$(( ${EXT3_ROOTFS_SECTORS} / 2048 )) + EXT3_BACKUP_FS_MB=$(( ${EXT3_BACKUP_FS_SECTORS} / 2048 )) + + echo Creating VFAT partition of ${FAT_MB} MB + echo Creating Linux partition of ${EXT3_ROOTFS_MB} MB + echo Creating backup Linux partition of ${EXT3_BACKUP_FS_MB} MB + FORMAT "${dev}" \ + main-vfat "${FAT_MB}" vfat \ + rootfs "${EXT3_ROOTFS_MB}" ext3 \ + backupfs "${EXT3_BACKUP_FS_MB}" ext3 + ;; + + # decode partition or partition list + *,*|100|[1-9][0-9]|[1-9]) + arg="${partition}," + for v in 1 2 3 4 + do + eval n${v}="\${arg%%,*}" + eval n${v}="\${n${v}:-0}" + arg="${arg#*,}," + done + total=$(( ${n1} + ${n2} + ${n3} + ${n4} )) + echo Percentage of disk partitioned = ${total}% + [ ${total} -gt 100 -o ${total} -lt 1 ] && USAGE partition: "'${partition}' => ${total}% outside [1..100]" + + EXT3_TOTAL_SECTORS=$(( $SECTORS - $REAR_SECTORS )) + EXT3_ROOTFS1_SECTORS=$(( $EXT3_TOTAL_SECTORS * $n1 / 100 )) + EXT3_ROOTFS2_SECTORS=$(( $EXT3_TOTAL_SECTORS * $n2 / 100 )) + EXT3_ROOTFS3_SECTORS=$(( $EXT3_TOTAL_SECTORS * $n3 / 100 )) + EXT3_ROOTFS4_SECTORS=$(( $EXT3_TOTAL_SECTORS * $n4 / 100 )) + EXT3_ROOTFS1_MB=$(( ${EXT3_ROOTFS1_SECTORS} / 2048 )) + EXT3_ROOTFS2_MB=$(( ${EXT3_ROOTFS2_SECTORS} / 2048 )) + EXT3_ROOTFS3_MB=$(( ${EXT3_ROOTFS3_SECTORS} / 2048 )) + EXT3_ROOTFS4_MB=$(( ${EXT3_ROOTFS4_SECTORS} / 2048 )) + + echo Creating Linux partition 1 of ${EXT3_ROOTFS1_MB} MB + echo Creating Linux partition 2 of ${EXT3_ROOTFS2_MB} MB + echo Creating Linux partition 3 of ${EXT3_ROOTFS3_MB} MB + echo Creating Linux partition 4 of ${EXT3_ROOTFS4_MB} MB + + FORMAT "${dev}" \ + rootfs1 "${EXT3_ROOTFS1_MB}" ext3 \ + rootfs2 "${EXT3_ROOTFS2_MB}" ext3 \ + rootfs3 "${EXT3_ROOTFS3_MB}" ext3 \ + rootfs4 "${EXT3_ROOTFS4_MB}" ext3 + ;; + + [Nn]*) + # do not format + ;; + + *) + USAGE "'${partition}' is an unknown partition config" + ;; +esac + + +# copy the full bootloader image to the right place after the +# partitioned area +echo +echo Installing Qi bootloader from: ${qi} + +dd if="${qi}" of="${dev}" bs=512 count=512 \ + seek=$(( $SECTORS - $REAR_SECTORS )) +dd if="${qi}" of="${dev}" bs=512 \ + seek=$(( $SECTORS - $REAR_SECTORS + $QI_ALLOCATION )) \ + count=$QI_INITIAL +dd if=/dev/zero of="${dev}" bs=512 \ + seek=$(( $SECTORS - $REAR_SECTORS + $QI_ALLOCATION + $QI_INITIAL )) \ + count=$(( $SIG + $PADDING )) + +# done +echo +echo "**** completed" diff --git a/qiboot/Makefile b/qiboot/Makefile new file mode 100644 index 0000000..2ac0e2c --- /dev/null +++ b/qiboot/Makefile @@ -0,0 +1,93 @@ +# 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., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include config.mk + +BUILD_DATE := $(shell date) +BUILD_HOST := $(shell hostname) +BUILD_BRANCH := $(shell git branch | grep ^\* | cut -d' ' -f2) +BUILD_HEAD := $(shell git show --pretty=oneline | head -n1 | cut -d' ' -f1 | cut -b1-16) +BUILD_VERSION := ${BUILD_BRANCH}_${BUILD_HEAD} + +LDS = src/cpu/$(CPU)/qi.lds +INCLUDE = include +IMAGE_DIR = image +TOOLS = tools +CFLAGS = -Wall -Werror -I $(INCLUDE) -g -c -Os -fno-strict-aliasing -mlong-calls \ + -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding \ + -march=armv4t -mno-thumb-interwork -Wstrict-prototypes \ + -DBUILD_HOST="${BUILD_HOST}" -DBUILD_VERSION="${BUILD_VERSION}" \ + -DBUILD_DATE="${BUILD_DATE}" -DQI_CPU="${CPU}" +LDFLAGS = + +S_SRCS = $(wildcard src/cpu/$(CPU)/*.S) +S_OBJS = $(patsubst %.S,%.o, $(S_SRCS)) +C_SRCS = $(wildcard src/*.c) \ + $(wildcard src/drivers/*.c) $(wildcard src/fs/*.c) \ + $(wildcard src/cpu/$(CPU)/*.c) +C_OBJS = $(patsubst %.c,%.o, $(C_SRCS)) + +SRCS = ${S_SRCS} ${C_SRCS} +OBJS = ${S_OBJS} ${C_OBJS} +LIBS = -L${COMPILER_LIB_PATH} -lgcc + +ifeq ($(CPU),s3c2410) + # GTA01 U-Boot IDs + UDFU_VID = 0x1457 + UDFU_PID = 0x5119 + UDFU_REV = 0x0240 +else + # GTA02 A5 and A6 U-Boot will eat these for DFU action + UDFU_VID = 0x1d50 + UDFU_PID = 0x5119 + UDFU_REV = 0x350 +endif + +TARGET = $(IMAGE_DIR)/start_qi_all-$(CPU) +IMAGE = $(IMAGE_DIR)/qi-$(CPU)-$(BUILD_VERSION) +UDFU_IMAGE = $(IMAGE_DIR)/qi-$(CPU)-$(BUILD_VERSION).udfu + +MKUDFU = $(TOOLS)/mkudfu + +%.o: %.S + @$(CC) $(CFLAGS) -o $@ $< + +%.o: %.c + @$(CC) $(CFLAGS) -o $@ $< + +all:${UDFU_IMAGE} + +${OBJS}:${SRCS} ${INCLUDE}/*.h + +${MKUDFU}: + make -C $(TOOLS) + +${UDFU_IMAGE}:${OBJS} ${MKUDFU} + mkdir -p image + @$(LD) ${LDFLAGS} -T$(LDS) -g $(OBJS) -o ${TARGET} ${LIBS} + @$(OBJCOPY) -O binary -S ${TARGET} ${IMAGE} + @$(MKUDFU) -v ${UDFU_VID} -p ${UDFU_PID} -r ${UDFU_REV} \ + -d ${IMAGE} ${UDFU_IMAGE} + @$(OBJDUMP) -d ${TARGET} >${IMAGE}.dis + +clean: + @rm -f *~ src/*.o src/*~ + @rm -f src/cpu/*/*.o src/cpu/*/*~ + @rm -f src/drivers/*.o src/drivers/*~ + @rm -f src/fs/*.o src/fs/*~ + @rm -f include/*~ ${IMAGE_DIR}/* + @make clean -C $(TOOLS) + diff --git a/qiboot/README b/qiboot/README new file mode 100644 index 0000000..0ab7a3f --- /dev/null +++ b/qiboot/README @@ -0,0 +1,149 @@ +Qi +== + +Qi (named by Alan Cox on Openmoko kernel list) is a minimal bootloader that +"breathes life" into Linux. Its goal is to stay close to the minimum needed +to "load" and then "boot" Linux -- no boot menus, additional peripheral init +or private states. + + +What's wrong with U-Boot, they keep telling people to not reinvent the wheel? +============================================================================= + +U-Boot is gradually becoming a simplified knockoff of Linux. After using it a +while, it became clear we were cutting and pasting drivers into U-Boot from +Linux, cutting them down and not having a plan to maintain the U-Boot versions +as the Linux ones were changed. + +We decided that we would use full Linux for things that Linux is good at and +only have the bootloader do the device init that is absolutely required before +Linux can be pulled into memory and started. In practice since we had a working +U-Boot implementation it meant cutting that right down to the bone (start.S +mainly for s3c2442) and then building it up from scratch optimized to just do +load and boot. + + +Samsung - specific boot sequence +================================ + +Right now Qi supports Samsung "steppingstone" scheme devices, but in fact it's +the same in processors like iMX31 that there is a small area of SRAM that is +prepped with NAND content via ROM on the device. There's nothing that stops Qi +use on processors without steppingstone, although the ATAG stuff assumes we deal +with ARM based processor. + + +Per-CPU Qi +========== + +Qi has a concept of a single bootloader binary created per CPU type. The +different devices that use that CPU are all supported in the same binary. At +runtime after the common init is done, Qi asks each supported device code in +turn if it recognizes the device as being handled by it, the first one to reply +that it knows the device gets to control the rest of the process. + +Consequently, there is NO build-time configuration file as found on U-Boot +except a make env var that sets the CPU type being built, eg: + + make CPU=s3c6410 + + +Booting Heuristics +================== + +Qi has one or more ways to fetch a kernel depending on the device it finds it is +running on, for example on GTA02 it can use NAND and SD card devices. It goes +through these device-specific storage devices in order and tries to boot the +first viable kernel it finds, usually /boot/.bin for example +/boot/uImage-GTA02.bin. + +The default order for GTA02 is: 1st SD primary partition, 2nd primary +partition, 3rd primary partition, NAND kernel partition. + +You can disable a rootfs for consideration for boot if you add a file +/boot/noboot-, eg, /boot/noboot-GTA02. This differs from renaming or +deleting the kernel image because updating the kernel package would give you a +working kernel again and allow boot, whereas the noboot indication will remain +until you remove it. + +The kernel commandline used is associated with the storage device and partition, +this allows the correct root= line to be arrived at without any work. + +If no kernel image can be found, Qi falls back to doing a memory test. + + +Appending to commandline +======================== + +You can append to the Qi commandline by creating a file /boot/append-, +eg, /boot/append-GTA02 containing the additional kernel commandline you want. + +This means you can affect the boot per-rootfs, but that if you reimage the +rootfs you at the same time define what is appeneded. Because these files are +looked for with the name in them, options can be selected depending on +the device the rootfs is run on. + + +Initrd support +============== + +Initrd or initramfs in separate file is supported to be loaded at given +memory address in addition to kernel image. The ATAGs are issued accordingly. + + +Interactive UI +============== + +Being minimalistic by its nature, Qi has very limited abilities to +interact with a user. On GTA02 the red LED and the vibrator are used +(if the battery is in good condition) to notify user of the following +actions: + +The LED is turned on either on: + - Successful partition mount + - Successful kernel pull + - Successful initramfs pull + +The LED is turned off and vibrator runs briefly either on: + - Fail of kernel pull + - Fail of initramfs pull + - Fail of mount partition + - Skipping of current boot possibility + +The LED is turned off either on: + - Start of the kernel + - Start of the mem test + - Start of the kernel pull + - Start of the initramfs pull + +If a user presses the AUX button after successful partition mount and +before start of the kernel pull (that is, while the red LED is on), +this boot possibility is skipped (and GTA02 owners can feel +vibration). If a user holds the POWER button just before start of the +kernel, debugging parameters are added to the kernel command line +and a lot of information is output to the screen. + +Functional Differences from U-Boot on GTA02 +=========================================== + + - Backlight and USB is not enabled until Linux starts after a few seconds + + - No startup splash screen + + - by default there is no boot spew on the LCM + + - On GTAxx boots from first uSD ext2 / 3 partition containing + /boot/uImage-.bin present, eg, /boot/uImage-GTA02.bin, it checks + first three partitions in turn + + - On GTA01 and 02 if nothing is workable on the SD Card, or it is not present, + Qi will try to boot from NAND + + - You can disable a partition for boot by creating /boot/noboot-, + eg, /boot/noboot-GTA02, it will skip it and check the next partition + + - Way faster + + - There is no concept of "staying in the bootloader". The bootloader exits to + Linux as fast as possible, that's all it does. + diff --git a/qiboot/build b/qiboot/build new file mode 100755 index 0000000..87684bb --- /dev/null +++ b/qiboot/build @@ -0,0 +1,12 @@ +#!/bin/sh + +make clean && \ +make CPU=s3c6410 && \ +make CPU=s3c2442 && \ +make CPU=s3c2410 + +# as root then... +# +# ./6410-partition-sd.sh sde sdhc image/qi-s3c6410-andy_???????????????? x +# mount /dev/sde2 /mnt ; cp ../kernel/linux-2.6/uImage.bin /mnt/boot ; umount /dev/sde2 + diff --git a/qiboot/config.mk b/qiboot/config.mk new file mode 100644 index 0000000..1fee1a3 --- /dev/null +++ b/qiboot/config.mk @@ -0,0 +1,22 @@ +# +# Include the make variables (CC, etc...) +# + +CROSS_PATH=/usr/local/openmoko/arm +CROSS_COMPILE=${CROSS_PATH}/bin/arm-angstrom-linux-gnueabi- + +#### +COMPILER_LIB_PATH_PRE=${CROSS_PATH}/lib/gcc/arm-angstrom-linux-gnueabi +COMPILER_LIB_PATH=${COMPILER_LIB_PATH_PRE}/`ls ${COMPILER_LIB_PATH_PRE}` + +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +CC = $(CROSS_COMPILE)gcc +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +HOSTCC = gcc + +# we need the mkudfu tool from U-Boot build +#MKUDFU = ../uboot/u-boot/tools/mkudfu + +export CROSS_COMPILE AD LD CC OBJCOPY OBJDUMP MKUDFU diff --git a/qiboot/dfu-qi b/qiboot/dfu-qi new file mode 100755 index 0000000..f5e6e1e --- /dev/null +++ b/qiboot/dfu-qi @@ -0,0 +1,7 @@ +#!/bin/bash +../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5119 -D image/qi-s3c2442*.udfu +if [ $? -eq 1 ] ; then +../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5120 -D image/qi-s3c2442*.udfu +../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5119 -D image/qi-s3c2442*.udfu +fi + diff --git a/qiboot/gta02-qi.ocd b/qiboot/gta02-qi.ocd new file mode 100755 index 0000000..9d2cf1f --- /dev/null +++ b/qiboot/gta02-qi.ocd @@ -0,0 +1,34 @@ +# gta02 Qi script +# Andy Green + +reset halt +wait_halt +sleep 2000 + +# bring the steppingstone part of qi image into steppingstone +# +load_binary /projects/openmoko/bootloader/image/qi 0x0 +# +# mark ourselves as JTAG load +# +mww 0x4 0xffffffff + +# +# we have to run that so SDRAM exists in a usable way +# fixed jumpthrough at 0x8 is executed after steppingstone +# init (including RAM) has completed +# +bp 0x8 4 hw +resume 0x0 +wait_halt +rbp 0x8 + +# +# now prep the SDRAM +# +load_binary /projects/openmoko/bootloader/image/qi 0x33000000 +# +# and continue... +resume 0x8 +# + diff --git a/qiboot/include/ext2.h b/qiboot/include/ext2.h new file mode 100644 index 0000000..85b0860 --- /dev/null +++ b/qiboot/include/ext2.h @@ -0,0 +1,80 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * (C) Copyright 2003 Sysgo Real-Time Solutions, AG + * Pavel Bartusek + * + * 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. + */ + +/* An implementation for the Ext2FS filesystem ported from GRUB. + * Some parts of this code (mainly the structures and defines) are + * from the original ext2 fs code, as found in the linux kernel. + */ + + +#define SECTOR_SIZE 0x200 +#define SECTOR_BITS 9 + +/* Error codes */ +typedef enum +{ + ERR_NONE = 0, + ERR_BAD_FILENAME, + ERR_BAD_FILETYPE, + ERR_BAD_GZIP_DATA, + ERR_BAD_GZIP_HEADER, + ERR_BAD_PART_TABLE, + ERR_BAD_VERSION, + ERR_BELOW_1MB, + ERR_BOOT_COMMAND, + ERR_BOOT_FAILURE, + ERR_BOOT_FEATURES, + ERR_DEV_FORMAT, + ERR_DEV_VALUES, + ERR_EXEC_FORMAT, + ERR_FILELENGTH, + ERR_FILE_NOT_FOUND, + ERR_FSYS_CORRUPT, + ERR_FSYS_MOUNT, + ERR_GEOM, + ERR_NEED_LX_KERNEL, + ERR_NEED_MB_KERNEL, + ERR_NO_DISK, + ERR_NO_PART, + ERR_NUMBER_PARSING, + ERR_OUTSIDE_PART, + ERR_READ, + ERR_SYMLINK_LOOP, + ERR_UNRECOGNIZED, + ERR_WONT_FIT, + ERR_WRITE, + ERR_BAD_ARGUMENT, + ERR_UNALIGNED, + ERR_PRIVILEGED, + ERR_DEV_NEED_INIT, + ERR_NO_DISK_SPACE, + ERR_NUMBER_OVERFLOW, + + MAX_ERR_NUM +} ext2fs_error_t; + + +extern int ext2fs_ls(char *dirname); +extern int ext2fs_open(const char *filename); +extern int ext2fs_read(char *buf, unsigned len); +extern int ext2fs_mount(void); +extern int ext2fs_close(void); diff --git a/qiboot/include/fat.h b/qiboot/include/fat.h new file mode 100644 index 0000000..f993cca --- /dev/null +++ b/qiboot/include/fat.h @@ -0,0 +1,220 @@ +/* + * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg + * + * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 + * 2003-03-10 - kharris@nexus-tech.net - ported to u-boot + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef _FAT_H_ +#define _FAT_H_ + +#include + +#define CONFIG_SUPPORT_VFAT + +#define SECTOR_SIZE FS_BLOCK_SIZE + +#define FS_BLOCK_SIZE 512 + +#if FS_BLOCK_SIZE != SECTOR_SIZE +#error FS_BLOCK_SIZE != SECTOR_SIZE - This code needs to be fixed! +#endif + +#define MAX_CLUSTSIZE 65536 +#define DIRENTSPERBLOCK (FS_BLOCK_SIZE/sizeof(dir_entry)) +#define DIRENTSPERCLUST ((mydata->clust_size*SECTOR_SIZE)/sizeof(dir_entry)) + +#define FATBUFBLOCKS 6 +#define FATBUFSIZE (FS_BLOCK_SIZE*FATBUFBLOCKS) +#define FAT12BUFSIZE ((FATBUFSIZE*2)/3) +#define FAT16BUFSIZE (FATBUFSIZE/2) +#define FAT32BUFSIZE (FATBUFSIZE/4) + + +/* Filesystem identifiers */ +#define FAT12_SIGN "FAT12 " +#define FAT16_SIGN "FAT16 " +#define FAT32_SIGN "FAT32 " +#define SIGNLEN 8 + +/* File attributes */ +#define ATTR_RO 1 +#define ATTR_HIDDEN 2 +#define ATTR_SYS 4 +#define ATTR_VOLUME 8 +#define ATTR_DIR 16 +#define ATTR_ARCH 32 + +#define ATTR_VFAT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) + +#define DELETED_FLAG ((char)0xe5) /* Marks deleted files when in name[0] */ +#define aRING 0x05 /* Used to represent 'å' in name[0] */ + +/* Indicates that the entry is the last long entry in a set of long + * dir entries + */ +#define LAST_LONG_ENTRY_MASK 0x40 + +/* Flags telling whether we should read a file or list a directory */ +#define LS_NO 0 +#define LS_YES 1 +#define LS_DIR 1 +#define LS_ROOT 2 + +#ifdef DEBUG +#define FAT_DPRINT(args...) printf(args) +#else +#define FAT_DPRINT(args...) +#endif +#define FAT_ERROR(arg) printf(arg) + +#define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') + +#define FSTYPE_NONE (-1) + +#if defined(__linux__) && defined(__KERNEL__) +#define FAT2CPU16 le16_to_cpu +#define FAT2CPU32 le32_to_cpu +#else +#if __LITTLE_ENDIAN +#define FAT2CPU16(x) (x) +#define FAT2CPU32(x) (x) +#else +#define FAT2CPU16(x) ((((x) & 0x00ff) << 8) | (((x) & 0xff00) >> 8)) +#define FAT2CPU32(x) ((((x) & 0x000000ff) << 24) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0xff000000) >> 24)) +#endif +#endif + +#define TOLOWER(c) if((c) >= 'A' && (c) <= 'Z'){(c)+=('a' - 'A');} +#define START(dent) (FAT2CPU16((dent)->start) \ + + (mydata->fatsize != 32 ? 0 : \ + (FAT2CPU16((dent)->starthi) << 16))) +#define CHECK_CLUST(x, fatsize) ((x) <= 1 || \ + (x) >= ((fatsize) != 32 ? 0xfff0 : 0xffffff0)) + +typedef struct boot_sector { + __u8 ignored[3]; /* Bootstrap code */ + char system_id[8]; /* Name of fs */ + __u8 sector_size[2]; /* Bytes/sector */ + __u8 cluster_size; /* Sectors/cluster */ + __u16 reserved; /* Number of reserved sectors */ + __u8 fats; /* Number of FATs */ + __u8 dir_entries[2]; /* Number of root directory entries */ + __u8 sectors[2]; /* Number of sectors */ + __u8 media; /* Media code */ + __u16 fat_length; /* Sectors/FAT */ + __u16 secs_track; /* Sectors/track */ + __u16 heads; /* Number of heads */ + __u32 hidden; /* Number of hidden sectors */ + __u32 total_sect; /* Number of sectors (if sectors == 0) */ + + /* FAT32 only */ + __u32 fat32_length; /* Sectors/FAT */ + __u16 flags; /* Bit 8: fat mirroring, low 4: active fat */ + __u8 version[2]; /* Filesystem version */ + __u32 root_cluster; /* First cluster in root directory */ + __u16 info_sector; /* Filesystem info sector */ + __u16 backup_boot; /* Backup boot sector */ + __u16 reserved2[6]; /* Unused */ +} boot_sector; + +typedef struct volume_info +{ + __u8 drive_number; /* BIOS drive number */ + __u8 reserved; /* Unused */ + __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ + __u8 volume_id[4]; /* Volume ID number */ + char volume_label[11]; /* Volume label */ + char fs_type[8]; /* Typically FAT12, FAT16, or FAT32 */ + /* Boot code comes next, all but 2 bytes to fill up sector */ + /* Boot sign comes last, 2 bytes */ +} volume_info; + +typedef struct dir_entry { + char name[8],ext[3]; /* Name and extension */ + __u8 attr; /* Attribute bits */ + __u8 lcase; /* Case for base and extension */ + __u8 ctime_ms; /* Creation time, milliseconds */ + __u16 ctime; /* Creation time */ + __u16 cdate; /* Creation date */ + __u16 adate; /* Last access date */ + __u16 starthi; /* High 16 bits of cluster in FAT32 */ + __u16 time,date,start;/* Time, date and first cluster */ + __u32 size; /* File size in bytes */ +} dir_entry; + +typedef struct dir_slot { + __u8 id; /* Sequence number for slot */ + __u8 name0_4[10]; /* First 5 characters in name */ + __u8 attr; /* Attribute byte */ + __u8 reserved; /* Unused */ + __u8 alias_checksum;/* Checksum for 8.3 alias */ + __u8 name5_10[12]; /* 6 more characters in name */ + __u16 start; /* Unused */ + __u8 name11_12[4]; /* Last 2 characters in name */ +} dir_slot; + +/* Private filesystem parameters + * + * Note: FAT buffer has to be 32 bit aligned + * (see FAT32 accesses) + */ +typedef struct { + __u8 fatbuf[FATBUFSIZE]; /* Current FAT buffer */ + int fatsize; /* Size of FAT in bits */ + __u16 fatlength; /* Length of FAT in sectors */ + __u16 fat_sect; /* Starting sector of the FAT */ + __u16 rootdir_sect; /* Start sector of root directory */ + __u16 clust_size; /* Size of clusters in sectors */ + short data_begin; /* The sector of the first cluster, can be negative */ + int fatbufnum; /* Used by get_fatent, init to -1 */ +} fsdata; + +typedef int (file_detectfs_func)(void); +typedef int (file_ls_func)(const char *dir); +typedef long (file_read_func)(const char *filename, void *buffer, + unsigned long maxsize); + +struct filesystem { + file_detectfs_func *detect; + file_ls_func *ls; + file_read_func *read; + const char name[12]; +}; + +/* FAT tables */ +file_detectfs_func file_fat_detectfs; +file_ls_func file_fat_ls; +file_read_func file_fat_read; + +/* Currently this doesn't check if the dir exists or is valid... */ +int file_cd(const char *path); +int file_fat_detectfs(void); +int file_fat_ls(const char *dir); +long file_fat_read(const char *filename, void *buffer, unsigned long maxsize); +const char *file_getfsname(int idx); +int fat_register_device(block_dev_desc_t *dev_desc, int part_no); + +#endif /* _FAT_H_ */ diff --git a/qiboot/include/glamo-init.h b/qiboot/include/glamo-init.h new file mode 100644 index 0000000..ca43d8a --- /dev/null +++ b/qiboot/include/glamo-init.h @@ -0,0 +1 @@ +extern void glamo_core_init(void); diff --git a/qiboot/include/glamo-mmc.h b/qiboot/include/glamo-mmc.h new file mode 100644 index 0000000..48e8161 --- /dev/null +++ b/qiboot/include/glamo-mmc.h @@ -0,0 +1,149 @@ +#ifndef __GLAMO_MMC_H__ +#define __GLAMO_MMC_H__ + +/* Standard MMC commands (4.1) type argument response */ + /* class 1 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ +#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ + +#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ + + /* class 2 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 3 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4 */ +#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 38 /* ac R1b */ + + /* class 9 */ +#define MMC_FAST_IO 39 /* ac R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ + + /* class 7 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ + +#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ +#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + + +#define MMC_RSP_PRESENT (1 << 0) +#define MMC_RSP_136 (1 << 1) /* 136 bit response */ +#define MMC_RSP_CRC (1 << 2) /* expect valid crc */ +#define MMC_RSP_BUSY (1 << 3) /* card may send busy */ +#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ + +#define MMC_CMD_MASK (3 << 5) /* non-SPI command type */ +#define MMC_CMD_AC (0 << 5) +#define MMC_CMD_ADTC (1 << 5) +#define MMC_CMD_BC (2 << 5) +#define MMC_CMD_BCR (3 << 5) + +#define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ +#define MMC_RSP_SPI_S2 (1 << 8) /* second byte */ +#define MMC_RSP_SPI_B4 (1 << 9) /* four data bytes */ +#define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ + +/* + * These are the native response types, and correspond to valid bit + * patterns of the above flags. One additional valid pattern + * is all zeros, which means we don't expect a response. + */ +#define MMC_RSP_NONE (0) +#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) +#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) +#define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) + +#define mmc_resp_type(f) ((f) & (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC |\ + MMC_RSP_BUSY | MMC_RSP_OPCODE)) +#define mmc_cmd_type(f) ((f) & MMC_CMD_MASK) + +/* + * These are the SPI response types for MMC, SD, and SDIO cards. + * Commands return R1, with maybe more info. Zero is an error type; + * callers must always provide the appropriate MMC_RSP_SPI_Rx flags. + */ +#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) +#define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY) +#define MMC_RSP_SPI_R2 (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2) +#define MMC_RSP_SPI_R3 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) +#define MMC_RSP_SPI_R4 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) +#define MMC_RSP_SPI_R5 (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2) +#define MMC_RSP_SPI_R7 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) + +#define MMC_DATA_WRITE (1 << 8) +#define MMC_DATA_READ (1 << 9) +#define MMC_DATA_STREAM (1 << 10) + +struct sd_cid { + char pnm_0; /* product name */ + char oid_1; /* OEM/application ID */ + char oid_0; + u8 mid; /* manufacturer ID */ + char pnm_4; + char pnm_3; + char pnm_2; + char pnm_1; + u8 psn_2; /* product serial number */ + u8 psn_1; + u8 psn_0; /* MSB */ + u8 prv; /* product revision */ + u8 crc; /* CRC7 checksum, b0 is unused and set to 1 */ + u8 mdt_1; /* manufacturing date, LSB, RRRRyyyy yyyymmmm */ + u8 mdt_0; /* MSB */ + u8 psn_3; /* LSB */ +}; + +enum card_type { + CARDTYPE_NONE = 0, + CARDTYPE_MMC, + CARDTYPE_SD, + CARDTYPE_SD20, + CARDTYPE_SDHC +}; + + +#endif /* __GLAMO_MMC_H__ */ diff --git a/qiboot/include/glamo-regs.h b/qiboot/include/glamo-regs.h new file mode 100644 index 0000000..bfc3919 --- /dev/null +++ b/qiboot/include/glamo-regs.h @@ -0,0 +1,628 @@ +#ifndef _GLAMO_REGS_H +#define _GLAMO_REGS_H + +/* Smedia Glamo 336x/337x driver + * + * (C) 2007 by OpenMoko, Inc. + * Author: Harald Welte + * All rights reserved. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +enum glamo_regster_offsets { + GLAMO_REGOFS_GENERIC = 0x0000, + GLAMO_REGOFS_HOSTBUS = 0x0200, + GLAMO_REGOFS_MEMORY = 0x0300, + GLAMO_REGOFS_VIDCAP = 0x0400, + GLAMO_REGOFS_ISP = 0x0500, + GLAMO_REGOFS_JPEG = 0x0800, + GLAMO_REGOFS_MPEG = 0x0c00, + GLAMO_REGOFS_LCD = 0x1100, + GLAMO_REGOFS_MMC = 0x1400, + GLAMO_REGOFS_MPROC0 = 0x1500, + GLAMO_REGOFS_MPROC1 = 0x1580, + GLAMO_REGOFS_CMDQUEUE = 0x1600, + GLAMO_REGOFS_RISC = 0x1680, + GLAMO_REGOFS_2D = 0x1700, + GLAMO_REGOFS_3D = 0x1b00, + GLAMO_REGOFS_END = 0x2400, +}; + + +enum glamo_register_generic { + GLAMO_REG_GCONF1 = 0x0000, + GLAMO_REG_GCONF2 = 0x0002, +#define GLAMO_REG_DEVICE_ID GLAMO_REG_GCONF2 + GLAMO_REG_GCONF3 = 0x0004, +#define GLAMO_REG_REVISION_ID GLAMO_REG_GCONF3 + GLAMO_REG_IRQ_GEN1 = 0x0006, +#define GLAMO_REG_IRQ_ENABLE GLAMO_REG_IRQ_GEN1 + GLAMO_REG_IRQ_GEN2 = 0x0008, +#define GLAMO_REG_IRQ_SET GLAMO_REG_IRQ_GEN2 + GLAMO_REG_IRQ_GEN3 = 0x000a, +#define GLAMO_REG_IRQ_CLEAR GLAMO_REG_IRQ_GEN3 + GLAMO_REG_IRQ_GEN4 = 0x000c, +#define GLAMO_REG_IRQ_STATUS GLAMO_REG_IRQ_GEN4 + GLAMO_REG_CLOCK_HOST = 0x0010, + GLAMO_REG_CLOCK_MEMORY = 0x0012, + GLAMO_REG_CLOCK_LCD = 0x0014, + GLAMO_REG_CLOCK_MMC = 0x0016, + GLAMO_REG_CLOCK_ISP = 0x0018, + GLAMO_REG_CLOCK_JPEG = 0x001a, + GLAMO_REG_CLOCK_3D = 0x001c, + GLAMO_REG_CLOCK_2D = 0x001e, + GLAMO_REG_CLOCK_RISC1 = 0x0020, /* 3365 only? */ + GLAMO_REG_CLOCK_RISC2 = 0x0022, /* 3365 only? */ + GLAMO_REG_CLOCK_MPEG = 0x0024, + GLAMO_REG_CLOCK_MPROC = 0x0026, + + GLAMO_REG_CLOCK_GEN5_1 = 0x0030, + GLAMO_REG_CLOCK_GEN5_2 = 0x0032, + GLAMO_REG_CLOCK_GEN6 = 0x0034, + GLAMO_REG_CLOCK_GEN7 = 0x0036, + GLAMO_REG_CLOCK_GEN8 = 0x0038, + GLAMO_REG_CLOCK_GEN9 = 0x003a, + GLAMO_REG_CLOCK_GEN10 = 0x003c, + GLAMO_REG_CLOCK_GEN11 = 0x003e, + GLAMO_REG_PLL_GEN1 = 0x0040, + GLAMO_REG_PLL_GEN2 = 0x0042, + GLAMO_REG_PLL_GEN3 = 0x0044, + GLAMO_REG_PLL_GEN4 = 0x0046, + GLAMO_REG_PLL_GEN5 = 0x0048, + GLAMO_REG_GPIO_GEN1 = 0x0050, + GLAMO_REG_GPIO_GEN2 = 0x0052, + GLAMO_REG_GPIO_GEN3 = 0x0054, + GLAMO_REG_GPIO_GEN4 = 0x0056, + GLAMO_REG_GPIO_GEN5 = 0x0058, + GLAMO_REG_GPIO_GEN6 = 0x005a, + GLAMO_REG_GPIO_GEN7 = 0x005c, + GLAMO_REG_GPIO_GEN8 = 0x005e, + GLAMO_REG_GPIO_GEN9 = 0x0060, + GLAMO_REG_GPIO_GEN10 = 0x0062, + GLAMO_REG_DFT_GEN1 = 0x0070, + GLAMO_REG_DFT_GEN2 = 0x0072, + GLAMO_REG_DFT_GEN3 = 0x0074, + GLAMO_REG_DFT_GEN4 = 0x0076, + + GLAMO_REG_PLL_GEN6 = 0x01e0, + GLAMO_REG_PLL_GEN7 = 0x01f0, +}; + +#define GLAMO_REG_HOSTBUS(x) (GLAMO_REGOFS_HOSTBUS-2+(x*2)) + +#define REG_MEM(x) (GLAMO_REGOFS_MEMORY+(x)) +#define GLAMO_REG_MEM_TIMING(x) (GLAMO_REG_MEM_TIMING1-2+(x*2)) + +enum glamo_register_mem { + GLAMO_REG_MEM_TYPE = REG_MEM(0x00), + GLAMO_REG_MEM_GEN = REG_MEM(0x02), + GLAMO_REG_MEM_TIMING1 = REG_MEM(0x04), + GLAMO_REG_MEM_TIMING2 = REG_MEM(0x06), + GLAMO_REG_MEM_TIMING3 = REG_MEM(0x08), + GLAMO_REG_MEM_TIMING4 = REG_MEM(0x0a), + GLAMO_REG_MEM_TIMING5 = REG_MEM(0x0c), + GLAMO_REG_MEM_TIMING6 = REG_MEM(0x0e), + GLAMO_REG_MEM_TIMING7 = REG_MEM(0x10), + GLAMO_REG_MEM_TIMING8 = REG_MEM(0x12), + GLAMO_REG_MEM_TIMING9 = REG_MEM(0x14), + GLAMO_REG_MEM_TIMING10 = REG_MEM(0x16), + GLAMO_REG_MEM_TIMING11 = REG_MEM(0x18), + GLAMO_REG_MEM_POWER1 = REG_MEM(0x1a), + GLAMO_REG_MEM_POWER2 = REG_MEM(0x1c), + GLAMO_REG_MEM_LCD_BUF1 = REG_MEM(0x1e), + GLAMO_REG_MEM_LCD_BUF2 = REG_MEM(0x20), + GLAMO_REG_MEM_LCD_BUF3 = REG_MEM(0x22), + GLAMO_REG_MEM_LCD_BUF4 = REG_MEM(0x24), + GLAMO_REG_MEM_BIST1 = REG_MEM(0x26), + GLAMO_REG_MEM_BIST2 = REG_MEM(0x28), + GLAMO_REG_MEM_BIST3 = REG_MEM(0x2a), + GLAMO_REG_MEM_BIST4 = REG_MEM(0x2c), + GLAMO_REG_MEM_BIST5 = REG_MEM(0x2e), + GLAMO_REG_MEM_MAH1 = REG_MEM(0x30), + GLAMO_REG_MEM_MAH2 = REG_MEM(0x32), + GLAMO_REG_MEM_DRAM1 = REG_MEM(0x34), + GLAMO_REG_MEM_DRAM2 = REG_MEM(0x36), + GLAMO_REG_MEM_CRC = REG_MEM(0x38), +}; + +#define GLAMO_MEM_TYPE_MASK 0x03 + +enum glamo_reg_mem_dram1 { + GLAMO_MEM_DRAM1_EN_SDRAM_CLK = (1 << 11), + GLAMO_MEM_DRAM1_SELF_REFRESH = (1 << 12), +}; + +enum glamo_reg_mem_dram2 { + GLAMO_MEM_DRAM2_DEEP_PWRDOWN = (1 << 12), +}; + +enum glamo_irq_index { + GLAMO_IRQIDX_HOSTBUS = 0, + GLAMO_IRQIDX_JPEG = 1, + GLAMO_IRQIDX_MPEG = 2, + GLAMO_IRQIDX_MPROC1 = 3, + GLAMO_IRQIDX_MPROC0 = 4, + GLAMO_IRQIDX_CMDQUEUE = 5, + GLAMO_IRQIDX_2D = 6, + GLAMO_IRQIDX_MMC = 7, + GLAMO_IRQIDX_RISC = 8, +}; + +enum glamo_irq { + GLAMO_IRQ_HOSTBUS = (1 << GLAMO_IRQIDX_HOSTBUS), + GLAMO_IRQ_JPEG = (1 << GLAMO_IRQIDX_JPEG), + GLAMO_IRQ_MPEG = (1 << GLAMO_IRQIDX_MPEG), + GLAMO_IRQ_MPROC1 = (1 << GLAMO_IRQIDX_MPROC1), + GLAMO_IRQ_MPROC0 = (1 << GLAMO_IRQIDX_MPROC0), + GLAMO_IRQ_CMDQUEUE = (1 << GLAMO_IRQIDX_CMDQUEUE), + GLAMO_IRQ_2D = (1 << GLAMO_IRQIDX_2D), + GLAMO_IRQ_MMC = (1 << GLAMO_IRQIDX_MMC), + GLAMO_IRQ_RISC = (1 << GLAMO_IRQIDX_RISC), +}; + +enum glamo_reg_clock_host { + GLAMO_CLOCK_HOST_DG_BCLK = 0x0001, + GLAMO_CLOCK_HOST_DG_M0CLK = 0x0004, + GLAMO_CLOCK_HOST_RESET = 0x1000, +}; + +enum glamo_reg_clock_mem { + GLAMO_CLOCK_MEM_DG_M1CLK = 0x0001, + GLAMO_CLOCK_MEM_EN_M1CLK = 0x0002, + GLAMO_CLOCK_MEM_DG_MOCACLK = 0x0004, + GLAMO_CLOCK_MEM_EN_MOCACLK = 0x0008, + GLAMO_CLOCK_MEM_RESET = 0x1000, + GLAMO_CLOCK_MOCA_RESET = 0x2000, +}; + +enum glamo_reg_clock_lcd { + GLAMO_CLOCK_LCD_DG_DCLK = 0x0001, + GLAMO_CLOCK_LCD_EN_DCLK = 0x0002, + GLAMO_CLOCK_LCD_DG_DMCLK = 0x0004, + GLAMO_CLOCK_LCD_EN_DMCLK = 0x0008, + // + GLAMO_CLOCK_LCD_EN_DHCLK = 0x0020, + GLAMO_CLOCK_LCD_DG_M5CLK = 0x0040, + GLAMO_CLOCK_LCD_EN_M5CLK = 0x0080, + GLAMO_CLOCK_LCD_RESET = 0x1000, +}; + +enum glamo_reg_clock_mmc { + GLAMO_CLOCK_MMC_DG_TCLK = 0x0001, + GLAMO_CLOCK_MMC_EN_TCLK = 0x0002, + GLAMO_CLOCK_MMC_DG_M9CLK = 0x0004, + GLAMO_CLOCK_MMC_EN_M9CLK = 0x0008, + GLAMO_CLOCK_MMC_RESET = 0x1000, +}; + +enum glamo_reg_basic_mmc { + /* set to disable CRC error rejection */ + GLAMO_BASIC_MMC_DISABLE_CRC = 0x0001, + /* enable completion interrupt */ + GLAMO_BASIC_MMC_EN_COMPL_INT = 0x0002, + /* stop MMC clock while enforced idle waiting for data from card */ + GLAMO_BASIC_MMC_NO_CLK_RD_WAIT = 0x0004, + /* 0 = 1-bit bus to card, 1 = use 4-bit bus (has to be negotiated) */ + GLAMO_BASIC_MMC_EN_4BIT_DATA = 0x0008, + /* enable 75K pullups on D3..D0 */ + GLAMO_BASIC_MMC_EN_DATA_PUPS = 0x0010, + /* enable 75K pullup on CMD */ + GLAMO_BASIC_MMC_EN_CMD_PUP = 0x0020, + /* IO drive strength 00=weak -> 11=strongest */ + GLAMO_BASIC_MMC_EN_DR_STR0 = 0x0040, + GLAMO_BASIC_MMC_EN_DR_STR1 = 0x0080, + /* TCLK delay stage A, 0000 = 500ps --> 1111 = 8ns */ + GLAMO_BASIC_MMC_EN_TCLK_DLYA0 = 0x0100, + GLAMO_BASIC_MMC_EN_TCLK_DLYA1 = 0x0200, + GLAMO_BASIC_MMC_EN_TCLK_DLYA2 = 0x0400, + GLAMO_BASIC_MMC_EN_TCLK_DLYA3 = 0x0800, + /* TCLK delay stage B (cumulative), 0000 = 500ps --> 1111 = 8ns */ + GLAMO_BASIC_MMC_EN_TCLK_DLYB0 = 0x1000, + GLAMO_BASIC_MMC_EN_TCLK_DLYB1 = 0x2000, + GLAMO_BASIC_MMC_EN_TCLK_DLYB2 = 0x4000, + GLAMO_BASIC_MMC_EN_TCLK_DLYB3 = 0x8000, +}; + +enum glamo_reg_stat1_mmc { + /* command "counter" (really: toggle) */ + GLAMO_STAT1_MMC_CMD_CTR = 0x8000, + /* engine is idle */ + GLAMO_STAT1_MMC_IDLE = 0x4000, + /* readback response is ready */ + GLAMO_STAT1_MMC_RB_RRDY = 0x0200, + /* readback data is ready */ + GLAMO_STAT1_MMC_RB_DRDY = 0x0100, + /* no response timeout */ + GLAMO_STAT1_MMC_RTOUT = 0x0020, + /* no data timeout */ + GLAMO_STAT1_MMC_DTOUT = 0x0010, + /* CRC error on block write */ + GLAMO_STAT1_MMC_BWERR = 0x0004, + /* CRC error on block read */ + GLAMO_STAT1_MMC_BRERR = 0x0002 +}; + +enum glamo_reg_fire_mmc { + /* command "counter" (really: toggle) + * the STAT1 register reflects this so you can ensure you don't look + * at status for previous command + */ + GLAMO_FIRE_MMC_CMD_CTR = 0x8000, + /* sets kind of response expected */ + GLAMO_FIRE_MMC_RES_MASK = 0x0700, + /* sets command type */ + GLAMO_FIRE_MMC_TYP_MASK = 0x00C0, + /* sets command class */ + GLAMO_FIRE_MMC_CLS_MASK = 0x000F, +}; + +enum glamo_fire_mmc_response_types { + GLAMO_FIRE_MMC_RSPT_R1 = 0x0000, + GLAMO_FIRE_MMC_RSPT_R1b = 0x0100, + GLAMO_FIRE_MMC_RSPT_R2 = 0x0200, + GLAMO_FIRE_MMC_RSPT_R3 = 0x0300, + GLAMO_FIRE_MMC_RSPT_R4 = 0x0400, + GLAMO_FIRE_MMC_RSPT_R5 = 0x0500, +}; + +enum glamo_fire_mmc_command_types { + /* broadcast, no response */ + GLAMO_FIRE_MMC_CMDT_BNR = 0x0000, + /* broadcast, with response */ + GLAMO_FIRE_MMC_CMDT_BR = 0x0040, + /* addressed, no data */ + GLAMO_FIRE_MMC_CMDT_AND = 0x0080, + /* addressed, with data */ + GLAMO_FIRE_MMC_CMDT_AD = 0x00C0, +}; + +enum glamo_fire_mmc_command_class { + /* "Stream Read" */ + GLAMO_FIRE_MMC_CC_STRR = 0x0000, + /* Single Block Read */ + GLAMO_FIRE_MMC_CC_SBR = 0x0001, + /* Multiple Block Read With Stop */ + GLAMO_FIRE_MMC_CC_MBRS = 0x0002, + /* Multiple Block Read No Stop */ + GLAMO_FIRE_MMC_CC_MBRNS = 0x0003, + /* RESERVED for "Stream Write" */ + GLAMO_FIRE_MMC_CC_STRW = 0x0004, + /* "Stream Write" */ + GLAMO_FIRE_MMC_CC_SBW = 0x0005, + /* RESERVED for Multiple Block Write With Stop */ + GLAMO_FIRE_MMC_CC_MBWS = 0x0006, + /* Multiple Block Write No Stop */ + GLAMO_FIRE_MMC_CC_MBWNS = 0x0007, + /* STOP command */ + GLAMO_FIRE_MMC_CC_STOP = 0x0008, + /* Cancel on Running Command */ + GLAMO_FIRE_MMC_CC_CANCL = 0x0009, + /* "Basic Command" */ + GLAMO_FIRE_MMC_CC_BASIC = 0x000a, +}; + +/* these are offsets from the start of the MMC register region */ +enum glamo_register_mmc { + /* MMC command, b15..8 = cmd arg b7..0; b7..1 = CRC; b0 = end bit */ + GLAMO_REG_MMC_CMD_REG1 = 0x00, + /* MMC command, b15..0 = cmd arg b23 .. 8 */ + GLAMO_REG_MMC_CMD_REG2 = 0x02, + /* MMC command, b15=start, b14=transmission, + * b13..8=cmd idx, b7..0=cmd arg b31..24 + */ + GLAMO_REG_MMC_CMD_REG3 = 0x04, + GLAMO_REG_MMC_CMD_FIRE = 0x06, + GLAMO_REG_MMC_CMD_RSP1 = 0x10, + GLAMO_REG_MMC_CMD_RSP2 = 0x12, + GLAMO_REG_MMC_CMD_RSP3 = 0x14, + GLAMO_REG_MMC_CMD_RSP4 = 0x16, + GLAMO_REG_MMC_CMD_RSP5 = 0x18, + GLAMO_REG_MMC_CMD_RSP6 = 0x1a, + GLAMO_REG_MMC_CMD_RSP7 = 0x1c, + GLAMO_REG_MMC_CMD_RSP8 = 0x1e, + GLAMO_REG_MMC_RB_STAT1 = 0x20, + GLAMO_REG_MMC_RB_BLKCNT = 0x22, + GLAMO_REG_MMC_RB_BLKLEN = 0x24, + GLAMO_REG_MMC_BASIC = 0x30, + GLAMO_REG_MMC_RDATADS1 = 0x34, + GLAMO_REG_MMC_RDATADS2 = 0x36, + GLAMO_REG_MMC_WDATADS1 = 0x38, + GLAMO_REG_MMC_WDATADS2 = 0x3a, + GLAMO_REG_MMC_DATBLKCNT = 0x3c, + GLAMO_REG_MMC_DATBLKLEN = 0x3e, + GLAMO_REG_MMC_TIMEOUT = 0x40, + +}; + +enum glamo_reg_clock_isp { + GLAMO_CLOCK_ISP_DG_I1CLK = 0x0001, + GLAMO_CLOCK_ISP_EN_I1CLK = 0x0002, + GLAMO_CLOCK_ISP_DG_CCLK = 0x0004, + GLAMO_CLOCK_ISP_EN_CCLK = 0x0008, + // + GLAMO_CLOCK_ISP_EN_SCLK = 0x0020, + GLAMO_CLOCK_ISP_DG_M2CLK = 0x0040, + GLAMO_CLOCK_ISP_EN_M2CLK = 0x0080, + GLAMO_CLOCK_ISP_DG_M15CLK = 0x0100, + GLAMO_CLOCK_ISP_EN_M15CLK = 0x0200, + GLAMO_CLOCK_ISP1_RESET = 0x1000, + GLAMO_CLOCK_ISP2_RESET = 0x2000, +}; + +enum glamo_reg_clock_jpeg { + GLAMO_CLOCK_JPEG_DG_JCLK = 0x0001, + GLAMO_CLOCK_JPEG_EN_JCLK = 0x0002, + GLAMO_CLOCK_JPEG_DG_M3CLK = 0x0004, + GLAMO_CLOCK_JPEG_EN_M3CLK = 0x0008, + GLAMO_CLOCK_JPEG_RESET = 0x1000, +}; + +enum glamo_reg_clock_2d { + GLAMO_CLOCK_2D_DG_GCLK = 0x0001, + GLAMO_CLOCK_2D_EN_GCLK = 0x0002, + GLAMO_CLOCK_2D_DG_M7CLK = 0x0004, + GLAMO_CLOCK_2D_EN_M7CLK = 0x0008, + GLAMO_CLOCK_2D_DG_M6CLK = 0x0010, + GLAMO_CLOCK_2D_EN_M6CLK = 0x0020, + GLAMO_CLOCK_2D_RESET = 0x1000, + GLAMO_CLOCK_2D_CQ_RESET = 0x2000, +}; + +enum glamo_reg_clock_3d { + GLAMO_CLOCK_3D_DG_ECLK = 0x0001, + GLAMO_CLOCK_3D_EN_ECLK = 0x0002, + GLAMO_CLOCK_3D_DG_RCLK = 0x0004, + GLAMO_CLOCK_3D_EN_RCLK = 0x0008, + GLAMO_CLOCK_3D_DG_M8CLK = 0x0010, + GLAMO_CLOCK_3D_EN_M8CLK = 0x0020, + GLAMO_CLOCK_3D_BACK_RESET = 0x1000, + GLAMO_CLOCK_3D_FRONT_RESET = 0x2000, +}; + +enum glamo_reg_clock_mpeg { + GLAMO_CLOCK_MPEG_DG_X0CLK = 0x0001, + GLAMO_CLOCK_MPEG_EN_X0CLK = 0x0002, + GLAMO_CLOCK_MPEG_DG_X1CLK = 0x0004, + GLAMO_CLOCK_MPEG_EN_X1CLK = 0x0008, + GLAMO_CLOCK_MPEG_DG_X2CLK = 0x0010, + GLAMO_CLOCK_MPEG_EN_X2CLK = 0x0020, + GLAMO_CLOCK_MPEG_DG_X3CLK = 0x0040, + GLAMO_CLOCK_MPEG_EN_X3CLK = 0x0080, + GLAMO_CLOCK_MPEG_DG_X4CLK = 0x0100, + GLAMO_CLOCK_MPEG_EN_X4CLK = 0x0200, + GLAMO_CLOCK_MPEG_DG_X6CLK = 0x0400, + GLAMO_CLOCK_MPEG_EN_X6CLK = 0x0800, + GLAMO_CLOCK_MPEG_ENC_RESET = 0x1000, + GLAMO_CLOCK_MPEG_DEC_RESET = 0x2000, +}; + +enum glamo_reg_clock51 { + GLAMO_CLOCK_GEN51_EN_DIV_MCLK = 0x0001, + GLAMO_CLOCK_GEN51_EN_DIV_SCLK = 0x0002, + GLAMO_CLOCK_GEN51_EN_DIV_JCLK = 0x0004, + GLAMO_CLOCK_GEN51_EN_DIV_DCLK = 0x0008, + GLAMO_CLOCK_GEN51_EN_DIV_DMCLK = 0x0010, + GLAMO_CLOCK_GEN51_EN_DIV_DHCLK = 0x0020, + GLAMO_CLOCK_GEN51_EN_DIV_GCLK = 0x0040, + GLAMO_CLOCK_GEN51_EN_DIV_TCLK = 0x0080, + /* FIXME: higher bits */ +}; + +enum glamo_reg_hostbus2 { + GLAMO_HOSTBUS2_MMIO_EN_ISP = 0x0001, + GLAMO_HOSTBUS2_MMIO_EN_JPEG = 0x0002, + GLAMO_HOSTBUS2_MMIO_EN_MPEG = 0x0004, + GLAMO_HOSTBUS2_MMIO_EN_LCD = 0x0008, + GLAMO_HOSTBUS2_MMIO_EN_MMC = 0x0010, + GLAMO_HOSTBUS2_MMIO_EN_MICROP0 = 0x0020, + GLAMO_HOSTBUS2_MMIO_EN_MICROP1 = 0x0040, + GLAMO_HOSTBUS2_MMIO_EN_CQ = 0x0080, + GLAMO_HOSTBUS2_MMIO_EN_RISC = 0x0100, + GLAMO_HOSTBUS2_MMIO_EN_2D = 0x0200, + GLAMO_HOSTBUS2_MMIO_EN_3D = 0x0400, +}; + +/* LCD Controller */ + +#define REG_LCD(x) (x) +enum glamo_reg_lcd { + GLAMO_REG_LCD_MODE1 = REG_LCD(0x00), + GLAMO_REG_LCD_MODE2 = REG_LCD(0x02), + GLAMO_REG_LCD_MODE3 = REG_LCD(0x04), + GLAMO_REG_LCD_WIDTH = REG_LCD(0x06), + GLAMO_REG_LCD_HEIGHT = REG_LCD(0x08), + GLAMO_REG_LCD_POLARITY = REG_LCD(0x0a), + GLAMO_REG_LCD_A_BASE1 = REG_LCD(0x0c), + GLAMO_REG_LCD_A_BASE2 = REG_LCD(0x0e), + GLAMO_REG_LCD_B_BASE1 = REG_LCD(0x10), + GLAMO_REG_LCD_B_BASE2 = REG_LCD(0x12), + GLAMO_REG_LCD_C_BASE1 = REG_LCD(0x14), + GLAMO_REG_LCD_C_BASE2 = REG_LCD(0x16), + GLAMO_REG_LCD_PITCH = REG_LCD(0x18), + /* RES */ + GLAMO_REG_LCD_HORIZ_TOTAL = REG_LCD(0x1c), + /* RES */ + GLAMO_REG_LCD_HORIZ_RETR_START = REG_LCD(0x20), + /* RES */ + GLAMO_REG_LCD_HORIZ_RETR_END = REG_LCD(0x24), + /* RES */ + GLAMO_REG_LCD_HORIZ_DISP_START = REG_LCD(0x28), + /* RES */ + GLAMO_REG_LCD_HORIZ_DISP_END = REG_LCD(0x2c), + /* RES */ + GLAMO_REG_LCD_VERT_TOTAL = REG_LCD(0x30), + /* RES */ + GLAMO_REG_LCD_VERT_RETR_START = REG_LCD(0x34), + /* RES */ + GLAMO_REG_LCD_VERT_RETR_END = REG_LCD(0x38), + /* RES */ + GLAMO_REG_LCD_VERT_DISP_START = REG_LCD(0x3c), + /* RES */ + GLAMO_REG_LCD_VERT_DISP_END = REG_LCD(0x40), + /* RES */ + GLAMO_REG_LCD_POL = REG_LCD(0x44), + GLAMO_REG_LCD_DATA_START = REG_LCD(0x46), + GLAMO_REG_LCD_FRATE_CONTRO = REG_LCD(0x48), + GLAMO_REG_LCD_DATA_CMD_HDR = REG_LCD(0x4a), + GLAMO_REG_LCD_SP_START = REG_LCD(0x4c), + GLAMO_REG_LCD_SP_END = REG_LCD(0x4e), + GLAMO_REG_LCD_CURSOR_BASE1 = REG_LCD(0x50), + GLAMO_REG_LCD_CURSOR_BASE2 = REG_LCD(0x52), + GLAMO_REG_LCD_CURSOR_PITCH = REG_LCD(0x54), + GLAMO_REG_LCD_CURSOR_X_SIZE = REG_LCD(0x56), + GLAMO_REG_LCD_CURSOR_Y_SIZE = REG_LCD(0x58), + GLAMO_REG_LCD_CURSOR_X_POS = REG_LCD(0x5a), + GLAMO_REG_LCD_CURSOR_Y_POS = REG_LCD(0x5c), + GLAMO_REG_LCD_CURSOR_PRESET = REG_LCD(0x5e), + GLAMO_REG_LCD_CURSOR_FG_COLOR = REG_LCD(0x60), + /* RES */ + GLAMO_REG_LCD_CURSOR_BG_COLOR = REG_LCD(0x64), + /* RES */ + GLAMO_REG_LCD_CURSOR_DST_COLOR = REG_LCD(0x68), + /* RES */ + GLAMO_REG_LCD_STATUS1 = REG_LCD(0x80), + GLAMO_REG_LCD_STATUS2 = REG_LCD(0x82), + GLAMO_REG_LCD_STATUS3 = REG_LCD(0x84), + GLAMO_REG_LCD_STATUS4 = REG_LCD(0x86), + /* RES */ + GLAMO_REG_LCD_COMMAND1 = REG_LCD(0xa0), + GLAMO_REG_LCD_COMMAND2 = REG_LCD(0xa2), + /* RES */ + GLAMO_REG_LCD_WFORM_DELAY1 = REG_LCD(0xb0), + GLAMO_REG_LCD_WFORM_DELAY2 = REG_LCD(0xb2), + /* RES */ + GLAMO_REG_LCD_GAMMA_CORR = REG_LCD(0x100), + /* RES */ + GLAMO_REG_LCD_GAMMA_R_ENTRY01 = REG_LCD(0x110), + GLAMO_REG_LCD_GAMMA_R_ENTRY23 = REG_LCD(0x112), + GLAMO_REG_LCD_GAMMA_R_ENTRY45 = REG_LCD(0x114), + GLAMO_REG_LCD_GAMMA_R_ENTRY67 = REG_LCD(0x116), + GLAMO_REG_LCD_GAMMA_R_ENTRY8 = REG_LCD(0x118), + /* RES */ + GLAMO_REG_LCD_GAMMA_G_ENTRY01 = REG_LCD(0x130), + GLAMO_REG_LCD_GAMMA_G_ENTRY23 = REG_LCD(0x132), + GLAMO_REG_LCD_GAMMA_G_ENTRY45 = REG_LCD(0x134), + GLAMO_REG_LCD_GAMMA_G_ENTRY67 = REG_LCD(0x136), + GLAMO_REG_LCD_GAMMA_G_ENTRY8 = REG_LCD(0x138), + /* RES */ + GLAMO_REG_LCD_GAMMA_B_ENTRY01 = REG_LCD(0x150), + GLAMO_REG_LCD_GAMMA_B_ENTRY23 = REG_LCD(0x152), + GLAMO_REG_LCD_GAMMA_B_ENTRY45 = REG_LCD(0x154), + GLAMO_REG_LCD_GAMMA_B_ENTRY67 = REG_LCD(0x156), + GLAMO_REG_LCD_GAMMA_B_ENTRY8 = REG_LCD(0x158), + /* RES */ + GLAMO_REG_LCD_SRAM_DRIVING1 = REG_LCD(0x160), + GLAMO_REG_LCD_SRAM_DRIVING2 = REG_LCD(0x162), + GLAMO_REG_LCD_SRAM_DRIVING3 = REG_LCD(0x164), +}; + +enum glamo_reg_lcd_mode1 { + GLAMO_LCD_MODE1_PWRSAVE = 0x0001, + GLAMO_LCD_MODE1_PARTIAL_PRT = 0x0002, + GLAMO_LCD_MODE1_HWFLIP = 0x0004, + GLAMO_LCD_MODE1_LCD2 = 0x0008, + /* RES */ + GLAMO_LCD_MODE1_PARTIAL_MODE = 0x0020, + GLAMO_LCD_MODE1_CURSOR_DSTCOLOR = 0x0040, + GLAMO_LCD_MODE1_PARTIAL_ENABLE = 0x0080, + GLAMO_LCD_MODE1_TVCLK_IN_ENABLE = 0x0100, + GLAMO_LCD_MODE1_HSYNC_HIGH_ACT = 0x0200, + GLAMO_LCD_MODE1_VSYNC_HIGH_ACT = 0x0400, + GLAMO_LCD_MODE1_HSYNC_FLIP = 0x0800, + GLAMO_LCD_MODE1_GAMMA_COR_EN = 0x1000, + GLAMO_LCD_MODE1_DITHER_EN = 0x2000, + GLAMO_LCD_MODE1_CURSOR_EN = 0x4000, + GLAMO_LCD_MODE1_ROTATE_EN = 0x8000, +}; + +enum glamo_reg_lcd_mode2 { + GLAMO_LCD_MODE2_CRC_CHECK_EN = 0x0001, + GLAMO_LCD_MODE2_DCMD_PER_LINE = 0x0002, + GLAMO_LCD_MODE2_NOUSE_BDEF = 0x0004, + GLAMO_LCD_MODE2_OUT_POS_MODE = 0x0008, + GLAMO_LCD_MODE2_FRATE_CTRL_EN = 0x0010, + GLAMO_LCD_MODE2_SINGLE_BUFFER = 0x0020, + GLAMO_LCD_MODE2_SER_LSB_TO_MSB = 0x0040, + /* FIXME */ +}; + +enum glamo_reg_lcd_mode3 { + /* LCD color source data format */ + GLAMO_LCD_SRC_RGB565 = 0x0000, + GLAMO_LCD_SRC_ARGB1555 = 0x4000, + GLAMO_LCD_SRC_ARGB4444 = 0x8000, + /* interface type */ + GLAMO_LCD_MODE3_LCD = 0x1000, + GLAMO_LCD_MODE3_RGB = 0x0800, + GLAMO_LCD_MODE3_CPU = 0x0000, + /* mode */ + GLAMO_LCD_MODE3_RGB332 = 0x0000, + GLAMO_LCD_MODE3_RGB444 = 0x0100, + GLAMO_LCD_MODE3_RGB565 = 0x0200, + GLAMO_LCD_MODE3_RGB666 = 0x0300, + /* depth */ + GLAMO_LCD_MODE3_6BITS = 0x0000, + GLAMO_LCD_MODE3_8BITS = 0x0010, + GLAMO_LCD_MODE3_9BITS = 0x0020, + GLAMO_LCD_MODE3_16BITS = 0x0030, + GLAMO_LCD_MODE3_18BITS = 0x0040, +}; + +enum glamo_lcd_rot_mode { + GLAMO_LCD_ROT_MODE_0 = 0x0000, + GLAMO_LCD_ROT_MODE_180 = 0x2000, + GLAMO_LCD_ROT_MODE_MIRROR = 0x4000, + GLAMO_LCD_ROT_MODE_FLIP = 0x6000, + GLAMO_LCD_ROT_MODE_90 = 0x8000, + GLAMO_LCD_ROT_MODE_270 = 0xa000, +}; +#define GLAMO_LCD_ROT_MODE_MASK 0xe000 + +enum glamo_lcd_cmd_type { + GLAMO_LCD_CMD_TYPE_DISP = 0x0000, + GLAMO_LCD_CMD_TYPE_PARALLEL = 0x4000, + GLAMO_LCD_CMD_TYPE_SERIAL = 0x8000, + GLAMO_LCD_CMD_TYPE_SERIAL_DIRECT= 0xc000, +}; +#define GLAMO_LCD_CMD_TYPE_MASK 0xc000 + +enum glamo_lcd_cmds { + GLAMO_LCD_CMD_DATA_DISP_FIRE = 0x00, + GLAMO_LCD_CMD_DATA_DISP_SYNC = 0x01, /* RGB only */ + /* switch to command mode, no display */ + GLAMO_LCD_CMD_DATA_FIRE_NO_DISP = 0x02, + /* display until VSYNC, switch to command */ + GLAMO_LCD_CMD_DATA_FIRE_VSYNC = 0x11, + /* display until HSYNC, switch to command */ + GLAMO_LCD_CMD_DATA_FIRE_HSYNC = 0x12, + /* display until VSYNC, 1 black frame, VSYNC, switch to command */ + GLAMO_LCD_CMD_DATA_FIRE_VSYNC_B = 0x13, + /* don't care about display and switch to command */ + GLAMO_LCD_CMD_DATA_FIRE_FREE = 0x14, /* RGB only */ + /* don't care about display, keep data display but disable data, + * and switch to command */ + GLAMO_LCD_CMD_DATA_FIRE_FREE_D = 0x15, /* RGB only */ +}; + +enum glamo_core_revisions { + GLAMO_CORE_REV_A0 = 0x0000, + GLAMO_CORE_REV_A1 = 0x0001, + GLAMO_CORE_REV_A2 = 0x0002, + GLAMO_CORE_REV_A3 = 0x0003, +}; + +#endif /* _GLAMO_REGS_H */ diff --git a/qiboot/include/i2c-bitbang-s3c24xx.h b/qiboot/include/i2c-bitbang-s3c24xx.h new file mode 100644 index 0000000..6be18b9 --- /dev/null +++ b/qiboot/include/i2c-bitbang-s3c24xx.h @@ -0,0 +1,3 @@ +#include + +extern struct i2c_bitbang bb_s3c24xx; diff --git a/qiboot/include/i2c-bitbang-s3c6410.h b/qiboot/include/i2c-bitbang-s3c6410.h new file mode 100644 index 0000000..b1c3ed5 --- /dev/null +++ b/qiboot/include/i2c-bitbang-s3c6410.h @@ -0,0 +1,3 @@ +#include + +extern struct i2c_bitbang bb_s3c6410; diff --git a/qiboot/include/i2c-bitbang.h b/qiboot/include/i2c-bitbang.h new file mode 100644 index 0000000..f5b86ef --- /dev/null +++ b/qiboot/include/i2c-bitbang.h @@ -0,0 +1,102 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * Generic i2c bitbang state machine + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* controls symbol sequencing on i2c */ + +enum i2c_bitbang_control { + IBCONTROL_DO_START = -1, + IBCONTROL_DO_STOP = -2, + IBCONTROL_DO_READ = -3, + IBCONTROL_COMPLETE = -4 +}; + +/* control intra-bit and byte states */ + +enum i2c_bitbang_states { + IBS_INIT, + + IBS_START1, + IBS_START2, + + IBS_ADS_TX_S, + IBS_ADS_TX_H, + IBS_ADS_TX_L, + IBS_ADS_TX_ACK_H, + IBS_ADS_TX_ACK_L, + + IBS_DATA_RX_S, + IBS_DATA_RX_H, + IBS_DATA_RX_L, + + IBS_DATA_RX_ACK_H, + IBS_DATA_RX_ACK_L, + + IBS_STOP1, + IBS_STOP2, + IBS_STOP3, + IBS_STOP4 +}; + +/* context for bitbang GPIO pins and transaction */ + +struct i2c_bitbang { + + enum i2c_bitbang_states state; + int count; + unsigned int data[8]; /* read result found here */ + int index; + int index_read; + + char (*read_sda)(void); + /* data = 0 = op low, 1 == inp */ + void (*set)(char clock, char data); + /* delay > 1 half-bit time, used by i2c_complete_synchronously() */ + void (*spin)(void); + void (*close)(void); +}; + +/* synchronous read and write functions spin until completed or failed + * i2c_read_sync returns -1 for fail or byte result from device + */ + +extern int i2c_read_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg); +extern void i2c_write_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg, unsigned char data); + + +/* + * set up an asynchronous read or write transaction + */ +extern void i2c_read(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg); +extern void i2c_write(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg, unsigned char data); + +/* + * after setting up a read or write transaction above, you loop calling this + * with >= 1.25us (400kHz) or >= 5us (100kHz) delay between calls. You don't + * have to spin but can do something useful if you know it will take more than + * an i2c bit-time, hiding the time for the i2c transaction completely. + */ +extern int i2c_next_state(struct i2c_bitbang * bb); /* return !=0 = completed */ diff --git a/qiboot/include/image.h b/qiboot/include/image.h new file mode 100644 index 0000000..af9ecda --- /dev/null +++ b/qiboot/include/image.h @@ -0,0 +1,570 @@ +/* + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ******************************************************************** + * NOTE: This header file defines an interface to U-Boot. Including + * this (unmodified) header file in another file is considered normal + * use of U-Boot, and does *not* fall under the heading of "derived + * work". + ******************************************************************** + */ + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +/* + * Operating System Codes + */ +#define IH_OS_INVALID 0 /* Invalid OS */ +#define IH_OS_OPENBSD 1 /* OpenBSD */ +#define IH_OS_NETBSD 2 /* NetBSD */ +#define IH_OS_FREEBSD 3 /* FreeBSD */ +#define IH_OS_4_4BSD 4 /* 4.4BSD */ +#define IH_OS_LINUX 5 /* Linux */ +#define IH_OS_SVR4 6 /* SVR4 */ +#define IH_OS_ESIX 7 /* Esix */ +#define IH_OS_SOLARIS 8 /* Solaris */ +#define IH_OS_IRIX 9 /* Irix */ +#define IH_OS_SCO 10 /* SCO */ +#define IH_OS_DELL 11 /* Dell */ +#define IH_OS_NCR 12 /* NCR */ +#define IH_OS_LYNXOS 13 /* LynxOS */ +#define IH_OS_VXWORKS 14 /* VxWorks */ +#define IH_OS_PSOS 15 /* pSOS */ +#define IH_OS_QNX 16 /* QNX */ +#define IH_OS_U_BOOT 17 /* Firmware */ +#define IH_OS_RTEMS 18 /* RTEMS */ +#define IH_OS_ARTOS 19 /* ARTOS */ +#define IH_OS_UNITY 20 /* Unity OS */ + +/* + * CPU Architecture Codes (supported by Linux) + */ +#define IH_ARCH_INVALID 0 /* Invalid CPU */ +#define IH_ARCH_ALPHA 1 /* Alpha */ +#define IH_ARCH_ARM 2 /* ARM */ +#define IH_ARCH_I386 3 /* Intel x86 */ +#define IH_ARCH_IA64 4 /* IA64 */ +#define IH_ARCH_MIPS 5 /* MIPS */ +#define IH_ARCH_MIPS64 6 /* MIPS 64 Bit */ +#define IH_ARCH_PPC 7 /* PowerPC */ +#define IH_ARCH_S390 8 /* IBM S390 */ +#define IH_ARCH_SH 9 /* SuperH */ +#define IH_ARCH_SPARC 10 /* Sparc */ +#define IH_ARCH_SPARC64 11 /* Sparc 64 Bit */ +#define IH_ARCH_M68K 12 /* M68K */ +#define IH_ARCH_NIOS 13 /* Nios-32 */ +#define IH_ARCH_MICROBLAZE 14 /* MicroBlaze */ +#define IH_ARCH_NIOS2 15 /* Nios-II */ +#define IH_ARCH_BLACKFIN 16 /* Blackfin */ +#define IH_ARCH_AVR32 17 /* AVR32 */ +#define IH_ARCH_ST200 18 /* STMicroelectronics ST200 */ + +/* + * Image Types + * + * "Standalone Programs" are directly runnable in the environment + * provided by U-Boot; it is expected that (if they behave + * well) you can continue to work in U-Boot after return from + * the Standalone Program. + * "OS Kernel Images" are usually images of some Embedded OS which + * will take over control completely. Usually these programs + * will install their own set of exception handlers, device + * drivers, set up the MMU, etc. - this means, that you cannot + * expect to re-enter U-Boot except by resetting the CPU. + * "RAMDisk Images" are more or less just data blocks, and their + * parameters (address, size) are passed to an OS kernel that is + * being started. + * "Multi-File Images" contain several images, typically an OS + * (Linux) kernel image and one or more data images like + * RAMDisks. This construct is useful for instance when you want + * to boot over the network using BOOTP etc., where the boot + * server provides just a single image file, but you want to get + * for instance an OS kernel and a RAMDisk image. + * + * "Multi-File Images" start with a list of image sizes, each + * image size (in bytes) specified by an "uint32_t" in network + * byte order. This list is terminated by an "(uint32_t)0". + * Immediately after the terminating 0 follow the images, one by + * one, all aligned on "uint32_t" boundaries (size rounded up to + * a multiple of 4 bytes - except for the last file). + * + * "Firmware Images" are binary images containing firmware (like + * U-Boot or FPGA images) which usually will be programmed to + * flash memory. + * + * "Script files" are command sequences that will be executed by + * U-Boot's command interpreter; this feature is especially + * useful when you configure U-Boot to use a real shell (hush) + * as command interpreter (=> Shell Scripts). + */ + +#define IH_TYPE_INVALID 0 /* Invalid Image */ +#define IH_TYPE_STANDALONE 1 /* Standalone Program */ +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ +#define IH_TYPE_MULTI 4 /* Multi-File Image */ +#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ +#define IH_TYPE_SCRIPT 6 /* Script file */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ +#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ + +/* + * Compression Types + */ +#define IH_COMP_NONE 0 /* No Compression Used */ +#define IH_COMP_GZIP 1 /* gzip Compression Used */ +#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ + +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +/* + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). + */ +typedef struct image_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +} image_header_t; + +/* + * Legacy and FIT format headers used by do_bootm() and do_bootm_() + * routines. + */ +typedef struct bootm_headers { + /* + * Legacy os image header, if it is a multi component image + * then boot_get_ramdisk() and get_fdt() will attempt to get + * data from second and third component accordingly. + */ + image_header_t *legacy_hdr_os; + ulong legacy_hdr_valid; + +#if defined(CONFIG_FIT) + const char *fit_uname_cfg; /* configuration node unit name */ + + void *fit_hdr_os; /* os FIT image header */ + const char *fit_uname_os; /* os subimage node unit name */ + int fit_noffset_os; /* os subimage node offset */ + + void *fit_hdr_rd; /* init ramdisk FIT image header */ + const char *fit_uname_rd; /* init ramdisk subimage node unit name */ + int fit_noffset_rd; /* init ramdisk subimage node offset */ + +#if defined(CONFIG_PPC) + void *fit_hdr_fdt; /* FDT blob FIT image header */ + const char *fit_uname_fdt; /* FDT blob subimage node unit name */ + int fit_noffset_fdt;/* FDT blob subimage node offset */ +#endif +#endif + + int verify; /* getenv("verify")[0] != 'n' */ + int autostart; /* getenv("autostart")[0] != 'n' */ + struct lmb *lmb; /* for memory mgmt */ +} bootm_headers_t; + +/* + * Some systems (for example LWMON) have very short watchdog periods; + * we must make sure to split long operations like memmove() or + * crc32() into reasonable chunks. + */ +#define CHUNKSZ (64 * 1024) + +#define uimage_to_cpu(x) __be32_to_cpu(x) +#define cpu_to_uimage(x) __cpu_to_be32(x) + +const char *genimg_get_os_name (uint8_t os); +const char *genimg_get_arch_name (uint8_t arch); +const char *genimg_get_type_name (uint8_t type); +const char *genimg_get_comp_name (uint8_t comp); +int genimg_get_os_id (const char *name); +int genimg_get_arch_id (const char *name); +int genimg_get_type_id (const char *name); +int genimg_get_comp_id (const char *name); + +#ifndef USE_HOSTCC +/* Image format types, returned by _get_format() routine */ +#define IMAGE_FORMAT_INVALID 0x00 +#define IMAGE_FORMAT_LEGACY 0x01 /* legacy image_header based format */ +#define IMAGE_FORMAT_FIT 0x02 /* new, libfdt based format */ + +int genimg_get_format (void *img_addr); +int genimg_has_config (bootm_headers_t *images); +ulong genimg_get_image (ulong img_addr); + +int boot_get_ramdisk (int argc, char *argv[], bootm_headers_t *images, + uint8_t arch, ulong *rd_start, ulong *rd_end); + +#if defined(CONFIG_PPC) || defined(CONFIG_M68K) +int boot_ramdisk_high (struct lmb *lmb, ulong rd_data, ulong rd_len, + ulong *initrd_start, ulong *initrd_end); + +int boot_get_cmdline (struct lmb *lmb, ulong *cmd_start, ulong *cmd_end, + ulong bootmap_base); +int boot_get_kbd (struct lmb *lmb, bd_t **kbd, ulong bootmap_base); +#endif /* CONFIG_PPC || CONFIG_M68K */ +#endif /* !USE_HOSTCC */ + +/*******************************************************************/ +/* Legacy format specific code (prefixed with image_) */ +/*******************************************************************/ +static inline uint32_t image_get_header_size (void) +{ + return (sizeof (image_header_t)); +} + +#define image_get_hdr_l(f) \ + static inline uint32_t image_get_##f(image_header_t *hdr) \ + { \ + return uimage_to_cpu (hdr->ih_##f); \ + } +image_get_hdr_l (magic); +image_get_hdr_l (hcrc); +image_get_hdr_l (time); +image_get_hdr_l (size); +image_get_hdr_l (load); +image_get_hdr_l (ep); +image_get_hdr_l (dcrc); + +#define image_get_hdr_b(f) \ + static inline uint8_t image_get_##f(image_header_t *hdr) \ + { \ + return hdr->ih_##f; \ + } +image_get_hdr_b (os); +image_get_hdr_b (arch); +image_get_hdr_b (type); +image_get_hdr_b (comp); + +static inline char *image_get_name (image_header_t *hdr) +{ + return (char *)hdr->ih_name; +} + +static inline uint32_t image_get_data_size (image_header_t *hdr) +{ + return image_get_size (hdr); +} + +/** + * image_get_data - get image payload start address + * @hdr: image header + * + * image_get_data() returns address of the image payload. For single + * component images it is image data start. For multi component + * images it points to the null terminated table of sub-images sizes. + * + * returns: + * image payload data start address + */ +static inline ulong image_get_data (image_header_t *hdr) +{ + return ((ulong)hdr + image_get_header_size ()); +} + +static inline uint32_t image_get_image_size (image_header_t *hdr) +{ + return (image_get_size (hdr) + image_get_header_size ()); +} +static inline ulong image_get_image_end (image_header_t *hdr) +{ + return ((ulong)hdr + image_get_image_size (hdr)); +} + +#define image_set_hdr_l(f) \ + static inline void image_set_##f(image_header_t *hdr, uint32_t val) \ + { \ + hdr->ih_##f = cpu_to_uimage (val); \ + } +image_set_hdr_l (magic); +image_set_hdr_l (hcrc); +image_set_hdr_l (time); +image_set_hdr_l (size); +image_set_hdr_l (load); +image_set_hdr_l (ep); +image_set_hdr_l (dcrc); + +#define image_set_hdr_b(f) \ + static inline void image_set_##f(image_header_t *hdr, uint8_t val) \ + { \ + hdr->ih_##f = val; \ + } +image_set_hdr_b (os); +image_set_hdr_b (arch); +image_set_hdr_b (type); +image_set_hdr_b (comp); + +static inline void image_set_name (image_header_t *hdr, const char *name) +{ + strncpy (image_get_name (hdr), name, IH_NMLEN); +} + +int image_check_hcrc (image_header_t *hdr); +int image_check_dcrc (image_header_t *hdr); +#ifndef USE_HOSTCC +int image_check_dcrc_wd (image_header_t *hdr, ulong chunksize); +int getenv_verify (void); +int getenv_autostart (void); +ulong getenv_bootm_low(void); +ulong getenv_bootm_size(void); +void memmove_wd (void *to, void *from, size_t len, ulong chunksz); +#endif + +static inline int image_check_magic (image_header_t *hdr) +{ + return (image_get_magic (hdr) == IH_MAGIC); +} +static inline int image_check_type (image_header_t *hdr, uint8_t type) +{ + return (image_get_type (hdr) == type); +} +static inline int image_check_arch (image_header_t *hdr, uint8_t arch) +{ + return (image_get_arch (hdr) == arch); +} +static inline int image_check_os (image_header_t *hdr, uint8_t os) +{ + return (image_get_os (hdr) == os); +} + +ulong image_multi_count (image_header_t *hdr); +void image_multi_getimg (image_header_t *hdr, ulong idx, + ulong *data, ulong *len); + +inline void image_print_contents (image_header_t *hdr); +inline void image_print_contents_noindent (image_header_t *hdr); + +#ifndef USE_HOSTCC +static inline int image_check_target_arch (image_header_t *hdr) +{ +#if defined(__ARM__) + if (!image_check_arch (hdr, IH_ARCH_ARM)) +#elif defined(__avr32__) + if (!image_check_arch (hdr, IH_ARCH_AVR32)) +#elif defined(__bfin__) + if (!image_check_arch (hdr, IH_ARCH_BLACKFIN)) +#elif defined(__I386__) + if (!image_check_arch (hdr, IH_ARCH_I386)) +#elif defined(__M68K__) + if (!image_check_arch (hdr, IH_ARCH_M68K)) +#elif defined(__microblaze__) + if (!image_check_arch (hdr, IH_ARCH_MICROBLAZE)) +#elif defined(__mips__) + if (!image_check_arch (hdr, IH_ARCH_MIPS)) +#elif defined(__nios__) + if (!image_check_arch (hdr, IH_ARCH_NIOS)) +#elif defined(__nios2__) + if (!image_check_arch (hdr, IH_ARCH_NIOS2)) +#elif defined(__PPC__) + if (!image_check_arch (hdr, IH_ARCH_PPC)) +#elif defined(__sh__) + if (!image_check_arch (hdr, IH_ARCH_SH)) +#else +# error Unknown CPU type +#endif + return 0; + + return 1; +} +#endif /* USE_HOSTCC */ + +/*******************************************************************/ +/* New uImage format specific code (prefixed with fit_) */ +/*******************************************************************/ +#if defined(CONFIG_FIT) + +#define FIT_IMAGES_PATH "/images" +#define FIT_CONFS_PATH "/configurations" + +/* hash node */ +#define FIT_HASH_NODENAME "hash" +#define FIT_ALGO_PROP "algo" +#define FIT_VALUE_PROP "value" + +/* image node */ +#define FIT_DATA_PROP "data" +#define FIT_TIMESTAMP_PROP "timestamp" +#define FIT_DESC_PROP "description" +#define FIT_ARCH_PROP "arch" +#define FIT_TYPE_PROP "type" +#define FIT_OS_PROP "os" +#define FIT_COMP_PROP "compression" +#define FIT_ENTRY_PROP "entry" +#define FIT_LOAD_PROP "load" + +/* configuration node */ +#define FIT_KERNEL_PROP "kernel" +#define FIT_RAMDISK_PROP "ramdisk" +#define FIT_FDT_PROP "fdt" +#define FIT_DEFAULT_PROP "default" + +#define FIT_MAX_HASH_LEN 20 /* max(crc32_len(4), sha1_len(20)) */ + +/* cmdline argument format parsing */ +inline int fit_parse_conf (const char *spec, ulong addr_curr, + ulong *addr, const char **conf_name); +inline int fit_parse_subimage (const char *spec, ulong addr_curr, + ulong *addr, const char **image_name); + +inline void fit_print_contents (const void *fit); +inline void fit_print_contents_noindent (const void *fit); +void fit_image_print (const void *fit, int noffset, const char *p); +void fit_image_print_hash (const void *fit, int noffset, const char *p); + +/** + * fit_get_end - get FIT image size + * @fit: pointer to the FIT format image header + * + * returns: + * size of the FIT image (blob) in memory + */ +static inline ulong fit_get_size (const void *fit) +{ + return fdt_totalsize (fit); +} + +/** + * fit_get_end - get FIT image end + * @fit: pointer to the FIT format image header + * + * returns: + * end address of the FIT image (blob) in memory + */ +static inline ulong fit_get_end (const void *fit) +{ + return (ulong)fit + fdt_totalsize (fit); +} + +/** + * fit_get_name - get FIT node name + * @fit: pointer to the FIT format image header + * + * returns: + * NULL, on error + * pointer to node name, on success + */ +static inline const char *fit_get_name (const void *fit_hdr, + int noffset, int *len) +{ + return fdt_get_name (fit_hdr, noffset, len); +} + +int fit_get_desc (const void *fit, int noffset, char **desc); +int fit_get_timestamp (const void *fit, int noffset, time_t *timestamp); + +int fit_image_get_node (const void *fit, const char *image_uname); +int fit_image_get_os (const void *fit, int noffset, uint8_t *os); +int fit_image_get_arch (const void *fit, int noffset, uint8_t *arch); +int fit_image_get_type (const void *fit, int noffset, uint8_t *type); +int fit_image_get_comp (const void *fit, int noffset, uint8_t *comp); +int fit_image_get_load (const void *fit, int noffset, ulong *load); +int fit_image_get_entry (const void *fit, int noffset, ulong *entry); +int fit_image_get_data (const void *fit, int noffset, + const void **data, size_t *size); + +int fit_image_hash_get_algo (const void *fit, int noffset, char **algo); +int fit_image_hash_get_value (const void *fit, int noffset, uint8_t **value, + int *value_len); + +int fit_set_timestamp (void *fit, int noffset, time_t timestamp); +int fit_set_hashes (void *fit); +int fit_image_set_hashes (void *fit, int image_noffset); +int fit_image_hash_set_value (void *fit, int noffset, uint8_t *value, + int value_len); + +int fit_image_check_hashes (const void *fit, int noffset); +int fit_image_check_os (const void *fit, int noffset, uint8_t os); +int fit_image_check_arch (const void *fit, int noffset, uint8_t arch); +int fit_image_check_type (const void *fit, int noffset, uint8_t type); +int fit_image_check_comp (const void *fit, int noffset, uint8_t comp); +int fit_check_format (const void *fit); + +int fit_conf_get_node (const void *fit, const char *conf_uname); +int fit_conf_get_kernel_node (const void *fit, int noffset); +int fit_conf_get_ramdisk_node (const void *fit, int noffset); +int fit_conf_get_fdt_node (const void *fit, int noffset); + +void fit_conf_print (const void *fit, int noffset, const char *p); + +#ifndef USE_HOSTCC +static inline int fit_image_check_target_arch (const void *fdt, int node) +{ +#if defined(__ARM__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_ARM)) +#elif defined(__avr32__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_AVR32)) +#elif defined(__bfin__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_BLACKFIN)) +#elif defined(__I386__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_I386)) +#elif defined(__M68K__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_M68K)) +#elif defined(__microblaze__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_MICROBLAZE)) +#elif defined(__mips__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_MIPS)) +#elif defined(__nios__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_NIOS)) +#elif defined(__nios2__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_NIOS2)) +#elif defined(__PPC__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_PPC)) +#elif defined(__sh__) + if (!fit_image_check_arch (fdt, node, IH_ARCH_SH)) +#else +# error Unknown CPU type +#endif + return 0; + + return 1; +} +#endif /* USE_HOSTCC */ + +#ifdef CONFIG_FIT_VERBOSE +#define fit_unsupported(msg) printf ("! %s:%d " \ + "FIT images not supported for '%s'\n", \ + __FILE__, __LINE__, (msg)) + +#define fit_unsupported_reset(msg) printf ("! %s:%d " \ + "FIT images not supported for '%s' " \ + "- must reset board to recover!\n", \ + __FILE__, __LINE__, (msg)) +#else +#define fit_unsupported(msg) +#define fit_unsupported_reset(msg) +#endif /* CONFIG_FIT_VERBOSE */ +#endif /* CONFIG_FIT */ + +#endif /* __IMAGE_H__ */ diff --git a/qiboot/include/linux-mmc-protocol.h b/qiboot/include/linux-mmc-protocol.h new file mode 100644 index 0000000..2d90273 --- /dev/null +++ b/qiboot/include/linux-mmc-protocol.h @@ -0,0 +1,382 @@ +/* + * Header for MultiMediaCard (MMC) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Based strongly on code by: + * + * Author: Yong-iL Joh + * Date : $Date: 2006/12/06 02:50:52 $ + * + * Author: Andrew Christian + * 15 May 2002 + */ + +#ifndef MMC_MMC_PROTOCOL_H +#define MMC_MMC_PROTOCOL_H + +#ifdef CONFIG_SUPPORT_MMC_PLUS +/* Standard MMC commands (4.2) type argument response */ +#else +/* Standard MMC commands (3.1) type argument response */ +#endif + /* class 1 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SWITCH 6 /* ac R1b */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_BUSTEST_R 14 /* adtc R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_BUSTEST_W 19 /* adtc R1 */ + + /* class 2 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 3 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4 */ +#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 38 /* ac R1b */ + + /* class 9 */ +#define MMC_FAST_IO 39 /* ac R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ + + /* class 7 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ + +/* SD commands type argument response */ + /* class 8 */ +/* This is basically the same command as for MMC with some quirks. */ +#define SD_SEND_RELATIVE_ADDR 3 /* ac R6 */ + + /* Application commands */ +#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + +/* + MMC status in R1 + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) (x & 0xFFFFE000) +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_APP_CMD (1 << 5) /* sr, c */ + +/* + MMC CURRENT_STATE in R1 [12:9] + */ +#define STATE_IDLE (0x0 << 9) /* 0 */ +#define STATE_READY (0x1 << 9) /* 1 */ +#define STATE_IDENT (0x2 << 9) /* 2 */ +#define STATE_STBY (0x3 << 9) /* 3 */ +#define STATE_TRAN (0x4 << 9) /* 4 */ +#define STATE_DATA (0x5 << 9) /* 5 */ +#define STATE_RCV (0x6 << 9) /* 6 */ +#define STATE_PRG (0x7 << 9) /* 7 */ +#define STATE_DIS (0x8 << 9) /* 8 */ +#define STATE_BTST (0x9 << 9) /* 9 */ + +/* These are unpacked versions of the actual responses */ + +struct _mmc_csd { + u8 csd_structure; + u8 spec_vers; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc; + u8 read_bl_len; + u8 read_bl_partial; + u8 write_blk_misalign; + u8 read_blk_misalign; + u8 dsr_imp; + u16 c_size; + u8 vdd_r_curr_min; + u8 vdd_r_curr_max; + u8 vdd_w_curr_min; + u8 vdd_w_curr_max; + u8 c_size_mult; + union { + struct { /* MMC system specification version 3.1 */ + u8 erase_grp_size; + u8 erase_grp_mult; + } v31; + struct { /* MMC system specification version 2.2 */ + u8 sector_size; + u8 erase_grp_size; + } v22; + } erase; + u8 wp_grp_size; + u8 wp_grp_enable; + u8 default_ecc; + u8 r2w_factor; + u8 write_bl_len; + u8 write_bl_partial; + u8 file_format_grp; + u8 copy; + u8 perm_write_protect; + u8 tmp_write_protect; + u8 file_format; + u8 ecc; +}; + +struct _mmc_ext_csd { + u8 s_cmd_set; + u32 sec_count; + u8 MIN_PERF_W_8_52; + u8 MIN_PERF_R_8_52; + u8 MIN_PERF_W_8_26_4_52; + u8 MIN_PERF_R_8_26_4_52; + u8 MIN_PERF_W_4_26; + u8 MIN_PERF_R_4_26; + u8 PWR_CL_26_360; + u8 PWR_CL_52_360; + u8 PWR_CL_26_195; + u8 PWR_CL_52_195; + u8 card_type; + u8 csd_structure; + u8 ext_csd_rev; + u8 cmd_set; + u8 cmd_set_rev; + u8 power_class; + u8 hs_timing; + u8 bus_width; +}; + +#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */ +#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */ +#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */ +#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */ +#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */ +#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */ +#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */ +#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */ +#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ +#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ +#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ +#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ +#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ +#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ +#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ +#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ +#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ +#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ +#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ +#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ +#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ +#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ +#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ +#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ +#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ + +/* + * Card Command Classes (CCC) + */ +#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ + /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ +#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ + /* (CMD11) */ +#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ + /* (CMD16,17,18) */ +#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */ + /* (CMD20) */ +#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */ + /* (CMD16,24,25,26,27) */ +#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */ + /* (CMD32,33,34,35,36,37,38,39) */ +#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */ + /* (CMD28,29,30) */ +#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */ + /* (CMD16,CMD42) */ +#define CCC_APP_SPEC (1<<8) /* (8) Application specific */ + /* (CMD55,56,57,ACMD*) */ +#define CCC_IO_MODE (1<<9) /* (9) I/O mode */ + /* (CMD5,39,40,52,53) */ +#define CCC_SWITCH (1<<10) /* (10) High speed switch */ + /* (CMD6,34,35,36,37,50) */ + /* (11) Reserved */ + /* (CMD?) */ + +/* + * CSD field definitions + */ + +#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ +#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ + +#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ +#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ +#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ +#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 ~ 4.2 */ + +/* + * SD bus widths + */ +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 + +/* + * EXT_CSD field definitions + */ + +/* + * S_CMD_SET + */ + +#define STANDARD_MMC 0 /* Standard MMC */ +#define SECURE_MMC 1 /* Secure MMC */ +#define CPS_MMC 2 /* Content Protection Secure MMC */ +#define SECURE_MMC_2 3 /* Secure MMC 2.0 */ +#define ATA_MMC 4 /* ATA on MMC */ + +/* + * MIN_PERF_a_b_ff + */ +#define NO_CLASS 0x0 /* For cards not reaching the 2.4MB/s minimum value */ +#define CLASS_A 0x08 /* Class A */ +#define CLASS_B 0x0A /* Class B */ +#define CLASS_C 0x0F /* Class C */ +#define CLASS_D 0x14 /* Class D */ +#define CLASS_E 0x1E /* Class E */ +#define CLASS_F 0x28 /* Class F */ +#define CLASS_G 0x32 /* Class G */ +#define CLASS_H 0x3c /* Class H */ +#define CLASS_J 0x46 /* Class J */ +#define CLASS_K 0x50 /* Class E */ +#define CLASS_M 0x64 /* Class M */ +#define CLASS_O 0x78 /* Class O */ +#define CLASS_R 0x8c /* Class R */ +#define CLASS_T 0xa0 /* Class T */ + +/* + * CARD_TYPE + */ + +#define MMCPLUS_26MHZ (1<<0) +#define MMCPLUS_52MHZ (1<<1) + +/* + * EXT_CSD_REV + */ + +#define EXT_CSD_REV_1_0 0 +#define EXT_CSD_REV_1_1 1 +#define EXT_CSD_REV_1_2 2 + +/* + * HS_TIMING + */ +#define HS_TIMING_LOW 0 +#define HS_TIMING_HIGH 1 + +/* + * BUS_WIDTH + */ +#define MMCPLUS_BUS_WIDTH_1 0 +#define MMCPLUS_BUS_WIDTH_4 1 +#define MMCPLUS_BUS_WIDTH_8 2 + + +/* + * ERASED_MEM_CONT + */ + +#define ERASED_MEM_CONT_0 0 +#define ERASED_MEM_CONT_1 1 + +/* + * Argument for CMD6 + */ + +/* + * EXT_CSD Access Modes + */ + +#define EXT_CSD_COMMAND_SET 0 +#define EXT_CSD_SET_BITS 1 +#define EXT_CSD_CLEAR_BITS 2 +#define EXT_CSD_WRITE_BYTE 3 + +/* + * EXT_CSD Argument Byte + */ + +#define EXT_CSD_POWER_CLASS 187 +#define EXT_CSD_BUS_WIDTH 183 +#define EXT_CSD_HS_TIMING 185 + +#endif /* MMC_MMC_PROTOCOL_H */ + diff --git a/qiboot/include/linux-mmc.h b/qiboot/include/linux-mmc.h new file mode 100644 index 0000000..2750a51 --- /dev/null +++ b/qiboot/include/linux-mmc.h @@ -0,0 +1,120 @@ +/* + * linux/include/linux/mmc/mmc.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef MMC_H +#define MMC_H + +/* removed by scsuh */ +#if 0 +#include +#include +#include + +struct request; +struct mmc_data; +struct mmc_request; +#endif + +#define MMC_RSP_PRESENT (1 << 0) +#define MMC_RSP_136 (1 << 1) /* 136 bit response */ +#define MMC_RSP_CRC (1 << 2) /* expect valid crc */ +#define MMC_RSP_BUSY (1 << 3) /* card may send busy */ +#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ +#define MMC_CMD_MASK (3 << 5) /* command type */ +#define MMC_CMD_AC (0 << 5) +#define MMC_CMD_ADTC (1 << 5) +#define MMC_CMD_BC (2 << 5) +#define MMC_CMD_BCR (3 << 5) + +/* + * These are the response types, and correspond to valid bit + * patterns of the above flags. One additional valid pattern + * is all zeros, which means we don't expect a response. + */ +#define MMC_RSP_NONE (0) +#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) +#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) +#define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC) + +#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) + +/* + * These are the command types. + */ +#define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK) + +#define MMC_ERR_NONE 0 +#define MMC_ERR_TIMEOUT 1 +#define MMC_ERR_BADCRC 2 +#define MMC_ERR_FIFO 3 +#define MMC_ERR_FAILED 4 +#define MMC_ERR_INVALID 5 + +struct mmc_command { + u32 opcode; + u32 arg; + u32 resp[4]; + unsigned int flags; /* expected response type */ + struct mmc_data *data; /* data segment associated with cmd */ + struct mmc_request *mrq; /* associated request */ + unsigned int retries; /* max number of retries */ + unsigned int error; /* command error */ + +}; + +struct mmc_data { + unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */ + unsigned int timeout_clks; /* data timeout (in clocks) */ + unsigned int blksz_bits; /* data block size */ + unsigned int blksz; /* data block size */ + unsigned int blocks; /* number of blocks */ + unsigned int error; /* data error */ + unsigned int flags; + +#define MMC_DATA_WRITE (1 << 8) +#define MMC_DATA_READ (1 << 9) +#define MMC_DATA_STREAM (1 << 10) +#define MMC_DATA_MULTI (1 << 11) + + unsigned int bytes_xfered; + + struct mmc_command *stop; /* stop command */ + struct mmc_request *mrq; /* associated request */ + + unsigned int sg_len; /* size of scatter list */ + struct scatterlist *sg; /* I/O scatter list */ +}; + +struct mmc_request { + struct mmc_command *cmd; + struct mmc_data *data; + struct mmc_command *stop; + + void *done_data; /* completion data */ + void (*done)(struct mmc_request *);/* completion function */ +}; + +struct mmc_host; +struct mmc_card; + +extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *); +extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); +extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int, + struct mmc_command *, int); + +extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card); + +static inline void mmc_claim_host(struct mmc_host *host) +{ + __mmc_claim_host(host, (struct mmc_card *)-1); +} + +extern void mmc_release_host(struct mmc_host *host); + +#endif diff --git a/qiboot/include/mmc.h b/qiboot/include/mmc.h new file mode 100644 index 0000000..1a81f2a --- /dev/null +++ b/qiboot/include/mmc.h @@ -0,0 +1,110 @@ +/* + * linux/drivers/mmc/mmc_pxa.h + * + * Author: Vladimir Shebordaev, Igor Oblakov + * Copyright: MontaVista Software Inc. + * + * $Id: mmc_pxa.h,v 0.3.1.6 2002/09/25 19:25:48 ted Exp ted $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __MMC_PXA_P_H__ +#define __MMC_PXA_P_H__ + +#define MMC_DEFAULT_RCA (1<<16) + +#define MMC_BLOCK_SIZE 512 +#define MMC_CMD_RESET 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RCA 3 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_BLOCK 17 +#define MMC_CMD_RD_BLK_MULTI 18 +#define MMC_CMD_WRITE_BLOCK 24 + +#define MMC_MAX_BLOCK_SIZE 512 + +#define MMC_R1_IDLE_STATE 0x01 +#define MMC_R1_ERASE_STATE 0x02 +#define MMC_R1_ILLEGAL_CMD 0x04 +#define MMC_R1_COM_CRC_ERR 0x08 +#define MMC_R1_ERASE_SEQ_ERR 0x01 +#define MMC_R1_ADDR_ERR 0x02 +#define MMC_R1_PARAM_ERR 0x04 + +#define MMC_R1B_WP_ERASE_SKIP 0x0002 +#define MMC_R1B_ERR 0x0004 +#define MMC_R1B_CC_ERR 0x0008 +#define MMC_R1B_CARD_ECC_ERR 0x0010 +#define MMC_R1B_WP_VIOLATION 0x0020 +#define MMC_R1B_ERASE_PARAM 0x0040 +#define MMC_R1B_OOR 0x0080 +#define MMC_R1B_IDLE_STATE 0x0100 +#define MMC_R1B_ERASE_RESET 0x0200 +#define MMC_R1B_ILLEGAL_CMD 0x0400 +#define MMC_R1B_COM_CRC_ERR 0x0800 +#define MMC_R1B_ERASE_SEQ_ERR 0x1000 +#define MMC_R1B_ADDR_ERR 0x2000 +#define MMC_R1B_PARAM_ERR 0x4000 + +typedef struct mmc_cid +{ + /* FIXME: BYTE_ORDER */ + u8 year:4, + month:4; + u8 sn[3]; + u8 fwrev:4, + hwrev:4; + u8 name[6]; + u8 id[3]; +} mmc_cid_t; + +typedef struct mmc_csd +{ + u8 ecc:2, + file_format:2, + tmp_write_protect:1, + perm_write_protect:1, + copy:1, + file_format_grp:1; + unsigned long long content_prot_app:1, + rsvd3:4, + write_bl_partial:1, + write_bl_len:4, + r2w_factor:3, + default_ecc:2, + wp_grp_enable:1, + wp_grp_size:5, + erase_grp_mult:5, + erase_grp_size:5, + c_size_mult1:3, + vdd_w_curr_max:3, + vdd_w_curr_min:3, + vdd_r_curr_max:3, + vdd_r_curr_min:3, + c_size:12, + rsvd2:2, + dsr_imp:1, + read_blk_misalign:1, + write_blk_misalign:1, + read_bl_partial:1; + + u16 read_bl_len:4, + ccc:12; + u8 tran_speed; + u8 nsac; + u8 taac; + u8 rsvd1:2, + spec_vers:4, + csd_structure:2; +} mmc_csd_t; + + +#endif /* __MMC_PXA_P_H__ */ diff --git a/qiboot/include/neo_gta01.h b/qiboot/include/neo_gta01.h new file mode 100644 index 0000000..6b4b174 --- /dev/null +++ b/qiboot/include/neo_gta01.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H +#ifndef __ASM_MODE__ +#include +extern const struct board_api board_api_gta01; +#endif + +#define TEXT_BASE 0x33000000 + +#endif /* __CONFIG_H */ diff --git a/qiboot/include/neo_gta02.h b/qiboot/include/neo_gta02.h new file mode 100644 index 0000000..7492630 --- /dev/null +++ b/qiboot/include/neo_gta02.h @@ -0,0 +1,32 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H +#ifndef __ASM_MODE__ +#include +extern const struct board_api board_api_gta02; +#endif + +#define TEXT_BASE 0x33000000 + +#endif /* __CONFIG_H */ diff --git a/qiboot/include/neo_om_3d7k.h b/qiboot/include/neo_om_3d7k.h new file mode 100644 index 0000000..141b390 --- /dev/null +++ b/qiboot/include/neo_om_3d7k.h @@ -0,0 +1,28 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_MODE__ +#include +extern const struct board_api board_api_om_3d7k; +#endif + +#define TEXT_BASE_OM_3D7K 0x53000000 diff --git a/qiboot/include/neo_smdk6410.h b/qiboot/include/neo_smdk6410.h new file mode 100644 index 0000000..a438170 --- /dev/null +++ b/qiboot/include/neo_smdk6410.h @@ -0,0 +1,6 @@ +#ifndef __ASM_MODE__ +#include +extern const struct board_api board_api_smdk6410; +#endif + +#define TEXT_BASE_SMDK6410 0x53000000 diff --git a/qiboot/include/pcf50606.h b/qiboot/include/pcf50606.h new file mode 100644 index 0000000..b0a1807 --- /dev/null +++ b/qiboot/include/pcf50606.h @@ -0,0 +1,260 @@ +#ifndef _PCF50606_H +#define _PCF50606_H + +/* Philips PCF50606 Power Managemnt Unit (PMU) driver + * (C) 2006-2007 by OpenMoko, Inc. + * Author: Harald Welte + * + */ + +enum pfc50606_regs { + PCF50606_REG_ID = 0x00, + PCF50606_REG_OOCS = 0x01, + PCF50606_REG_INT1 = 0x02, /* Interrupt Status */ + PCF50606_REG_INT2 = 0x03, /* Interrupt Status */ + PCF50606_REG_INT3 = 0x04, /* Interrupt Status */ + PCF50606_REG_INT1M = 0x05, /* Interrupt Mask */ + PCF50606_REG_INT2M = 0x06, /* Interrupt Mask */ + PCF50606_REG_INT3M = 0x07, /* Interrupt Mask */ + PCF50606_REG_OOCC1 = 0x08, + PCF50606_REG_OOCC2 = 0x09, + PCF50606_REG_RTCSC = 0x0a, /* Second */ + PCF50606_REG_RTCMN = 0x0b, /* Minute */ + PCF50606_REG_RTCHR = 0x0c, /* Hour */ + PCF50606_REG_RTCWD = 0x0d, /* Weekday */ + PCF50606_REG_RTCDT = 0x0e, /* Day */ + PCF50606_REG_RTCMT = 0x0f, /* Month */ + PCF50606_REG_RTCYR = 0x10, /* Year */ + PCF50606_REG_RTCSCA = 0x11, /* Alarm Second */ + PCF50606_REG_RTCMNA = 0x12, /* Alarm Minute */ + PCF50606_REG_RTCHRA = 0x13, /* Alarm Hour */ + PCF50606_REG_RTCWDA = 0x14, /* Alarm Weekday */ + PCF50606_REG_RTCDTA = 0x15, /* Alarm Day */ + PCF50606_REG_RTCMTA = 0x16, /* Alarm Month */ + PCF50606_REG_RTCYRA = 0x17, /* Alarm Year */ + PCF50606_REG_PSSC = 0x18, /* Power sequencing */ + PCF50606_REG_PWROKM = 0x19, /* PWROK mask */ + PCF50606_REG_PWROKS = 0x1a, /* PWROK status */ + PCF50606_REG_DCDC1 = 0x1b, + PCF50606_REG_DCDC2 = 0x1c, + PCF50606_REG_DCDC3 = 0x1d, + PCF50606_REG_DCDC4 = 0x1e, + PCF50606_REG_DCDEC1 = 0x1f, + PCF50606_REG_DCDEC2 = 0x20, + PCF50606_REG_DCUDC1 = 0x21, + PCF50606_REG_DCUDC2 = 0x22, + PCF50606_REG_IOREGC = 0x23, + PCF50606_REG_D1REGC1 = 0x24, + PCF50606_REG_D2REGC1 = 0x25, + PCF50606_REG_D3REGC1 = 0x26, + PCF50606_REG_LPREGC1 = 0x27, + PCF50606_REG_LPREGC2 = 0x28, + PCF50606_REG_MBCC1 = 0x29, + PCF50606_REG_MBCC2 = 0x2a, + PCF50606_REG_MBCC3 = 0x2b, + PCF50606_REG_MBCS1 = 0x2c, + PCF50606_REG_BBCC = 0x2d, + PCF50606_REG_ADCC1 = 0x2e, + PCF50606_REG_ADCC2 = 0x2f, + PCF50606_REG_ADCS1 = 0x30, + PCF50606_REG_ADCS2 = 0x31, + PCF50606_REG_ADCS3 = 0x32, + PCF50606_REG_ACDC1 = 0x33, + PCF50606_REG_BVMC = 0x34, + PCF50606_REG_PWMC1 = 0x35, + PCF50606_REG_LEDC1 = 0x36, + PCF50606_REG_LEDC2 = 0x37, + PCF50606_REG_GPOC1 = 0x38, + PCF50606_REG_GPOC2 = 0x39, + PCF50606_REG_GPOC3 = 0x3a, + PCF50606_REG_GPOC4 = 0x3b, + PCF50606_REG_GPOC5 = 0x3c, + __NUM_PCF50606_REGS +}; + +enum pcf50606_reg_oocs { + PFC50606_OOCS_ONKEY = 0x01, + PCF50606_OOCS_EXTON = 0x02, + PCF50606_OOCS_PWROKRST = 0x04, + PCF50606_OOCS_BATOK = 0x08, + PCF50606_OOCS_BACKOK = 0x10, + PCF50606_OOCS_CHGOK = 0x20, + PCF50606_OOCS_TEMPOK = 0x40, + PCF50606_OOCS_WDTEXP = 0x80, +}; + +enum pcf50606_reg_oocc1 { + PCF50606_OOCC1_GOSTDBY = 0x01, + PCF50606_OOCC1_TOTRST = 0x02, + PCF50606_OOCC1_CLK32ON = 0x04, + PCF50606_OOCC1_WDTRST = 0x08, + PCF50606_OOCC1_RTCWAK = 0x10, + PCF50606_OOCC1_CHGWAK = 0x20, + PCF50606_OOCC1_EXTONWAK_HIGH = 0x40, + PCF50606_OOCC1_EXTONWAK_LOW = 0x80, + PCF50606_OOCC1_EXTONWAK_NO_WAKEUP = 0x3f, +}; + +enum pcf50606_reg_oocc2 { + PCF50606_OOCC2_ONKEYDB_NONE = 0x00, + PCF50606_OOCC2_ONKEYDB_14ms = 0x01, + PCF50606_OOCC2_ONKEYDB_62ms = 0x02, + PCF50606_OOCC2_ONKEYDB_500ms = 0x03, + PCF50606_OOCC2_EXTONDB_NONE = 0x00, + PCF50606_OOCC2_EXTONDB_14ms = 0x04, + PCF50606_OOCC2_EXTONDB_62ms = 0x08, + PCF50606_OOCC2_EXTONDB_500ms = 0x0c, +}; + +enum pcf50606_reg_int1 { + PCF50606_INT1_ONKEYR = 0x01, /* ONKEY rising edge */ + PCF50606_INT1_ONKEYF = 0x02, /* ONKEY falling edge */ + PCF50606_INT1_ONKEY1S = 0x04, /* OMKEY at least 1sec low */ + PCF50606_INT1_EXTONR = 0x08, /* EXTON rising edge */ + PCF50606_INT1_EXTONF = 0x10, /* EXTON falling edge */ + PCF50606_INT1_SECOND = 0x40, /* RTC periodic second interrupt */ + PCF50606_INT1_ALARM = 0x80, /* RTC alarm time is reached */ +}; + +enum pcf50606_reg_int2 { + PCF50606_INT2_CHGINS = 0x01, /* Charger inserted */ + PCF50606_INT2_CHGRM = 0x02, /* Charger removed */ + PCF50606_INT2_CHGFOK = 0x04, /* Fast charging OK */ + PCF50606_INT2_CHGERR = 0x08, /* Error in charging mode */ + PCF50606_INT2_CHGFRDY = 0x10, /* Fast charge completed */ + PCF50606_INT2_CHGPROT = 0x20, /* Charging protection interrupt */ + PCF50606_INT2_CHGWD10S = 0x40, /* Charger watchdig expires in 10s */ + PCF50606_INT2_CHGWDEXP = 0x80, /* Charger watchdog expires */ +}; + +enum pcf50606_reg_int3 { + PCF50606_INT3_ADCRDY = 0x01, /* ADC conversion finished */ + PCF50606_INT3_ACDINS = 0x02, /* Accessory inserted */ + PCF50606_INT3_ACDREM = 0x04, /* Accessory removed */ + PCF50606_INT3_TSCPRES = 0x08, /* Touch screen pressed */ + PCF50606_INT3_LOWBAT = 0x40, /* Low battery voltage */ + PCF50606_INT3_HIGHTMP = 0x80, /* High temperature */ +}; + +/* used by PSSC, PWROKM, PWROKS, */ +enum pcf50606_regu { + PCF50606_REGU_DCD = 0x01, /* DCD in phase 2 */ + PCF50606_REGU_DCDE = 0x02, /* DCDE in phase 2 */ + PCF50606_REGU_DCUD = 0x04, /* DCDU in phase 2 */ + PCF50606_REGU_IO = 0x08, /* IO in phase 2 */ + PCF50606_REGU_D1 = 0x10, /* D1 in phase 2 */ + PCF50606_REGU_D2 = 0x20, /* D2 in phase 2 */ + PCF50606_REGU_D3 = 0x40, /* D3 in phase 2 */ + PCF50606_REGU_LP = 0x80, /* LP in phase 2 */ +}; + +enum pcf50606_reg_dcdc4 { + PCF50606_DCDC4_MODE_AUTO = 0x00, + PCF50606_DCDC4_MODE_PWM = 0x01, + PCF50606_DCDC4_MODE_PCF = 0x02, + PCF50606_DCDC4_OFF_FLOAT = 0x00, + PCF50606_DCDC4_OFF_BYPASS = 0x04, + PCF50606_DCDC4_OFF_PULLDOWN = 0x08, + PCF50606_DCDC4_CURLIM_500mA = 0x00, + PCF50606_DCDC4_CURLIM_750mA = 0x10, + PCF50606_DCDC4_CURLIM_1000mA = 0x20, + PCF50606_DCDC4_CURLIM_1250mA = 0x30, + PCF50606_DCDC4_TOGGLE = 0x40, + PCF50606_DCDC4_REGSEL_DCDC2 = 0x80, +}; + +enum pcf50606_reg_dcdec2 { + PCF50606_DCDEC2_MODE_AUTO = 0x00, + PCF50606_DCDEC2_MODE_PWM = 0x01, + PCF50606_DCDEC2_MODE_PCF = 0x02, + PCF50606_DCDEC2_OFF_FLOAT = 0x00, + PCF50606_DCDEC2_OFF_BYPASS = 0x04, +}; + +enum pcf50606_reg_dcudc2 { + PCF50606_DCUDC2_MODE_AUTO = 0x00, + PCF50606_DCUDC2_MODE_PWM = 0x01, + PCF50606_DCUDC2_MODE_PCF = 0x02, + PCF50606_DCUDC2_OFF_FLOAT = 0x00, + PCF50606_DCUDC2_OFF_BYPASS = 0x04, +}; + +enum pcf50606_reg_adcc1 { + PCF50606_ADCC1_TSCMODACT = 0x01, + PCF50606_ADCC1_TSCMODSTB = 0x02, + PCF50606_ADCC1_TRATSET = 0x04, + PCF50606_ADCC1_NTCSWAPE = 0x08, + PCF50606_ADCC1_NTCSWAOFF = 0x10, + PCF50606_ADCC1_EXTSYNCBREAK = 0x20, + /* reserved */ + PCF50606_ADCC1_TSCINT = 0x80, +}; + +enum pcf50606_reg_adcc2 { + PCF50606_ADCC2_ADCSTART = 0x01, + /* see enum pcf50606_adcc2_adcmux */ + PCF50606_ADCC2_SYNC_NONE = 0x00, + PCF50606_ADCC2_SYNC_TXON = 0x20, + PCF50606_ADCC2_SYNC_PWREN1 = 0x40, + PCF50606_ADCC2_SYNC_PWREN2 = 0x60, + PCF50606_ADCC2_RES_10BIT = 0x00, + PCF50606_ADCC2_RES_8BIT = 0x80, +}; + +#define PCF50606_ADCC2_ADCMUX_MASK (0xf << 1) + +#define ADCMUX_SHIFT 1 +enum pcf50606_adcc2_adcmux { + PCF50606_ADCMUX_BATVOLT_RES = 0x0 << ADCMUX_SHIFT, + PCF50606_ADCMUX_BATVOLT_SUBTR = 0x1 << ADCMUX_SHIFT, + PCF50606_ADCMUX_ADCIN1_RES = 0x2 << ADCMUX_SHIFT, + PCF50606_ADCMUX_ADCIN1_SUBTR = 0x3 << ADCMUX_SHIFT, + PCF50606_ADCMUX_BATTEMP = 0x4 << ADCMUX_SHIFT, + PCF50606_ADCMUX_ADCIN2 = 0x5 << ADCMUX_SHIFT, + PCF50606_ADCMUX_ADCIN3 = 0x6 << ADCMUX_SHIFT, + PCF50606_ADCMUX_ADCIN3_RATIO = 0x7 << ADCMUX_SHIFT, + PCF50606_ADCMUX_XPOS = 0x8 << ADCMUX_SHIFT, + PCF50606_ADCMUX_YPOS = 0x9 << ADCMUX_SHIFT, + PCF50606_ADCMUX_P1 = 0xa << ADCMUX_SHIFT, + PCF50606_ADCMUX_P2 = 0xb << ADCMUX_SHIFT, + PCF50606_ADCMUX_BATVOLT_ADCIN1 = 0xc << ADCMUX_SHIFT, + PCF50606_ADCMUX_XY_SEQUENCE = 0xe << ADCMUX_SHIFT, + PCF50606_P1_P2_RESISTANCE = 0xf << ADCMUX_SHIFT, +}; + +enum pcf50606_adcs2 { + PCF50606_ADCS2_ADCRDY = 0x80, +}; + +enum pcf50606_reg_mbcc1 { + PCF50606_MBCC1_CHGAPE = 0x01, + PCF50606_MBCC1_AUTOFST = 0x02, +#define PCF50606_MBCC1_CHGMOD_MASK 0x1c +#define PCF50606_MBCC1_CHGMOD_SHIFT 2 + PCF50606_MBCC1_CHGMOD_QUAL = 0x00, + PCF50606_MBCC1_CHGMOD_PRE = 0x04, + PCF50606_MBCC1_CHGMOD_TRICKLE = 0x08, + PCF50606_MBCC1_CHGMOD_FAST_CCCV = 0x0c, + PCF50606_MBCC1_CHGMOD_FAST_NOCC = 0x10, + PCF50606_MBCC1_CHGMOD_FAST_NOCV = 0x14, + PCF50606_MBCC1_CHGMOD_FAST_SW = 0x18, + PCF50606_MBCC1_CHGMOD_IDLE = 0x1c, + PCF50606_MBCC1_DETMOD_LOWCHG = 0x20, + PCF50606_MBCC1_DETMOD_WDRST = 0x40, +}; + +enum pcf50606_reg_bvmc { + PCF50606_BVMC_LOWBAT = 0x01, + PCF50606_BVMC_THRSHLD_NULL = 0x00, + PCF50606_BVMC_THRSHLD_2V8 = 0x02, + PCF50606_BVMC_THRSHLD_2V9 = 0x04, + PCF50606_BVMC_THRSHLD_3V = 0x08, + PCF50606_BVMC_THRSHLD_3V1 = 0x08, + PCF50606_BVMC_THRSHLD_3V2 = 0x0a, + PCF50606_BVMC_THRSHLD_3V3 = 0x0c, + PCF50606_BVMC_THRSHLD_3V4 = 0x0e, + PCF50606_BVMC_DISDB = 0x10, +}; + +#endif /* _PCF50606_H */ + diff --git a/qiboot/include/pcf50633.h b/qiboot/include/pcf50633.h new file mode 100644 index 0000000..51da119 --- /dev/null +++ b/qiboot/include/pcf50633.h @@ -0,0 +1,392 @@ +#ifndef _PCF50633_H +#define _PCF50633_H + +/* Philips PCF50633 Power Managemnt Unit (PMU) driver + * (C) 2006-2007 by OpenMoko, Inc. + * Author: Harald Welte + * + */ + +enum pfc50633_regs { + PCF50633_REG_VERSION = 0x00, + PCF50633_REG_VARIANT = 0x01, + PCF50633_REG_INT1 = 0x02, /* Interrupt Status */ + PCF50633_REG_INT2 = 0x03, /* Interrupt Status */ + PCF50633_REG_INT3 = 0x04, /* Interrupt Status */ + PCF50633_REG_INT4 = 0x05, /* Interrupt Status */ + PCF50633_REG_INT5 = 0x06, /* Interrupt Status */ + PCF50633_REG_INT1M = 0x07, /* Interrupt Mask */ + PCF50633_REG_INT2M = 0x08, /* Interrupt Mask */ + PCF50633_REG_INT3M = 0x09, /* Interrupt Mask */ + PCF50633_REG_INT4M = 0x0a, /* Interrupt Mask */ + PCF50633_REG_INT5M = 0x0b, /* Interrupt Mask */ + PCF50633_REG_OOCSHDWN = 0x0c, + PCF50633_REG_OOCWAKE = 0x0d, + PCF50633_REG_OOCTIM1 = 0x0e, + PCF50633_REG_OOCTIM2 = 0x0f, + PCF50633_REG_OOCMODE = 0x10, + PCF50633_REG_OOCCTL = 0x11, + PCF50633_REG_OOCSTAT = 0x12, + PCF50633_REG_GPIOCTL = 0x13, + PCF50633_REG_GPIO1CFG = 0x14, + PCF50633_REG_GPIO2CFG = 0x15, + PCF50633_REG_GPIO3CFG = 0x16, + PCF50633_REG_GPOCFG = 0x17, + PCF50633_REG_BVMCTL = 0x18, + PCF50633_REG_SVMCTL = 0x19, + PCF50633_REG_AUTOOUT = 0x1a, + PCF50633_REG_AUTOENA = 0x1b, + PCF50633_REG_AUTOCTL = 0x1c, + PCF50633_REG_AUTOMXC = 0x1d, + PCF50633_REG_DOWN1OUT = 0x1e, + PCF50633_REG_DOWN1ENA = 0x1f, + PCF50633_REG_DOWN1CTL = 0x20, + PCF50633_REG_DOWN1MXC = 0x21, + PCF50633_REG_DOWN2OUT = 0x22, + PCF50633_REG_DOWN2ENA = 0x23, + PCF50633_REG_DOWN2CTL = 0x24, + PCF50633_REG_DOWN2MXC = 0x25, + PCF50633_REG_MEMLDOOUT = 0x26, + PCF50633_REG_MEMLDOENA = 0x27, + PCF50633_REG_LEDOUT = 0x28, + PCF50633_REG_LEDENA = 0x29, + PCF50633_REG_LEDCTL = 0x2a, + PCF50633_REG_LEDDIM = 0x2b, + /* reserved */ + PCF50633_REG_LDO1OUT = 0x2d, + PCF50633_REG_LDO1ENA = 0x2e, + PCF50633_REG_LDO2OUT = 0x2f, + PCF50633_REG_LDO2ENA = 0x30, + PCF50633_REG_LDO3OUT = 0x31, + PCF50633_REG_LDO3ENA = 0x32, + PCF50633_REG_LDO4OUT = 0x33, + PCF50633_REG_LDO4ENA = 0x34, + PCF50633_REG_LDO5OUT = 0x35, + PCF50633_REG_LDO5ENA = 0x36, + PCF50633_REG_LDO6OUT = 0x37, + PCF50633_REG_LDO6ENA = 0x38, + PCF50633_REG_HCLDOOUT = 0x39, + PCF50633_REG_HCLDOENA = 0x3a, + PCF50633_REG_STBYCTL1 = 0x3b, + PCF50633_REG_STBYCTL2 = 0x3c, + PCF50633_REG_DEBPF1 = 0x3d, + PCF50633_REG_DEBPF2 = 0x3e, + PCF50633_REG_DEBPF3 = 0x3f, + PCF50633_REG_HCLDOOVL = 0x40, + PCF50633_REG_DCDCSTAT = 0x41, + PCF50633_REG_LDOSTAT = 0x42, + PCF50633_REG_MBCC1 = 0x43, + PCF50633_REG_MBCC2 = 0x44, + PCF50633_REG_MBCC3 = 0x45, + PCF50633_REG_MBCC4 = 0x46, + PCF50633_REG_MBCC5 = 0x47, + PCF50633_REG_MBCC6 = 0x48, + PCF50633_REG_MBCC7 = 0x49, + PCF50633_REG_MBCC8 = 0x4a, + PCF50633_REG_MBCS1 = 0x4b, + PCF50633_REG_MBCS2 = 0x4c, + PCF50633_REG_MBCS3 = 0x4d, + PCF50633_REG_BBCCTL = 0x4e, + PCF50633_REG_ALMGAIN = 0x4f, + PCF50633_REG_ALMDATA = 0x50, + /* reserved */ + PCF50633_REG_ADCC3 = 0x52, + PCF50633_REG_ADCC2 = 0x53, + PCF50633_REG_ADCC1 = 0x54, + PCF50633_REG_ADCS1 = 0x55, + PCF50633_REG_ADCS2 = 0x56, + PCF50633_REG_ADCS3 = 0x57, + /* reserved */ + PCF50633_REG_RTCSC = 0x59, /* Second */ + PCF50633_REG_RTCMN = 0x5a, /* Minute */ + PCF50633_REG_RTCHR = 0x5b, /* Hour */ + PCF50633_REG_RTCWD = 0x5c, /* Weekday */ + PCF50633_REG_RTCDT = 0x5d, /* Day */ + PCF50633_REG_RTCMT = 0x5e, /* Month */ + PCF50633_REG_RTCYR = 0x5f, /* Year */ + PCF50633_REG_RTCSCA = 0x60, /* Alarm Second */ + PCF50633_REG_RTCMNA = 0x61, /* Alarm Minute */ + PCF50633_REG_RTCHRA = 0x62, /* Alarm Hour */ + PCF50633_REG_RTCWDA = 0x63, /* Alarm Weekday */ + PCF50633_REG_RTCDTA = 0x64, /* Alarm Day */ + PCF50633_REG_RTCMTA = 0x65, /* Alarm Month */ + PCF50633_REG_RTCYRA = 0x66, /* Alarm Year */ + + PCF50633_REG_MEMBYTE0 = 0x67, + PCF50633_REG_MEMBYTE1 = 0x68, + PCF50633_REG_MEMBYTE2 = 0x69, + PCF50633_REG_MEMBYTE3 = 0x6a, + PCF50633_REG_MEMBYTE4 = 0x6b, + PCF50633_REG_MEMBYTE5 = 0x6c, + PCF50633_REG_MEMBYTE6 = 0x6d, + PCF50633_REG_MEMBYTE7 = 0x6e, + /* reserved */ + PCF50633_REG_DCDCPFM = 0x84, + __NUM_PCF50633_REGS +}; + +enum pcf50633_reg_int1 { + PCF50633_INT1_ADPINS = 0x01, /* Adapter inserted */ + PCF50633_INT1_ADPREM = 0x02, /* Adapter removed */ + PCF50633_INT1_USBINS = 0x04, /* USB inserted */ + PCF50633_INT1_USBREM = 0x08, /* USB removed */ + /* reserved */ + PCF50633_INT1_ALARM = 0x40, /* RTC alarm time is reached */ + PCF50633_INT1_SECOND = 0x80, /* RTC periodic second interrupt */ +}; + +enum pcf50633_reg_int2 { + PCF50633_INT2_ONKEYR = 0x01, /* ONKEY rising edge */ + PCF50633_INT2_ONKEYF = 0x02, /* ONKEY falling edge */ + PCF50633_INT2_EXTON1R = 0x04, /* EXTON1 rising edge */ + PCF50633_INT2_EXTON1F = 0x08, /* EXTON1 falling edge */ + PCF50633_INT2_EXTON2R = 0x10, /* EXTON2 rising edge */ + PCF50633_INT2_EXTON2F = 0x20, /* EXTON2 falling edge */ + PCF50633_INT2_EXTON3R = 0x40, /* EXTON3 rising edge */ + PCF50633_INT2_EXTON3F = 0x80, /* EXTON3 falling edge */ +}; + +enum pcf50633_reg_int3 { + PCF50633_INT3_BATFULL = 0x01, /* Battery full */ + PCF50633_INT3_CHGHALT = 0x02, /* Charger halt */ + PCF50633_INT3_THLIMON = 0x04, + PCF50633_INT3_THLIMOFF = 0x08, + PCF50633_INT3_USBLIMON = 0x10, + PCF50633_INT3_USBLIMOFF = 0x20, + PCF50633_INT3_ADCRDY = 0x40, /* ADC conversion finished */ + PCF50633_INT3_ONKEY1S = 0x80, /* ONKEY pressed 1 second */ +}; + +enum pcf50633_reg_int4 { + PCF50633_INT4_LOWSYS = 0x01, + PCF50633_INT4_LOWBAT = 0x02, + PCF50633_INT4_HIGHTMP = 0x04, + PCF50633_INT4_AUTOPWRFAIL = 0x08, + PCF50633_INT4_DWN1PWRFAIL = 0x10, + PCF50633_INT4_DWN2PWRFAIL = 0x20, + PCF50633_INT4_LEDPWRFAIL = 0x40, + PCF50633_INT4_LEDOVP = 0x80, +}; + +enum pcf50633_reg_int5 { + PCF50633_INT4_LDO1PWRFAIL = 0x01, + PCF50633_INT4_LDO2PWRFAIL = 0x02, + PCF50633_INT4_LDO3PWRFAIL = 0x04, + PCF50633_INT4_LDO4PWRFAIL = 0x08, + PCF50633_INT4_LDO5PWRFAIL = 0x10, + PCF50633_INT4_LDO6PWRFAIL = 0x20, + PCF50633_INT4_HCLDOPWRFAIL = 0x40, + PCF50633_INT4_HCLDOOVL = 0x80, +}; + +enum pcf50633_reg_oocwake { + PCF50633_OOCWAKE_ONKEY = 0x01, + PCF50633_OOCWAKE_EXTON1 = 0x02, + PCF50633_OOCWAKE_EXTON2 = 0x04, + PCF50633_OOCWAKE_EXTON3 = 0x08, + PCF50633_OOCWAKE_RTC = 0x10, + /* reserved */ + PCF50633_OOCWAKE_USB = 0x40, + PCF50633_OOCWAKE_ADP = 0x80, +}; + +enum pcf50633_reg_mbcc1 { + PCF50633_MBCC1_CHGENA = 0x01, /* Charger enable */ + PCF50633_MBCC1_AUTOSTOP = 0x02, + PCF50633_MBCC1_AUTORES = 0x04, /* automatic resume */ + PCF50633_MBCC1_RESUME = 0x08, /* explicit resume cmd */ + PCF50633_MBCC1_RESTART = 0x10, /* restart charging */ + PCF50633_MBCC1_PREWDTIME_60M = 0x20, /* max. precharging time */ + PCF50633_MBCC1_WDTIME_1H = 0x00, + PCF50633_MBCC1_WDTIME_2H = 0x40, + PCF50633_MBCC1_WDTIME_4H = 0x80, + PCF50633_MBCC1_WDTIME_6H = 0xc0, +}; +#define PCF50633_MBCC1_WDTIME_MASK 0xc0 + +enum pcf50633_reg_mbcc2 { + PCF50633_MBCC2_VBATCOND_2V7 = 0x00, + PCF50633_MBCC2_VBATCOND_2V85 = 0x01, + PCF50633_MBCC2_VBATCOND_3V = 0x02, + PCF50633_MBCC2_VBATCOND_3V15 = 0x03, + PCF50633_MBCC2_VMAX_4V = 0x00, + PCF50633_MBCC2_VMAX_4V20 = 0x28, + PCF50633_MBCC2_VRESDEBTIME_64S = 0x80, /* debounce time (32/64sec) */ +}; +#define PCF50633_MBCC2_VBATCOND_MASK 0x03 +#define PCF50633_MBCC2_VMAX_MASK 0x3c + +#define PCF50633_OOCSTAT_ONKEY 0x01 + + +enum pcf50633_reg_adcc1 { + PCF50633_ADCC1_ADCSTART = 0x01, + PCF50633_ADCC1_RES_10BIT = 0x02, + PCF50633_ADCC1_AVERAGE_NO = 0x00, + PCF50633_ADCC1_AVERAGE_4 = 0x04, + PCF50633_ADCC1_AVERAGE_8 = 0x08, + PCF50633_ADCC1_AVERAGE_16 = 0x0c, + + PCF50633_ADCC1_MUX_BATSNS_RES = 0x00, + PCF50633_ADCC1_MUX_BATSNS_SUBTR = 0x10, + PCF50633_ADCC1_MUX_ADCIN2_RES = 0x20, + PCF50633_ADCC1_MUX_ADCIN2_SUBTR = 0x30, + PCF50633_ADCC1_MUX_BATTEMP = 0x60, + PCF50633_ADCC1_MUX_ADCIN1 = 0x70, +}; +#define PCF50633_ADCC1_AVERAGE_MASK 0x0c +#define PCF50633_ADCC1_ADCMUX_MASK 0xf0 + +enum pcf50633_reg_adcc2 { + PCF50633_ADCC2_RATIO_NONE = 0x00, + PCF50633_ADCC2_RATIO_BATTEMP = 0x01, + PCF50633_ADCC2_RATIO_ADCIN1 = 0x02, + PCF50633_ADCC2_RATIO_BOTH = 0x03, + PCF50633_ADCC2_RATIOSETTL_100US = 0x04, +}; +#define PCF50633_ADCC2_RATIO_MASK 0x03 + +enum pcf50633_reg_adcc3 { + PCF50633_ADCC3_ACCSW_EN = 0x01, + PCF50633_ADCC3_NTCSW_EN = 0x04, + PCF50633_ADCC3_RES_DIV_TWO = 0x10, + PCF50633_ADCC3_RES_DIV_THREE = 0x00, +}; + +enum pcf50633_reg_adcs3 { + PCF50633_ADCS3_REF_NTCSW = 0x00, + PCF50633_ADCS3_REF_ACCSW = 0x10, + PCF50633_ADCS3_REF_2V0 = 0x20, + PCF50633_ADCS3_REF_VISA = 0x30, + PCF50633_ADCS3_REF_2V0_2 = 0x70, + PCF50633_ADCS3_ADCRDY = 0x80, +}; +#define PCF50633_ADCS3_ADCDAT1L_MASK 0x03 +#define PCF50633_ADCS3_ADCDAT2L_MASK 0x0c +#define PCF50633_ADCS3_ADCDAT2L_SHIFT 2 +#define PCF50633_ASCS3_REF_MASK 0x70 + +enum pcf50633_regulator_enable { + PCF50633_REGULATOR_ON = 0x01, + PCF50633_REGULATOR_ON_GPIO1 = 0x02, + PCF50633_REGULATOR_ON_GPIO2 = 0x04, + PCF50633_REGULATOR_ON_GPIO3 = 0x08, +}; +#define PCF50633_REGULATOR_ON_MASK 0x0f + +enum pcf50633_regulator_phase { + PCF50633_REGULATOR_ACTPH1 = 0x00, + PCF50633_REGULATOR_ACTPH2 = 0x10, + PCF50633_REGULATOR_ACTPH3 = 0x20, + PCF50633_REGULATOR_ACTPH4 = 0x30, +}; +#define PCF50633_REGULATOR_ACTPH_MASK 0x30 + +enum pcf50633_reg_gpocfg { + PCF50633_GPOCFG_GPOSEL_0 = 0x00, + PCF50633_GPOCFG_GPOSEL_LED_NFET = 0x01, + PCF50633_GPOCFG_GPOSEL_SYSxOK = 0x02, + PCF50633_GPOCFG_GPOSEL_CLK32K = 0x03, + PCF50633_GPOCFG_GPOSEL_ADAPUSB = 0x04, + PCF50633_GPOCFG_GPOSEL_USBxOK = 0x05, + PCF50633_GPOCFG_GPOSEL_ACTPH4 = 0x06, + PCF50633_GPOCFG_GPOSEL_1 = 0x07, + PCF50633_GPOCFG_GPOSEL_INVERSE = 0x08, +}; +#define PCF50633_GPOCFG_GPOSEL_MASK 0x07 + +#if 0 +enum pcf50633_reg_mbcc1 { + PCF50633_MBCC1_CHGENA = 0x01, + PCF50633_MBCC1_AUTOSTOP = 0x02, + PCF50633_MBCC1_AUTORES = 0x04, + PCF50633_MBCC1_RESUME = 0x08, + PCF50633_MBCC1_RESTART = 0x10, + PCF50633_MBCC1_PREWDTIME_30MIN = 0x00, + PCF50633_MBCC1_PREWDTIME_60MIN = 0x20, + PCF50633_MBCC1_WDTIME_2HRS = 0x40, + PCF50633_MBCC1_WDTIME_4HRS = 0x80, + PCF50633_MBCC1_WDTIME_6HRS = 0xc0, +}; + +enum pcf50633_reg_mbcc2 { + PCF50633_MBCC2_VBATCOND_2V7 = 0x00, + PCF50633_MBCC2_VBATCOND_2V85 = 0x01, + PCF50633_MBCC2_VBATCOND_3V0 = 0x02, + PCF50633_MBCC2_VBATCOND_3V15 = 0x03, + PCF50633_MBCC2_VRESDEBTIME_64S = 0x80, +}; +#define PCF50633_MBCC2_VMAX_MASK 0x3c +#endif + +enum pcf50633_reg_mbcc7 { + PCF50633_MBCC7_USB_100mA = 0x00, + PCF50633_MBCC7_USB_500mA = 0x01, + PCF50633_MBCC7_USB_1000mA = 0x02, + PCF50633_MBCC7_USB_SUSPEND = 0x03, + PCF50633_MBCC7_BATTEMP_EN = 0x04, + PCF50633_MBCC7_BATSYSIMAX_1A6 = 0x00, + PCF50633_MBCC7_BATSYSIMAX_1A8 = 0x40, + PCF50633_MBCC7_BATSYSIMAX_2A0 = 0x80, + PCF50633_MBCC7_BATSYSIMAX_2A2 = 0xc0, +}; +#define PCF56033_MBCC7_USB_MASK 0x03 + +enum pcf50633_reg_mbcc8 { + PCF50633_MBCC8_USBENASUS = 0x10, +}; + +enum pcf50633_reg_mbcs1 { + PCF50633_MBCS1_USBPRES = 0x01, + PCF50633_MBCS1_USBOK = 0x02, + PCF50633_MBCS1_ADAPTPRES = 0x04, + PCF50633_MBCS1_ADAPTOK = 0x08, + PCF50633_MBCS1_TBAT_OK = 0x00, + PCF50633_MBCS1_TBAT_ABOVE = 0x10, + PCF50633_MBCS1_TBAT_BELOW = 0x20, + PCF50633_MBCS1_TBAT_UNDEF = 0x30, + PCF50633_MBCS1_PREWDTEXP = 0x40, + PCF50633_MBCS1_WDTEXP = 0x80, +}; + +enum pcf50633_reg_mbcs2_mbcmod { + PCF50633_MBCS2_MBC_PLAY = 0x00, + PCF50633_MBCS2_MBC_USB_PRE = 0x01, + PCF50633_MBCS2_MBC_USB_PRE_WAIT = 0x02, + PCF50633_MBCS2_MBC_USB_FAST = 0x03, + PCF50633_MBCS2_MBC_USB_FAST_WAIT= 0x04, + PCF50633_MBCS2_MBC_USB_SUSPEND = 0x05, + PCF50633_MBCS2_MBC_ADP_PRE = 0x06, + PCF50633_MBCS2_MBC_ADP_PRE_WAIT = 0x07, + PCF50633_MBCS2_MBC_ADP_FAST = 0x08, + PCF50633_MBCS2_MBC_ADP_FAST_WAIT= 0x09, + PCF50633_MBCS2_MBC_BAT_FULL = 0x0a, + PCF50633_MBCS2_MBC_HALT = 0x0b, +}; +#define PCF50633_MBCS2_MBC_MASK 0x0f +enum pcf50633_reg_mbcs2_chgstat { + PCF50633_MBCS2_CHGS_NONE = 0x00, + PCF50633_MBCS2_CHGS_ADAPTER = 0x10, + PCF50633_MBCS2_CHGS_USB = 0x20, + PCF50633_MBCS2_CHGS_BOTH = 0x30, +}; +#define PCF50633_MBCS2_RESSTAT_AUTO 0x40 + +enum pcf50633_reg_mbcs3 { + PCF50633_MBCS3_USBLIM_PLAY = 0x01, + PCF50633_MBCS3_USBLIM_CGH = 0x02, + PCF50633_MBCS3_TLIM_PLAY = 0x04, + PCF50633_MBCS3_TLIM_CHG = 0x08, + PCF50633_MBCS3_ILIM = 0x10, /* 1: Ibat > Icutoff */ + PCF50633_MBCS3_VLIM = 0x20, /* 1: Vbat == Vmax */ + PCF50633_MBCS3_VBATSTAT = 0x40, /* 1: Vbat > Vbatcond */ + PCF50633_MBCS3_VRES = 0x80, /* 1: Vbat > Vth(RES) */ +}; + +struct pcf50633_init { + u8 index; + u8 value; +}; + +#endif /* _PCF50633_H */ + diff --git a/qiboot/include/ports-s3c24xx.h b/qiboot/include/ports-s3c24xx.h new file mode 100644 index 0000000..e784d85 --- /dev/null +++ b/qiboot/include/ports-s3c24xx.h @@ -0,0 +1,41 @@ +#ifndef __PORTS_S3C24XX_H__ +#define __PORTS_S3C24XX_H__ + + +// I/O PORT +#define rGPACON (*(volatile unsigned *)0x56000000) +#define rGPADAT (*(volatile unsigned *)0x56000004) + +#define rGPBCON (*(volatile unsigned *)0x56000010) +#define rGPBDAT (*(volatile unsigned *)0x56000014) +#define rGPBUP (*(volatile unsigned *)0x56000018) + +#define rGPCCON (*(volatile unsigned *)0x56000020) +#define rGPCDAT (*(volatile unsigned *)0x56000024) +#define rGPCUP (*(volatile unsigned *)0x56000028) + +#define rGPDCON (*(volatile unsigned *)0x56000030) +#define rGPDDAT (*(volatile unsigned *)0x56000034) +#define rGPDUP (*(volatile unsigned *)0x56000038) + +#define rGPECON (*(volatile unsigned *)0x56000040) +#define rGPEDAT (*(volatile unsigned *)0x56000044) +#define rGPEUP (*(volatile unsigned *)0x56000048) + +#define rGPFCON (*(volatile unsigned *)0x56000050) +#define rGPFDAT (*(volatile unsigned *)0x56000054) +#define rGPFUP (*(volatile unsigned *)0x56000058) + +#define rGPGCON (*(volatile unsigned *)0x56000060) +#define rGPGDAT (*(volatile unsigned *)0x56000064) +#define rGPGUP (*(volatile unsigned *)0x56000068) + +#define rGPHCON (*(volatile unsigned *)0x56000070) +#define rGPHDAT (*(volatile unsigned *)0x56000074) +#define rGPHUP (*(volatile unsigned *)0x56000078) + +#define rGPJCON (*(volatile unsigned *)0x560000d0) //Port J control +#define rGPJDAT (*(volatile unsigned *)0x560000d4) //Port J data +#define rGPJUP (*(volatile unsigned *)0x560000d8) //Port J data + +#endif diff --git a/qiboot/include/qi-ctype.h b/qiboot/include/qi-ctype.h new file mode 100644 index 0000000..ed65522 --- /dev/null +++ b/qiboot/include/qi-ctype.h @@ -0,0 +1,45 @@ +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern unsigned char _ctype[]; + +#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) + +#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) +#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) +#define iscntrl(c) ((__ismask(c)&(_C)) != 0) +#define isdigit(c) ((__ismask(c)&(_D)) != 0) +#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) +#define islower(c) ((__ismask(c)&(_L)) != 0) +#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) +#define ispunct(c) ((__ismask(c)&(_P)) != 0) +#define isspace(c) ((__ismask(c)&(_S)) != 0) +#define isupper(c) ((__ismask(c)&(_U)) != 0) +#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define toascii(c) (((unsigned char)(c))&0x7f) + +static inline unsigned char __tolower(unsigned char c) +{ + if (isupper(c)) + c -= 'A'-'a'; + return c; +} + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + +#define tolower(c) __tolower(c) +#define toupper(c) __toupper(c) + diff --git a/qiboot/include/qi.h b/qiboot/include/qi.h new file mode 100644 index 0000000..b99695d --- /dev/null +++ b/qiboot/include/qi.h @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2008 Openmoko, Inc. + * Author: Andy Green + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __QI_H__ +#define __QI_H__ + +#include +#include +#include + +#define MALLOC_POOL_EXTENT (100 * 1024) + +#define u32 unsigned int +#define u16 unsigned short +#define u8 unsigned char +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +enum filesystem { + FS_RAW, + FS_FAT, + FS_EXT2 +}; + +enum ui_actions { + UI_ACTION_ADD_DEBUG = (1 << 0), + UI_ACTION_SKIPKERNEL = (1 << 1), +}; + +enum ui_indication { + UI_IND_UPDATE_ONLY, + UI_IND_MOUNT_PART, + UI_IND_MOUNT_FAIL, + UI_IND_SKIPPING, + UI_IND_KERNEL_PULL, + UI_IND_KERNEL_PULL_OK, + UI_IND_KERNEL_PULL_FAIL, + UI_IND_INITRAMFS_PULL, + UI_IND_INITRAMFS_PULL_OK, + UI_IND_INITRAMFS_PULL_FAIL, + UI_IND_KERNEL_START, + UI_IND_MEM_TEST +}; + +/* describes a source for getting kernel image */ + +struct kernel_source { + const char *name; /* NULL name means invalid */ + const char *filepath; + const char *initramfs_filepath; + int (*block_init)(void); + int (*block_read)(unsigned char * buf, unsigned long start512, + int blocks512); + int partition_index; /* -1 means no partition table */ + int offset_blocks512_if_no_partition; /* used if partition_index is -1 */ + enum filesystem filesystem; + const char * commandline_append; +}; + +/* describes a board variant, eg, PCB revision */ + +struct board_variant { + const char * name; + int machine_revision; /* passed in revision tag to linux */ +}; + +/* describes a "board", ie, a device like GTA02 including revisions */ + +struct board_api { + const char * name; + int linux_machine_id; + unsigned long linux_mem_start; + unsigned long linux_mem_size; + unsigned long linux_tag_placement; + const char *commandline_board; + const char *commandline_board_debug; + const char *noboot; + const char *append; + + const struct board_variant const * (*get_board_variant)(void); + int (*is_this_board)(void); + void (*early_port_init)(void); + void (*port_init)(void); + void (*post_serial_init)(void); /* print device-specific things */ + char * (*append_device_specific_cmdline)(char *); + void (*putc)(char); + void (*close)(void); + u8 (*get_ui_keys)(void); + u8 (*get_ui_debug)(void); + void (*set_ui_indication)(enum ui_indication); + + struct kernel_source kernel_source[8]; +}; + +/* this is the board we are running on */ + +extern struct board_api const * this_board; +extern struct kernel_source const * this_kernel; + +int printk(const char *fmt, ...); +int vsprintf(char *buf, const char *fmt, va_list args); +int puts(const char *string); +void printhex(unsigned char v); +void print8(unsigned char u); +void print32(unsigned int u); +void printdec(int n); +void hexdump(unsigned char *start, int len); +void udelay(int n); + +/* phase2 only */ +void setnybble(char *p, unsigned char n); +void set8(char *p, unsigned char n); +void set32(char *p, unsigned int u); + +unsigned long crc32(unsigned long crc, const unsigned char *buf, + unsigned int len); +int nand_read_ll(unsigned char *buf, unsigned long start512, int blocks512); + +extern void memory_test(void * start, unsigned int length); + +void set_putc_func(void (*p)(char)); + +#endif + diff --git a/qiboot/include/s3c24xx-mci.h b/qiboot/include/s3c24xx-mci.h new file mode 100644 index 0000000..7abeb1f --- /dev/null +++ b/qiboot/include/s3c24xx-mci.h @@ -0,0 +1,33 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _S3C24XX_MMC_H_ +#define _S3C24XX_MMC_H_ +#include + +int s3c24xx_mmc_init(int verbose); +u32 s3c24xx_mmc_bread(int dev_num, u32 blknr, u32 blkcnt, void *dst); +int s3c24xx_mmc_read(u32 src, u8 *dst, int size); +int s3c24xx_mmc_write(u8 *src, u32 dst, int size); + +#endif /* _MMC_H_ */ diff --git a/qiboot/include/s3c24xx-regs-sdi.h b/qiboot/include/s3c24xx-regs-sdi.h new file mode 100644 index 0000000..9597542 --- /dev/null +++ b/qiboot/include/s3c24xx-regs-sdi.h @@ -0,0 +1,110 @@ +/* linux/include/asm/arch-s3c2410/regs-sdi.h + * + * Copyright (c) 2004 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * S3C2410 MMC/SDIO register definitions + * + * Changelog: + * 18-Aug-2004 Ben Dooks Created initial file + * 29-Nov-2004 Koen Martens Added some missing defines, fixed duplicates + * 29-Nov-2004 Ben Dooks Updated Koen's patch +*/ + +#ifndef __ASM_ARM_REGS_SDI +#define __ASM_ARM_REGS_SDI "regs-sdi.h" + +#define S3C2440_SDICON_SDRESET (1<<8) +#define S3C2440_SDICON_MMCCLOCK (1<<5) +#define S3C2410_SDICON_BYTEORDER (1<<4) +#define S3C2410_SDICON_SDIOIRQ (1<<3) +#define S3C2410_SDICON_RWAITEN (1<<2) +#define S3C2410_SDICON_FIFORESET (1<<1) +#define S3C2410_SDICON_CLOCKTYPE (1<<0) + +#define S3C2410_SDICMDCON_ABORT (1<<12) +#define S3C2410_SDICMDCON_WITHDATA (1<<11) +#define S3C2410_SDICMDCON_LONGRSP (1<<10) +#define S3C2410_SDICMDCON_WAITRSP (1<<9) +#define S3C2410_SDICMDCON_CMDSTART (1<<8) +#define S3C2410_SDICMDCON_SENDERHOST (1<<6) +#define S3C2410_SDICMDCON_INDEX (0x3f) + +#define S3C2410_SDICMDSTAT_CRCFAIL (1<<12) +#define S3C2410_SDICMDSTAT_CMDSENT (1<<11) +#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1<<10) +#define S3C2410_SDICMDSTAT_RSPFIN (1<<9) +#define S3C2410_SDICMDSTAT_XFERING (1<<8) +#define S3C2410_SDICMDSTAT_INDEX (0xff) + +#define S3C2440_SDIDCON_DS_BYTE (0<<22) +#define S3C2440_SDIDCON_DS_HALFWORD (1<<22) +#define S3C2440_SDIDCON_DS_WORD (2<<22) +#define S3C2410_SDIDCON_IRQPERIOD (1<<21) +#define S3C2410_SDIDCON_TXAFTERRESP (1<<20) +#define S3C2410_SDIDCON_RXAFTERCMD (1<<19) +#define S3C2410_SDIDCON_BUSYAFTERCMD (1<<18) +#define S3C2410_SDIDCON_BLOCKMODE (1<<17) +#define S3C2410_SDIDCON_WIDEBUS (1<<16) +#define S3C2410_SDIDCON_DMAEN (1<<15) +#define S3C2410_SDIDCON_STOP (1<<14) +#define S3C2440_SDIDCON_DATSTART (1<<14) +#define S3C2410_SDIDCON_DATMODE (3<<12) +#define S3C2410_SDIDCON_BLKNUM (0x7ff) + +/* constants for S3C2410_SDIDCON_DATMODE */ +#define S3C2410_SDIDCON_XFER_READY (0<<12) +#define S3C2410_SDIDCON_XFER_CHKSTART (1<<12) +#define S3C2410_SDIDCON_XFER_RXSTART (2<<12) +#define S3C2410_SDIDCON_XFER_TXSTART (3<<12) + +#define S3C2410_SDIDCNT_BLKNUM_MASK (0xFFF) +#define S3C2410_SDIDCNT_BLKNUM_SHIFT (12) + +#define S3C2410_SDIDSTA_RDYWAITREQ (1<<10) +#define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9) +#define S3C2410_SDIDSTA_FIFOFAIL (1<<8) /* reserved on 2440 */ +#define S3C2410_SDIDSTA_CRCFAIL (1<<7) +#define S3C2410_SDIDSTA_RXCRCFAIL (1<<6) +#define S3C2410_SDIDSTA_DATATIMEOUT (1<<5) +#define S3C2410_SDIDSTA_XFERFINISH (1<<4) +#define S3C2410_SDIDSTA_BUSYFINISH (1<<3) +#define S3C2410_SDIDSTA_SBITERR (1<<2) /* reserved on 2410a/2440 */ +#define S3C2410_SDIDSTA_TXDATAON (1<<1) +#define S3C2410_SDIDSTA_RXDATAON (1<<0) + +#define S3C2440_SDIFSTA_FIFORESET (1<<16) +#define S3C2440_SDIFSTA_FIFOFAIL (3<<14) /* 3 is correct (2 bits) */ +#define S3C2410_SDIFSTA_TFDET (1<<13) +#define S3C2410_SDIFSTA_RFDET (1<<12) +#define S3C2410_SDIFSTA_TFHALF (1<<11) +#define S3C2410_SDIFSTA_TFEMPTY (1<<10) +#define S3C2410_SDIFSTA_RFLAST (1<<9) +#define S3C2410_SDIFSTA_RFFULL (1<<8) +#define S3C2410_SDIFSTA_RFHALF (1<<7) +#define S3C2410_SDIFSTA_COUNTMASK (0x7f) + +#define S3C2410_SDIIMSK_RESPONSECRC (1<<17) +#define S3C2410_SDIIMSK_CMDSENT (1<<16) +#define S3C2410_SDIIMSK_CMDTIMEOUT (1<<15) +#define S3C2410_SDIIMSK_RESPONSEND (1<<14) +#define S3C2410_SDIIMSK_READWAIT (1<<13) +#define S3C2410_SDIIMSK_SDIOIRQ (1<<12) +#define S3C2410_SDIIMSK_FIFOFAIL (1<<11) +#define S3C2410_SDIIMSK_CRCSTATUS (1<<10) +#define S3C2410_SDIIMSK_DATACRC (1<<9) +#define S3C2410_SDIIMSK_DATATIMEOUT (1<<8) +#define S3C2410_SDIIMSK_DATAFINISH (1<<7) +#define S3C2410_SDIIMSK_BUSYFINISH (1<<6) +#define S3C2410_SDIIMSK_SBITERR (1<<5) /* reserved 2440/2410a */ +#define S3C2410_SDIIMSK_TXFIFOHALF (1<<4) +#define S3C2410_SDIIMSK_TXFIFOEMPTY (1<<3) +#define S3C2410_SDIIMSK_RXFIFOLAST (1<<2) +#define S3C2410_SDIIMSK_RXFIFOFULL (1<<1) +#define S3C2410_SDIIMSK_RXFIFOHALF (1<<0) + +#endif /* __ASM_ARM_REGS_SDI */ diff --git a/qiboot/include/s3c6410.h b/qiboot/include/s3c6410.h new file mode 100644 index 0000000..6689bfa --- /dev/null +++ b/qiboot/include/s3c6410.h @@ -0,0 +1,1394 @@ +/* + * (C) Copyright 2007 + * Byungjae Lee, Samsung Erectronics, bjlee@samsung.com. + * - only support for S3C6400 + * $Id: s3c6410.h,v 1.6 2008/07/02 11:01:48 jsgood Exp $ + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/************************************************ + * NAME : s3c6400.h + * + * Based on S3C6400 User's manual Rev 0.0 + ************************************************/ + +#ifndef __S3C6410_H__ +#define __S3C6410_H__ + +#ifndef CONFIG_S3C6410 +#define CONFIG_S3C6410 1 +#endif + +#define S3C64XX_UART_CHANNELS 4 +#define S3C64XX_SPI_CHANNELS 2 + +#define HSMMC_CHANNEL 0 +#define MOVI_INIT_REQUIRED 0 +#define TCM_BASE 0x0C004000 +#define BL2_BASE 0x57E00000 +#define CopyMovitoMem(a,b,c,d,e) (((int(*)(int, uint, ushort, uint *, int))(*((uint *)(TCM_BASE + 0x8))))(a,b,c,d,e)) +#define SS_SIZE (8 * 1024) +#define eFUSE_SIZE (1 * 1024) // 0.5k eFuse, 0.5k reserved` +#define PART_UBOOT_OFFSET 0x0 +#define PART_ZIMAGE_OFFSET 0x40000 +#define PART_ROOTFS_OFFSET 0x200000 +#define PART_EXTRA_OFFSET 0x3200000 + +/* movinand definitions */ +#define MOVI_BLKSIZE 512 + +#define MOVI_TOTAL_BLKCNT 7864320 // 7864320 // 3995648 // 1003520 /* static movinand total block count: for writing to movinand when nand boot */ +#define MOVI_HIGH_CAPACITY 0 + +#define MOVI_LAST_BLKPOS (MOVI_TOTAL_BLKCNT - (eFUSE_SIZE / MOVI_BLKSIZE)) +#define MOVI_BL1_BLKCNT (SS_SIZE / MOVI_BLKSIZE) +#define MOVI_ENV_BLKCNT (CFG_ENV_SIZE / MOVI_BLKSIZE) +#define MOVI_BL2_BLKCNT (((PART_ZIMAGE_OFFSET - PART_UBOOT_OFFSET) / MOVI_BLKSIZE) - MOVI_ENV_BLKCNT) +#define MOVI_ZIMAGE_BLKCNT ((PART_ROOTFS_OFFSET - PART_ZIMAGE_OFFSET) / MOVI_BLKSIZE) +#define MOVI_BL2_POS (MOVI_LAST_BLKPOS - MOVI_BL1_BLKCNT - MOVI_BL2_BLKCNT - MOVI_ENV_BLKCNT) +#ifndef __ASSEMBLY__ + +struct movi_offset_t { + uint last; + uint bl1; + uint env; + uint bl2; + uint zimage; +}; + +/* external functions */ +extern void hsmmc_set_gpio(void); +extern void hsmmc_reset (void); +extern int hsmmc_init (void); + +extern void test_hsmmc (uint width, uint test, uint start_blk, uint blknum); + + +typedef enum { + S3C64XX_UART0, + S3C64XX_UART1, + S3C64XX_UART2, + S3C64XX_UART3, +} S3C64XX_UARTS_NR; + +#define __REG(x) (*((volatile unsigned int *)(x))) + +//#include +#endif + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#define ROM_BASE0 0x00000000 /* base address of rom bank 0 */ +#define ROM_BASE1 0x04000000 /* base address of rom bank 1 */ +#define DRAM_BASE0 0x40000000 /* base address of dram bank 0 */ +#define DRAM_BASE1 0x50000000 /* base address of dram bank 1 */ + + +/* S3C6400 device base addresses */ +#define ELFIN_DMA_BASE 0x75000000 +#define ELFIN_LCD_BASE 0x77100000 +#define ELFIN_USB_HOST_BASE 0x74300000 +#define ELFIN_I2C_BASE 0x7f004000 +#define ELFIN_I2S_BASE 0x7f002000 +#define ELFIN_ADC_BASE 0x7e00b000 +#define ELFIN_SPI_BASE 0x7f00b000 +#define ELFIN_HSMMC_0_BASE 0x7c200000 +#define ELFIN_HSMMC_1_BASE 0x7c300000 +#define ELFIN_HSMMC_2_BASE 0x7c400000 + +#define ELFIN_CLOCK_POWER_BASE 0x7e00f000 + +/* Clock & Power Controller for mDirac3*/ +#define APLL_LOCK_OFFSET 0x00 +#define MPLL_LOCK_OFFSET 0x04 +#define EPLL_LOCK_OFFSET 0x08 +#define APLL_CON_OFFSET 0x0C +#define MPLL_CON_OFFSET 0x10 +#define EPLL_CON0_OFFSET 0x14 +#define EPLL_CON1_OFFSET 0x18 +#define CLK_SRC_OFFSET 0x1C +#define CLK_DIV0_OFFSET 0x20 +#define CLK_DIV1_OFFSET 0x24 +#define CLK_DIV2_OFFSET 0x28 +#define CLK_OUT_OFFSET 0x2C +#define HCLK_GATE_OFFSET 0x30 +#define PCLK_GATE_OFFSET 0x34 +#define SCLK_GATE_OFFSET 0x38 +#define AHB_CON0_OFFSET 0x100 +#define AHB_CON1_OFFSET 0x104 +#define AHB_CON2_OFFSET 0x108 +#define SELECT_DMA_OFFSET 0x110 +#define SW_RST_OFFSET 0x114 +#define SYS_ID_OFFSET 0x118 +#define MEM_SYS_CFG_OFFSET 0x120 +#define QOS_OVERRIDE0_OFFSET 0x124 +#define QOS_OVERRIDE1_OFFSET 0x128 +#define MEM_CFG_STAT_OFFSET 0x12C +#define PWR_CFG_OFFSET 0x804 +#define EINT_MASK_OFFSET 0x808 +#define NOR_CFG_OFFSET 0x810 +#define STOP_CFG_OFFSET 0x814 +#define SLEEP_CFG_OFFSET 0x818 +#define STOP_MEM_CFG_OFFSET 0x81c +#define OSC_FREQ_OFFSET 0x820 +#define OSC_STABLE_OFFSET 0x824 +#define PWR_STABLE_OFFSET 0x828 +#define FPC_STABLE_OFFSET 0x82C +#define MTC_STABLE_OFFSET 0x830 +#define OTHERS_OFFSET 0x900 +#define RST_STAT_OFFSET 0x904 +#define WAKEUP_STAT_OFFSET 0x908 +#define BLK_PWR_STAT_OFFSET 0x90C +#define INF_REG0_OFFSET 0xA00 +#define INF_REG1_OFFSET 0xA04 +#define INF_REG2_OFFSET 0xA08 +#define INF_REG3_OFFSET 0xA0C +#define INF_REG4_OFFSET 0xA10 +#define INF_REG5_OFFSET 0xA14 +#define INF_REG6_OFFSET 0xA18 +#define INF_REG7_OFFSET 0xA1C + +#define OSC_CNT_VAL_OFFSET 0x824 +#define PWR_CNT_VAL_OFFSET 0x828 +#define FPC_CNT_VAL_OFFSET 0x82C +#define MTC_CNT_VAL_OFFSET 0x830 + + +#define APLL_LOCK_REG __REG(ELFIN_CLOCK_POWER_BASE+APLL_LOCK_OFFSET) +#define MPLL_LOCK_REG __REG(ELFIN_CLOCK_POWER_BASE+MPLL_LOCK_OFFSET) +#define EPLL_LOCK_REG __REG(ELFIN_CLOCK_POWER_BASE+EPLL_LOCK_OFFSET) +#define APLL_CON_REG __REG(ELFIN_CLOCK_POWER_BASE+APLL_CON_OFFSET) +#define MPLL_CON_REG __REG(ELFIN_CLOCK_POWER_BASE+MPLL_CON_OFFSET) +#define EPLL_CON0_REG __REG(ELFIN_CLOCK_POWER_BASE+EPLL_CON0_OFFSET) +#define EPLL_CON1_REG __REG(ELFIN_CLOCK_POWER_BASE+EPLL_CON1_OFFSET) +#define CLK_SRC_REG __REG(ELFIN_CLOCK_POWER_BASE+CLK_SRC_OFFSET) +#define CLK_DIV0_REG __REG(ELFIN_CLOCK_POWER_BASE+CLK_DIV0_OFFSET) +#define CLK_DIV1_REG __REG(ELFIN_CLOCK_POWER_BASE+CLK_DIV1_OFFSET) +#define CLK_DIV2_REG __REG(ELFIN_CLOCK_POWER_BASE+CLK_DIV2_OFFSET) +#define CLK_OUT_REG __REG(ELFIN_CLOCK_POWER_BASE+CLK_OUT_OFFSET) +#define HCLK_GATE_REG __REG(ELFIN_CLOCK_POWER_BASE+HCLK_GATE_OFFSET) +#define PCLK_GATE_REG __REG(ELFIN_CLOCK_POWER_BASE+PCLK_GATE_OFFSET) +#define SCLK_GATE_REG __REG(ELFIN_CLOCK_POWER_BASE+SCLK_GATE_OFFSET) +#define AHB_CON0_REG __REG(ELFIN_CLOCK_POWER_BASE+AHB_CON0_OFFSET) +#define AHB_CON1_REG __REG(ELFIN_CLOCK_POWER_BASE+AHB_CON1_OFFSET) +#define AHB_CON2_REG __REG(ELFIN_CLOCK_POWER_BASE+AHB_CON2_OFFSET) +#define SELECT_DMA_REG __REG(ELFIN_CLOCK_POWER_BASE+SELECT_DMA_OFFSET) +#define SW_RST_REG __REG(ELFIN_CLOCK_POWER_BASE+SW_RST_OFFSET) +#define SYS_ID_REG __REG(ELFIN_CLOCK_POWER_BASE+SYS_ID_OFFSET) +#define MEM_SYS_CFG_REG __REG(ELFIN_CLOCK_POWER_BASE+MEM_SYS_CFG_OFFSET) +#define QOS_OVERRIDE0_REG __REG(ELFIN_CLOCK_POWER_BASE+QOS_OVERRIDE0_OFFSET) +#define QOS_OVERRIDE1_REG __REG(ELFIN_CLOCK_POWER_BASE+QOS_OVERRIDE1_OFFSET) +#define MEM_CFG_STAT_REG __REG(ELFIN_CLOCK_POWER_BASE+MEM_CFG_STAT_OFFSET) +#define PWR_CFG_REG __REG(ELFIN_CLOCK_POWER_BASE+PWR_CFG_OFFSET) +#define EINT_MASK_REG __REG(ELFIN_CLOCK_POWER_BASE+EINT_MASK_OFFSET) +#define NOR_CFG_REG __REG(ELFIN_CLOCK_POWER_BASE+NOR_CFG_OFFSET) +#define STOP_MEM_CFG_REG __REG(ELFIN_CLOCK_POWER_BASE+STOP_MEM_CFG_OFFSET) +#define SLEEP_CFG_REG __REG(ELFIN_CLOCK_POWER_BASE+SLEEP_CFG_OFFSET) +#define OSC_FREQ_REG __REG(ELFIN_CLOCK_POWER_BASE+OSC_FREQ_OFFSET) +#define OSC_CNT_VAL_REG __REG(ELFIN_CLOCK_POWER_BASE+OSC_CNT_VAL_OFFSET) +#define PWR_CNT_VAL_REG __REG(ELFIN_CLOCK_POWER_BASE+PWR_CNT_VAL_OFFSET) +#define FPC_CNT_VAL_REG __REG(ELFIN_CLOCK_POWER_BASE+FPC_CNT_VAL_OFFSET) +#define MTC_CNT_VAL_REG __REG(ELFIN_CLOCK_POWER_BASE+MTC_CNT_VAL_OFFSET) +#define OTHERS_REG __REG(ELFIN_CLOCK_POWER_BASE+OTHERS_OFFSET) +#define RST_STAT_REG __REG(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET) +#define WAKEUP_STAT_REG __REG(ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET) +#define BLK_PWR_STAT_REG __REG(ELFIN_CLOCK_POWER_BASE+BLK_PWR_STAT_OFFSET) +#define INF_REG0_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET) +#define INF_REG1_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG1_OFFSET) +#define INF_REG2_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG2_OFFSET) +#define INF_REG3_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG3_OFFSET) +#define INF_REG4_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG4_OFFSET) +#define INF_REG5_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG5_OFFSET) +#define INF_REG6_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG6_OFFSET) +#define INF_REG7_REG __REG(ELFIN_CLOCK_POWER_BASE+INF_REG7_OFFSET) + +#define APLL_LOCK (ELFIN_CLOCK_POWER_BASE+APLL_LOCK_OFFSET) +#define MPLL_LOCK (ELFIN_CLOCK_POWER_BASE+MPLL_LOCK_OFFSET) +#define EPLL_LOCK (ELFIN_CLOCK_POWER_BASE+EPLL_LOCK_OFFSET) +#define APLL_CON (ELFIN_CLOCK_POWER_BASE+APLL_CON_OFFSET) +#define MPLL_CON (ELFIN_CLOCK_POWER_BASE+MPLL_CON_OFFSET) +#define EPLL_CON0 (ELFIN_CLOCK_POWER_BASE+EPLL_CON0_OFFSET) +#define EPLL_CON1 (ELFIN_CLOCK_POWER_BASE+EPLL_CON1_OFFSET) +#define CLK_SRC (ELFIN_CLOCK_POWER_BASE+CLK_SRC_OFFSET) +#define CLK_DIV0 (ELFIN_CLOCK_POWER_BASE+CLK_DIV0_OFFSET) +#define CLK_DIV1 (ELFIN_CLOCK_POWER_BASE+CLK_DIV1_OFFSET) +#define CLK_DIV2 (ELFIN_CLOCK_POWER_BASE+CLK_DIV2_OFFSET) +#define CLK_OUT (ELFIN_CLOCK_POWER_BASE+CLK_OUT_OFFSET) +#define HCLK_GATE (ELFIN_CLOCK_POWER_BASE+HCLK_GATE_OFFSET) +#define PCLK_GATE (ELFIN_CLOCK_POWER_BASE+PCLK_GATE_OFFSET) +#define SCLK_GATE (ELFIN_CLOCK_POWER_BASE+SCLK_GATE_OFFSET) +#define AHB_CON0 (ELFIN_CLOCK_POWER_BASE+AHB_CON0_OFFSET) +#define AHB_CON1 (ELFIN_CLOCK_POWER_BASE+AHB_CON1_OFFSET) +#define AHB_CON2 (ELFIN_CLOCK_POWER_BASE+AHB_CON2_OFFSET) +#define SELECT_DMA (ELFIN_CLOCK_POWER_BASE+SELECT_DMA_OFFSET) +#define SW_RST (ELFIN_CLOCK_POWER_BASE+SW_RST_OFFSET) +#define SYS_ID (ELFIN_CLOCK_POWER_BASE+SYS_ID_OFFSET) +#define MEM_SYS_CFG (ELFIN_CLOCK_POWER_BASE+MEM_SYS_CFG_OFFSET) +#define QOS_OVERRIDE0 (ELFIN_CLOCK_POWER_BASE+QOS_OVERRIDE0_OFFSET) +#define QOS_OVERRIDE1 (ELFIN_CLOCK_POWER_BASE+QOS_OVERRIDE1_OFFSET) +#define MEM_CFG_STAT (ELFIN_CLOCK_POWER_BASE+MEM_CFG_STAT_OFFSET) +#define PWR_CFG (ELFIN_CLOCK_POWER_BASE+PWR_CFG_OFFSET) +#define EINT_MASK (ELFIN_CLOCK_POWER_BASE+EINT_MASK_OFFSET) +#define NOR_CFG (ELFIN_CLOCK_POWER_BASE+NOR_CFG_OFFSET) +#define STOP_CFG (ELFIN_CLOCK_POWER_BASE+STOP_CFG_OFFSET) +#define SLEEP_CFG (ELFIN_CLOCK_POWER_BASE+SLEEP_CFG_OFFSET) +#define STOP_MEM_CFG (ELFIN_CLOCK_POWER_BASE+STOP_MEM_CFG_OFFSET) +#define OSC_FREQ (ELFIN_CLOCK_POWER_BASE+OSC_FREQ_OFFSET) +#define OSC_CNT_VAL (ELFIN_CLOCK_POWER_BASE+OSC_CNT_VAL_OFFSET) +#define PWR_CNT_VAL (ELFIN_CLOCK_POWER_BASE+PWR_CNT_VAL_OFFSET) +#define FPC_CNT_VAL (ELFIN_CLOCK_POWER_BASE+FPC_CNT_VAL_OFFSET) +#define MTC_CNT_VAL (ELFIN_CLOCK_POWER_BASE+MTC_CNT_VAL_OFFSET) +#define OTHERS (ELFIN_CLOCK_POWER_BASE+OTHERS_OFFSET) +#define RST_STAT (ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET) +#define WAKEUP_STAT (ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET) +#define BLK_PWR_STAT (ELFIN_CLOCK_POWER_BASE+BLK_PWR_STAT_OFFSET) +#define INF_REG0 (ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET) +#define INF_REG1 (ELFIN_CLOCK_POWER_BASE+INF_REG1_OFFSET) +#define INF_REG2 (ELFIN_CLOCK_POWER_BASE+INF_REG2_OFFSET) +#define INF_REG3 (ELFIN_CLOCK_POWER_BASE+INF_REG3_OFFSET) +#define INF_REG4 (ELFIN_CLOCK_POWER_BASE+INF_REG4_OFFSET) +#define INF_REG5 (ELFIN_CLOCK_POWER_BASE+INF_REG5_OFFSET) +#define INF_REG6 (ELFIN_CLOCK_POWER_BASE+INF_REG6_OFFSET) +#define INF_REG7 (ELFIN_CLOCK_POWER_BASE+INF_REG7_OFFSET) + + +/* + * GPIO + */ +#define ELFIN_GPIO_BASE 0x7f008000 + +#define GPACON_OFFSET 0x00 +#define GPADAT_OFFSET 0x04 +#define GPAPUD_OFFSET 0x08 +#define GPACONSLP_OFFSET 0x0C +#define GPAPUDSLP_OFFSET 0x10 +#define GPBCON_OFFSET 0x20 +#define GPBDAT_OFFSET 0x24 +#define GPBPUD_OFFSET 0x28 +#define GPBCONSLP_OFFSET 0x2C +#define GPBPUDSLP_OFFSET 0x30 +#define GPCCON_OFFSET 0x40 +#define GPCDAT_OFFSET 0x44 +#define GPCPUD_OFFSET 0x48 +#define GPCCONSLP_OFFSET 0x4C +#define GPCPUDSLP_OFFSET 0x50 +#define GPDCON_OFFSET 0x60 +#define GPDDAT_OFFSET 0x64 +#define GPDPUD_OFFSET 0x68 +#define GPDCONSLP_OFFSET 0x6C +#define GPDPUDSLP_OFFSET 0x70 +#define GPECON_OFFSET 0x80 +#define GPEDAT_OFFSET 0x84 +#define GPEPUD_OFFSET 0x88 +#define GPECONSLP_OFFSET 0x8C +#define GPEPUDSLP_OFFSET 0x90 +#define GPFCON_OFFSET 0xA0 +#define GPFDAT_OFFSET 0xA4 +#define GPFPUD_OFFSET 0xA8 +#define GPFCONSLP_OFFSET 0xAC +#define GPFPUDSLP_OFFSET 0xB0 +#define GPGCON_OFFSET 0xC0 +#define GPGDAT_OFFSET 0xC4 +#define GPGPUD_OFFSET 0xC8 +#define GPGCONSLP_OFFSET 0xCC +#define GPGPUDSLP_OFFSET 0xD0 +#define GPHCON0_OFFSET 0xE0 +#define GPHCON1_OFFSET 0xE4 +#define GPHDAT_OFFSET 0xE8 +#define GPHPUD_OFFSET 0xEC +#define GPHCONSLP_OFFSET 0xF0 +#define GPHPUDSLP_OFFSET 0xF4 +#define GPICON_OFFSET 0x100 +#define GPIDAT_OFFSET 0x104 +#define GPIPUD_OFFSET 0x108 +#define GPICONSLP_OFFSET 0x10C +#define GPIPUDSLP_OFFSET 0x110 +#define GPJCON_OFFSET 0x120 +#define GPJDAT_OFFSET 0x124 +#define GPJPUD_OFFSET 0x128 +#define GPJCONSLP_OFFSET 0x12C +#define GPJPUDSLP_OFFSET 0x130 +#define SPCON_OFFSET 0x1A0 +#define MEM0DRVCON_OFFSET 0x1D0 +#define MEM1DRVCON_OFFSET 0x1D4 +#define GPKCON0_OFFSET 0x800 +#define GPKCON1_OFFSET 0x804 +#define GPKDAT_OFFSET 0x808 +#define GPKPUD_OFFSET 0x80C +#define GPLCON0_OFFSET 0x810 +#define GPLCON1_OFFSET 0x814 +#define GPLDAT_OFFSET 0x818 +#define GPLPUD_OFFSET 0x81C +#define GPMCON_OFFSET 0x820 +#define GPMDAT_OFFSET 0x824 +#define GPMPUD_OFFSET 0x828 +#define GPNCON_OFFSET 0x830 +#define GPNDAT_OFFSET 0x834 +#define GPNPUD_OFFSET 0x838 +#define GPOCON_OFFSET 0x140 +#define GPODAT_OFFSET 0x144 +#define GPOPUD_OFFSET 0x148 +#define GPOCONSLP_OFFSET 0x14C +#define GPOPUDSLP_OFFSET 0x150 +#define GPPCON_OFFSET 0x160 +#define GPPDAT_OFFSET 0x164 +#define GPPPUD_OFFSET 0x168 +#define GPPCONSLP_OFFSET 0x16C +#define GPPPUDSLP_OFFSET 0x170 +#define GPQCON_OFFSET 0x180 +#define GPQDAT_OFFSET 0x184 +#define GPQPUD_OFFSET 0x188 +#define GPQCONSLP_OFFSET 0x18C +#define GPQPUDSLP_OFFSET 0x190 + +#define EINTPEND_OFFSET 0x924 + +#define GPACON_REG __REG(ELFIN_GPIO_BASE+GPACON_OFFSET) +#define GPADAT_REG __REG(ELFIN_GPIO_BASE+GPADAT_OFFSET) +#define GPAPUD_REG __REG(ELFIN_GPIO_BASE+GPAPUD_OFFSET) +#define GPACONSLP_REG __REG(ELFIN_GPIO_BASE+GPACONSLP_OFFSET) +#define GPAPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPAPUDSLP_OFFSET) +#define GPBCON_REG __REG(ELFIN_GPIO_BASE+GPBCON_OFFSET) +#define GPBDAT_REG __REG(ELFIN_GPIO_BASE+GPBDAT_OFFSET) +#define GPBPUD_REG __REG(ELFIN_GPIO_BASE+GPBPUD_OFFSET) +#define GPBCONSLP_REG __REG(ELFIN_GPIO_BASE+GPBCONSLP_OFFSET) +#define GPBPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPBPUDSLP_OFFSET) +#define GPCCON_REG __REG(ELFIN_GPIO_BASE+GPCCON_OFFSET) +#define GPCDAT_REG __REG(ELFIN_GPIO_BASE+GPCDAT_OFFSET) +#define GPCPUD_REG __REG(ELFIN_GPIO_BASE+GPCPUD_OFFSET) +#define GPCCONSLP_REG __REG(ELFIN_GPIO_BASE+GPCCONSLP_OFFSET) +#define GPCPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPCPUDSLP_OFFSET) +#define GPDCON_REG __REG(ELFIN_GPIO_BASE+GPDCON_OFFSET) +#define GPDDAT_REG __REG(ELFIN_GPIO_BASE+GPDDAT_OFFSET) +#define GPDPUD_REG __REG(ELFIN_GPIO_BASE+GPDPUD_OFFSET) +#define GPDCONSLP_REG __REG(ELFIN_GPIO_BASE+GPDCONSLP_OFFSET) +#define GPDPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPDPUDSLP_OFFSET) +#define GPECON_REG __REG(ELFIN_GPIO_BASE+GPECON_OFFSET) +#define GPEDAT_REG __REG(ELFIN_GPIO_BASE+GPEDAT_OFFSET) +#define GPEPUD_REG __REG(ELFIN_GPIO_BASE+GPEPUD_OFFSET) +#define GPECONSLP_REG __REG(ELFIN_GPIO_BASE+GPECONSLP_OFFSET) +#define GPEPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPEPUDSLP_OFFSET) +#define GPFCON_REG __REG(ELFIN_GPIO_BASE+GPFCON_OFFSET) +#define GPFDAT_REG __REG(ELFIN_GPIO_BASE+GPFDAT_OFFSET) +#define GPFPUD_REG __REG(ELFIN_GPIO_BASE+GPFPUD_OFFSET) +#define GPFCONSLP_REG __REG(ELFIN_GPIO_BASE+GPFCONSLP_OFFSET) +#define GPFPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPFPUDSLP_OFFSET) +#define GPGCON_REG __REG(ELFIN_GPIO_BASE+GPGCON_OFFSET) +#define GPGDAT_REG __REG(ELFIN_GPIO_BASE+GPGDAT_OFFSET) +#define GPGPUD_REG __REG(ELFIN_GPIO_BASE+GPGPUD_OFFSET) +#define GPGCONSLP_REG __REG(ELFIN_GPIO_BASE+GPGCONSLP_OFFSET) +#define GPGPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPGPUDSLP_OFFSET) +#define GPHCON0_REG __REG(ELFIN_GPIO_BASE+GPHCON0_OFFSET) +#define GPHCON1_REG __REG(ELFIN_GPIO_BASE+GPHCON1_OFFSET) +#define GPHDAT_REG __REG(ELFIN_GPIO_BASE+GPHDAT_OFFSET) +#define GPHPUD_REG __REG(ELFIN_GPIO_BASE+GPHPUD_OFFSET) +#define GPHCONSLP_REG __REG(ELFIN_GPIO_BASE+GPHCONSLP_OFFSET) +#define GPHPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPHPUDSLP_OFFSET) +#define GPICON_REG __REG(ELFIN_GPIO_BASE+GPICON_OFFSET) +#define GPIDAT_REG __REG(ELFIN_GPIO_BASE+GPIDAT_OFFSET) +#define GPIPUD_REG __REG(ELFIN_GPIO_BASE+GPIPUD_OFFSET) +#define GPICONSLP_REG __REG(ELFIN_GPIO_BASE+GPICONSLP_OFFSET) +#define GPIPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPIPUDSLP_OFFSET) +#define GPJCON_REG __REG(ELFIN_GPIO_BASE+GPJCON_OFFSET) +#define GPJDAT_REG __REG(ELFIN_GPIO_BASE+GPJDAT_OFFSET) +#define GPJPUD_REG __REG(ELFIN_GPIO_BASE+GPJPUD_OFFSET) +#define GPJCONSLP_REG __REG(ELFIN_GPIO_BASE+GPJCONSLP_OFFSET) +#define GPJPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPJPUDSLP_OFFSET) +#define GPKCON0_REG __REG(ELFIN_GPIO_BASE+GPKCON0_OFFSET) +#define GPKCON1_REG __REG(ELFIN_GPIO_BASE+GPKCON1_OFFSET) +#define GPKDAT_REG __REG(ELFIN_GPIO_BASE+GPKDAT_OFFSET) +#define GPKPUD_REG __REG(ELFIN_GPIO_BASE+GPKPUD_OFFSET) +#define GPLCON0_REG __REG(ELFIN_GPIO_BASE+GPLCON0_OFFSET) +#define GPLCON1_REG __REG(ELFIN_GPIO_BASE+GPLCON1_OFFSET) +#define GPLDAT_REG __REG(ELFIN_GPIO_BASE+GPLDAT_OFFSET) +#define GPLPUD_REG __REG(ELFIN_GPIO_BASE+GPLPUD_OFFSET) +#define GPMCON_REG __REG(ELFIN_GPIO_BASE+GPMCON_OFFSET) +#define GPMDAT_REG __REG(ELFIN_GPIO_BASE+GPMDAT_OFFSET) +#define GPMPUD_REG __REG(ELFIN_GPIO_BASE+GPMPUD_OFFSET) +#define GPNCON_REG __REG(ELFIN_GPIO_BASE+GPNCON_OFFSET) +#define GPNDAT_REG __REG(ELFIN_GPIO_BASE+GPNDAT_OFFSET) +#define GPNPUD_REG __REG(ELFIN_GPIO_BASE+GPNPUD_OFFSET) +#define GPOCON_REG __REG(ELFIN_GPIO_BASE+GPOCON_OFFSET) +#define GPODAT_REG __REG(ELFIN_GPIO_BASE+GPODAT_OFFSET) +#define GPOPUD_REG __REG(ELFIN_GPIO_BASE+GPOPUD_OFFSET) +#define GPOCONSLP_REG __REG(ELFIN_GPIO_BASE+GPOCONSLP_OFFSET) +#define GPOPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPOPUDSLP_OFFSET) +#define GPPCON_REG __REG(ELFIN_GPIO_BASE+GPPCON_OFFSET) +#define GPPDAT_REG __REG(ELFIN_GPIO_BASE+GPPDAT_OFFSET) +#define GPPPUD_REG __REG(ELFIN_GPIO_BASE+GPPPUD_OFFSET) +#define GPPCONSLP_REG __REG(ELFIN_GPIO_BASE+GPPCONSLP_OFFSET) +#define GPPPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPPPUDSLP_OFFSET) +#define GPQCON_REG __REG(ELFIN_GPIO_BASE+GPQCON_OFFSET) +#define GPQDAT_REG __REG(ELFIN_GPIO_BASE+GPQDAT_OFFSET) +#define GPQPUD_REG __REG(ELFIN_GPIO_BASE+GPQPUD_OFFSET) +#define GPQCONSLP_REG __REG(ELFIN_GPIO_BASE+GPQCONSLP_OFFSET) +#define GPQPUDSLP_REG __REG(ELFIN_GPIO_BASE+GPQPUDSLP_OFFSET) + +#define GPACON (ELFIN_GPIO_BASE+GPACON_OFFSET) +#define GPADAT (ELFIN_GPIO_BASE+GPADAT_OFFSET) +#define GPAPUD (ELFIN_GPIO_BASE+GPAPUD_OFFSET) +#define GPACONSLP (ELFIN_GPIO_BASE+GPACONSLP_OFFSET) +#define GPAPUDSLP (ELFIN_GPIO_BASE+GPAPUDSLP_OFFSET) +#define GPBCON (ELFIN_GPIO_BASE+GPBCON_OFFSET) +#define GPBDAT (ELFIN_GPIO_BASE+GPBDAT_OFFSET) +#define GPBPUD (ELFIN_GPIO_BASE+GPBPUD_OFFSET) +#define GPBCONSLP (ELFIN_GPIO_BASE+GPBCONSLP_OFFSET) +#define GPBPUDSLP (ELFIN_GPIO_BASE+GPBPUDSLP_OFFSET) +#define GPCCON (ELFIN_GPIO_BASE+GPCCON_OFFSET) +#define GPCDAT (ELFIN_GPIO_BASE+GPCDAT_OFFSET) +#define GPCPUD (ELFIN_GPIO_BASE+GPCPUD_OFFSET) +#define GPCCONSLP (ELFIN_GPIO_BASE+GPCCONSLP_OFFSET) +#define GPCPUDSLP (ELFIN_GPIO_BASE+GPCPUDSLP_OFFSET) +#define GPDCON (ELFIN_GPIO_BASE+GPDCON_OFFSET) +#define GPDDAT (ELFIN_GPIO_BASE+GPDDAT_OFFSET) +#define GPDPUD (ELFIN_GPIO_BASE+GPDPUD_OFFSET) +#define GPDCONSLP (ELFIN_GPIO_BASE+GPDCONSLP_OFFSET) +#define GPDPUDSLP (ELFIN_GPIO_BASE+GPDPUDSLP_OFFSET) +#define GPECON (ELFIN_GPIO_BASE+GPECON_OFFSET) +#define GPEDAT (ELFIN_GPIO_BASE+GPEDAT_OFFSET) +#define GPEPUD (ELFIN_GPIO_BASE+GPEPUD_OFFSET) +#define GPECONSLP (ELFIN_GPIO_BASE+GPECONSLP_OFFSET) +#define GPEPUDSLP (ELFIN_GPIO_BASE+GPEPUDSLP_OFFSET) +#define GPFCON (ELFIN_GPIO_BASE+GPFCON_OFFSET) +#define GPFDAT (ELFIN_GPIO_BASE+GPFDAT_OFFSET) +#define GPFPUD (ELFIN_GPIO_BASE+GPFPUD_OFFSET) +#define GPFCONSLP (ELFIN_GPIO_BASE+GPFCONSLP_OFFSET) +#define GPFPUDSLP (ELFIN_GPIO_BASE+GPFPUDSLP_OFFSET) +#define GPGCON (ELFIN_GPIO_BASE+GPGCON_OFFSET) +#define GPGDAT (ELFIN_GPIO_BASE+GPGDAT_OFFSET) +#define GPGPUD (ELFIN_GPIO_BASE+GPGPUD_OFFSET) +#define GPGCONSLP (ELFIN_GPIO_BASE+GPGCONSLP_OFFSET) +#define GPGPUDSLP (ELFIN_GPIO_BASE+GPGPUDSLP_OFFSET) +#define GPHCON0 (ELFIN_GPIO_BASE+GPHCON0_OFFSET) +#define GPHCON1 (ELFIN_GPIO_BASE+GPHCON1_OFFSET) +#define GPHDAT (ELFIN_GPIO_BASE+GPHDAT_OFFSET) +#define GPHPUD (ELFIN_GPIO_BASE+GPHPUD_OFFSET) +#define GPHCONSLP (ELFIN_GPIO_BASE+GPHCONSLP_OFFSET) +#define GPHPUDSLP (ELFIN_GPIO_BASE+GPHPUDSLP_OFFSET) +#define GPICON (ELFIN_GPIO_BASE+GPICON_OFFSET) +#define GPIDAT (ELFIN_GPIO_BASE+GPIDAT_OFFSET) +#define GPIPUD (ELFIN_GPIO_BASE+GPIPUD_OFFSET) +#define GPICONSLP (ELFIN_GPIO_BASE+GPICONSLP_OFFSET) +#define GPIPUDSLP (ELFIN_GPIO_BASE+GPIPUDSLP_OFFSET) +#define GPJCON (ELFIN_GPIO_BASE+GPJCON_OFFSET) +#define GPJDAT (ELFIN_GPIO_BASE+GPJDAT_OFFSET) +#define GPJPUD (ELFIN_GPIO_BASE+GPJPUD_OFFSET) +#define GPJCONSLP (ELFIN_GPIO_BASE+GPJCONSLP_OFFSET) +#define GPJPUDSLP (ELFIN_GPIO_BASE+GPJPUDSLP_OFFSET) +#define GPKCON0 (ELFIN_GPIO_BASE+GPKCON0_OFFSET) +#define GPKCON1 (ELFIN_GPIO_BASE+GPKCON1_OFFSET) +#define GPKDAT (ELFIN_GPIO_BASE+GPKDAT_OFFSET) +#define GPKPUD (ELFIN_GPIO_BASE+GPKPUD_OFFSET) +#define GPLCON0 (ELFIN_GPIO_BASE+GPLCON0_OFFSET) +#define GPLCON1 (ELFIN_GPIO_BASE+GPLCON1_OFFSET) +#define GPLDAT (ELFIN_GPIO_BASE+GPLDAT_OFFSET) +#define GPLPUD (ELFIN_GPIO_BASE+GPLPUD_OFFSET) +#define GPMCON (ELFIN_GPIO_BASE+GPMCON_OFFSET) +#define GPMDAT (ELFIN_GPIO_BASE+GPMDAT_OFFSET) +#define GPMPUD (ELFIN_GPIO_BASE+GPMPUD_OFFSET) +#define GPNCON (ELFIN_GPIO_BASE+GPNCON_OFFSET) +#define GPNDAT (ELFIN_GPIO_BASE+GPNDAT_OFFSET) +#define GPNPUD (ELFIN_GPIO_BASE+GPNPUD_OFFSET) +#define GPOCON (ELFIN_GPIO_BASE+GPOCON_OFFSET) +#define GPODAT (ELFIN_GPIO_BASE+GPODAT_OFFSET) +#define GPOPUD (ELFIN_GPIO_BASE+GPOPUD_OFFSET) +#define GPOCONSLP (ELFIN_GPIO_BASE+GPOCONSLP_OFFSET) +#define GPOPUDSLP (ELFIN_GPIO_BASE+GPOPUDSLP_OFFSET) +#define GPPCON (ELFIN_GPIO_BASE+GPPCON_OFFSET) +#define GPPDAT (ELFIN_GPIO_BASE+GPPDAT_OFFSET) +#define GPPPUD (ELFIN_GPIO_BASE+GPPPUD_OFFSET) +#define GPPCONSLP (ELFIN_GPIO_BASE+GPPCONSLP_OFFSET) +#define GPPPUDSLP (ELFIN_GPIO_BASE+GPPPUDSLP_OFFSET) +#define GPQCON (ELFIN_GPIO_BASE+GPQCON_OFFSET) +#define GPQDAT (ELFIN_GPIO_BASE+GPQDAT_OFFSET) +#define GPQPUD (ELFIN_GPIO_BASE+GPQPUD_OFFSET) +#define GPQCONSLP (ELFIN_GPIO_BASE+GPQCONSLP_OFFSET) +#define GPQPUDSLP (ELFIN_GPIO_BASE+GPQPUDSLP_OFFSET) + +/* + * Bus Matrix + */ +#define ELFIN_MEM_SYS_CFG 0x7e00f120 + + + +/* + * Memory controller + */ +#define ELFIN_SROM_BASE 0x70000000 + +#define SROM_BW_REG __REG(ELFIN_SROM_BASE+0x0) +#define SROM_BC0_REG __REG(ELFIN_SROM_BASE+0x4) +#define SROM_BC1_REG __REG(ELFIN_SROM_BASE+0x8) +#define SROM_BC2_REG __REG(ELFIN_SROM_BASE+0xC) +#define SROM_BC3_REG __REG(ELFIN_SROM_BASE+0x10) +#define SROM_BC4_REG __REG(ELFIN_SROM_BASE+0x14) +#define SROM_BC5_REG __REG(ELFIN_SROM_BASE+0x18) + + + +/* + * SDRAM Controller + */ +#define ELFIN_DMC0_BASE 0x7e000000 +#define ELFIN_DMC1_BASE 0x7e001000 + +#define INDEX_DMC_MEMC_STATUS (0x00) +#define INDEX_DMC_MEMC_CMD (0x04) +#define INDEX_DMC_DIRECT_CMD (0x08) +#define INDEX_DMC_MEMORY_CFG (0x0C) +#define INDEX_DMC_REFRESH_PRD (0x10) +#define INDEX_DMC_CAS_LATENCY (0x14) +#define INDEX_DMC_T_DQSS (0x18) +#define INDEX_DMC_T_MRD (0x1C) +#define INDEX_DMC_T_RAS (0x20) +#define INDEX_DMC_T_RC (0x24) +#define INDEX_DMC_T_RCD (0x28) +#define INDEX_DMC_T_RFC (0x2C) +#define INDEX_DMC_T_RP (0x30) +#define INDEX_DMC_T_RRD (0x34) +#define INDEX_DMC_T_WR (0x38) +#define INDEX_DMC_T_WTR (0x3C) +#define INDEX_DMC_T_XP (0x40) +#define INDEX_DMC_T_XSR (0x44) +#define INDEX_DMC_T_ESR (0x48) +#define INDEX_DMC_MEMORY_CFG2 (0x4C) +#define INDEX_DMC_CHIP_0_CFG (0x200) +#define INDEX_DMC_CHIP_1_CFG (0x204) +#define INDEX_DMC_CHIP_2_CFG (0x208) +#define INDEX_DMC_CHIP_3_CFG (0x20C) +#define INDEX_DMC_USER_STATUS (0x300) +#define INDEX_DMC_USER_CONFIG (0x304) + +/* +* Memory Chip direct command +*/ +#define DMC_NOP0 0x0c0000 +#define DMC_NOP1 0x1c0000 +#define DMC_PA0 0x000000 //Precharge all +#define DMC_PA1 0x100000 +#define DMC_AR0 0x040000 //Autorefresh +#define DMC_AR1 0x140000 +#define DMC_SDR_MR0 0x080032 //MRS, CAS 3, Burst Length 4 +#define DMC_SDR_MR1 0x180032 +#define DMC_DDR_MR0 0x080162 +#define DMC_DDR_MR1 0x180162 +#define DMC_mDDR_MR0 0x080032 //CAS 3, Burst Length 4 +#define DMC_mDDR_MR1 0x180032 +#define DMC_mSDR_EMR0 0x0a0000 //EMRS, DS:Full, PASR:Full Array +#define DMC_mSDR_EMR1 0x1a0000 +#define DMC_DDR_EMR0 0x090000 +#define DMC_DDR_EMR1 0x190000 +#define DMC_mDDR_EMR0 0x0a0000 // DS:Full, PASR:Full Array +#define DMC_mDDR_EMR1 0x1a0000 + + +/**************************************************************** + Definitions for memory configuration + Set memory configuration + active_chips = 1'b0 (1 chip) + qos_master_chip = 3'b000(ARID[3:0]) + memory burst = 3'b010(burst 4) + stop_mem_clock = 1'b0(disable dynamical stop) + auto_power_down = 1'b0(disable auto power-down mode) + power_down_prd = 6'b00_0000(0 cycle for auto power-down) + ap_bit = 1'b0 (bit position of auto-precharge is 10) + row_bits = 3'b010(# row address 13) + column_bits = 3'b010(# column address 10 ) + + Set user configuration + 2'b10=SDRAM/mSDRAM, 2'b11=DDR, 2'b01=mDDR + + Set chip select for chip [n] + row bank control, bank address 0x3000_0000 ~ 0x37ff_ffff + CHIP_[n]_CFG=0x30F8, 30: ADDR[31:24], F8: Mask[31:24] +******************************************************************/ + +/* + * HS MMC Interface + */ +#define ELFIN_HSMMC_BASE 0x7C200000 + +#define HM_SYSAD (0x00) +#define HM_BLKSIZE (0x04) +#define HM_BLKCNT (0x06) +#define HM_ARGUMENT (0x08) +#define HM_TRNMOD (0x0c) +#define HM_CMDREG (0x0e) +#define HM_RSPREG0 (0x10) +#define HM_RSPREG1 (0x14) +#define HM_RSPREG2 (0x18) +#define HM_RSPREG3 (0x1c) +#define HM_BDATA (0x20) +#define HM_PRNSTS (0x24) +#define HM_HOSTCTL (0x28) +#define HM_PWRCON (0x29) +#define HM_BLKGAP (0x2a) +#define HM_WAKCON (0x2b) +#define HM_CLKCON (0x2c) +#define HM_TIMEOUTCON (0x2e) +#define HM_SWRST (0x2f) +#define HM_NORINTSTS (0x30) +#define HM_ERRINTSTS (0x32) +#define HM_NORINTSTSEN (0x34) +#define HM_ERRINTSTSEN (0x36) +#define HM_NORINTSIGEN (0x38) +#define HM_ERRINTSIGEN (0x3a) +#define HM_ACMD12ERRSTS (0x3c) +#define HM_CAPAREG (0x40) +#define HM_MAXCURR (0x48) +#define HM_CONTROL2 (0x80) +#define HM_CONTROL3 (0x84) +#define HM_CONTROL4 (0x8c) +#define HM_HCVER (0xfe) + +/* + * Nand flash controller + */ +#define ELFIN_NAND_BASE 0x70200000 + +#define NFCONF_OFFSET 0x00 +#define NFCONT_OFFSET 0x04 +#define NFCMMD_OFFSET 0x08 +#define NFADDR_OFFSET 0x0c +#define NFDATA_OFFSET 0x10 +#define NFMECCDATA0_OFFSET 0x14 +#define NFMECCDATA1_OFFSET 0x18 +#define NFSECCDATA0_OFFSET 0x1c +#define NFSBLK_OFFSET 0x20 +#define NFEBLK_OFFSET 0x24 +#define NFSTAT_OFFSET 0x28 +#define NFESTAT0_OFFSET 0x2c +#define NFESTAT1_OFFSET 0x30 +#define NFMECC0_OFFSET 0x34 +#define NFMECC1_OFFSET 0x38 +#define NFSECC_OFFSET 0x3c +#define NFMLCBITPT_OFFSET 0x40 +#define NF8ECCERR0_OFFSET 0x44 +#define NF8ECCERR1_OFFSET 0x48 +#define NF8ECCERR2_OFFSET 0x4c +#define NFM8ECC0_OFFSET 0x50 +#define NFM8ECC1_OFFSET 0x54 +#define NFM8ECC2_OFFSET 0x58 +#define NFM8ECC3_OFFSET 0x5c +#define NFMLC8BITPT0_OFFSET 0x60 +#define NFMLC8BITPT1_OFFSET 0x64 + +#define NFCONF (ELFIN_NAND_BASE+NFCONF_OFFSET) +#define NFCONT (ELFIN_NAND_BASE+NFCONT_OFFSET) +#define NFCMMD (ELFIN_NAND_BASE+NFCMMD_OFFSET) +#define NFADDR (ELFIN_NAND_BASE+NFADDR_OFFSET) +#define NFDATA (ELFIN_NAND_BASE+NFDATA_OFFSET) +#define NFMECCDATA0 (ELFIN_NAND_BASE+NFMECCDATA0_OFFSET) +#define NFMECCDATA1 (ELFIN_NAND_BASE+NFMECCDATA1_OFFSET) +#define NFSECCDATA0 (ELFIN_NAND_BASE+NFSECCDATA0_OFFSET) +#define NFSBLK (ELFIN_NAND_BASE+NFSBLK_OFFSET) +#define NFEBLK (ELFIN_NAND_BASE+NFEBLK_OFFSET) +#define NFSTAT (ELFIN_NAND_BASE+NFSTAT_OFFSET) +#define NFESTAT0 (ELFIN_NAND_BASE+NFESTAT0_OFFSET) +#define NFESTAT1 (ELFIN_NAND_BASE+NFESTAT1_OFFSET) +#define NFMECC0 (ELFIN_NAND_BASE+NFMECC0_OFFSET) +#define NFMECC1 (ELFIN_NAND_BASE+NFMECC1_OFFSET) +#define NFSECC (ELFIN_NAND_BASE+NFSECC_OFFSET) +#define NFMLCBITPT (ELFIN_NAND_BASE+NFMLCBITPT_OFFSET) +#define NF8ECCERR0 (ELFIN_NAND_BASE+NF8ECCERR0_OFFSET) +#define NF8ECCERR1 (ELFIN_NAND_BASE+NF8ECCERR1_OFFSET) +#define NF8ECCERR2 (ELFIN_NAND_BASE+NF8ECCERR2_OFFSET) +#define NFM8ECC0 (ELFIN_NAND_BASE+NFM8ECC0_OFFSET) +#define NFM8ECC1 (ELFIN_NAND_BASE+NFM8ECC1_OFFSET) +#define NFM8ECC2 (ELFIN_NAND_BASE+NFM8ECC2_OFFSET) +#define NFM8ECC3 (ELFIN_NAND_BASE+NFM8ECC3_OFFSET) +#define NFMLC8BITPT0 (ELFIN_NAND_BASE+NFMLC8BITPT0_OFFSET) +#define NFMLC8BITPT1 (ELFIN_NAND_BASE+NFMLC8BITPT1_OFFSET) + +#define NFCONF_REG __REG(ELFIN_NAND_BASE+NFCONF_OFFSET) +#define NFCONT_REG __REG(ELFIN_NAND_BASE+NFCONT_OFFSET) +#define NFCMD_REG __REG(ELFIN_NAND_BASE+NFCMMD_OFFSET) +#define NFADDR_REG __REG(ELFIN_NAND_BASE+NFADDR_OFFSET) +#define NFDATA_REG __REG(ELFIN_NAND_BASE+NFDATA_OFFSET) +#define NFDATA8_REG __REGb(ELFIN_NAND_BASE+NFDATA_OFFSET) +#define NFMECCDATA0_REG __REG(ELFIN_NAND_BASE+NFMECCDATA0_OFFSET) +#define NFMECCDATA1_REG __REG(ELFIN_NAND_BASE+NFMECCDATA1_OFFSET) +#define NFSECCDATA0_REG __REG(ELFIN_NAND_BASE+NFSECCDATA0_OFFSET) +#define NFSBLK_REG __REG(ELFIN_NAND_BASE+NFSBLK_OFFSET) +#define NFEBLK_REG __REG(ELFIN_NAND_BASE+NFEBLK_OFFSET) +#define NFSTAT_REG __REG(ELFIN_NAND_BASE+NFSTAT_OFFSET) +#define NFESTAT0_REG __REG(ELFIN_NAND_BASE+NFESTAT0_OFFSET) +#define NFESTAT1_REG __REG(ELFIN_NAND_BASE+NFESTAT1_OFFSET) +#define NFMECC0_REG __REG(ELFIN_NAND_BASE+NFMECC0_OFFSET) +#define NFMECC1_REG __REG(ELFIN_NAND_BASE+NFMECC1_OFFSET) +#define NFSECC_REG __REG(ELFIN_NAND_BASE+NFSECC_OFFSET) +#define NFMLCBITPT_REG __REG(ELFIN_NAND_BASE+NFMLCBITPT_OFFSET) + +#define NFCONF_ECC_MLC (1<<24) +#define NFCONT_ECC_ENC (1<<18) +#define NFCONT_WP (1<<16) +#define NFCONT_MECCLOCK (1<<7) +#define NFCONT_SECCLOCK (1<<6) +#define NFCONT_INITMECC (1<<5) +#define NFCONT_INITSECC (1<<4) +#define NFCONT_INITECC (NFCONT_INITMECC | NFCONT_INITSECC) +#define NFCONT_CS_ALT (1<<1) +#define NFCONT_CS (1<<1) +#define NFSTAT_ECCENCDONE (1<<7) +#define NFSTAT_ECCDECDONE (1<<6) +#define NFSTAT_RnB (1<<0) +#define NFESTAT0_ECCBUSY (1<<31) + + + +/************************************************************* + * OneNAND Controller + *************************************************************/ + +/* + * S3C6400 SFRs + */ +#define ONENAND_REG_MEM_CFG (0x000) +#define ONENAND_REG_BURST_LEN (0x010) +#define ONENAND_REG_MEM_RESET (0x020) +#define ONENAND_REG_INT_ERR_STAT (0x030) +#define ONENAND_REG_INT_ERR_MASK (0x040) +#define ONENAND_REG_INT_ERR_ACK (0x050) +#define ONENAND_REG_ECC_ERR_STAT (0x060) +#define ONENAND_REG_MANUFACT_ID (0x070) +#define ONENAND_REG_DEVICE_ID (0x080) +#define ONENAND_REG_DATA_BUF_SIZE (0x090) +#define ONENAND_REG_BOOT_BUF_SIZE (0x0A0) +#define ONENAND_REG_BUF_AMOUNT (0x0B0) +#define ONENAND_REG_TECH (0x0C0) +#define ONENAND_REG_FBA_WIDTH (0x0D0) +#define ONENAND_REG_FPA_WIDTH (0x0E0) +#define ONENAND_REG_FSA_WIDTH (0x0F0) +#define ONENAND_REG_REVISION (0x100) +#define ONENAND_REG_DATARAM0 (0x110) +#define ONENAND_REG_DATARAM1 (0x120) +#define ONENAND_REG_SYNC_MODE (0x130) +#define ONENAND_REG_TRANS_SPARE (0x140) +#define ONENAND_REG_LOCK_BIT (0x150) +#define ONENAND_REG_DBS_DFS_WIDTH (0x160) +#define ONENAND_REG_PAGE_CNT (0x170) +#define ONENAND_REG_ERR_PAGE_ADDR (0x180) +#define ONENAND_REG_BURST_RD_LAT (0x190) +#define ONENAND_REG_INT_PIN_ENABLE (0x1A0) +#define ONENAND_REG_INT_MON_CYC (0x1B0) +#define ONENAND_REG_ACC_CLOCK (0x1C0) +#define ONENAND_REG_SLOW_RD_PATH (0x1D0) +#define ONENAND_REG_ERR_BLK_ADDR (0x1E0) +#define ONENAND_REG_FLASH_VER_ID (0x1F0) +#define ONENAND_REG_FLASH_AUX_CNTRL (0x300) + +/* + * S3C6400 SFR values + */ +#define ONENAND_MEM_CFG_SYNC_READ (1 << 15) +#define ONENAND_MEM_CFG_BRL_7 (7 << 12) +#define ONENAND_MEM_CFG_BRL_6 (6 << 12) +#define ONENAND_MEM_CFG_BRL_5 (5 << 12) +#define ONENAND_MEM_CFG_BRL_4 (4 << 12) +#define ONENAND_MEM_CFG_BRL_3 (3 << 12) +#define ONENAND_MEM_CFG_BRL_10 (2 << 12) +#define ONENAND_MEM_CFG_BRL_9 (1 << 12) +#define ONENAND_MEM_CFG_BRL_8 (0 << 12) +#define ONENAND_MEM_CFG_BRL_SHIFT (12) +#define ONENAND_MEM_CFG_BL_1K (5 << 9) +#define ONENAND_MEM_CFG_BL_32 (4 << 9) +#define ONENAND_MEM_CFG_BL_16 (3 << 9) +#define ONENAND_MEM_CFG_BL_8 (2 << 9) +#define ONENAND_MEM_CFG_BL_4 (1 << 9) +#define ONENAND_MEM_CFG_BL_CONT (0 << 9) +#define ONENAND_MEM_CFG_BL_SHIFT (9) +#define ONENAND_MEM_CFG_NO_ECC (1 << 8) +#define ONENAND_MEM_CFG_RDY_HIGH (1 << 7) +#define ONENAND_MEM_CFG_INT_HIGH (1 << 6) +#define ONENAND_MEM_CFG_IOBE (1 << 5) +#define ONENAND_MEM_CFG_RDY_CONF (1 << 4) +#define ONENAND_MEM_CFG_HF (1 << 2) +#define ONENAND_MEM_CFG_WM_SYNC (1 << 1) +#define ONENAND_MEM_CFG_BWPS_UNLOCK (1 << 0) + +#define ONENAND_BURST_LEN_CONT (0) +#define ONENAND_BURST_LEN_4 (4) +#define ONENAND_BURST_LEN_8 (8) +#define ONENAND_BURST_LEN_16 (16) + +#define ONENAND_MEM_RESET_WARM (0x1) +#define ONENAND_MEM_RESET_COLD (0x2) +#define ONENAND_MEM_RESET_HOT (0x3) + +#define ONENAND_INT_ERR_CACHE_OP_ERR (1 << 13) +#define ONENAND_INT_ERR_RST_CMP (1 << 12) +#define ONENAND_INT_ERR_RDY_ACT (1 << 11) +#define ONENAND_INT_ERR_INT_ACT (1 << 10) +#define ONENAND_INT_ERR_UNSUP_CMD (1 << 9) +#define ONENAND_INT_ERR_LOCKED_BLK (1 << 8) +#define ONENAND_INT_ERR_BLK_RW_CMP (1 << 7) +#define ONENAND_INT_ERR_ERS_CMP (1 << 6) +#define ONENAND_INT_ERR_PGM_CMP (1 << 5) +#define ONENAND_INT_ERR_LOAD_CMP (1 << 4) +#define ONENAND_INT_ERR_ERS_FAIL (1 << 3) +#define ONENAND_INT_ERR_PGM_FAIL (1 << 2) +#define ONENAND_INT_ERR_INT_TO (1 << 1) +#define ONENAND_INT_ERR_LD_FAIL_ECC_ERR (1 << 0) + +#define ONENAND_DEVICE_DENSITY_SHIFT (4) +#define ONENAND_DEVICE_IS_DDP (1 << 3) +#define ONENAND_DEVICE_IS_DEMUX (1 << 2) +#define ONENAND_DEVICE_VCC_MASK (0x3) +#define ONENAND_DEVICE_DENSITY_128Mb (0x000) +#define ONENAND_DEVICE_DENSITY_256Mb (0x001) +#define ONENAND_DEVICE_DENSITY_512Mb (0x002) +#define ONENAND_DEVICE_DENSITY_1Gb (0x003) +#define ONENAND_DEVICE_DENSITY_2Gb (0x004) +#define ONENAND_DEVICE_DENSITY_4Gb (0x005) + +#define ONENAND_SYNC_MODE_RM_SYNC (1 << 1) +#define ONENAND_SYNC_MODE_WM_SYNC (1 << 0) + +#define ONENAND_TRANS_SPARE_TSRF_INC (1 << 0) + +#define ONENAND_INT_PIN_ENABLE (1 << 0) + +#define ONENAND_ACC_CLOCK_266_133 (0x5) +#define ONENAND_ACC_CLOCK_166_83 (0x3) +#define ONENAND_ACC_CLOCK_134_67 (0x3) +#define ONENAND_ACC_CLOCK_100_50 (0x2) +#define ONENAND_ACC_CLOCK_60_30 (0x2) + +#define ONENAND_FLASH_AUX_WD_DISABLE (1 << 0) + +/* + * Datain values for mapped commands + */ +#define ONENAND_DATAIN_ERASE_STATUS (0x00) +#define ONENAND_DATAIN_ERASE_MULTI (0x01) +#define ONENAND_DATAIN_ERASE_SINGLE (0x03) +#define ONENAND_DATAIN_ERASE_VERIFY (0x15) +#define ONENAND_DATAIN_UNLOCK_START (0x08) +#define ONENAND_DATAIN_UNLOCK_END (0x09) +#define ONENAND_DATAIN_LOCK_START (0x0A) +#define ONENAND_DATAIN_LOCK_END (0x0B) +#define ONENAND_DATAIN_LOCKTIGHT_START (0x0C) +#define ONENAND_DATAIN_LOCKTIGHT_END (0x0D) +#define ONENAND_DATAIN_UNLOCK_ALL (0x0E) +#define ONENAND_DATAIN_COPYBACK_SRC (0x1000) +#define ONENAND_DATAIN_COPYBACK_DST (0x2000) +#define ONENAND_DATAIN_ACCESS_OTP (0x12) +#define ONENAND_DATAIN_ACCESS_MAIN (0x14) +#define ONENAND_DATAIN_PIPELINE_READ (0x4000) +#define ONENAND_DATAIN_PIPELINE_WRITE (0x4100) +#define ONENAND_DATAIN_RMW_LOAD (0x10) +#define ONENAND_DATAIN_RMW_MODIFY (0x11) + +/* + * Device ID Register F001h (R) + */ +#define ONENAND_DEVICE_DENSITY_SHIFT (4) +#define ONENAND_DEVICE_IS_DDP (1 << 3) +#define ONENAND_DEVICE_IS_DEMUX (1 << 2) +#define ONENAND_DEVICE_VCC_MASK (0x3) + +/* + * Version ID Register F002h (R) + */ +#define ONENAND_VERSION_PROCESS_SHIFT (8) + +/* + * Start Address 1 F100h (R/W) + */ +#define ONENAND_DDP_SHIFT (15) +#define ONENAND_DDP_CHIP0 (0) +#define ONENAND_DDP_CHIP1 (1 << ONENAND_DDP_SHIFT) + +/* + * Start Buffer Register F200h (R/W) + */ +#define ONENAND_BSA_MASK (0x03) +#define ONENAND_BSA_SHIFT (8) +#define ONENAND_BSA_BOOTRAM (0 << 2) +#define ONENAND_BSA_DATARAM0 (2 << 2) +#define ONENAND_BSA_DATARAM1 (3 << 2) +#define ONENAND_BSC_MASK (0x03) + +/* + * Command Register F220h (R/W) + */ +#define ONENAND_CMD_READ (0x00) +#define ONENAND_CMD_READOOB (0x13) +#define ONENAND_CMD_PROG (0x80) +#define ONENAND_CMD_PROGOOB (0x1A) +#define ONENAND_CMD_UNLOCK (0x23) +#define ONENAND_CMD_LOCK (0x2A) +#define ONENAND_CMD_LOCK_TIGHT (0x2C) +#define ONENAND_CMD_UNLOCK_ALL (0x27) +#define ONENAND_CMD_ERASE (0x94) +#define ONENAND_CMD_RESET (0xF0) +#define ONENAND_CMD_OTP_ACCESS (0x65) +#define ONENAND_CMD_READID (0x90) +#define ONENAND_CMD_STARTADDR1 (0xE0) +#define ONENAND_CMD_WP_STATUS (0xE1) +#define ONENAND_CMD_PIPELINE_READ (0x01) +#define ONENAND_CMD_PIPELINE_WRITE (0x81) + +/* + * Command Mapping for S3C6400 OneNAND Controller + */ +#define ONENAND_AHB_ADDR (0x20000000) +#define ONENAND_DUMMY_ADDR (0x20400000) +#define ONENAND_CMD_SHIFT (24) +#define ONENAND_CMD_MAP_00 (0x0) +#define ONENAND_CMD_MAP_01 (0x1) +#define ONENAND_CMD_MAP_10 (0x2) +#define ONENAND_CMD_MAP_11 (0x3) +#define ONENAND_CMD_MAP_FF (0xF) + +/* + * Mask for Mapping table + */ +#define ONENAND_MEM_ADDR_MASK (0xffffff) +#define ONENAND_DDP_SHIFT_1Gb (21) +#define ONENAND_DDP_SHIFT_2Gb (22) +#define ONENAND_DDP_SHIFT_4Gb (23) +#define ONENAND_FBA_SHIFT (12) +#define ONENAND_FPA_SHIFT (6) +#define ONENAND_FSA_SHIFT (4) +#define ONENAND_FBA_MASK_128Mb (0xff) +#define ONENAND_FBA_MASK_256Mb (0x1ff) +#define ONENAND_FBA_MASK_512Mb (0x1ff) +#define ONENAND_FBA_MASK_1Gb_DDP (0x1ff) +#define ONENAND_FBA_MASK_1Gb (0x3ff) +#define ONENAND_FBA_MASK_2Gb_DDP (0x3ff) +#define ONENAND_FBA_MASK_2Gb (0x7ff) +#define ONENAND_FBA_MASK_4Gb_DDP (0x7ff) +#define ONENAND_FBA_MASK_4Gb (0xfff) +#define ONENAND_FPA_MASK (0x3f) +#define ONENAND_FSA_MASK (0x3) + +/* + * System Configuration 1 Register F221h (R, R/W) + */ +#define ONENAND_SYS_CFG1_SYNC_READ (1 << 15) +#define ONENAND_SYS_CFG1_BRL_7 (7 << 12) +#define ONENAND_SYS_CFG1_BRL_6 (6 << 12) +#define ONENAND_SYS_CFG1_BRL_5 (5 << 12) +#define ONENAND_SYS_CFG1_BRL_4 (4 << 12) +#define ONENAND_SYS_CFG1_BRL_3 (3 << 12) +#define ONENAND_SYS_CFG1_BRL_10 (2 << 12) +#define ONENAND_SYS_CFG1_BRL_9 (1 << 12) +#define ONENAND_SYS_CFG1_BRL_8 (0 << 12) +#define ONENAND_SYS_CFG1_BRL_SHIFT (12) +#define ONENAND_SYS_CFG1_BL_32 (4 << 9) +#define ONENAND_SYS_CFG1_BL_16 (3 << 9) +#define ONENAND_SYS_CFG1_BL_8 (2 << 9) +#define ONENAND_SYS_CFG1_BL_4 (1 << 9) +#define ONENAND_SYS_CFG1_BL_CONT (0 << 9) +#define ONENAND_SYS_CFG1_BL_SHIFT (9) +#define ONENAND_SYS_CFG1_NO_ECC (1 << 8) +#define ONENAND_SYS_CFG1_RDY (1 << 7) +#define ONENAND_SYS_CFG1_INT (1 << 6) +#define ONENAND_SYS_CFG1_IOBE (1 << 5) +#define ONENAND_SYS_CFG1_RDY_CONF (1 << 4) + +/* + * Controller Status Register F240h (R) + */ +#define ONENAND_CTRL_ONGO (1 << 15) +#define ONENAND_CTRL_LOCK (1 << 14) +#define ONENAND_CTRL_LOAD (1 << 13) +#define ONENAND_CTRL_PROGRAM (1 << 12) +#define ONENAND_CTRL_ERASE (1 << 11) +#define ONENAND_CTRL_ERROR (1 << 10) +#define ONENAND_CTRL_RSTB (1 << 7) +#define ONENAND_CTRL_OTP_L (1 << 6) +#define ONENAND_CTRL_OTP_BL (1 << 5) + +/* + * Interrupt Status Register F241h (R) + */ +#define ONENAND_INT_MASTER (1 << 15) +#define ONENAND_INT_READ (1 << 7) +#define ONENAND_INT_WRITE (1 << 6) +#define ONENAND_INT_ERASE (1 << 5) +#define ONENAND_INT_RESET (1 << 4) +#define ONENAND_INT_CLEAR (0 << 0) + +/* + * NAND Flash Write Protection Status Register F24Eh (R) + */ +#define ONENAND_WP_US (1 << 2) +#define ONENAND_WP_LS (1 << 1) +#define ONENAND_WP_LTS (1 << 0) + +/* + * ECC Status Register FF00h (R) + */ +#define ONENAND_ECC_1BIT (1 << 0) +#define ONENAND_ECC_1BIT_ALL (0x5555) +#define ONENAND_ECC_2BIT (1 << 1) +#define ONENAND_ECC_2BIT_ALL (0xAAAA) + +/* + * One-Time Programmable (OTP) + */ +#define ONENAND_OTP_LOCK_OFFSET (14) + +/************************************************************* + * End of OneNAND Controller + *************************************************************/ + + +/* + * Interrupt + */ +#define ELFIN_VIC0_BASE_ADDR (0x71200000) +#define ELFIN_VIC1_BASE_ADDR (0x71300000) +#define oINTMOD (0x0C) // VIC INT SELECT (IRQ or FIQ) +#define oINTUNMSK (0x10) // VIC INT EN (Unmask by writing 1) +#define oINTMSK (0x14) // VIC INT EN CLEAR (Mask by writing 1) +#define oINTSUBMSK (0x1C) // VIC SOFT INT CLEAR +#define oVECTADDR (0xF00) // VIC ADDRESS + + + +/* + * Watchdog timer + */ +#define ELFIN_WATCHDOG_BASE 0x7E004000 + +#define WTCON_REG __REG(0x7E004004) +#define WTDAT_REG __REG(0x7E004008) +#define WTCNT_REG __REG(0x7E00400C) + + + +/* + * UART + */ +#define ELFIN_UART_BASE 0x7F005000 + +#define ELFIN_UART0_OFFSET 0x0000 +#define ELFIN_UART1_OFFSET 0x0400 +#define ELFIN_UART2_OFFSET 0x0800 +#define ELFIN_UART3_OFFSET 0x0c00 + +#define ULCON_OFFSET 0x00 +#define UCON_OFFSET 0x04 +#define UFCON_OFFSET 0x08 +#define UMCON_OFFSET 0x0C +#define UTRSTAT_OFFSET 0x10 +#define UERSTAT_OFFSET 0x14 +#define UFSTAT_OFFSET 0x18 +#define UMSTAT_OFFSET 0x1C +#define UTXH_OFFSET 0x20 +#define URXH_OFFSET 0x24 +#define UBRDIV_OFFSET 0x28 +#define UDIVSLOT_OFFSET 0x2C +#define UINTP_OFFSET 0x30 +#define UINTSP_OFFSET 0x34 +#define UINTM_OFFSET 0x38 + +#define ULCON0_REG __REG(0x7F005000) +#define UCON0_REG __REG(0x7F005004) +#define UFCON0_REG __REG(0x7F005008) +#define UMCON0_REG __REG(0x7F00500C) +#define UTRSTAT0_REG __REG(0x7F005010) +#define UERSTAT0_REG __REG(0x7F005014) +#define UFSTAT0_REG __REG(0x7F005018) +#define UMSTAT0_REG __REG(0x7F00501c) +#define UTXH0_REG __REG(0x7F005020) +#define URXH0_REG __REG(0x7F005024) +#define UBRDIV0_REG __REG(0x7F005028) +#define UDIVSLOT0_REG __REG(0x7F00502c) +#define UINTP0_REG __REG(0x7F005030) +#define UINTSP0_REG __REG(0x7F005034) +#define UINTM0_REG __REG(0x7F005038) + +#define ULCON1_REG __REG(0x7F005400) +#define UCON1_REG __REG(0x7F005404) +#define UFCON1_REG __REG(0x7F005408) +#define UMCON1_REG __REG(0x7F00540C) +#define UTRSTAT1_REG __REG(0x7F005410) +#define UERSTAT1_REG __REG(0x7F005414) +#define UFSTAT1_REG __REG(0x7F005418) +#define UMSTAT1_REG __REG(0x7F00541c) +#define UTXH1_REG __REG(0x7F005420) +#define URXH1_REG __REG(0x7F005424) +#define UBRDIV1_REG __REG(0x7F005428) +#define UDIVSLOT1_REG __REG(0x7F00542c) +#define UINTP1_REG __REG(0x7F005430) +#define UINTSP1_REG __REG(0x7F005434) +#define UINTM1_REG __REG(0x7F005438) + +#define UTRSTAT_TX_EMPTY BIT2 +#define UTRSTAT_RX_READY BIT0 +#define UART_ERR_MASK 0xF + + +/* + * PWM timer + */ +#define ELFIN_TIMER_BASE 0x7F006000 + +#define TCFG0_REG __REG(0x7F006000) +#define TCFG1_REG __REG(0x7F006004) +#define TCON_REG __REG(0x7F006008) +#define TCNTB0_REG __REG(0x7F00600c) +#define TCMPB0_REG __REG(0x7F006010) +#define TCNTO0_REG __REG(0x7F006014) +#define TCNTB1_REG __REG(0x7F006018) +#define TCMPB1_REG __REG(0x7F00601c) +#define TCNTO1_REG __REG(0x7F006020) +#define TCNTB2_REG __REG(0x7F006024) +#define TCMPB2_REG __REG(0x7F006028) +#define TCNTO2_REG __REG(0x7F00602c) +#define TCNTB3_REG __REG(0x7F006030) +#define TCMPB3_REG __REG(0x7F006034) +#define TCNTO3_REG __REG(0x7F006038) +#define TCNTB4_REG __REG(0x7F00603c) +#define TCNTO4_REG __REG(0x7F006040) + +/* Fields */ +#define fTCFG0_DZONE Fld(8,16) /* the dead zone length (= timer 0) */ +#define fTCFG0_PRE1 Fld(8,8) /* prescaler value for time 2,3,4 */ +#define fTCFG0_PRE0 Fld(8,0) /* prescaler value for time 0,1 */ +#define fTCFG1_MUX4 Fld(4,16) +/* bits */ +#define TCFG0_DZONE(x) FInsrt((x), fTCFG0_DZONE) +#define TCFG0_PRE1(x) FInsrt((x), fTCFG0_PRE1) +#define TCFG0_PRE0(x) FInsrt((x), fTCFG0_PRE0) +#define TCON_4_AUTO (1 << 22) /* auto reload on/off for Timer 4 */ +#define TCON_4_UPDATE (1 << 21) /* manual Update TCNTB4 */ +#define TCON_4_ONOFF (1 << 20) /* 0: Stop, 1: start Timer 4 */ +#define COUNT_4_ON (TCON_4_ONOFF*1) +#define COUNT_4_OFF (TCON_4_ONOFF*0) +#define TCON_3_AUTO (1 << 19) /* auto reload on/off for Timer 3 */ +#define TIMER3_ATLOAD_ON (TCON_3_AUTO*1) +#define TIMER3_ATLAOD_OFF FClrBit(TCON, TCON_3_AUTO) +#define TCON_3_INVERT (1 << 18) /* 1: Inverter on for TOUT3 */ +#define TIMER3_IVT_ON (TCON_3_INVERT*1) +#define TIMER3_IVT_OFF (FClrBit(TCON, TCON_3_INVERT)) +#define TCON_3_MAN (1 << 17) /* manual Update TCNTB3,TCMPB3 */ +#define TIMER3_MANUP (TCON_3_MAN*1) +#define TIMER3_NOP (FClrBit(TCON, TCON_3_MAN)) +#define TCON_3_ONOFF (1 << 16) /* 0: Stop, 1: start Timer 3 */ +#define TIMER3_ON (TCON_3_ONOFF*1) +#define TIMER3_OFF (FClrBit(TCON, TCON_3_ONOFF)) +/* macros */ +#define GET_PRESCALE_TIMER4(x) FExtr((x), fTCFG0_PRE1) +#define GET_DIVIDER_TIMER4(x) FExtr((x), fTCFG1_MUX4) + +/* + * RTC Controller + */ +#define ELFIN_RTC_BASE 0x7e005000 + +#define RTCCON_REG __REG(0x7e005040) +#define TICNT_REG __REG(0x7e005044) +#define RTCALM_REG __REG(0x7e005050) +#define ALMSEC_REG __REG(0x7e005054) +#define ALMMIN_REG __REG(0x7e005058) +#define ALMHOUR_REG __REG(0x7e00505c) +#define ALMDATE_REG __REG(0x7e005060) +#define ALMMON_REG __REG(0x7e005064) +#define ALMYEAR_REG __REG(0x7e005068) +#define BCDSEC_REG __REG(0x7e005070) +#define BCDMIN_REG __REG(0x7e005074) +#define BCDHOUR_REG __REG(0x7e005078) +#define BCDDATE_REG __REG(0x7e00507c) +#define BCDDAY_REG __REG(0x7e005080) +#define BCDMON_REG __REG(0x7e005084) +#define BCDYEAR_REG __REG(0x7e005088) + +/* + * USB2.0 HS OTG (Chapter 26) + */ +#define USBOTG_LINK_BASE (0x7C000000) +#define USBOTG_PHY_BASE (0x7C100000) + +/* Core Global Registers */ +#define S3C_OTG_GOTGCTL (USBOTG_LINK_BASE + 0x000) /* OTG Control & Status */ +#define S3C_OTG_GOTGINT (USBOTG_LINK_BASE + 0x004) /* OTG Interrupt */ +#define S3C_OTG_GAHBCFG (USBOTG_LINK_BASE + 0x008) /* Core AHB Configuration */ +#define S3C_OTG_GUSBCFG (USBOTG_LINK_BASE + 0x00C) /* Core USB Configuration */ +#define S3C_OTG_GRSTCTL (USBOTG_LINK_BASE + 0x010) /* Core Reset */ +#define S3C_OTG_GINTSTS (USBOTG_LINK_BASE + 0x014) /* Core Interrupt */ +#define S3C_OTG_GINTMSK (USBOTG_LINK_BASE + 0x018) /* Core Interrupt Mask */ +#define S3C_OTG_GRXSTSR (USBOTG_LINK_BASE + 0x01C) /* Receive Status Debug Read/Status Read */ +#define S3C_OTG_GRXSTSP (USBOTG_LINK_BASE + 0x020) /* Receive Status Debug Pop/Status Pop */ +#define S3C_OTG_GRXFSIZ (USBOTG_LINK_BASE + 0x024) /* Receive FIFO Size */ +#define S3C_OTG_GNPTXFSIZ (USBOTG_LINK_BASE + 0x028) /* Non-Periodic Transmit FIFO Size */ +#define S3C_OTG_GNPTXSTS (USBOTG_LINK_BASE + 0x02C) /* Non-Periodic Transmit FIFO/Queue Status */ + +#define S3C_OTG_HPTXFSIZ (USBOTG_LINK_BASE + 0x100) /* Host Periodic Transmit FIFO Size */ +#define S3C_OTG_DPTXFSIZ1 (USBOTG_LINK_BASE + 0x104) /* Device Periodic Transmit FIFO-1 Size */ +#define S3C_OTG_DPTXFSIZ2 (USBOTG_LINK_BASE + 0x108) /* Device Periodic Transmit FIFO-2 Size */ +#define S3C_OTG_DPTXFSIZ3 (USBOTG_LINK_BASE + 0x10C) /* Device Periodic Transmit FIFO-3 Size */ +#define S3C_OTG_DPTXFSIZ4 (USBOTG_LINK_BASE + 0x110) /* Device Periodic Transmit FIFO-4 Size */ +#define S3C_OTG_DPTXFSIZ5 (USBOTG_LINK_BASE + 0x114) /* Device Periodic Transmit FIFO-5 Size */ +#define S3C_OTG_DPTXFSIZ6 (USBOTG_LINK_BASE + 0x118) /* Device Periodic Transmit FIFO-6 Size */ +#define S3C_OTG_DPTXFSIZ7 (USBOTG_LINK_BASE + 0x11C) /* Device Periodic Transmit FIFO-7 Size */ +#define S3C_OTG_DPTXFSIZ8 (USBOTG_LINK_BASE + 0x120) /* Device Periodic Transmit FIFO-8 Size */ +#define S3C_OTG_DPTXFSIZ9 (USBOTG_LINK_BASE + 0x124) /* Device Periodic Transmit FIFO-9 Size */ +#define S3C_OTG_DPTXFSIZ10 (USBOTG_LINK_BASE + 0x128) /* Device Periodic Transmit FIFO-10 Size */ +#define S3C_OTG_DPTXFSIZ11 (USBOTG_LINK_BASE + 0x12C) /* Device Periodic Transmit FIFO-11 Size */ +#define S3C_OTG_DPTXFSIZ12 (USBOTG_LINK_BASE + 0x130) /* Device Periodic Transmit FIFO-12 Size */ +#define S3C_OTG_DPTXFSIZ13 (USBOTG_LINK_BASE + 0x134) /* Device Periodic Transmit FIFO-13 Size */ +#define S3C_OTG_DPTXFSIZ14 (USBOTG_LINK_BASE + 0x138) /* Device Periodic Transmit FIFO-14 Size */ +#define S3C_OTG_DPTXFSIZ15 (USBOTG_LINK_BASE + 0x13C) /* Device Periodic Transmit FIFO-15 Size */ + +/* Host Global Registers */ +#define S3C_OTG_HCFG (USBOTG_LINK_BASE + 0x400) /* Host Configuration */ +#define S3C_OTG_HFIR (USBOTG_LINK_BASE + 0x404) /* Host Frame Interval */ +#define S3C_OTG_HFNUM (USBOTG_LINK_BASE + 0x408) /* Host Frame Number/Frame Time Remaining */ +#define S3C_OTG_HPTXSTS (USBOTG_LINK_BASE + 0x410) /* Host Periodic Transmit FIFO/Queue Status */ +#define S3C_OTG_HAINT (USBOTG_LINK_BASE + 0x414) /* Host All Channels Interrupt */ +#define S3C_OTG_HAINTMSK (USBOTG_LINK_BASE + 0x418) /* Host All Channels Interrupt Mask */ + +/* Host Port Control & Status Registers */ +#define S3C_OTG_HPRT (USBOTG_LINK_BASE + 0x440) /* Host Port Control & Status */ + +/* Host Channel-Specific Registers */ +#define S3C_OTG_HCCHAR0 (USBOTG_LINK_BASE + 0x500) /* Host Channel-0 Characteristics */ +#define S3C_OTG_HCSPLT0 (USBOTG_LINK_BASE + 0x504) /* Host Channel-0 Split Control */ +#define S3C_OTG_HCINT0 (USBOTG_LINK_BASE + 0x508) /* Host Channel-0 Interrupt */ +#define S3C_OTG_HCINTMSK0 (USBOTG_LINK_BASE + 0x50C) /* Host Channel-0 Interrupt Mask */ +#define S3C_OTG_HCTSIZ0 (USBOTG_LINK_BASE + 0x510) /* Host Channel-0 Transfer Size */ +#define S3C_OTG_HCDMA0 (USBOTG_LINK_BASE + 0x514) /* Host Channel-0 DMA Address */ + + +/* Device Global Registers */ +#define S3C_OTG_DCFG (USBOTG_LINK_BASE + 0x800) /* Device Configuration */ +#define S3C_OTG_DCTL (USBOTG_LINK_BASE + 0x804) /* Device Control */ +#define S3C_OTG_DSTS (USBOTG_LINK_BASE + 0x808) /* Device Status */ +#define S3C_OTG_DIEPMSK (USBOTG_LINK_BASE + 0x810) /* Device IN Endpoint Common Interrupt Mask */ +#define S3C_OTG_DOEPMSK (USBOTG_LINK_BASE + 0x814) /* Device OUT Endpoint Common Interrupt Mask */ +#define S3C_OTG_DAINT (USBOTG_LINK_BASE + 0x818) /* Device All Endpoints Interrupt */ +#define S3C_OTG_DAINTMSK (USBOTG_LINK_BASE + 0x81C) /* Device All Endpoints Interrupt Mask */ +#define S3C_OTG_DTKNQR1 (USBOTG_LINK_BASE + 0x820) /* Device IN Token Sequence Learning Queue Read 1 */ +#define S3C_OTG_DTKNQR2 (USBOTG_LINK_BASE + 0x824) /* Device IN Token Sequence Learning Queue Read 2 */ +#define S3C_OTG_DVBUSDIS (USBOTG_LINK_BASE + 0x828) /* Device VBUS Discharge Time */ +#define S3C_OTG_DVBUSPULSE (USBOTG_LINK_BASE + 0x82C) /* Device VBUS Pulsing Time */ +#define S3C_OTG_DTKNQR3 (USBOTG_LINK_BASE + 0x830) /* Device IN Token Sequence Learning Queue Read 3 */ +#define S3C_OTG_DTKNQR4 (USBOTG_LINK_BASE + 0x834) /* Device IN Token Sequence Learning Queue Read 4 */ + +/* Device Logical IN Endpoint-Specific Registers */ +#define S3C_OTG_DIEPCTL0 (USBOTG_LINK_BASE + 0x900) /* Device IN Endpoint 0 Control */ +#define S3C_OTG_DIEPINT0 (USBOTG_LINK_BASE + 0x908) /* Device IN Endpoint 0 Interrupt */ +#define S3C_OTG_DIEPTSIZ0 (USBOTG_LINK_BASE + 0x910) /* Device IN Endpoint 0 Transfer Size */ +#define S3C_OTG_DIEPDMA0 (USBOTG_LINK_BASE + 0x914) /* Device IN Endpoint 0 DMA Address */ + +/* Device Logical OUT Endpoint-Specific Registers */ +#define S3C_OTG_DOEPCTL0 (USBOTG_LINK_BASE + 0xB00) /* Device OUT Endpoint 0 Control */ +#define S3C_OTG_DOEPINT0 (USBOTG_LINK_BASE + 0xB08) /* Device OUT Endpoint 0 Interrupt */ +#define S3C_OTG_DOEPTSIZ0 (USBOTG_LINK_BASE + 0xB10) /* Device OUT Endpoint 0 Transfer Size */ +#define S3C_OTG_DOEPDMA0 (USBOTG_LINK_BASE + 0xB14) /* Device OUT Endpoint 0 DMA Address */ + +/* Power & clock gating registers */ +#define S3C_OTG_PCGCCTRL (USBOTG_LINK_BASE + 0xE00) + +/* Endpoint FIFO address */ +#define S3C_OTG_EP0_FIFO (USBOTG_LINK_BASE + 0x1000) + + + +/* OTG PHY CORE REGISTERS */ +#define S3C_OTG_PHYPWR (USBOTG_PHY_BASE+0x00) +#define S3C_OTG_PHYCTRL (USBOTG_PHY_BASE+0x04) +#define S3C_OTG_RSTCON (USBOTG_PHY_BASE+0x08) + +/* include common stuff */ +#ifndef __ASSEMBLY__ +#if 0 +static inline S3C2410_SDI * S3C2410_GetBase_SDI(void) +{ + return (S3C2410_SDI *)ELFIN_SDI_BASE; +} +#endif +#else /* #ifndef __ASSEMBLY__ */ + +/* watchdog */ +#define WTCON_OFFSET 0x00 + +/* LCD controller */ +#define LCDBGCON_OFFSET 0x5c + +#endif /* #ifndef __ASSEMBLY__ */ + +/* PENDING BIT */ +#define BIT_EINT0 (0x1) +#define BIT_EINT1 (0x1<<1) +#define BIT_EINT2 (0x1<<2) +#define BIT_EINT3 (0x1<<3) +#define BIT_EINT4_7 (0x1<<4) +#define BIT_EINT8_23 (0x1<<5) +#define BIT_BAT_FLT (0x1<<7) +#define BIT_TICK (0x1<<8) +#define BIT_WDT (0x1<<9) +#define BIT_TIMER0 (0x1<<10) +#define BIT_TIMER1 (0x1<<11) +#define BIT_TIMER2 (0x1<<12) +#define BIT_TIMER3 (0x1<<13) +#define BIT_TIMER4 (0x1<<14) +#define BIT_UART2 (0x1<<15) +#define BIT_LCD (0x1<<16) +#define BIT_DMA0 (0x1<<17) +#define BIT_DMA1 (0x1<<18) +#define BIT_DMA2 (0x1<<19) +#define BIT_DMA3 (0x1<<20) +#define BIT_SDI (0x1<<21) +#define BIT_SPI0 (0x1<<22) +#define BIT_UART1 (0x1<<23) +#define BIT_USBH (0x1<<26) +#define BIT_IIC (0x1<<27) +#define BIT_UART0 (0x1<<28) +#define BIT_SPI1 (0x1<<29) +#define BIT_RTC (0x1<<30) +#define BIT_ADC (0x1<<31) +#define BIT_ALLMSK (0xFFFFFFFF) + +#endif /*__S3C6410_H__*/ diff --git a/qiboot/include/serial-s3c24xx.h b/qiboot/include/serial-s3c24xx.h new file mode 100644 index 0000000..6209401 --- /dev/null +++ b/qiboot/include/serial-s3c24xx.h @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#ifndef __SERIAL_S3C24XX_H__ +#define __SERIAL_S3C24XX_H__ + +#define UART0 0 +#define UART1 1 +#define UART2 2 + +#define rGPHCON (*(volatile unsigned *)0x56000070) /*UART 0 Line control*/ + +#define rULCON0 (*(volatile unsigned *)0x50000000) /*UART 0 Line control*/ +#define rUCON0 (*(volatile unsigned *)0x50000004) /*UART 0 Control*/ +#define rUFCON0 (*(volatile unsigned *)0x50000008) /*UART 0 FIFO control*/ +#define rUMCON0 (*(volatile unsigned *)0x5000000c) /*UART 0 Modem control*/ +#define rUTRSTAT0 (*(volatile unsigned *)0x50000010) /*UART 0 Tx/Rx status*/ +#define rUERSTAT0 (*(volatile unsigned *)0x50000014) /*UART 0 Rx error status*/ +#define rUFSTAT0 (*(volatile unsigned *)0x50000018) /*UART 0 FIFO status*/ +#define rUMSTAT0 (*(volatile unsigned *)0x5000001c) /*UART 0 Modem status*/ +#define rUBRDIV0 (*(volatile unsigned *)0x50000028) /*UART 0 Baud rate divisor*/ + +#define rULCON1 (*(volatile unsigned *)0x50004000) /*UART 1 Line control*/ +#define rUCON1 (*(volatile unsigned *)0x50004004) /*UART 1 Control*/ +#define rUFCON1 (*(volatile unsigned *)0x50004008) /*UART 1 FIFO control*/ +#define rUMCON1 (*(volatile unsigned *)0x5000400c) /*UART 1 Modem control*/ +#define rUTRSTAT1 (*(volatile unsigned *)0x50004010) /*UART 1 Tx/Rx status*/ +#define rUERSTAT1 (*(volatile unsigned *)0x50004014) /*UART 1 Rx error status*/ +#define rUFSTAT1 (*(volatile unsigned *)0x50004018) /*UART 1 FIFO status*/ +#define rUMSTAT1 (*(volatile unsigned *)0x5000401c) /*UART 1 Modem status*/ +#define rUBRDIV1 (*(volatile unsigned *)0x50004028) /*UART 1 Baud rate divisor*/ + +#define rULCON2 (*(volatile unsigned *)0x50008000) /*UART 2 Line control*/ +#define rUCON2 (*(volatile unsigned *)0x50008004) /*UART 2 Control*/ +#define rUFCON2 (*(volatile unsigned *)0x50008008) /*UART 2 FIFO control*/ +#define rUTRSTAT2 (*(volatile unsigned *)0x50008010) /*UART 2 Tx/Rx status*/ +#define rUERSTAT2 (*(volatile unsigned *)0x50008014) /*UART 2 Rx error status*/ +#define rUFSTAT2 (*(volatile unsigned *)0x50008018) /*UART 2 FIFO status*/ +#define rUBRDIV2 (*(volatile unsigned *)0x50008028) /*UART 2 Baud rate divisor*/ + +#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch) +#define RdURXH0() (*(volatile unsigned char *)0x50000024) +#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004020)=(unsigned char)(ch) +#define RdURXH1() (*(volatile unsigned char *)0x50004024) +#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008020)=(unsigned char)(ch) +#define RdURXH2() (*(volatile unsigned char *)0x50008024) + +extern void serial_init_115200_s3c24xx(const int uart, const int pclk_MHz); +extern void serial_putc_s3c24xx(const int uart, const char c); +extern int puts(const char *string); + +#endif diff --git a/qiboot/include/serial-s3c64xx.h b/qiboot/include/serial-s3c64xx.h new file mode 100644 index 0000000..bab0872 --- /dev/null +++ b/qiboot/include/serial-s3c64xx.h @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#ifndef __SERIAL_S3C64XX_H__ +#define __SERIAL_S3C64XX_H__ + +#define UART0 0 +#define UART1 1 +#define UART2 2 + +#define rGPHCON (*(volatile unsigned *)0x56000070) /*UART 0 Line control*/ + +#define rULCON0 (*(volatile unsigned *)0x50000000) /*UART 0 Line control*/ +#define rUCON0 (*(volatile unsigned *)0x50000004) /*UART 0 Control*/ +#define rUFCON0 (*(volatile unsigned *)0x50000008) /*UART 0 FIFO control*/ +#define rUMCON0 (*(volatile unsigned *)0x5000000c) /*UART 0 Modem control*/ +#define rUTRSTAT0 (*(volatile unsigned *)0x50000010) /*UART 0 Tx/Rx status*/ +#define rUERSTAT0 (*(volatile unsigned *)0x50000014) /*UART 0 Rx error status*/ +#define rUFSTAT0 (*(volatile unsigned *)0x50000018) /*UART 0 FIFO status*/ +#define rUMSTAT0 (*(volatile unsigned *)0x5000001c) /*UART 0 Modem status*/ +#define rUBRDIV0 (*(volatile unsigned *)0x50000028) /*UART 0 Baud rate divisor*/ + +#define rULCON1 (*(volatile unsigned *)0x50004000) /*UART 1 Line control*/ +#define rUCON1 (*(volatile unsigned *)0x50004004) /*UART 1 Control*/ +#define rUFCON1 (*(volatile unsigned *)0x50004008) /*UART 1 FIFO control*/ +#define rUMCON1 (*(volatile unsigned *)0x5000400c) /*UART 1 Modem control*/ +#define rUTRSTAT1 (*(volatile unsigned *)0x50004010) /*UART 1 Tx/Rx status*/ +#define rUERSTAT1 (*(volatile unsigned *)0x50004014) /*UART 1 Rx error status*/ +#define rUFSTAT1 (*(volatile unsigned *)0x50004018) /*UART 1 FIFO status*/ +#define rUMSTAT1 (*(volatile unsigned *)0x5000401c) /*UART 1 Modem status*/ +#define rUBRDIV1 (*(volatile unsigned *)0x50004028) /*UART 1 Baud rate divisor*/ + +#define rULCON2 (*(volatile unsigned *)0x50008000) /*UART 2 Line control*/ +#define rUCON2 (*(volatile unsigned *)0x50008004) /*UART 2 Control*/ +#define rUFCON2 (*(volatile unsigned *)0x50008008) /*UART 2 FIFO control*/ +#define rUTRSTAT2 (*(volatile unsigned *)0x50008010) /*UART 2 Tx/Rx status*/ +#define rUERSTAT2 (*(volatile unsigned *)0x50008014) /*UART 2 Rx error status*/ +#define rUFSTAT2 (*(volatile unsigned *)0x50008018) /*UART 2 FIFO status*/ +#define rUBRDIV2 (*(volatile unsigned *)0x50008028) /*UART 2 Baud rate divisor*/ + +#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch) +#define RdURXH0() (*(volatile unsigned char *)0x50000024) +#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004020)=(unsigned char)(ch) +#define RdURXH1() (*(volatile unsigned char *)0x50004024) +#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008020)=(unsigned char)(ch) +#define RdURXH2() (*(volatile unsigned char *)0x50008024) + +extern void serial_init_115200_s3c64xx(const int uart, const int pclk_MHz); +extern void serial_putc_s3c64xx(const int uart, const char c); +extern int puts(const char *string); + +#endif diff --git a/qiboot/include/setup.h b/qiboot/include/setup.h new file mode 100644 index 0000000..89df4dc --- /dev/null +++ b/qiboot/include/setup.h @@ -0,0 +1,269 @@ +/* + * linux/include/asm/setup.h + * + * Copyright (C) 1997-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Structure passed to kernel to tell it about the + * hardware it's running on. See linux/Documentation/arm/Setup + * for more info. + * + * NOTE: + * This file contains two ways to pass information from the boot + * loader to the kernel. The old struct param_struct is deprecated, + * but it will be kept in the kernel for 5 years from now + * (2001). This will allow boot loaders to convert to the new struct + * tag way. + */ +#ifndef __ASMARM_SETUP_H +#define __ASMARM_SETUP_H + +/* + * Usage: + * - do not go blindly adding fields, add them at the end + * - when adding fields, don't rely on the address until + * a patch from me has been released + * - unused fields should be zero (for future expansion) + * - this structure is relatively short-lived - only + * guaranteed to contain useful data in setup_arch() + */ +#define COMMAND_LINE_SIZE 1024 + +/* This is the old deprecated way to pass parameters to the kernel */ +struct param_struct { + union { + struct { + unsigned long page_size; /* 0 */ + unsigned long nr_pages; /* 4 */ + unsigned long ramdisk_size; /* 8 */ + unsigned long flags; /* 12 */ +#define FLAG_READONLY 1 +#define FLAG_RDLOAD 4 +#define FLAG_RDPROMPT 8 + unsigned long rootdev; /* 16 */ + unsigned long video_num_cols; /* 20 */ + unsigned long video_num_rows; /* 24 */ + unsigned long video_x; /* 28 */ + unsigned long video_y; /* 32 */ + unsigned long memc_control_reg; /* 36 */ + unsigned char sounddefault; /* 40 */ + unsigned char adfsdrives; /* 41 */ + unsigned char bytes_per_char_h; /* 42 */ + unsigned char bytes_per_char_v; /* 43 */ + unsigned long pages_in_bank[4]; /* 44 */ + unsigned long pages_in_vram; /* 60 */ + unsigned long initrd_start; /* 64 */ + unsigned long initrd_size; /* 68 */ + unsigned long rd_start; /* 72 */ + unsigned long system_rev; /* 76 */ + unsigned long system_serial_low; /* 80 */ + unsigned long system_serial_high; /* 84 */ + unsigned long mem_fclk_21285; /* 88 */ + } s; + char unused[256]; + } u1; + union { + char paths[8][128]; + struct { + unsigned long magic; + char n[1024 - sizeof(unsigned long)]; + } s; + } u2; + char commandline[COMMAND_LINE_SIZE]; +}; + + +/* + * The new way of passing information: a list of tagged entries + */ + +/* The list ends with an ATAG_NONE node. */ +#define ATAG_NONE 0x00000000 + +struct tag_header { + u32 size; + u32 tag; +}; + +/* The list must start with an ATAG_CORE node */ +#define ATAG_CORE 0x54410001 + +struct tag_core { + u32 flags; /* bit 0 = read-only */ + u32 pagesize; + u32 rootdev; +}; + +/* it is allowed to have multiple ATAG_MEM nodes */ +#define ATAG_MEM 0x54410002 + +struct tag_mem32 { + u32 size; + u32 start; /* physical start address */ +}; + +/* VGA text type displays */ +#define ATAG_VIDEOTEXT 0x54410003 + +struct tag_videotext { + u8 x; + u8 y; + u16 video_page; + u8 video_mode; + u8 video_cols; + u16 video_ega_bx; + u8 video_lines; + u8 video_isvga; + u16 video_points; +}; + +/* describes how the ramdisk will be used in kernel */ +#define ATAG_RAMDISK 0x54410004 + +struct tag_ramdisk { + u32 flags; /* bit 0 = load, bit 1 = prompt */ + u32 size; /* decompressed ramdisk size in _kilo_ bytes */ + u32 start; /* starting block of floppy-based RAM disk image */ +}; + +/* describes where the compressed ramdisk image lives (virtual address) */ +/* + * this one accidentally used virtual addresses - as such, + * its depreciated. + */ +#define ATAG_INITRD 0x54410005 + +/* describes where the compressed ramdisk image lives (physical address) */ +#define ATAG_INITRD2 0x54420005 + +struct tag_initrd { + u32 start; /* physical start address */ + u32 size; /* size of compressed ramdisk image in bytes */ +}; + +/* board serial number. "64 bits should be enough for everybody" */ +#define ATAG_SERIAL 0x54410006 + +struct tag_serialnr { + u32 low; + u32 high; +}; + +/* board revision */ +#define ATAG_REVISION 0x54410007 + +struct tag_revision { + u32 rev; +}; + +/* initial values for vesafb-type framebuffers. see struct screen_info + * in include/linux/tty.h + */ +#define ATAG_VIDEOLFB 0x54410008 + +struct tag_videolfb { + u16 lfb_width; + u16 lfb_height; + u16 lfb_depth; + u16 lfb_linelength; + u32 lfb_base; + u32 lfb_size; + u8 red_size; + u8 red_pos; + u8 green_size; + u8 green_pos; + u8 blue_size; + u8 blue_pos; + u8 rsvd_size; + u8 rsvd_pos; +}; + +/* command line: \0 terminated string */ +#define ATAG_CMDLINE 0x54410009 + +struct tag_cmdline { + char cmdline[1]; /* this is the minimum size */ +}; + +/* acorn RiscPC specific information */ +#define ATAG_ACORN 0x41000101 + +struct tag_acorn { + u32 memc_control_reg; + u32 vram_pages; + u8 sounddefault; + u8 adfsdrives; +}; + +/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */ +#define ATAG_MEMCLK 0x41000402 + +struct tag_memclk { + u32 fmemclk; +}; + +struct tag { + struct tag_header hdr; + union { + struct tag_core core; + struct tag_mem32 mem; + struct tag_videotext videotext; + struct tag_ramdisk ramdisk; + struct tag_initrd initrd; + struct tag_serialnr serialnr; + struct tag_revision revision; + struct tag_videolfb videolfb; + struct tag_cmdline cmdline; + + /* + * Acorn specific + */ + struct tag_acorn acorn; + + /* + * DC21285 specific + */ + struct tag_memclk memclk; + } u; +}; + +struct tagtable { + u32 tag; + int (*parse)(const struct tag *); +}; + +#define __tag __attribute__((unused, __section__(".taglist"))) +#define __tagtable(tag, fn) \ +static struct tagtable __tagtable_##fn __tag = { tag, fn } + +#define tag_member_present(tag,member) \ + ((unsigned long)(&((struct tag *)0L)->member + 1) \ + <= (tag)->hdr.size * 4) + +#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) +#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) + +#define for_each_tag(t,base) \ + for (t = base; t->hdr.size; t = tag_next(t)) + +/* + * Memory map description + */ +#define NR_BANKS 8 + +struct meminfo { + int nr_banks; + unsigned long end; + struct { + unsigned long start; + unsigned long size; + int node; + } bank[NR_BANKS]; +}; + +extern struct meminfo meminfo; + +#endif diff --git a/qiboot/include/smdk6410.h b/qiboot/include/smdk6410.h new file mode 100644 index 0000000..a438170 --- /dev/null +++ b/qiboot/include/smdk6410.h @@ -0,0 +1,6 @@ +#ifndef __ASM_MODE__ +#include +extern const struct board_api board_api_smdk6410; +#endif + +#define TEXT_BASE_SMDK6410 0x53000000 diff --git a/qiboot/openocd-openmoko-debug-6410.cfg b/qiboot/openocd-openmoko-debug-6410.cfg new file mode 100644 index 0000000..a8ac051 --- /dev/null +++ b/qiboot/openocd-openmoko-debug-6410.cfg @@ -0,0 +1,16 @@ +# ARM1176 / s3c6410 OpenOCD config suitable for Openmoko Debug board usage + +telnet_port 4444 +gdb_port 3333 +interface ft2232 +jtag_speed 18 +ft2232_layout oocdlink + +#Info: 446 309386 jtag.c:1410 jtag_examine_chain(): JTAG device found: 0x2b900f0f (Manufacturer: 0x787, Part: 0xb900, Version: 0x2) +#Info: 447 309386 jtag.c:1410 jtag_examine_chain(): JTAG device found: 0x07b76f0f (Manufacturer: 0x787, Part: 0x7b76, Version: 0x0) +jtag_device 4 0x1 0xF 0xE +jtag_device 5 0x1 0x1F 0x1E + +reset_config trst_and_srst +target create target0 arm11 -endian little -chain-position 1 -variant arm11 + diff --git a/qiboot/src/blink_led.c b/qiboot/src/blink_led.c new file mode 100644 index 0000000..6bac9e7 --- /dev/null +++ b/qiboot/src/blink_led.c @@ -0,0 +1,90 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "blink_led.h" + +int delay(int time) +{ + int i=0; + for(i=0;i + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __BLINK_LED_H +#define __BLINK_LED_H + +#define GPBCON (*(volatile unsigned *)0x56000010) +#define GPBDAT (*(volatile unsigned *)0x56000014) +#define GPBDW (*(volatile unsigned *)0x56000018) +#define ORANGE_OFF() (GPBDAT &= ~(0x1)) +#define BLUE_OFF() (GPBDAT &= ~(0x2)) +#define ORANGE_ON() (GPBDAT |= (0x1)) +#define BLUE_ON() (GPBDAT |= (0x2)) + +int orange_on(int times); +int blue_on(int times); +int blink_led(void); +int delay(int time); + +#endif /* __BLINK_LED_H */ diff --git a/qiboot/src/common.h b/qiboot/src/common.h new file mode 100644 index 0000000..055dec2 --- /dev/null +++ b/qiboot/src/common.h @@ -0,0 +1,681 @@ +/* + * (C) Copyright 2000-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __COMMON_H_ +#define __COMMON_H_ 1 + +#undef _LINUX_CONFIG_H +#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */ + +typedef unsigned char uchar; +typedef volatile unsigned long vu_long; +typedef volatile unsigned short vu_short; +typedef volatile unsigned char vu_char; + +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_PCI) && (defined(CONFIG_4xx) && !defined(CONFIG_AP1000)) +#include +#endif +#if defined(CONFIG_8xx) +#include +#if defined(CONFIG_MPC852) || defined(CONFIG_MPC852T) || \ + defined(CONFIG_MPC859) || defined(CONFIG_MPC859T) || \ + defined(CONFIG_MPC859DSL) || \ + defined(CONFIG_MPC866) || defined(CONFIG_MPC866T) || \ + defined(CONFIG_MPC866P) +# define CONFIG_MPC866_FAMILY 1 +#elif defined(CONFIG_MPC870) \ + || defined(CONFIG_MPC875) \ + || defined(CONFIG_MPC880) \ + || defined(CONFIG_MPC885) +# define CONFIG_MPC885_FAMILY 1 +#endif +#if defined(CONFIG_MPC860) \ + || defined(CONFIG_MPC860T) \ + || defined(CONFIG_MPC866_FAMILY) \ + || defined(CONFIG_MPC885_FAMILY) +# define CONFIG_MPC86x 1 +#endif +#elif defined(CONFIG_5xx) +#include +#elif defined(CONFIG_MPC5xxx) +#include +#elif defined(CONFIG_MPC512X) +#include +#include +#elif defined(CONFIG_MPC8220) +#include +#elif defined(CONFIG_8260) +#if defined(CONFIG_MPC8247) \ + || defined(CONFIG_MPC8248) \ + || defined(CONFIG_MPC8271) \ + || defined(CONFIG_MPC8272) +#define CONFIG_MPC8272_FAMILY 1 +#endif +#if defined(CONFIG_MPC8272_FAMILY) +#define CONFIG_MPC8260 1 +#endif +#include +#endif +#ifdef CONFIG_MPC86xx +#include +#include +#endif +#ifdef CONFIG_MPC85xx +#include +#include +#endif +#ifdef CONFIG_MPC83XX +#include +#include +#endif +#ifdef CONFIG_4xx +#include +#endif +#ifdef CONFIG_HYMOD +#include +#endif +#ifdef CONFIG_ARM +#define asmlinkage /* nothing */ +#endif +#ifdef CONFIG_BLACKFIN +#include +#endif + +#include +#include +#include + +#ifdef DEBUG +#define debug(fmt,args...) printf (fmt ,##args) +#define debugX(level,fmt,args...) if (DEBUG>=level) printf(fmt,##args); +#else +#define debug(fmt,args...) +#define debugX(level,fmt,args...) +#endif /* DEBUG */ + +#define BUG() do { \ + printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \ + panic("BUG!"); \ +} while (0) +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + +typedef void (interrupt_handler_t)(void *); + +#include /* boot information for Linux kernel */ +#include /* global data used for startup functions */ + +/* + * enable common handling for all TQM8xxL/M boards: + * - CONFIG_TQM8xxM will be defined for all TQM8xxM boards + * - CONFIG_TQM8xxL will be defined for all TQM8xxL _and_ TQM8xxM boards + * and for the TQM885D board + */ +#if defined(CONFIG_TQM823M) || defined(CONFIG_TQM850M) || \ + defined(CONFIG_TQM855M) || defined(CONFIG_TQM860M) || \ + defined(CONFIG_TQM862M) || defined(CONFIG_TQM866M) +# ifndef CONFIG_TQM8xxM +# define CONFIG_TQM8xxM +# endif +#endif +#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L) || \ + defined(CONFIG_TQM855L) || defined(CONFIG_TQM860L) || \ + defined(CONFIG_TQM862L) || defined(CONFIG_TQM8xxM) || \ + defined(CONFIG_TQM885D) +# ifndef CONFIG_TQM8xxL +# define CONFIG_TQM8xxL +# endif +#endif + +#ifndef CONFIG_SERIAL_MULTI + +#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2) \ + || defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) \ + || defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4) + +#define CONFIG_SERIAL_MULTI 1 + +#endif + +#endif /* CONFIG_SERIAL_MULTI */ + +/* + * General Purpose Utilities + */ +#define min(X, Y) \ + ({ typeof (X) __x = (X), __y = (Y); \ + (__x < __y) ? __x : __y; }) + +#define max(X, Y) \ + ({ typeof (X) __x = (X), __y = (Y); \ + (__x > __y) ? __x : __y; }) + + +/* + * Function Prototypes + */ + +#ifdef CONFIG_SERIAL_SOFTWARE_FIFO +void serial_buffered_init (void); +void serial_buffered_putc (const char); +void serial_buffered_puts (const char *); +int serial_buffered_getc (void); +int serial_buffered_tstc (void); +#endif /* CONFIG_SERIAL_SOFTWARE_FIFO */ + +void hang (void) __attribute__ ((noreturn)); + +/* */ +long int initdram (int); +int display_options (void); +void print_size (ulong, const char *); +int print_buffer (ulong addr, void* data, uint width, uint count, uint linelen); + +/* common/main.c */ +void main_loop (void); +int run_command (const char *cmd, int flag); +int readline (const char *const prompt); +int readline_into_buffer (const char *const prompt, char * buffer); +int parse_line (char *, char *[]); +void init_cmd_timeout(void); +void reset_cmd_timeout(void); + +/* lib_$(ARCH)/board.c */ +void board_init_f (ulong) __attribute__ ((noreturn)); +void board_init_r (gd_t *, ulong) __attribute__ ((noreturn)); +int checkboard (void); +int checkflash (void); +int checkdram (void); +char * strmhz(char *buf, long hz); +int last_stage_init(void); +extern ulong monitor_flash_len; +#ifdef CFG_ID_EEPROM +int mac_read_from_eeprom(void); +#endif + +/* common/flash.c */ +void flash_perror (int); + +/* common/cmd_autoscript.c */ +int autoscript (ulong addr, const char *fit_uname); + +extern ulong load_addr; /* Default Load Address */ + +/* common/cmd_nvedit.c */ +int env_init (void); +void env_relocate (void); +int envmatch (uchar *, int); +char *getenv (char *); +int getenv_r (char *name, char *buf, unsigned len); +int saveenv (void); +#ifdef CONFIG_PPC /* ARM version to be fixed! */ +void inline setenv (char *, char *); +#else +void setenv (char *, char *); +#ifdef CONFIG_HAS_UID +void forceenv (char *, char *); +#endif +#endif /* CONFIG_PPC */ +#ifdef CONFIG_ARM +# include +# include +# include /* ARM version to be fixed! */ +#endif /* CONFIG_ARM */ +#ifdef CONFIG_I386 /* x86 version to be fixed! */ +# include +#endif /* CONFIG_I386 */ + +#ifdef CONFIG_AUTO_COMPLETE +int env_complete(char *var, int maxv, char *cmdv[], int maxsz, char *buf); +#endif + +void pci_init (void); +void pci_init_board(void); +void pciinfo (int, int); + +#if defined(CONFIG_PCI) && (defined(CONFIG_4xx) && !defined(CONFIG_AP1000)) + int pci_pre_init (struct pci_controller * ); +#endif + +#if defined(CONFIG_PCI) && (defined(CONFIG_440) || defined(CONFIG_405EX)) +# if defined(CFG_PCI_TARGET_INIT) + void pci_target_init (struct pci_controller *); +# endif +# if defined(CFG_PCI_MASTER_INIT) + void pci_master_init (struct pci_controller *); +# endif + int is_pci_host (struct pci_controller *); +#if defined(CONFIG_440SPE) || \ + defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ + defined(CONFIG_405EX) + void pcie_setup_hoses(int busno); +#endif +#endif + +int misc_init_f (void); +int misc_init_r (void); + +/* common/exports.c */ +void jumptable_init(void); + +/* api/api.c */ +void api_init (void); + +/* common/memsize.c */ +long get_ram_size (volatile long *, long); + +/* $(BOARD)/$(BOARD).c */ +void reset_phy (void); +void fdc_hw_init (void); + +/* $(BOARD)/eeprom.c */ +void eeprom_init (void); +#ifndef CONFIG_SPI +int eeprom_probe (unsigned dev_addr, unsigned offset); +#endif +int eeprom_read (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt); +int eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt); +#ifdef CONFIG_LWMON +extern uchar pic_read (uchar reg); +extern void pic_write (uchar reg, uchar val); +#endif + +/* + * Set this up regardless of board + * type, to prevent errors. + */ +#if defined(CONFIG_SPI) || !defined(CFG_I2C_EEPROM_ADDR) +# define CFG_DEF_EEPROM_ADDR 0 +#else +# define CFG_DEF_EEPROM_ADDR CFG_I2C_EEPROM_ADDR +#endif /* CONFIG_SPI || !defined(CFG_I2C_EEPROM_ADDR) */ + +#if defined(CONFIG_SPI) +extern void spi_init_f (void); +extern void spi_init_r (void); +extern ssize_t spi_read (uchar *, int, uchar *, int); +extern ssize_t spi_write (uchar *, int, uchar *, int); +#endif + +#ifdef CONFIG_RPXCLASSIC +void rpxclassic_init (void); +#endif + +void rpxlite_init (void); + +#ifdef CONFIG_MBX +/* $(BOARD)/mbx8xx.c */ +void mbx_init (void); +void board_serial_init (void); +void board_ether_init (void); +#endif + +#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_MBX) || \ + defined(CONFIG_IAD210) || defined(CONFIG_XPEDITE1K) || \ + defined(CONFIG_METROBOX) || defined(CONFIG_KAREF) || \ + defined(CONFIG_V38B) +void board_get_enetaddr (uchar *addr); +#endif + +#ifdef CONFIG_HERMES +/* $(BOARD)/hermes.c */ +void hermes_start_lxt980 (int speed); +#endif + +#ifdef CONFIG_EVB64260 +void evb64260_init(void); +void debug_led(int, int); +void display_mem_map(void); +void perform_soft_reset(void); +#endif + +void load_sernum_ethaddr (void); + +/* $(BOARD)/$(BOARD).c */ +int board_early_init_f (void); +int board_late_init (void); +int board_postclk_init (void); /* after clocks/timebase, before env/serial */ +int board_early_init_r (void); +void board_poweroff (void); + +#if defined(CFG_DRAM_TEST) +int testdram(void); +#endif /* CFG_DRAM_TEST */ + +/* $(CPU)/start.S */ +#if defined(CONFIG_5xx) || \ + defined(CONFIG_8xx) +uint get_immr (uint); +#endif +uint get_pir (void); +#if defined(CONFIG_MPC5xxx) +uint get_svr (void); +#endif +uint get_pvr (void); +uint get_svr (void); +uint rd_ic_cst (void); +void wr_ic_cst (uint); +void wr_ic_adr (uint); +uint rd_dc_cst (void); +void wr_dc_cst (uint); +void wr_dc_adr (uint); +int icache_status (void); +void icache_enable (void); +void icache_disable(void); +int dcache_status (void); +void dcache_enable (void); +void dcache_disable(void); +void relocate_code (ulong, gd_t *, ulong) __attribute__ ((noreturn)); +ulong get_endaddr (void); +void trap_init (ulong); +#if defined (CONFIG_4xx) || \ + defined (CONFIG_MPC5xxx) || \ + defined (CONFIG_74xx_7xx) || \ + defined (CONFIG_74x) || \ + defined (CONFIG_75x) || \ + defined (CONFIG_74xx) || \ + defined (CONFIG_MPC8220) || \ + defined (CONFIG_MPC85xx) || \ + defined (CONFIG_MPC86xx) || \ + defined (CONFIG_MPC83XX) +unsigned char in8(unsigned int); +void out8(unsigned int, unsigned char); +unsigned short in16(unsigned int); +unsigned short in16r(unsigned int); +void out16(unsigned int, unsigned short value); +void out16r(unsigned int, unsigned short value); +unsigned long in32(unsigned int); +unsigned long in32r(unsigned int); +void out32(unsigned int, unsigned long value); +void out32r(unsigned int, unsigned long value); +void ppcDcbf(unsigned long value); +void ppcDcbi(unsigned long value); +void ppcSync(void); +void ppcDcbz(unsigned long value); +#endif +#if defined (CONFIG_MICROBLAZE) +unsigned short in16(unsigned int); +void out16(unsigned int, unsigned short value); +#endif + +#if defined (CONFIG_MPC83XX) +void ppcDWload(unsigned int *addr, unsigned int *ret); +void ppcDWstore(unsigned int *addr, unsigned int *value); +#endif + +/* $(CPU)/cpu.c */ +int checkcpu (void); +int checkicache (void); +int checkdcache (void); +void upmconfig (unsigned int, unsigned int *, unsigned int); +ulong get_tbclk (void); +void reset_cpu (ulong addr); +#if defined (CONFIG_OF_LIBFDT) && defined (CONFIG_OF_BOARD_SETUP) +void ft_cpu_setup(void *blob, bd_t *bd); +#ifdef CONFIG_PCI +void ft_pci_setup(void *blob, bd_t *bd); +#endif +#endif + + +/* $(CPU)/serial.c */ +int serial_init (void); +void serial_addr (unsigned int); +void serial_setbrg (void); +void serial_putc (const char); +void serial_putc_raw(const char); +void serial_puts (const char *); +int serial_getc (void); +int serial_tstc (void); + +void _serial_setbrg (const int); +void _serial_putc (const char, const int); +void _serial_putc_raw(const char, const int); +void _serial_puts (const char *, const int); +int _serial_getc (const int); +int _serial_tstc (const int); + +/* $(CPU)/speed.c */ +int get_clocks (void); +int get_clocks_866 (void); +int sdram_adjust_866 (void); +int adjust_sdram_tbs_8xx (void); +#if defined(CONFIG_8260) +int prt_8260_clks (void); +#elif defined(CONFIG_MPC5xxx) +int prt_mpc5xxx_clks (void); +#endif +#if defined(CONFIG_MPC512X) +int prt_mpc512xxx_clks (void); +#endif +#if defined(CONFIG_MPC8220) +int prt_mpc8220_clks (void); +#endif +#ifdef CONFIG_4xx +ulong get_OPB_freq (void); +ulong get_PCI_freq (void); +#endif +#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || \ + defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || \ + defined(CONFIG_LH7A40X) +void s3c2410_irq(void); +#define ARM920_IRQ_CALLBACK s3c2410_irq +ulong get_FCLK (void); +ulong get_HCLK (void); +ulong get_PCLK (void); +ulong get_UCLK (void); +#endif +#if defined(CONFIG_LH7A40X) +ulong get_PLLCLK (void); +#endif +#if defined CONFIG_INCA_IP +uint incaip_get_cpuclk (void); +#endif +#if defined(CONFIG_IMX) +ulong get_systemPLLCLK(void); +ulong get_FCLK(void); +ulong get_HCLK(void); +ulong get_BCLK(void); +ulong get_PERCLK1(void); +ulong get_PERCLK2(void); +ulong get_PERCLK3(void); +#endif +ulong get_bus_freq (ulong); + +#if defined(CONFIG_MPC85xx) +typedef MPC85xx_SYS_INFO sys_info_t; +void get_sys_info ( sys_info_t * ); +ulong get_ddr_freq (ulong); +#endif +#if defined(CONFIG_MPC86xx) +typedef MPC86xx_SYS_INFO sys_info_t; +void get_sys_info ( sys_info_t * ); +#endif + +#if defined(CONFIG_4xx) || defined(CONFIG_IOP480) +# if defined(CONFIG_440) +# if defined(CONFIG_440SPE) + unsigned long determine_sysper(void); + unsigned long determine_pci_clock_per(void); +# endif +# endif +typedef PPC4xx_SYS_INFO sys_info_t; +int ppc440spe_revB(void); +void get_sys_info ( sys_info_t * ); +#endif + +/* $(CPU)/cpu_init.c */ +#if defined(CONFIG_8xx) || defined(CONFIG_8260) +void cpu_init_f (volatile immap_t *immr); +#endif +#if defined(CONFIG_4xx) || defined(CONFIG_MPC85xx) || defined(CONFIG_MCF52x2) ||defined(CONFIG_MPC86xx) +void cpu_init_f (void); +#endif + +int cpu_init_r (void); +#if defined(CONFIG_8260) +int prt_8260_rsr (void); +#elif defined(CONFIG_MPC83XX) +int prt_83xx_rsr (void); +#endif + +/* $(CPU)/interrupts.c */ +int interrupt_init (void); +void timer_interrupt (struct pt_regs *); +void external_interrupt (struct pt_regs *); +void irq_install_handler(int, interrupt_handler_t *, void *); +void irq_free_handler (int); +void reset_timer (void); +ulong get_timer (ulong base); +void set_timer (ulong t); +void enable_interrupts (void); +int disable_interrupts (void); + +/* $(CPU)/.../commproc.c */ +int dpram_init (void); +uint dpram_base(void); +uint dpram_base_align(uint align); +uint dpram_alloc(uint size); +uint dpram_alloc_align(uint size,uint align); +void post_word_store (ulong); +ulong post_word_load (void); +void bootcount_store (ulong); +ulong bootcount_load (void); +#define BOOTCOUNT_MAGIC 0xB001C041 + +/* $(CPU)/.../ */ +void mii_init (void); + +/* $(CPU)/.../lcd.c */ +ulong lcd_setmem (ulong); + +/* $(CPU)/.../vfd.c */ +ulong vfd_setmem (ulong); + +/* $(CPU)/.../video.c */ +ulong video_setmem (ulong); + +/* lib_$(ARCH)/cache.c */ +void flush_cache (unsigned long, unsigned long); + + +/* lib_$(ARCH)/ticks.S */ +unsigned long long get_ticks(void); +void wait_ticks (unsigned long); + +/* lib_$(ARCH)/time.c */ +void udelay (unsigned long); +ulong usec2ticks (unsigned long usec); +ulong ticks2usec (unsigned long ticks); +int init_timebase (void); + +/* lib_generic/vsprintf.c */ +ulong simple_strtoul(const char *cp,char **endp,unsigned int base); +#ifdef CFG_64BIT_VSPRINTF +unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base); +#endif +long simple_strtol(const char *cp,char **endp,unsigned int base); +void panic(const char *fmt, ...); +int sprintf(char * buf, const char *fmt, ...); +int vsprintf(char *buf, const char *fmt, va_list args); + +/* lib_generic/crc32.c */ +ulong crc32 (ulong, const unsigned char *, uint); +ulong crc32_no_comp (ulong, const unsigned char *, uint); + +/* common/console.c */ +int console_init_f(void); /* Before relocation; uses the serial stuff */ +int console_init_r(void); /* After relocation; uses the console stuff */ +int console_assign (int file, char *devname); /* Assign the console */ +int ctrlc (void); +int had_ctrlc (void); /* have we had a Control-C since last clear? */ +void clear_ctrlc (void); /* clear the Control-C condition */ +int disable_ctrlc (int); /* 1 to disable, 0 to enable Control-C detect */ + +/* + * STDIO based functions (can always be used) + */ + +/* serial stuff */ +void serial_printf (const char *fmt, ...); + +/* stdin */ +int getc(void); +int tstc(void); + +/* stdout */ +void putc(const char c); +void puts(const char *s); +void printf(const char *fmt, ...); +void vprintf(const char *fmt, va_list args); + +/* stderr */ +#define eputc(c) fputc(stderr, c) +#define eputs(s) fputs(stderr, s) +#define eprintf(fmt,args...) fprintf(stderr,fmt ,##args) + +/* + * FILE based functions (can only be used AFTER relocation!) + */ + +#define stdin 0 +#define stdout 1 +#define stderr 2 +#define MAX_FILES 3 + +void fprintf(int file, const char *fmt, ...); +void fputs(int file, const char *s); +void fputc(int file, const char c); +int ftstc(int file); +int fgetc(int file); + +int pcmcia_init (void); + +#ifdef CONFIG_STATUS_LED +# include +#endif +/* + * Board-specific Platform code can reimplement show_boot_progress () if needed + */ +void inline show_boot_progress (int val); + +#ifdef CONFIG_INIT_CRITICAL +#error CONFIG_INIT_CRITICAL is deprecated! +#error Read section CONFIG_SKIP_LOWLEVEL_INIT in README. +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* Multicore arch functions */ +#ifdef CONFIG_MP +int cpu_status(int nr); +int cpu_reset(int nr); +int cpu_release(int nr, int argc, char *argv[]); +#endif + +#endif /* __COMMON_H_ */ diff --git a/qiboot/src/cpu/s3c2410/gta01.c b/qiboot/src/cpu/s3c2410/gta01.c new file mode 100644 index 0000000..4686fa2 --- /dev/null +++ b/qiboot/src/cpu/s3c2410/gta01.c @@ -0,0 +1,312 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define GTA01_DEBUG_UART 0 +#define PCF50606_I2C_ADS 0x08 + + +struct pcf50606_init { + u8 index; + u8 value; +}; + +/* initial register set for PCF50606 in Neo1973 devices */ +const struct pcf50606_init pcf50606_initial_regs[] = { + { PCF50606_REG_OOCS, 0x00 }, + { PCF50606_REG_INT1M, 0x00 }, + { PCF50606_REG_INT2M, 0x00 }, + { PCF50606_REG_INT3M, PCF50606_INT3_TSCPRES }, + { PCF50606_REG_OOCC1, PCF50606_OOCC1_RTCWAK | PCF50606_OOCC1_CHGWAK | + PCF50606_OOCC1_EXTONWAK_HIGH }, + { PCF50606_REG_OOCC2, PCF50606_OOCC2_ONKEYDB_14ms | PCF50606_OOCC2_EXTONDB_14ms }, + { PCF50606_REG_PSSC, 0x00 }, + { PCF50606_REG_PWROKM, 0x00 }, + { PCF50606_REG_DCDC1, 0x18 }, /* GL_1V5: off */ + { PCF50606_REG_DCDC2, 0x00 }, + { PCF50606_REG_DCDC3, 0x00 }, + { PCF50606_REG_DCDC4, 0x30 }, /* 1.25A */ + + { PCF50606_REG_DCDEC1, 0xe8 }, /* IO_3V3: on */ + { PCF50606_REG_DCDEC2, 0x00 }, + + { PCF50606_REG_DCUDC1, 0xc4 }, /* CORE_1V8: 2.1V if PWREN2 = HIGH */ + { PCF50606_REG_DCUDC2, 0x30 }, /* 1.25A current limit */ + + { PCF50606_REG_IOREGC, 0xf8 }, /* CODEC_3V3: on */ + { PCF50606_REG_D1REGC1, 0x16 }, /* BT_3V15: off */ + + { PCF50606_REG_D2REGC1, 0x10 }, /* GL_2V5: off */ + + { PCF50606_REG_D3REGC1, 0xec }, /* STBY_1V8: 2.1V */ + + { PCF50606_REG_LPREGC1, 0xf8 }, /* LCM_3V3: on */ + { PCF50606_REG_LPREGC2, 0x00 }, + + { PCF50606_REG_MBCC1, 0x01 }, /* CHGAPE */ + { PCF50606_REG_MBCC2, 0x00 }, /* unlimited charging */ + { PCF50606_REG_MBCC3, 0x1a }, /* 0.2*Ifast, 4.20V */ + { PCF50606_REG_BBCC, 0x1f }, /* 400uA */ + { PCF50606_REG_ADCC1, 0x00 }, + { PCF50606_REG_ADCC2, 0x00 }, + { PCF50606_REG_ACDC1, 0x86 }, /* ACD thresh 1.6V, enabled */ + { PCF50606_REG_BVMC, PCF50606_BVMC_THRSHLD_3V3 }, + { PCF50606_REG_PWMC1, 0x00 }, + { PCF50606_REG_LEDC1, 0x00 }, + { PCF50606_REG_LEDC2, 0x00 }, + { PCF50606_REG_GPOC1, 0x00 }, + { PCF50606_REG_GPOC2, 0x00 }, + { PCF50606_REG_GPOC3, 0x00 }, + { PCF50606_REG_GPOC4, 0x00 }, + { PCF50606_REG_GPOC5, 0x00 }, +}; + + +static const struct board_variant board_variants[] = { + [0] = { + .name = "Bv4", + .machine_revision = 0x240, + } +}; + + +void port_init_gta01(void) +{ + int n; + unsigned int * MPLLCON = (unsigned int *)0x4c000004; + + rGPACON = 0x005E0FFF; + rGPADAT = 0x00010000; /* nNAND_WP set high */ + + rGPBCON = 0x00045455; + rGPBUP = 0x000007FF; + rGPBDAT = 0x00000004; /* SD-card pwr off */ + + rGPCCON = 0xAAAA12A9; + rGPCUP = 0x0000FFFF; + + rGPDCON = 0xAAAAAAAA; + rGPDUP = 0x0000FFFF; + + rGPECON = 0xAAAAAAAA; + rGPEUP = 0x0000FFFF; + + rGPFCON = 0x0000aa99; + rGPFUP = 0x000000FF; + rGPFDAT = 0x00000004; + + rGPGCON = 0xFF14F0F8; + rGPGUP = 0x0000AFEF; + + rGPHCON = 0x0000FAAA; + rGPHUP = 0x000007FF; + + + /* Load PMU with safe values */ + + for (n = 0; n < ARRAY_SIZE(pcf50606_initial_regs); n++) + i2c_write_sync(&bb_s3c24xx, PCF50606_I2C_ADS, + pcf50606_initial_regs[n].index, + pcf50606_initial_regs[n].value); + + /* Give a short vibrate notification */ + rGPBDAT |= (1 << 3); + udelay(1000000); + rGPBDAT &= ~(1 << 3); + + + /* change CPU to 266MHz 1:2:4 */ + *MPLLCON = ((0x7d << 12) + (0x1 << 4) + 0x1); + /* Delay after update of PLL: Page 7-19, seven nops */ + asm __volatile__ ( + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + ); + + + /* set debug UART working at 115kbps */ + serial_init_115200_s3c24xx(GTA01_DEBUG_UART, 66 /* 66.5MHz PCLK */); +} + + +int sd_card_init_gta01(void) +{ + int retval = -1; + + /* Check if AUX is held. Then skip SD-card kernels! + * FIXME: This would be nicer to do with an API. + */ + if (!(rGPFDAT & (1 << 6))) { + return -1; + } + + /* if SD card inserted, power it up and initialize*/ + if (!(rGPFDAT & (1 << 5))) + { + rGPBDAT &= ~(1 << 2); + retval = s3c24xx_mmc_init(1); + } + return retval; +} + +int sd_card_block_read_gta01(unsigned char * buf, unsigned long start512, + int blocks512) +{ + return s3c24xx_mmc_bread(0, start512, blocks512, buf); +} + +int is_this_board_gta01(void) +{ + /* FIXME: How to check for GTA01 ? */ + return 1; +} + +const struct board_variant const * get_board_variant_gta01(void) +{ + return &board_variants[0]; +} + +static __attribute__ (( section (".steppingstone") )) void putc_gta01(char c) +{ + serial_putc_s3c24xx(GTA01_DEBUG_UART, c); +} + +static void close_gta01(void) +{ + /* set I2C GPIO back to peripheral unit */ + (bb_s3c24xx.close)(); +} + +/* Here we will care only about AUX button as polling for PWR button + * through i2c slows down the boot */ + +static u8 get_ui_keys_gta01(void) +{ + u8 keys; + u8 ret = 0; + static u8 old_keys = 0; /* previous state for debounce */ + static u8 older_keys = 0; /* previous debounced output for edge detect */ + + /* GPF6 is AUX on GTA01, map to UI_ACTION_SKIPKERNEL, down = 0 */ + keys = ! (rGPFDAT & (1 << 6)); + + /* edge action */ + if ((old_keys & 1) && !(older_keys & 1)) + ret |= UI_ACTION_SKIPKERNEL; + + older_keys = old_keys; + old_keys = keys; + + return ret; +} + +static u8 get_ui_debug_gta01(void) +{ + /* PWR button state can be seen in OOCS b0, down = 0, map to UI_ACTION_ADD_DEBUG */ + return !(i2c_read_sync(&bb_s3c24xx, PCF50606_I2C_ADS, PCF50606_REG_OOCS) & 1); +} + +/* + * API for bootloader on this machine + */ + +const struct board_api board_api_gta01 = { + .name = "Neo1973 GTA01", + .linux_machine_id = 1182, + .linux_mem_start = 0x30000000, + .linux_mem_size = (128 * 1024 * 1024), + .linux_tag_placement = 0x30000000 + 0x100, + .get_board_variant = get_board_variant_gta01, + .is_this_board = is_this_board_gta01, + .port_init = port_init_gta01, + .putc = putc_gta01, + .close = close_gta01, + .get_ui_keys = get_ui_keys_gta01, + .get_ui_debug = get_ui_debug_gta01, + + .commandline_board = "mtdparts=" + "neo1973-nand:" + "0x00040000(qi)," + "0x00004000(u-boot_env)," + "0x00200000(kernel)," + "0x000a0000(splash)," + "0x03d1c000(rootfs) " + "loglevel=4 " + "console=tty0 " + "console=ttySAC0,115200 " + "init=/sbin/init " + "ro ", + .commandline_board_debug = " loglevel=8 ", + .noboot = "boot/noboot-GTA01", + .append = "boot/append-GTA01", + /* these are the ways we could boot GTA01 in order to try */ + .kernel_source = { + [0] = { + .name = "SD Card EXT2 Kernel p1", + .block_init = sd_card_init_gta01, + .block_read = sd_card_block_read_gta01, + .partition_index = 1, + .filesystem = FS_EXT2, + .filepath = "boot/uImage-GTA01.bin", + .commandline_append = "root=/dev/mmcblk0p1 rootdelay=1 ", + }, + [1] = { + .name = "SD Card EXT2 Kernel p2", + .block_init = sd_card_init_gta01, + .block_read = sd_card_block_read_gta01, + .partition_index = 2, + .filesystem = FS_EXT2, + .filepath = "boot/uImage-GTA01.bin", + .commandline_append = "root=/dev/mmcblk0p2 rootdelay=1 ", + }, + [2] = { + .name = "SD Card EXT2 Kernel p3", + .block_init = sd_card_init_gta01, + .block_read = sd_card_block_read_gta01, + .partition_index = 3, + .filesystem = FS_EXT2, + .filepath = "boot/uImage-GTA01.bin", + .commandline_append = "root=/dev/mmcblk0p3 rootdelay=1 ", + }, + [3] = { + .name = "NAND Kernel", + .block_read = nand_read_ll, + .offset_blocks512_if_no_partition = 0x44000 / 512, + .filesystem = FS_RAW, + .commandline_append = "rootfstype=jffs2 " + "root=/dev/mtdblock4 ", + }, + }, +}; diff --git a/qiboot/src/cpu/s3c2410/i2c-bitbang-s3c24xx.c b/qiboot/src/cpu/s3c2410/i2c-bitbang-s3c24xx.c new file mode 100644 index 0000000..c2d46ed --- /dev/null +++ b/qiboot/src/cpu/s3c2410/i2c-bitbang-s3c24xx.c @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * s3c24xx-specific i2c shared by, eg, GTA02 and GTA03 + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include + +static char i2c_read_sda_s3c24xx(void) +{ + return (rGPEDAT & 0x8000) != 0; +} + +static void i2c_set_s3c24xx(char clock, char data) +{ + if (clock) /* SCL <- input */ + rGPECON = (rGPECON & ~0x30000000); + else { /* SCL <- output 0 */ + rGPEDAT = (rGPEDAT & ~0x4000); + rGPECON = (rGPECON & ~0x30000000) | 0x10000000; + } + if (data) /* SDA <- input */ + rGPECON = (rGPECON & ~0xc0000000); + else { /* SDA <- output 0 */ + rGPEDAT = (rGPEDAT & ~0x8000); + rGPECON = (rGPECON & ~0xc0000000) | 0x40000000; + } +} + +static void i2c_close_s3c24xx(void) +{ + /* set back to hardware I2C ready for Linux */ + rGPECON = (rGPECON & ~0xf0000000) | 0xa0000000; +} + +static void i2c_spin_s3c24xx(void) +{ + int n; + + for (n = 0; n < 1000; n++) + rGPJDAT |= (1 << 5); +} + +struct i2c_bitbang bb_s3c24xx = { + .read_sda = i2c_read_sda_s3c24xx, + .set = i2c_set_s3c24xx, + .spin = i2c_spin_s3c24xx, + .close = i2c_close_s3c24xx, +}; diff --git a/qiboot/src/cpu/s3c2410/lowlevel_init.S b/qiboot/src/cpu/s3c2410/lowlevel_init.S new file mode 100644 index 0000000..2b14373 --- /dev/null +++ b/qiboot/src/cpu/s3c2410/lowlevel_init.S @@ -0,0 +1,162 @@ +/* + * Memory Setup stuff - taken from blob memsetup.S + * + * Modified for the FIC Neo1973 GTA01 by Harald Welte + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* NOTE this stuff runs in steppingstone context! */ + + +/* + * #include + * #include + */ +#define __ASM_MODE__ +#include + +/* + * + * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S + * + * Copyright (C) 2002 Samsung Electronics SW.LEE + * + */ + +#define BWSCON 0x48000000 + +/* BWSCON */ +#define DW8 (0x0) +#define DW16 (0x1) +#define DW32 (0x2) +#define WAIT (0x1<<2) +#define UBLB (0x1<<3) + +#define B1_BWSCON (DW16 + WAIT + UBLB) +#define B2_BWSCON (DW16) +#define B3_BWSCON (DW16 + WAIT + UBLB) +#define B4_BWSCON (DW16) +#define B5_BWSCON (DW16) +#define B6_BWSCON (DW32) +#define B7_BWSCON (DW32) + +/* BANK0CON */ +#define B0_Tacs 0x0 /* 0clk */ +#define B0_Tcos 0x0 /* 0clk */ +#define B0_Tacc 0x7 /* 14clk */ +#define B0_Tcoh 0x0 /* 0clk */ +#define B0_Tah 0x0 /* 0clk */ +#define B0_Tacp 0x0 +#define B0_PMC 0x0 /* normal */ + +/* BANK1CON: Smedia Glamo 3362 (on GTA02) */ +#define B1_Tacs 0x0 /* 0clk */ +#define B1_Tcos 0x3 /* 4clk */ +#define B1_Tacc 0x3 /* 4clk */ +#define B1_Tcoh 0x3 /* 4clk */ +#define B1_Tah 0x0 /* 0clk */ +#define B1_Tacp 0x0 +#define B1_PMC 0x0 + +#define B2_Tacs 0x0 +#define B2_Tcos 0x0 +#define B2_Tacc 0x7 +#define B2_Tcoh 0x0 +#define B2_Tah 0x0 +#define B2_Tacp 0x0 +#define B2_PMC 0x0 + +#define B3_Tacs 0x0 /* 0clk */ +#define B3_Tcos 0x3 /* 4clk */ +#define B3_Tacc 0x7 /* 14clk */ +#define B3_Tcoh 0x1 /* 1clk */ +#define B3_Tah 0x0 /* 0clk */ +#define B3_Tacp 0x3 /* 6clk */ +#define B3_PMC 0x0 /* normal */ + +#define B4_Tacs 0x0 /* 0clk */ +#define B4_Tcos 0x0 /* 0clk */ +#define B4_Tacc 0x7 /* 14clk */ +#define B4_Tcoh 0x0 /* 0clk */ +#define B4_Tah 0x0 /* 0clk */ +#define B4_Tacp 0x0 +#define B4_PMC 0x0 /* normal */ + +#define B5_Tacs 0x0 /* 0clk */ +#define B5_Tcos 0x0 /* 0clk */ +#define B5_Tacc 0x7 /* 14clk */ +#define B5_Tcoh 0x0 /* 0clk */ +#define B5_Tah 0x0 /* 0clk */ +#define B5_Tacp 0x0 +#define B5_PMC 0x0 /* normal */ + +#define B6_MT 0x3 /* SDRAM */ +#define B6_Trcd 0x1 /* 3clk */ + +#define B6_SCAN 0x2 /* 10bit */ +#define B7_SCAN 0x2 /* 10bit */ + + +#define B7_MT 0x3 /* SDRAM */ +#define B7_Trcd 0x1 /* 3clk */ + +/* REFRESH parameter */ +#define REFEN 0x1 /* Refresh enable */ +#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ +#define Trp 0x1 /* 3clk */ +#define Trc 0x3 /* 7clk */ +#define Tchr 0x2 /* 3clk */ +//#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */ +#define REFCNT 997 /* period=17.5us, HCLK=60Mhz, (2048+1-15.6*60) */ +/**************************************/ + +.globl lowlevel_init +lowlevel_init: + + ldr r0, =SMRDATA + ldr r1, =BWSCON /* Bus Width Status Controller */ + add r2, r0, #13*4 +0: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r2, r0 + bne 0b + + /* setup asynchronous bus mode */ + mrc p15, 0, r1 ,c1 ,c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 + + /* everything is fine now */ + mov pc, lr + + .ltorg +/* the literal pools origin */ +SMRDATA: + .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) + .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) + .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) + .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) + .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) + .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) + .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) + .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) + .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) + .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) + .word 0xb2 + .word 0x30 + .word 0x30 diff --git a/qiboot/src/cpu/s3c2410/nand_read.c b/qiboot/src/cpu/s3c2410/nand_read.c new file mode 100644 index 0000000..83b1651 --- /dev/null +++ b/qiboot/src/cpu/s3c2410/nand_read.c @@ -0,0 +1,136 @@ +/* + * nand_read.c: Simple NAND read functions for booting from NAND + * + * This is used by cpu/arm920/start.S assembler code, + * and the board-specific linker script must make sure this + * file is linked within the first 4kB of NAND flash. + * + * Taken from GPLv2 licensed vivi bootloader, + * Copyright (C) 2002 MIZI Research, Inc. + * + * Author: Hwang, Chideok + * Date : $Date: 2004/02/04 10:37:37 $ + * + * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. + * Author: Harald Welte + */ + +/* NOTE this stuff runs in steppingstone context! */ + +/* the API refers to 512-byte blocks */ + +#include +#include "nand_read.h" + +#define NAND_CMD_READ0 0 +#define NAND_CMD_READOOB 0x50 + +#define __REGb(x) (*(volatile unsigned char *)(x)) +#define __REGw(x) (*(volatile unsigned short *)(x)) +#define __REGi(x) (*(volatile unsigned int *)(x)) +#define NF_BASE 0x4e000000 +#define NFCONF __REGi(NF_BASE + 0x0) +#define NFCMD __REGb(NF_BASE + 0x4) +#define NFADDR __REGb(NF_BASE + 0x8) +#define NFDATA __REGb(NF_BASE + 0xc) +#define NFSTAT __REGb(NF_BASE + 0x10) +#define NFSTAT_BUSY 1 +#define nand_select() (NFCONF &= ~0x800) +#define nand_deselect() (NFCONF |= 0x800) +#define nand_clear_RnB() do {} while (0) + + +static inline void nand_wait(void) +{ + int i; + + while (!(NFSTAT & NFSTAT_BUSY)) + for (i=0; i<10; i++); +} + +/* configuration for 2410 with 512byte sized flash */ +#define NAND_PAGE_SIZE 512 +#define BAD_BLOCK_OFFSET 5 +#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1) +#define NAND_BLOCK_SIZE 0x4000 + +static int is_bad_block(unsigned long block_index) +{ + unsigned char data; + + nand_clear_RnB(); + + NFCMD = NAND_CMD_READOOB; /* 0x50 */ + NFADDR = BAD_BLOCK_OFFSET & 0xf; + NFADDR = (block_index ) & 0xff; + NFADDR = (block_index >> 8 ) & 0xff; + NFADDR = (block_index >> 16) & 0xff; + + nand_wait(); + data = (NFDATA & 0xff); + + if (data != 0xff) + return 1; + + return 0; +} + +static int nand_read_page_ll(unsigned char *buf, unsigned long block512) +{ + unsigned int i; + + nand_clear_RnB(); + + NFCMD = NAND_CMD_READ0; + + /* Write Address */ + NFADDR = 0; + NFADDR = (block512 ) & 0xff; + NFADDR = (block512 >> 8 ) & 0xff; + NFADDR = (block512 >> 16) & 0xff; + + nand_wait(); + + for (i = 0; i < NAND_PAGE_SIZE; i++) { + *buf = (NFDATA & 0xff); + buf++; + } + + return 1; +} + +/* low level nand read function */ +int nand_read_ll(unsigned char *buf, unsigned long start_block512, int blocks512) +{ + int i, j; + int bad_count = 0; + + /* chip Enable */ + nand_select(); + nand_clear_RnB(); + + for (i = 0; i < 10; i++) + ; + + while (blocks512 > 0) { + if (is_bad_block(start_block512) || + is_bad_block(start_block512 + 1)) { + start_block512 += 1; + blocks512 += 1; + if (bad_count++ == 4) + return -1; + continue; + } + + j = nand_read_page_ll(buf, start_block512); + start_block512 += j; + buf += j << 9; + blocks512 -= j; + } + + /* chip Disable */ + nand_deselect(); + + return 0; +} + diff --git a/qiboot/src/cpu/s3c2410/nand_read.h b/qiboot/src/cpu/s3c2410/nand_read.h new file mode 100644 index 0000000..71aeda5 --- /dev/null +++ b/qiboot/src/cpu/s3c2410/nand_read.h @@ -0,0 +1,22 @@ +/* + * nand_read.c: Simple NAND read functions for booting from NAND + * + * This is used by cpu/arm920/start.S assembler code, + * and the board-specific linker script must make sure this + * file is linked within the first 4kB of NAND flash. + * + * Taken from GPLv2 licensed vivi bootloader, + * Copyright (C) 2002 MIZI Research, Inc. + * + * Author: Hwang, Chideok + * Date : $Date: 2004/02/04 10:37:37 $ + * + * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. + * Author: Harald Welte + */ +#ifndef __NAND_READ_H +#define __NAND_READ_H + +int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size); + +#endif /* __NAND_READ_H */ diff --git a/qiboot/src/cpu/s3c2410/qi.lds b/qiboot/src/cpu/s3c2410/qi.lds new file mode 100644 index 0000000..27ba2f0 --- /dev/null +++ b/qiboot/src/cpu/s3c2410/qi.lds @@ -0,0 +1,63 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + /* this is intended to take the first 4KBytes of stuff initially. + * We have to make sure we have .rodata* in there for everything + * because we do not compile PIC. + */ + + . = ALIGN(4); + .text : + { + src/cpu/s3c2410/start.o (.text .rodata* .data .bss) + src/cpu/s3c2410/lowlevel_init.o (.text .rodata* .data .bss) + src/cpu/s3c2410/start_qi.o (.text .rodata* .data .bss) + src/cpu/s3c2410/nand_read.o (.text .rodata* .data .bss) + src/cpu/s3c2410/serial-s3c24xx.o (.text .rodata* .data .bss) + src/memory-test.o (.text .rodata* .data .bss) + src/utils.o (.text .rodata* .data .bss) + src/ctype.o (.text .rodata* .data .bss) + * (.steppingstone) + } + + . = ALIGN(4); + .everything_else ADDR (.text) + SIZEOF (.text) + 0x33000000 : + AT ( ADDR (.text) + SIZEOF (.text) ) { *(.text .rodata* .data) } + + . = 0x33800000 ; + __bss_start = .; + .bss (NOLOAD) : + { + *(.bss) + } + + _end = .; +} diff --git a/qiboot/src/cpu/s3c2410/s3c24xx-mci.c b/qiboot/src/cpu/s3c2410/s3c24xx-mci.c new file mode 100644 index 0000000..dbef90d --- /dev/null +++ b/qiboot/src/cpu/s3c2410/s3c24xx-mci.c @@ -0,0 +1,579 @@ +/* + * qi s3c24xx SD card driver + * Author: Andy Green + * based on ----> + * + * u-boot S3C2410 MMC/SD card driver + * (C) Copyright 2006 by OpenMoko, Inc. + * Author: Harald Welte + * + * based on u-boot pxa MMC driver and linux/drivers/mmc/s3c2410mci.c + * (C) 2005-2005 Thomas Kleffel + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#define SDICON (*(u32 *)0x5a000000) +#define SDIPRE (*(u32 *)0x5a000004) +#define SDICARG (*(u32 *)0x5a000008) +#define SDICCON (*(u32 *)0x5a00000c) +#define SDICSTA (*(u32 *)0x5a000010) +#define SDIRSP0 (*(u32 *)0x5a000014) +#define SDIRSP1 (*(u32 *)0x5a000018) +#define SDIRSP2 (*(u32 *)0x5a00001c) +#define SDIRSP3 (*(u32 *)0x5a000020) +#define SDIDTIMER (*(u32 *)0x5a000024) +#define SDIBSIZE (*(u32 *)0x5a000028) +#define SDIDCON (*(u32 *)0x5a00002c) +#define SDIDCNT (*(u32 *)0x5a000030) +#define SDIDSTA (*(u32 *)0x5a000034) +#define SDIFSTA (*(u32 *)0x5a000038) +/* s3c2410 in GTA01 has these two last ones the other way around!!! */ +#define SDIIMSK (*(u32 *)0x5a00003c) +#define SDIDAT (*(u32 *)0x5a000040) +#define SDIDAT2410 (*(u32 *)0x5a00003c) +#define SDIIMSK2410 (*(u32 *)0x5a000040) + +#define CFG_MMC_BASE 0xff000000 + +int am_i_s3c2410(void) +{ + return 1; +} + +#define CONFIG_MMC_WIDE +#define MMC_BLOCK_SIZE 512 + +/* + * FIXME needs to read cid and csd info to determine block size + * and other parameters + */ +static u8 mmc_buf[MMC_BLOCK_SIZE]; +static mmc_csd_t mmc_csd; +static int mmc_ready = 0; +static int wide = 0; +static int is_sdhc = 0; + + +#define CMD_F_RESP 0x01 +#define CMD_F_RESP_LONG 0x02 + +static u32 *mmc_cmd(u16 cmd, u32 arg, u16 flags) +{ + static u32 resp[5]; + + u32 ccon, csta; + u32 csta_rdy_bit = S3C2410_SDICMDSTAT_CMDSENT; + + memset(resp, 0, sizeof(resp)); + +// debug("mmc_cmd CMD%d arg=0x%08x flags=%x\n", cmd, arg, flags); + + SDICSTA = 0xffffffff; + SDIDSTA = 0xffffffff; + SDIFSTA = 0xffffffff; + + SDICARG = arg; + + ccon = cmd & S3C2410_SDICMDCON_INDEX; + ccon |= S3C2410_SDICMDCON_SENDERHOST|S3C2410_SDICMDCON_CMDSTART; + + if (flags & CMD_F_RESP) { + ccon |= S3C2410_SDICMDCON_WAITRSP; + csta_rdy_bit = S3C2410_SDICMDSTAT_RSPFIN; /* 1 << 9 */ + } + + if (flags & CMD_F_RESP_LONG) + ccon |= S3C2410_SDICMDCON_LONGRSP; + + SDICCON = ccon; + + while (1) { + csta = SDICSTA; + if (csta & csta_rdy_bit) + break; + if (csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { + puts("===============> MMC CMD Timeout\n"); + SDICSTA |= S3C2410_SDICMDSTAT_CMDTIMEOUT; + break; + } + } + +// debug("final MMC CMD status 0x%x\n", csta); + + SDICSTA |= csta_rdy_bit; + + if (flags & CMD_F_RESP) { + resp[0] = SDIRSP0; + resp[1] = SDIRSP1; + resp[2] = SDIRSP2; + resp[3] = SDIRSP3; + } + + return resp; +} + +#define FIFO_FILL() ((SDIFSTA & S3C2410_SDIFSTA_COUNTMASK) >> 2) + +static int mmc_block_read(u8 *dst, u32 src, u32 len) +{ + u32 dcon, fifo; + u32 *dst_u32 = (u32 *)dst; + u32 *resp; + + if (len == 0) + return 0; + +// debug("mmc_block_rd dst %lx src %lx len %d\n", (u32)dst, src, len); + + /* set block len */ + resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, len, CMD_F_RESP); + SDIBSIZE = len; + + //SDIPRE = 0xff; + + /* setup data */ + dcon = (len >> 9) & S3C2410_SDIDCON_BLKNUM; + dcon |= S3C2410_SDIDCON_BLOCKMODE; + dcon |= S3C2410_SDIDCON_RXAFTERCMD|S3C2410_SDIDCON_XFER_RXSTART; + if (wide) + dcon |= S3C2410_SDIDCON_WIDEBUS; + + if (!am_i_s3c2410()) + dcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART; + + SDIDCON = dcon; + + /* send read command */ + if (!is_sdhc) + resp = mmc_cmd(MMC_CMD_READ_BLOCK, src, CMD_F_RESP); + else + resp = mmc_cmd(MMC_CMD_READ_BLOCK, src / MMC_BLOCK_SIZE, CMD_F_RESP); + + while (len > 0) { + u32 sdidsta = SDIDSTA; + fifo = FIFO_FILL(); + if (sdidsta & (S3C2410_SDIDSTA_FIFOFAIL| + S3C2410_SDIDSTA_CRCFAIL| + S3C2410_SDIDSTA_RXCRCFAIL| + S3C2410_SDIDSTA_DATATIMEOUT)) { + puts("mmc_block_read: err SDIDSTA=0x"); + print32(sdidsta); + puts("\n"); + return -1; + } + + if (am_i_s3c2410()) { + while (fifo--) { + //debug("dst_u32 = 0x%08x\n", dst_u32); + *(dst_u32++) = SDIDAT2410; + if (len >= 4) + len -= 4; + else { + len = 0; + break; + } + } + } else { + while (fifo--) { + //debug("dst_u32 = 0x%08x\n", dst_u32); + *(dst_u32++) = SDIDAT; + if (len >= 4) + len -= 4; + else { + len = 0; + break; + } + } + } + } + +// debug("waiting for SDIDSTA (currently 0x%08x\n", SDIDSTA); + while (!(SDIDSTA & (1 << 4))) {} +// debug("done waiting for SDIDSTA (currently 0x%08x\n", SDIDSTA); + + SDIDCON = 0; + + if (!(SDIDSTA & S3C2410_SDIDSTA_XFERFINISH)) + puts("mmc_block_read; transfer not finished!\n"); + + return 0; +} + +static int mmc_block_write(u32 dst, u8 *src, int len) +{ + puts("MMC block write not yet supported on S3C2410!\n"); + return -1; +} + + +int s3c24xx_mmc_read(u32 src, u8 *dst, int size) +{ + u32 end, part_start, part_end, part_len, aligned_start, aligned_end; + u32 mmc_block_size, mmc_block_address; + + if (size == 0) + return 0; + + if (!mmc_ready) { + puts("Please initialize the MMC first\n"); + return -1; + } + + mmc_block_size = MMC_BLOCK_SIZE; + mmc_block_address = ~(mmc_block_size - 1); + + src -= CFG_MMC_BASE; + end = src + size; + part_start = ~mmc_block_address & src; + part_end = ~mmc_block_address & end; + aligned_start = mmc_block_address & src; + aligned_end = mmc_block_address & end; + + /* all block aligned accesses */ +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_start) { + part_len = mmc_block_size - part_start; +// debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) + return -1; + + memcpy(dst, mmc_buf+part_start, part_len); + dst += part_len; + src += part_len; + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) { +// debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read((u8 *)(dst), src, mmc_block_size)) < 0) + return -1; + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_end && src < end) { +// debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) + return -1; + + memcpy(dst, mmc_buf, part_end); + } + return 0; +} + +int s3c24xx_mmc_write(u8 *src, u32 dst, int size) +{ + u32 end, part_start, part_end, part_len, aligned_start, aligned_end; + u32 mmc_block_size, mmc_block_address; + + if (size == 0) + return 0; + + if (!mmc_ready) { + puts("Please initialize the MMC first\n"); + return -1; + } + + mmc_block_size = MMC_BLOCK_SIZE; + mmc_block_address = ~(mmc_block_size - 1); + + dst -= CFG_MMC_BASE; + end = dst + size; + part_start = ~mmc_block_address & dst; + part_end = ~mmc_block_address & end; + aligned_start = mmc_block_address & dst; + aligned_end = mmc_block_address & end; + + /* all block aligned accesses */ +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_start) { + part_len = mmc_block_size - part_start; +// debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// (u32)src, dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) + return -1; + + memcpy(mmc_buf+part_start, src, part_len); + if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < 0) + return -1; + + dst += part_len; + src += part_len; + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) { +// debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_write(dst, (u8 *)src, mmc_block_size)) < 0) + return -1; + + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_end && dst < end) { +// debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) + return -1; + + memcpy(mmc_buf, src, part_end); + if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) + return -1; + + } + return 0; +} + +u32 s3c24xx_mmc_bread(int dev_num, u32 blknr, u32 blkcnt, void *dst) +{ + int mmc_block_size = MMC_BLOCK_SIZE; + u32 src = blknr * mmc_block_size + CFG_MMC_BASE; + + s3c24xx_mmc_read(src, dst, blkcnt*mmc_block_size); + return blkcnt; +} + +/* MMC_DEFAULT_RCA should probably be just 1, but this may break other code + that expects it to be shifted. */ +static u_int16_t rca = MMC_DEFAULT_RCA >> 16; + +#if 0 +static u32 mmc_size(const struct mmc_csd *csd) +{ + u32 block_len, mult, blocknr; + + block_len = csd->read_bl_len << 12; + mult = csd->c_size_mult1 << 8; + blocknr = (csd->c_size+1) * mult; + + return blocknr * block_len; +} +#endif + +struct sd_cid { + char pnm_0; /* product name */ + char oid_1; /* OEM/application ID */ + char oid_0; + uint8_t mid; /* manufacturer ID */ + char pnm_4; + char pnm_3; + char pnm_2; + char pnm_1; + uint8_t psn_2; /* product serial number */ + uint8_t psn_1; + uint8_t psn_0; /* MSB */ + uint8_t prv; /* product revision */ + uint8_t crc; /* CRC7 checksum, b0 is unused and set to 1 */ + uint8_t mdt_1; /* manufacturing date, LSB, RRRRyyyy yyyymmmm */ + uint8_t mdt_0; /* MSB */ + uint8_t psn_3; /* LSB */ +}; + +static void print_mmc_cid(mmc_cid_t *cid) +{ + puts("MMC found. Card desciption is:\n"); + puts("Manufacturer ID = "); + print8(cid->id[0]); + print8(cid->id[1]); + print8(cid->id[2]); + puts("\nHW/FW Revision = "); + print8(cid->hwrev); + print8(cid->fwrev); + cid->hwrev = cid->fwrev = 0; /* null terminate string */ + puts("Product Name = "); + puts((char *)cid->name); + puts("\nSerial Number = "); + print8(cid->sn[0]); + print8(cid->sn[1]); + print8(cid->sn[2]); + puts("\nMonth = "); + printdec(cid->month); + puts("\nYear = "); + printdec(1997 + cid->year); + puts("\n"); +} + +static void print_sd_cid(const struct sd_cid *cid) +{ + puts("Manufacturer: 0x"); + print8(cid->mid); + puts("OEM \""); + this_board->putc(cid->oid_0); + this_board->putc(cid->oid_1); + puts("\"\nProduct name: \""); + this_board->putc(cid->pnm_0); + this_board->putc(cid->pnm_1); + this_board->putc(cid->pnm_2); + this_board->putc(cid->pnm_3); + this_board->putc(cid->pnm_4); + puts("\", revision "); + printdec(cid->prv >> 4); + puts("."); + printdec(cid->prv & 15); + puts("\nSerial number: "); + printdec(cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 | + cid->psn_3); + puts("\nManufacturing date: "); + printdec(cid->mdt_1 & 15); + puts("/"); + printdec(2000+((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4)); + puts("\nCRC: 0x"); + print8(cid->crc >> 1); + puts(" b0 = "); + print8(cid->crc & 1); + puts("\n"); +} + +int s3c24xx_mmc_init(int verbose) +{ + int retries, rc = -2; + int is_sd = 0; + u32 *resp; + u32 hcs = 0; + + SDICON = S3C2410_SDICON_FIFORESET | S3C2410_SDICON_CLOCKTYPE; + SDIBSIZE = 512; + if (am_i_s3c2410()) { + /* S3C2410 has some bug that prevents reliable operation at higher speed */ + //SDIPRE = 0x3e; /* SDCLK = PCLK/2 / (SDIPRE+1) = 396kHz */ + SDIPRE = 0x02; /* 2410: SDCLK = PCLK/2 / (SDIPRE+1) = 11MHz */ + SDIDTIMER = 0xffff; + SDIIMSK2410 = 0x0; + } else { + SDIPRE = 0x05; /* 2410: SDCLK = PCLK / (SDIPRE+1) = 11MHz */ + SDIDTIMER = 0x7fffff; + SDIIMSK = 0x0; + } + + udelay(1250000); /* FIXME: 74 SDCLK cycles */ + + mmc_csd.c_size = 0; + + puts("Sending reset...\n"); + + /* reset */ + retries = 10; + resp = mmc_cmd(MMC_CMD_RESET, 0, 0); + + resp = mmc_cmd(8, 0x000001aa, CMD_F_RESP); + if ((resp[0] & 0xff) == 0xaa) { + puts("The card is either SD2.0 or SDHC\n"); + hcs = 0x40000000; + } + + puts("trying to detect SD Card...\n"); + while (retries--) { + udelay(1000000); + resp = mmc_cmd(55, 0x00000000, CMD_F_RESP); + resp = mmc_cmd(41, hcs | 0x00300000, CMD_F_RESP); + + if (resp[0] & (1 << 30)) + is_sdhc = 1; + + if (resp[0] & (1 << 31)) { + is_sd = 1; + break; + } + } + + if (retries < 0 && !is_sd) + return -3; + + /* try to get card id */ + resp = mmc_cmd(MMC_CMD_ALL_SEND_CID, hcs, CMD_F_RESP|CMD_F_RESP_LONG); + if (resp) { + if (!is_sd) { + /* TODO configure mmc driver depending on card + attributes */ + mmc_cid_t *cid = (mmc_cid_t *)resp; + + if (verbose) + print_mmc_cid(cid); +#if 0 + sprintf((char *) mmc_dev.vendor, + "Man %02x%02x%02x Snr %02x%02x%02x", + cid->id[0], cid->id[1], cid->id[2], + cid->sn[0], cid->sn[1], cid->sn[2]); + sprintf((char *) mmc_dev.product,"%s",cid->name); + sprintf((char *) mmc_dev.revision,"%x %x", + cid->hwrev, cid->fwrev); +#endif + } + else { + struct sd_cid *cid = (struct sd_cid *) resp; + + if (verbose) + print_sd_cid(cid); +#if 0 + sprintf((char *) mmc_dev.vendor, + "Man %02 OEM %c%c \"%c%c%c%c%c\"", + cid->mid, cid->oid_0, cid->oid_1, + cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, + cid->pnm_4); + sprintf((char *) mmc_dev.product, "%d", + cid->psn_0 << 24 | cid->psn_1 << 16 | + cid->psn_2 << 8 | cid->psn_3); + sprintf((char *) mmc_dev.revision, "%d.%d", + cid->prv >> 4, cid->prv & 15); +#endif + } + + + /* MMC exists, get CSD too */ + resp = mmc_cmd(MMC_CMD_SET_RCA, MMC_DEFAULT_RCA, CMD_F_RESP); + if (is_sd) + rca = resp[0] >> 16; + + resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, CMD_F_RESP|CMD_F_RESP_LONG); + if (resp) { + mmc_csd_t *csd = (mmc_csd_t *)resp; + memcpy(&mmc_csd, csd, sizeof(csd)); + rc = 0; + mmc_ready = 1; +#if 0 + /* FIXME add verbose printout for csd */ + printf("READ_BL_LEN=%u, C_SIZE_MULT=%u, C_SIZE=%u\n", + csd->read_bl_len, csd->c_size_mult1, csd->c_size); + printf("size = %u\n", mmc_size(csd)); +#endif + } + } + + resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca<<16, CMD_F_RESP); + +#ifdef CONFIG_MMC_WIDE + if (is_sd) { + resp = mmc_cmd(55, rca<<16, CMD_F_RESP); + resp = mmc_cmd(6, 0x02, CMD_F_RESP); + wide = 1; + } +#endif + + return rc; +} + + diff --git a/qiboot/src/cpu/s3c2410/serial-s3c24xx.c b/qiboot/src/cpu/s3c2410/serial-s3c24xx.c new file mode 100644 index 0000000..0f4ba22 --- /dev/null +++ b/qiboot/src/cpu/s3c2410/serial-s3c24xx.c @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +void serial_init_115200_s3c24xx(const int uart, const int pclk_MHz) +{ + int div = (((54 * pclk_MHz) + 26) / 100) -1; + switch(uart) + { + case UART0: + rULCON0 = 0x3; + rUCON0 = 0x245; + rUFCON0 = 0x0; + rUMCON0 = 0x0; + rUBRDIV0 = div; + break; + case UART1: + rULCON1 = 0x3; + rUCON1 = 0x245; + rUFCON1 = 0x0; + rUMCON1 = 0x0; + rUBRDIV1 = div; + break; + case UART2: + rULCON2 = 0x3; + rUCON2 = 0x245; + rUFCON2 = 0x1; + rUBRDIV2 = div; + break; + default: + break; + } +} +/* + * Output a single byte to the serial port. + */ +void serial_putc_s3c24xx(const int uart, const char c) +{ + switch(uart) + { + case UART0: + while ( !( rUTRSTAT0 & 0x2 ) ); + WrUTXH0(c); + break; + case UART1: + while ( !( rUTRSTAT1 & 0x2 ) ); + WrUTXH1(c); + break; + case UART2: + while ( !( rUTRSTAT2 & 0x2 ) ); + WrUTXH2(c); + break; + default: + break; + } +} diff --git a/qiboot/src/cpu/s3c2410/start.S b/qiboot/src/cpu/s3c2410/start.S new file mode 100644 index 0000000..5c9d3db --- /dev/null +++ b/qiboot/src/cpu/s3c2410/start.S @@ -0,0 +1,304 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define __ASM_MODE__ +#define __ASSEMBLY__ + +#include + +#define S3C2410_MISCCR_nEN_SCLK0 (1 << 17) +#define S3C2410_MISCCR_nEN_SCLK1 (1 << 18) +#define S3C2410_MISCCR_nEN_SCLKE (1 << 19) + + +.globl _start, processor_id, is_jtag + +_start: b start_code +/* if we are injected by JTAG, the script sets _istag content to nonzero */ +is_jtag: + .word 0 + +/* it's at a fixed address (+0x8) so we can breakpoint it in the JTAG script + * we need to go through this hassle because before this moment, SDRAM is not + * working so we can't prep it from JTAG + */ + +_steppingstone_done: + ldr pc, _start_armboot + +_start_armboot: + .word start_qi + +_TEXT_BASE: + .word TEXT_BASE + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end +/* + * we have a stack in steppingstone because we can want to run full memory + * memory tests + */ + + .fill 128 +.globl _ss_stack +_ss_stack: + + +start_code: + /* + * set the cpu to SVC32 mode + */ + mrs r0,cpsr + bic r0,r0,#0x1f + orr r0,r0,#0xd3 + msr cpsr,r0 + +# define pWTCON 0x53000000 + + ldr r0, =pWTCON + mov r1, #0x0 + str r1, [r0] + + /* + * mask all IRQs by setting all bits in the INTMR - default + */ +# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ +# define INTSUBMSK 0x4A00001C +# define INTSUBMSK_val 0x000007ff + + mov r1, #0xffffffff + ldr r0, =INTMSK + str r1, [r0] + + ldr r1, =INTSUBMSK_val + ldr r0, =INTSUBMSK + str r1, [r0] + + /* Clock asynchronous mode */ + mrc p15, 0, r1, c1, c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 + +#define LOCKTIME 0x4c000000 + + ldr r0, =LOCKTIME + mov r1, #0xffffff + str r1, [r0] + +# define UPLLCON 0x4c000008 +# define MPLLCON_val ((0x90 << 12) + (0x7 << 4) + 0x0) /* 202 MHz */ +# define UPLLCON_val ((0x78 << 12) + (0x2 << 4) + 0x3) + + ldr r0, =UPLLCON + ldr r1, =UPLLCON_val + str r1, [r0] + + /* Page 7-19, seven nops between UPLL and MPLL */ + nop + nop + nop + nop + nop + nop + nop + + ldr r1, =MPLLCON_val + str r1, [r0, #-4] /* MPLLCON */ + +# define CLKDIVN 0x4C000014 /* clock divisor register */ +# define CLKDIVN_val 3 /* FCLK:HCLK:PCLK = 1:2:4 */ + + /* FCLK:HCLK:PCLK = 1:3:6 */ + ldr r0, =CLKDIVN + mov r1, #CLKDIVN_val + str r1, [r0] + + /* enable only CPU peripheral block clocks we actually use */ + ldr r0, =0x4c00000c /* clkcon */ + ldr r1, =0x3f10 /* uart, pwm, gpio, nand, sdi clocks on */ + str r1, [r0] + + /* gpio UART0 init */ + ldr r0, =0x56000070 + ldr r1, =0x000000AA + str r1, [r0] + + /* init uart0 */ + ldr r0, =0x50000000 + mov r1, #0x03 + str r1, [r0] + ldr r1, =0x245 + str r1, [r0, #0x04] + mov r1, #0x01 + str r1, [r0, #0x08] + mov r1, #0x00 + str r1, [r0, #0x0c] + mov r1, #0x1a + str r1, [r0, #0x28] + +/* reset nand controller, or it is dead to us */ + +#define oNFCONF 0x00 +#define oNFCMD 0x04 +#define oNFSTAT 0x10 + + mov r1, #0x4E000000 + ldr r2, =0xf842 @ initial value enable tacls=3,rph0=6,rph1=0 + str r2, [r1, #oNFCONF] + ldr r2, [r1, #oNFCONF] + bic r2, r2, #0x800 @ enable chip + str r2, [r1, #oNFCONF] + mov r2, #0xff @ RESET command + strb r2, [r1, #oNFCMD] + mov r3, #0 @ wait +1: add r3, r3, #0x1 + cmp r3, #0xa + blt 1b +2: ldr r2, [r1, #oNFSTAT] @ wait ready + tst r2, #0x1 + beq 2b + ldr r2, [r1, #oNFCONF] + orr r2, r2, #0x800 @ disable chip + str r2, [r1, #oNFCONF] + + /* take sdram out of power down */ + ldr r0, =0x56000080 /* misccr */ + ldr r1, [ r0 ] + bic r1, r1, #(S3C2410_MISCCR_nEN_SCLK0 | S3C2410_MISCCR_nEN_SCLK1 | S3C2410_MISCCR_nEN_SCLKE) + str r1, [ r0 ] + + /* ensure signals stabalise */ + mov r1, #128 +3: subs r1, r1, #1 + bpl 3b + + bl cpu_init_crit + + /* ensure some refresh has happened */ + ldr r1, =0xfffff +4: subs r1, r1, #1 + bpl 4b + + /* capture full EINT situation into gstatus 4 */ + + ldr r0, =0x4A000000 /* SRCPND */ + ldr r1, [ r0 ] + and r1, r1, #0xf + + ldr r0, =0x560000BC /* gstatus4 */ + str r1, [ r0 ] + + ldr r0, =0x560000A8 /* EINTPEND */ + ldr r1, [ r0 ] + ldr r0, =0xfff0 + and r1, r1, r0 + ldr r0, =0x560000BC /* gstatus4 */ + ldr r0, [ r0 ] + orr r1, r1, r0 + ldr r0, =0x560000BC /* gstatus4 */ + str r1, [ r0 ] + + /* test for resume */ + + ldr r1, =0x560000B4 /* gstatus2 */ + ldr r0, [ r1 ] + tst r0, #0x02 /* is this resume from power down */ + /* well, if it was, we are going to jump to + * whatever address we stashed in gstatus3, + * and gstatus4 will hold the wake interrupt + * source for the OS to look at + */ + ldrne pc, [r1, #4] + + + /* >> CFG_VIDEO_LOGO_MAX_SIZE */ +#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ + +stack_setup: + ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ + sub sp, r0, #12 /* leave 3 words for abort-stack */ + +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0x00000000 /* clear */ + +clbss_l: + str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + +/* we are going to jump into the C part of the init now */ +spin: + b _steppingstone_done + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ + +cpu_init_crit: + + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + mcr p15, 0, r0, c1, c0, 0 + + /* + * before relocating, we have to setup RAM timing + * because memory timing is board-dependend, you will + * find a lowlevel_init.S in your board directory. + */ + mov ip, lr + + bl lowlevel_init + + mov lr, ip + mov pc, lr + diff --git a/qiboot/src/cpu/s3c2410/start_qi.c b/qiboot/src/cpu/s3c2410/start_qi.c new file mode 100644 index 0000000..4d9b7ae --- /dev/null +++ b/qiboot/src/cpu/s3c2410/start_qi.c @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * Andy Green + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* NOTE this stuff runs in steppingstone context! */ + + +#include +#include "nand_read.h" +#include + +#define stringify2(s) stringify1(s) +#define stringify1(s) #s + + +extern void bootloader_second_phase(void); + +const struct board_api *boards[] = { + &board_api_gta01, + NULL /* always last */ +}; + + +struct board_api const * this_board; +extern int is_jtag; + +void start_qi(void) +{ + int flag = 0; + int board = 0; + + /* + * well, we can be running on this CPU two different ways. + * + * 1) We were copied into steppingstone and TEXT_BASE already + * by JTAG. We don't have to do anything else. JTAG script + * then sets data at address 0x4 to 0xffffffff as a signal we + * are running by JTAG. + * + * 2) We only got our first 4K into steppingstone, we need to copy + * the rest of ourselves into TEXT_BASE. + * + * So we do the copy out of NAND only if we see we did not come up + * under control of JTAG. + */ + + if (!is_jtag) + /* + * We got the first 4KBytes of the bootloader pulled into the + * steppingstone SRAM for free. Now we pull the whole bootloader + * image into SDRAM. + * + * This code and the .S files are arranged by the linker script + * to expect to run from 0x0. But the linker script has told + * everything else to expect to run from 0x33000000+. That's + * why we are going to be able to copy this code and not have it + * crash when we run it from there. + */ + + /* We randomly pull 32KBytes of bootloader */ + if (nand_read_ll((u8 *)TEXT_BASE, 0, 32 * 1024 / 512) < 0) + goto unhappy; + + /* ask all the boards we support in turn if they recognize this + * hardware we are running on, accept the first positive answer + */ + + this_board = boards[board]; + while (!flag && this_board) { + + /* check if it is the right board... */ + if (this_board->is_this_board()) { + flag = 1; + continue; + } + + this_board = boards[board++]; + } + + /* No valid board found */ + if (!this_board) + goto unhappy; + + this_board->port_init(); + set_putc_func(this_board->putc); + + /* stick some hello messages on debug console */ + + puts("\n\n\nQi Bootloader "stringify2(QI_CPU)" " + stringify2(BUILD_HOST)" " + stringify2(BUILD_VERSION)" " + "\n"); + + puts(stringify2(BUILD_DATE) " Copyright (C) 2008 Openmoko, Inc.\n"); + puts("\n Detected: "); + + puts(this_board->name); + puts(", "); + puts((this_board->get_board_variant)()->name); + puts("\n"); + + + /* + * jump to bootloader_second_phase() running from DRAM copy + */ + bootloader_second_phase(); + +unhappy: + while(1) + ; + +} diff --git a/qiboot/src/cpu/s3c2442/gta02.c b/qiboot/src/cpu/s3c2442/gta02.c new file mode 100644 index 0000000..13be2ac --- /dev/null +++ b/qiboot/src/cpu/s3c2442/gta02.c @@ -0,0 +1,740 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * (port_init_gta02 came out of Openmoko U-Boot) + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GTA02_DEBUG_UART 2 +#define PCF50633_I2C_ADS 0x73 +#define BOOST_TO_400MHZ 1 + +static int battery_condition_reasonable = 0; + +extern unsigned long partition_offset_blocks; +extern unsigned long partition_length_blocks; + +const struct board_api board_api_gta02; + +struct nand_dynparts { + const char *name; /* name of this partition for Linux */ + u32 good_length; /* bytes needed from good sectors in this partition */ + u32 true_offset; +}; + +/* + * These are the NAND partitions U-Boot leaves in GTA02 NAND. + * The "dynparts" business means that in the case of bad blocks, all the + * following partitions move up accordingly to have the right amount of + * good blocks. To allow for this, the length of the last, largest + * partition is computed according to the bad blocks that went before. + */ + +static struct nand_dynparts nand_dynparts[] = { + { "qi", 0x40000 }, + { "depr-ub-env", 0x40000 }, + { "kernel", 0x800000 }, + { "depr", 0xa0000 }, + { "identity-ext2", 0x40000 }, + { "rootfs", 0 }, +}; + +static u32 nand_extent_block512 = 256 * 1024 * 1024 / 512; + +const struct pcf50633_init pcf50633_init[] = { + + { PCF50633_REG_OOCWAKE, 0xd3 }, /* wake from ONKEY,EXTON!,RTC,USB,ADP */ + { PCF50633_REG_OOCTIM1, 0xaa }, /* debounce 14ms everything */ + { PCF50633_REG_OOCTIM2, 0x4a }, + { PCF50633_REG_OOCMODE, 0x55 }, + { PCF50633_REG_OOCCTL, 0x47 }, + + { PCF50633_REG_GPIO2CFG, 0x00 }, /* GSM_ON = 0 */ + { PCF50633_REG_GPIOCTL, 0x01 }, /* only GPIO1 is input */ + + { PCF50633_REG_SVMCTL, 0x08 }, /* 3.10V SYS vth, 62ms filter */ + { PCF50633_REG_BVMCTL, 0x02 }, /* 2.80V BAT vth, 62ms filter */ + + { PCF50633_REG_AUTOENA, 0x01 }, /* always on */ + + { PCF50633_REG_DOWN1OUT, 0x1b }, /* 1.3V (0x1b * .025V + 0.625V) */ + { PCF50633_REG_DOWN1ENA, 0x02 }, /* enabled if GPIO1 = HIGH */ + { PCF50633_REG_HCLDOOUT, 21 }, /* 3.0V (21 * 0.1V + 0.9V) */ + { PCF50633_REG_HCLDOENA, 0x01 }, /* ON by default*/ + + { PCF50633_REG_DOWN1OUT, 0x1b }, /* 1.3V (0x1b * .025V + 0.625V) */ + { PCF50633_REG_DOWN1ENA, 0x02 }, /* enabled if GPIO1 = HIGH */ + + { PCF50633_REG_INT1M, 0x00 }, + { PCF50633_REG_INT2M, 0x00 }, + { PCF50633_REG_INT3M, 0x00 }, + { PCF50633_REG_INT4M, 0x00 }, + { PCF50633_REG_INT5M, 0x00 }, + + { PCF50633_REG_MBCC2, 0x28 }, /* Vbatconid=2.7V, Vmax=4.20V */ + { PCF50633_REG_MBCC3, 0x19 }, /* 25/255 == 98mA pre-charge */ + { PCF50633_REG_MBCC4, 0xff }, /* 255/255 == 1A adapter fast */ + { PCF50633_REG_MBCC5, 0xff }, /* 255/255 == 1A usb fast */ + { PCF50633_REG_MBCC6, 0x01 }, /* cutoff current 2/32 * Ichg */ + { PCF50633_REG_MBCC7, 0x00 }, /* 1.6A max bat curr, USB 100mA */ + { PCF50633_REG_MBCC8, 0x00 }, + { PCF50633_REG_MBCC1, 0xff }, /* chgena */ + + { PCF50633_REG_LDO1ENA, 2 }, /* accel enabled if GPIO1 = H */ + { PCF50633_REG_LDO2ENA, 2 }, /* codec enabled if GPIO1 = H */ + { PCF50633_REG_LDO4ENA, 0 }, /* bt off */ + { PCF50633_REG_LDO5ENA, 0 }, /* gps off */ + { PCF50633_REG_LDO6ENA, 2 }, /* lcm enabled if GPIO1 = H */ + + { PCF50633_REG_BBCCTL, 0x19 }, /* 3V, 200uA, on */ + { PCF50633_REG_OOCSHDWN, 0x04 }, /* defeat 8s death from lowsys on A5 */ + +}; + +static const struct board_variant board_variants[] = { + [0] = { + .name = "A5 PCB", + .machine_revision = 0x350, + }, + [1] = { + .name = "A6 PCB", + .machine_revision = 0x360, + }, + [9] = { /* 01001 */ + .name = "A7 PCB", + .machine_revision = 0x360, /* report as A6 */ + }, +}; + + +void port_init_gta02(void) +{ + unsigned int * MPLLCON = (unsigned int *)0x4c000004; + unsigned int * UPLLCON = (unsigned int *)0x4c000008; + unsigned int * CLKDIVN = (unsigned int *)0x4c000014; + int n; + u32 block512 = 0; + u32 start_block512 = 0; + const u32 GTA02_NAND_READBLOCK_SIZE = 2048; + extern int s3c2442_nand_is_bad_block(unsigned long block_index_512); + + //CAUTION:Follow the configuration order for setting the ports. + // 1) setting value(GPnDAT) + // 2) setting control register (GPnCON) + // 3) configure pull-down resistor(GPnUP) + + /* 32bit data bus configuration */ + /* + * === PORT A GROUP + * Ports : GPA22 GPA21 GPA20 GPA19 GPA18 GPA17 GPA16 GPA15 GPA14 GPA13 GPA12 + * Signal : nFCE nRSTOUT nFRE nFWE ALE CLE nGCS5 nGCS4 nGCS3 nGCS2 nGCS1 + * Binary : 1 1 1 , 1 1 1 1 , 1 1 1 1 + * Ports : GPA11 GPA10 GPA9 GPA8 GPA7 GPA6 GPA5 GPA4 GPA3 GPA2 GPA1 GPA0 + * Signal : ADDR26 ADDR25 ADDR24 ADDR23 ADDR22 ADDR21 ADDR20 ADDR19 ADDR18 ADDR17 ADDR16 ADDR0 + * Binary : 1 1 1 1 , 1 1 1 1 , 1 1 1 1 + */ + rGPACON = 0x007E5FFF; + rGPADAT = 0x00000000; + /* + * ===* PORT B GROUP + * Ports : GPB10 GPB9 GPB8 GPB7 GPB6 GPB5 GPB4 GPB3 GPB2 GPB1 GPB0 + * Signal : nXDREQ0 nXDACK0 nXDREQ1 nXDACK1 nSS_KBD nDIS_OFF L3CLOCK L3DATA L3MODE nIrDATXDEN Keyboard + * Setting: INPUT OUTPUT INPUT OUTPUT INPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT + * Binary : 00 , 01 00 , 01 00 , 01 01 , 01 01 , 01 01 + */ + rGPBCON = 0x00155555; + rGPBUP = 0x000007FF; + rGPBDAT = 0x00000000; + /* + * === PORT C GROUP + * Ports : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8 GPC7 GPC6 GPC5 GPC4 GPC3 GPC2 GPC1 GPC0 + * Signal : VD7 VD6 VD5 VD4 VD3 VD2 VD1 VD0 LCDVF2 LCDVF1 LCDVF0 VM VFRAME VLINE VCLK LEND + * Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 + */ + rGPCCON = 0x55555155; + rGPCUP = 0x0000FFFF & ~(1 << 5); + rGPCDAT = (1 << 13) | (1 << 15); /* index detect -> hi */ + /* + * === PORT D GROUP + * Ports : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0 + * Signal : VD23 VD22 VD21 VD20 VD19 VD18 VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9 VD8 + * Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 ,10 10 + */ + rGPDCON = 0x55555555; + rGPDUP = 0x0000FFFF; + rGPDDAT = (1 << 0) | (1 << 3) | (1 << 4); /* index detect -> hi */ + /* + * === PORT E GROUP + * Ports : GPE15 GPE14 GPE13 GPE12 GPE11 GPE10 GPE9 GPE8 GPE7 GPE6 GPE5 GPE4 + * Signal : IICSDA IICSCL SPICLK SPIMOSI SPIMISO SDDATA3 SDDATA2 SDDATA1 SDDATA0 SDCMD SDCLK I2SSDO + * Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , + * ------------------------------------------------------------------------------------------------------- + * Ports : GPE3 GPE2 GPE1 GPE0 + * Signal : I2SSDI CDCLK I2SSCLK I2SLRCK + * Binary : 10 10 , 10 10 + */ + rGPECON = 0xAAAAAAAA; + rGPEUP = 0x0000FFFF & ~(1 << 11); + rGPEDAT = 0x00000000; + /* + * === PORT F GROUP + * Ports : GPF7 GPF6 GPF5 GPF4 GPF3 GPF2 GPF1 GPF0 + * Signal : nLED_8 nLED_4 nLED_2 nLED_1 nIRQ_PCMCIA EINT2 KBDINT EINT0 + * Setting: Output Output Output Output EINT3 EINT2 EINT1 EINT0 + * Binary : 01 01 , 01 01 , 10 10 , 10 10 + */ + /* pulldown on GPF03: TP-4705+debug - debug conn will float */ + rGPFCON = 0x00008AAA; + rGPFUP = 0x000000FF & ~(1 << 3); + rGPFDAT = 0x00000000; + + + /* + * === PORT G GROUP + * Ports : GPG15 GPG14 GPG13 GPG12 GPG11 GPG10 GPG9 GPG8 GPG7 GPG6 + * Signal : nYPON YMON nXPON XMON EINT19 DMAMODE1 DMAMODE0 DMASTART KBDSPICLK KBDSPIMOSI + * Setting: nYPON YMON nXPON XMON EINT19 Output Output Output SPICLK1 SPIMOSI1 + * Binary : 11 11 , 11 11 , 10 01 , 01 01 , 11 11 + * ----------------------------------------------------------------------------------------- + * Ports : GPG5 GPG4 GPG3 GPG2 GPG1 GPG0 + * Signal : KBDSPIMISO LCD_PWREN EINT11 nSS_SPI IRQ_LAN IRQ_PCMCIA + * Setting: SPIMISO1 LCD_PWRDN EINT11 nSS0 EINT9 EINT8 + * Binary : 11 11 , 10 11 , 10 10 + */ + rGPGCON = 0x01AAFE79; + rGPGUP = 0x0000FFFF; + rGPGDAT = 0x00000000; + + /* + * === PORT H GROUP + * Ports : GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1 GPH0 + * Signal : CLKOUT1 CLKOUT0 UCLK RXD2 TXD2 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0 + * Binary : 10 , 10 10 , 11 11 , 10 10 , 10 10 , 10 10 + */ + +/* + * FIXME the following should be removed eventually and only the first stanza + * kept unconditionally. As it stands it allows TX and RTS to drive high into + * a powered-down GSM unit, which draws considerable fault current. + * + * However kernels earlier than andy-tracking from end Feb 2009 do not enforce + * the mode of these GPIOs, so Qi doing the correct thing here "breaks GSM" + * apparently for those users. + * + * Upgrading to current kernel will solve this, so after most distros are on + * 2.6.29-rc3 and later, we should return here and again disable driving out + * into unpowered GSM. + */ + +#if 0 + rGPHCON = 0x001AAA82; /* H1 and H2 are INPUTs to start with, not UART */ +#else + rGPHCON = 0x001AAAAA; /* Wrong but compatible: H1 and H2 = UART */ +#endif + + /* pulldown on GPH08: UEXTCLK, just floats! + * pulldown GPH1 -- nCTS0 / RTS_MODEM -- floats when GSM off + * pulldown GPH3 -- RXD[0] / RX_MODEM -- floats when GSM off + */ + rGPHUP = 0x000007FF & ~(1 << 8) & ~(1 << 1) & ~(1 << 3); + rGPHDAT = 0x00000000; + + /* pulldown on GPJ00: input, just floats! */ + /* pulldown on GPJ07: WLAN module WLAN_GPIO0, no ext pull */ + rGPJCON = 0x1551544; + rGPJUP = 0x1ffff & ~(1 << 0) & ~(1 << 7); + rGPJDAT = 0x00000100; + + rGPJDAT |= (1 << 4) | (1 << 6); + /* Set GPJ4 to high (nGSM_EN) */ + /* Set GPJ6 to high (nDL_GSM) */ + rGPJDAT &= ~(1 << 5); /* Set GPJ5 to low 3D RST */ + + /* leaving Glamo forced to Reset# active here killed + * U-Boot when you touched the memory region + */ + + rGPJDAT |= (1 << 5); /* Set GPJ5 to high 3D RST */ + + + /* + * We have to talk to the PMU a little bit + */ + + for (n = 0; n < ARRAY_SIZE(pcf50633_init); n++) + i2c_write_sync(&bb_s3c24xx, PCF50633_I2C_ADS, + pcf50633_init[n].index, pcf50633_init[n].value); + + /* what does the battery monitoring unit say about the battery? */ + + battery_condition_reasonable = !(i2c_read_sync(&bb_s3c24xx, + PCF50633_I2C_ADS, PCF50633_REG_BVMCTL) & 1); + + if (battery_condition_reasonable) { + /* change CPU clocking to 400MHz 1:4:8 */ + + /* clock divide 1:4:8 - do it first */ + *CLKDIVN = 5; + /* configure UPLL */ + *UPLLCON = ((88 << 12) + (4 << 4) + 2); + /* Magic delay: Page 7-19, seven nops between UPLL and MPLL */ + asm __volatile__ ( + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + ); + /* configure MPLL */ + *MPLLCON = ((42 << 12) + (1 << 4) + 0); + + /* get debug UART working at 115kbps */ + serial_init_115200_s3c24xx(GTA02_DEBUG_UART, 50 /* 50MHz */); + } else { + serial_init_115200_s3c24xx(GTA02_DEBUG_UART, 33 /* 33MHz */); + } + + /* we're going to use Glamo for SD Card access, so we need to init the + * evil beast + */ + glamo_core_init(); + + /* + * dynparts computation + */ + + n = 0; + while (n < ARRAY_SIZE(nand_dynparts)) { + + if (nand_dynparts[n].good_length) + while (nand_dynparts[n].good_length) { + if (!s3c2442_nand_is_bad_block(block512)) + nand_dynparts[n].good_length -= + GTA02_NAND_READBLOCK_SIZE; + block512 += GTA02_NAND_READBLOCK_SIZE / 512; + } + else + /* + * cannot afford to compute real size of last block + * set it to extent - end of last block + */ + block512 = nand_extent_block512; + + /* stash a copy of real offset for each partition */ + nand_dynparts[n].true_offset = start_block512; + + /* and the accurate length */ + nand_dynparts[n].good_length = block512 - start_block512; + + start_block512 = block512; + + n++; + } + + /* fix up the true start of kernel partition */ + + ((struct board_api *)&board_api_gta02)->kernel_source[3]. + offset_blocks512_if_no_partition = nand_dynparts[2].true_offset; + +} + +/** + * returns PCB revision information in b9,b8 and b2,b1,b0 + * Pre-GTA02 A6 returns 0x000 + * GTA02 A6 returns 0x001 + */ + +int gta02_get_pcb_revision(void) +{ + int n; + u32 u; + + /* make C13 and C15 pulled-down inputs */ + rGPCCON &= ~0xcc000000; + rGPCUP &= ~((1 << 13) | (1 << 15)); + /* D0, D3 and D4 pulled-down inputs */ + rGPDCON &= ~0x000003c3; + rGPDUP &= ~((1 << 0) | (1 << 3) | (1 << 4)); + + /* delay after changing pulldowns */ + u = rGPCDAT; + u = rGPDDAT; + + /* read the version info */ + u = rGPCDAT; + n = (u >> (13 - 0)) & 0x001; + n |= (u >> (15 - 1)) & 0x002; + u = rGPDDAT; + n |= (u << (0 + 2)) & 0x004; + + n |= (u << (3 - 3)) & 0x008; + n |= (u << (4 - 4)) & 0x010; + + /* + * when not being interrogated, all of the revision GPIO + * are set to output HIGH without pulldown so no current flows + * if they are NC or pulled up. + */ + /* make C13 and C15 high ouputs with no pulldowns */ + rGPCCON |= 0x44000000; + rGPCUP |= (1 << 13) | (1 << 15); + rGPCDAT |= (1 << 13) | (1 << 15); + /* D0, D3 and D4 high ouputs with no pulldowns */ + rGPDCON |= 0x00000141; + rGPDUP |= (1 << 0) | (1 << 3) | (1 << 4); + rGPDDAT |= (1 << 0) | (1 << 3) | (1 << 4); + + n &= 1; + + return n; +} + +int sd_card_init_gta02(void) +{ + extern int mmc_init(int verbose); + + return mmc_init(1); +} + +int sd_card_block_read_gta02(unsigned char * buf, unsigned long start512, + int blocks512) +{ +unsigned long mmc_bread(int dev_num, unsigned long blknr, unsigned long blkcnt, + void *dst); + + return mmc_bread(0, start512, blocks512, buf); +} + +/* return nonzero if we believe we run on GTA02 */ + +int is_this_board_gta02(void) +{ + /* look for GTA02 NOR */ + + *(volatile unsigned short *)(0x18000000) = 0x98; + + return !!(*(volatile unsigned short *)(0x18000000) == 0x0020); +} + +const struct board_variant const * get_board_variant_gta02(void) +{ + int rev = gta02_get_pcb_revision() & 0x1f; + + if (!board_variants[rev].name) + return &board_variants[1]; /* A6 */ + + return &board_variants[rev]; +} + +static __attribute__ (( section (".steppingstone") )) void putc_gta02(char c) +{ + serial_putc_s3c24xx(GTA02_DEBUG_UART, c); +} + +static void close_gta02(void) +{ + /* explicitly clear any pending 8s timeout */ + + i2c_write_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_OOCSHDWN, 0x04); + + /* clear any pending timeouts by reading interrupts */ + + i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT1); + i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT2); + i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT3); + i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT4); + i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT5); + + /* set I2C GPIO back to peripheral unit */ + + (bb_s3c24xx.close)(); + + /* aux back to being EINT */ + rGPFCON = 0x0000AAAA; + +} + +/* Here we will care only about AUX button as polling for PWR button + * through i2c slows down the boot */ + +static u8 get_ui_keys_gta02(void) +{ + u8 keys; + u8 ret = 0; + static u8 old_keys = 0; /* previous state for debounce */ + static u8 older_keys = 0; /* previous debounced output for edge detect */ + + /* GPF6 is AUX on GTA02, map to UI_ACTION_SKIPKERNEL, down = 1 */ + keys = !!(rGPFDAT & (1 << 6)); + + /* edge action */ + if ((old_keys & 1) && !(older_keys & 1)) + ret |= UI_ACTION_SKIPKERNEL; + + older_keys = old_keys; + old_keys = keys; + + return ret; +} + +static u8 get_ui_debug_gta02(void) +{ + /* PWR button state can be seen in OOCSTAT b0, down = 0, map to UI_ACTION_ADD_DEBUG */ + return !(i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_OOCSTAT) & 1); +} + +static void set_ui_indication_gta02(enum ui_indication ui_indication) +{ + + switch (ui_indication) { + case UI_IND_UPDATE_ONLY: + break; + + case UI_IND_MOUNT_PART: + case UI_IND_KERNEL_PULL_OK: + case UI_IND_INITRAMFS_PULL_OK: + if (battery_condition_reasonable) + rGPBDAT |= 4; + break; + + case UI_IND_KERNEL_PULL_FAIL: + case UI_IND_SKIPPING: + case UI_IND_INITRAMFS_PULL_FAIL: + case UI_IND_MOUNT_FAIL: + rGPBDAT &= ~4; + if (battery_condition_reasonable) { + rGPBDAT |= 8; + udelay(2000000); + rGPBDAT &= ~8; + udelay(200000); + } + break; + + case UI_IND_KERNEL_START: + case UI_IND_MEM_TEST: + case UI_IND_KERNEL_PULL: + case UI_IND_INITRAMFS_PULL: + rGPBDAT &= ~4; + break; + } +} + + +void post_serial_init_gta02(void) +{ + if (battery_condition_reasonable) + puts("Battery condition reasonable\n"); + else + puts("BATTERY CONDITION LOW\n"); +} + +/* + * Increment a hexadecimal digit represented by a char and + * return 1 if an overflow occured. + */ +static char inc_hexchar(char * p) +{ + if (*p == '9') + *p = 'A'; + else if (*p != 'F') + (*p)++; + else { + *p = '0'; + return 1; + } + return 0; +} + +/* + * create and append device-specific Linux kernel commandline + * + * This takes care of legacy dyanmic partition sizing and USB Ethernet + * MAC address identity information. + */ + +char * append_device_specific_cmdline_gta02(char * cmdline) +{ + int n = 0; + int i; + int len; + static char mac[64]; + struct kernel_source const * real_kernel = this_kernel; + + /* + * dynparts computation + */ + + cmdline += strlen(strcpy(cmdline, + " mtdparts=physmap-flash:-(nor);neo1973-nand:")); + + while (n < ARRAY_SIZE(nand_dynparts)) { + + *cmdline++ = '0'; + *cmdline++ = 'x'; + set32(cmdline, nand_dynparts[n].good_length * 512); + cmdline += 8; + *cmdline++ = '('; + cmdline += strlen(strcpy(cmdline, nand_dynparts[n].name)); + *cmdline++ = ')'; + + if (++n == ARRAY_SIZE(nand_dynparts)) + *cmdline++ = ' '; + else + *cmdline++ = ','; + + } + + *cmdline = '\0'; + + /* + * Identity + */ + + /* position ourselves at true start of GTA02 identity partition */ + partition_offset_blocks = nand_dynparts[4].true_offset; + partition_length_blocks = 0x40000 / 512; + + /* + * lie that we are in NAND context... GTA02 specific + * all filesystem access is completed before we are called + */ + this_kernel = &board_api_gta02.kernel_source[3]; + + if (!ext2fs_mount()) { + puts("Unable to mount ext2 filesystem\n"); + goto bail; + } + + len = ext2fs_open("usb"); + if (len < 0) { + puts(" Open failed\n"); + goto bail; + } + + n = ext2fs_read(mac, sizeof(mac)); + if (n < 0) { + puts(" Read failed\n"); + goto bail; + } + + mac[len] = '\0'; + + cmdline += strlen(strcpy(cmdline, " g_ether.dev_addr=")); + cmdline += strlen(strcpy(cmdline, &mac[2])); + + for (i = 0; i != 10; i++) { + if ((i % 3) == 2) + continue; + if (!inc_hexchar(mac + 18 - i)) + break; /* Carry not needed. */ + } + + cmdline += strlen(strcpy(cmdline, " g_ether.host_addr=")); + cmdline += strlen(strcpy(cmdline, &mac[2])); + *cmdline++ = ' ' ; +bail: + this_kernel = real_kernel; + + *cmdline = '\0'; + + return cmdline; +} + +/* + * our API for bootloader on this machine + */ + +const struct board_api board_api_gta02 = { + .name = "Freerunner / GTA02", + .linux_machine_id = 1304, + .linux_mem_start = 0x30000000, + .linux_mem_size = (128 * 1024 * 1024), + .linux_tag_placement = 0x30000000 + 0x100, + .get_board_variant = get_board_variant_gta02, + .is_this_board = is_this_board_gta02, + .port_init = port_init_gta02, + .post_serial_init = post_serial_init_gta02, + .append_device_specific_cmdline = append_device_specific_cmdline_gta02, + .putc = putc_gta02, + .close = close_gta02, + .get_ui_keys = get_ui_keys_gta02, + .get_ui_debug = get_ui_debug_gta02, + .set_ui_indication = set_ui_indication_gta02, + .commandline_board = "loglevel=4 " + "console=tty0 " + "console=ttySAC2,115200 " + "init=/sbin/init " + "ro ", + .commandline_board_debug = " loglevel=8", + .noboot = "boot/noboot-GTA02", + .append = "boot/append-GTA02", + /* these are the ways we could boot GTA02 in the order to try */ + .kernel_source = { + [0] = { + .name = "SD Card EXT2 P1 Kernel", + .block_init = sd_card_init_gta02, + .block_read = sd_card_block_read_gta02, + .partition_index = 1, + .filesystem = FS_EXT2, + .filepath = "boot/uImage-GTA02.bin", + .commandline_append = " root=/dev/mmcblk0p1 rootdelay=1 ", + }, + [1] = { + .name = "SD Card EXT2 P2 Kernel", + .block_init = sd_card_init_gta02, + .block_read = sd_card_block_read_gta02, + .partition_index = 2, + .filesystem = FS_EXT2, + .filepath = "boot/uImage-GTA02.bin", + .commandline_append = " root=/dev/mmcblk0p2 rootdelay=1 ", + }, + [2] = { + .name = "SD Card EXT2 P3 Kernel", + .block_init = sd_card_init_gta02, + .block_read = sd_card_block_read_gta02, + .partition_index = 3, + .filesystem = FS_EXT2, + .filepath = "boot/uImage-GTA02.bin", + .commandline_append = " root=/dev/mmcblk0p3 rootdelay=1 ", + }, + [3] = { + .name = "NAND Kernel", + .block_read = nand_read_ll, + /* NOTE offset below is replaced at runtime */ + .offset_blocks512_if_no_partition = 0x80000 / 512, + .filesystem = FS_RAW, + .commandline_append = " rootfstype=jffs2 " + "root=/dev/mtdblock6 ", + }, + }, +}; diff --git a/qiboot/src/cpu/s3c2442/i2c-bitbang-s3c24xx.c b/qiboot/src/cpu/s3c2442/i2c-bitbang-s3c24xx.c new file mode 100644 index 0000000..e68b9b9 --- /dev/null +++ b/qiboot/src/cpu/s3c2442/i2c-bitbang-s3c24xx.c @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * s3c24xx-specific i2c used by, eg, GTA02 + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include + +static char i2c_read_sda_s3c24xx(void) +{ + return (rGPEDAT & 0x8000) != 0; +} + +static void i2c_set_s3c24xx(char clock, char data) +{ + if (clock) /* SCL <- input */ + rGPECON = (rGPECON & ~0x30000000); + else { /* SCL <- output 0 */ + rGPEDAT = (rGPEDAT & ~0x4000); + rGPECON = (rGPECON & ~0x30000000) | 0x10000000; + } + if (data) /* SDA <- input */ + rGPECON = (rGPECON & ~0xc0000000); + else { /* SDA <- output 0 */ + rGPEDAT = (rGPEDAT & ~0x8000); + rGPECON = (rGPECON & ~0xc0000000) | 0x40000000; + } +} + +static void i2c_close_s3c24xx(void) +{ + /* set back to hardware I2C ready for Linux */ + rGPECON = (rGPECON & ~0xf0000000) | 0xa0000000; +} + +static void i2c_spin_s3c24xx(void) +{ + int n; + + for (n = 0; n < 1000; n++) + rGPJDAT |= (1 << 5); +} + +struct i2c_bitbang bb_s3c24xx = { + .read_sda = i2c_read_sda_s3c24xx, + .set = i2c_set_s3c24xx, + .spin = i2c_spin_s3c24xx, + .close = i2c_close_s3c24xx, +}; diff --git a/qiboot/src/cpu/s3c2442/lowlevel_init.S b/qiboot/src/cpu/s3c2442/lowlevel_init.S new file mode 100644 index 0000000..2a1654c --- /dev/null +++ b/qiboot/src/cpu/s3c2442/lowlevel_init.S @@ -0,0 +1,162 @@ +/* + * Memory Setup stuff - taken from blob memsetup.S + * + * Modified for the FIC Neo1973 GTA01 by Harald Welte + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* NOTE this stuff runs in steppingstone context! */ + + +/* + * #include + * #include + */ +#define __ASM_MODE__ +#include + +/* + * + * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S + * + * Copyright (C) 2002 Samsung Electronics SW.LEE + * + */ + +#define BWSCON 0x48000000 + +/* BWSCON */ +#define DW8 (0x0) +#define DW16 (0x1) +#define DW32 (0x2) +#define WAIT (0x1<<2) +#define UBLB (0x1<<3) + +#define B1_BWSCON (DW16 + WAIT + UBLB) +#define B2_BWSCON (DW16) +#define B3_BWSCON (DW16 + WAIT + UBLB) +#define B4_BWSCON (DW16) +#define B5_BWSCON (DW16) +#define B6_BWSCON (DW32) +#define B7_BWSCON (DW32) + +/* BANK0CON */ +#define B0_Tacs 0x0 /* 0clk */ +#define B0_Tcos 0x0 /* 0clk */ +#define B0_Tacc 0x7 /* 14clk */ +#define B0_Tcoh 0x0 /* 0clk */ +#define B0_Tah 0x0 /* 0clk */ +#define B0_Tacp 0x0 +#define B0_PMC 0x0 /* normal */ + +/* BANK1CON: Smedia Glamo 3362 (on GTA02) */ +#define B1_Tacs 0x0 /* 0clk */ +#define B1_Tcos 0x3 /* 4clk */ +#define B1_Tacc 0x3 /* 4clk */ +#define B1_Tcoh 0x3 /* 4clk */ +#define B1_Tah 0x0 /* 0clk */ +#define B1_Tacp 0x0 +#define B1_PMC 0x0 + +#define B2_Tacs 0x0 +#define B2_Tcos 0x0 +#define B2_Tacc 0x7 +#define B2_Tcoh 0x0 +#define B2_Tah 0x0 +#define B2_Tacp 0x0 +#define B2_PMC 0x0 + +#define B3_Tacs 0x0 /* 0clk */ +#define B3_Tcos 0x3 /* 4clk */ +#define B3_Tacc 0x7 /* 14clk */ +#define B3_Tcoh 0x1 /* 1clk */ +#define B3_Tah 0x0 /* 0clk */ +#define B3_Tacp 0x3 /* 6clk */ +#define B3_PMC 0x0 /* normal */ + +#define B4_Tacs 0x0 /* 0clk */ +#define B4_Tcos 0x0 /* 0clk */ +#define B4_Tacc 0x7 /* 14clk */ +#define B4_Tcoh 0x0 /* 0clk */ +#define B4_Tah 0x0 /* 0clk */ +#define B4_Tacp 0x0 +#define B4_PMC 0x0 /* normal */ + +#define B5_Tacs 0x0 /* 0clk */ +#define B5_Tcos 0x0 /* 0clk */ +#define B5_Tacc 0x7 /* 14clk */ +#define B5_Tcoh 0x0 /* 0clk */ +#define B5_Tah 0x0 /* 0clk */ +#define B5_Tacp 0x0 +#define B5_PMC 0x0 /* normal */ + +#define B6_MT 0x3 /* SDRAM */ +#define B6_Trcd 0x1 /* 3clk */ + +#define B6_SCAN 0x1 /* 9bit */ +#define B7_SCAN 0x1 /* 9bit */ + + +#define B7_MT 0x3 /* SDRAM */ +#define B7_Trcd 0x1 /* 3clk */ + +/* REFRESH parameter */ +#define REFEN 0x1 /* Refresh enable */ +#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ +#define Trp 0x1 /* 3clk */ +#define Trc 0x3 /* 7clk */ +#define Tchr 0x2 /* 3clk */ +//#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */ +#define REFCNT 997 /* period=17.5us, HCLK=60Mhz, (2048+1-15.6*60) */ +/**************************************/ + +.globl lowlevel_init +lowlevel_init: + + ldr r0, =SMRDATA + ldr r1, =BWSCON /* Bus Width Status Controller */ + add r2, r0, #13*4 +0: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r2, r0 + bne 0b + + /* setup asynchronous bus mode */ + mrc p15, 0, r1 ,c1 ,c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 + + /* everything is fine now */ + mov pc, lr + + .ltorg +/* the literal pools origin */ +SMRDATA: + .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) + .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) + .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) + .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) + .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) + .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) + .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) + .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) + .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) + .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) + .word 0xb1 + .word 0x30 + .word 0x30 diff --git a/qiboot/src/cpu/s3c2442/nand_read.c b/qiboot/src/cpu/s3c2442/nand_read.c new file mode 100644 index 0000000..8206717 --- /dev/null +++ b/qiboot/src/cpu/s3c2442/nand_read.c @@ -0,0 +1,156 @@ +/* + * nand_read.c: Simple NAND read functions for booting from NAND + * + * This is used by cpu/arm920/start.S assembler code, + * and the board-specific linker script must make sure this + * file is linked within the first 4kB of NAND flash. + * + * Taken from GPLv2 licensed vivi bootloader, + * Copyright (C) 2002 MIZI Research, Inc. + * + * Author: Hwang, Chideok + * Date : $Date: 2004/02/04 10:37:37 $ + * + * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. + * Author: Harald Welte + */ + +/* NOTE this stuff runs in steppingstone context! */ + +/* the API refers to 512-byte blocks */ + +#include +#include "nand_read.h" + +#define NAND_CMD_READ0 0 +#define NAND_CMD_READSTART 0x30 + +#define __REGb(x) (*(volatile unsigned char *)(x)) +#define __REGw(x) (*(volatile unsigned short *)(x)) +#define __REGi(x) (*(volatile unsigned int *)(x)) +#define NF_BASE 0x4e000000 +#define NFCONF __REGi(NF_BASE + 0x0) +#define NFCONT __REGi(NF_BASE + 0x4) +#define NFCMD __REGb(NF_BASE + 0x8) +#define NFADDR __REGb(NF_BASE + 0xc) +#define NFDATA __REGb(NF_BASE + 0x10) +#define NFDATA16 __REGw(NF_BASE + 0x10) +#define NFSTAT __REGb(NF_BASE + 0x20) +#define NFSTAT_BUSY 1 +#define nand_select() (NFCONT &= ~(1 << 1)) +#define nand_deselect() (NFCONT |= (1 << 1)) +#define nand_clear_RnB() (NFSTAT |= (1 << 2)) + +static inline void nand_wait(void) +{ + int i; + + while (!(NFSTAT & NFSTAT_BUSY)) + for (i=0; i<10; i++); +} + +/* configuration for 2440 with 2048byte sized flash */ +#define NAND_5_ADDR_CYCLE +#define NAND_PAGE_SIZE 2048 +#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE +#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1) +#define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64) + +int s3c2442_nand_is_bad_block(unsigned long block_index) +{ + unsigned char data; + unsigned long page_num; + + nand_select(); + nand_clear_RnB(); + page_num = block_index >> 2; /* addr / 2048 */ + NFCMD = NAND_CMD_READ0; + NFADDR = BAD_BLOCK_OFFSET & 0xff; + NFADDR = (BAD_BLOCK_OFFSET >> 8) & 0xff; + NFADDR = page_num & 0xff; + NFADDR = (page_num >> 8) & 0xff; + NFADDR = (page_num >> 16) & 0xff; + NFCMD = NAND_CMD_READSTART; + nand_wait(); + data = (NFDATA & 0xff); + + if (data != 0xff) + return 1; + + return 0; +} + +static int nand_read_page_ll(unsigned char *buf, unsigned long block512, int blocks512) +{ + unsigned short *ptr16 = (unsigned short *)buf; + unsigned int i, page_num; + unsigned int block_amount; + int blocks_possible = (3 - (block512 & 3)) + 1; + + + if (blocks512 > blocks_possible) + blocks512 = blocks_possible; + + block_amount = (NAND_PAGE_SIZE / 4 / 2) * blocks512; + + nand_clear_RnB(); + + NFCMD = NAND_CMD_READ0; + + page_num = block512 >> 2; /* 512 block -> 2048 block */ + /* Write Address */ + NFADDR = 0; + NFADDR = (block512 & 3) << 1; /* which 512 block in 2048 */ + NFADDR = page_num & 0xff; + NFADDR = (page_num >> 8) & 0xff; + NFADDR = (page_num >> 16) & 0xff; + NFCMD = NAND_CMD_READSTART; + nand_wait(); + + for (i = 0; i < block_amount; i++) + *ptr16++ = NFDATA16; + + return blocks512; +} + + +/* low level nand read function */ +int nand_read_ll(unsigned char *buf, unsigned long start_block512, + int blocks512) +{ + int i, j; + + /* chip Enable */ + nand_select(); + nand_clear_RnB(); + + for (i = 0; i < 10; i++) + ; + + while (blocks512 > 0) { + if (s3c2442_nand_is_bad_block(start_block512)) { + start_block512 += 4; + if (start_block512 >> 2 > BAD_BLOCK_OFFSET) + /* end of NAND */ + return -1; + continue; + } + + j = nand_read_page_ll(buf, start_block512, blocks512); + start_block512 += j; + buf += j << 9; + blocks512 -= j; + + if (this_board->get_ui_keys) + if ((this_board->get_ui_keys)() & UI_ACTION_SKIPKERNEL) { + puts(" ** skipping \n"); + return -3; + } + } + + /* chip Disable */ + nand_deselect(); + + return 0; +} + diff --git a/qiboot/src/cpu/s3c2442/nand_read.h b/qiboot/src/cpu/s3c2442/nand_read.h new file mode 100644 index 0000000..71aeda5 --- /dev/null +++ b/qiboot/src/cpu/s3c2442/nand_read.h @@ -0,0 +1,22 @@ +/* + * nand_read.c: Simple NAND read functions for booting from NAND + * + * This is used by cpu/arm920/start.S assembler code, + * and the board-specific linker script must make sure this + * file is linked within the first 4kB of NAND flash. + * + * Taken from GPLv2 licensed vivi bootloader, + * Copyright (C) 2002 MIZI Research, Inc. + * + * Author: Hwang, Chideok + * Date : $Date: 2004/02/04 10:37:37 $ + * + * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. + * Author: Harald Welte + */ +#ifndef __NAND_READ_H +#define __NAND_READ_H + +int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size); + +#endif /* __NAND_READ_H */ diff --git a/qiboot/src/cpu/s3c2442/qi.lds b/qiboot/src/cpu/s3c2442/qi.lds new file mode 100644 index 0000000..600f950 --- /dev/null +++ b/qiboot/src/cpu/s3c2442/qi.lds @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + __steppingstone_always = 0x40000000; + __qi_sdram_copy = 0x33000000; + + . = __steppingstone_always; + + /* this is intended to take the first 4KBytes of stuff initially. + * We have to make sure we have .rodata* in there for everything + * because we do not compile PIC. + */ + + .text __steppingstone_always : AT (0x0) + { + src/cpu/s3c2442/start.o (.text .rodata* .data .bss) + src/cpu/s3c2442/lowlevel_init.o (.text .rodata* .data .bss) + src/cpu/s3c2442/start_qi.o (.text .rodata* .data .bss) + src/cpu/s3c2442/nand_read.o (.text .rodata* .data .bss) + src/cpu/s3c2442/serial-s3c24xx.o (.text .rodata* .data .bss) + src/memory-test.o (.text .rodata* .data .bss) + src/utils.o (.text .rodata* .data .bss) + src/ctype.o (.text .rodata* .data .bss) + * (.steppingstone) + } + + . = ALIGN(4); + .everything_else ADDR (.text) - __steppingstone_always + SIZEOF (.text) + __qi_sdram_copy : + AT ( ADDR (.text) - __steppingstone_always + SIZEOF (.text) ) { *(.text .rodata* .data) } + + . = __qi_sdram_copy + 0x800000 ; + __bss_start = .; + .bss (NOLOAD) : + { + *(.bss) + } + + _end = .; +} diff --git a/qiboot/src/cpu/s3c2442/s3c24xx-mci.c b/qiboot/src/cpu/s3c2442/s3c24xx-mci.c new file mode 100644 index 0000000..42eecb9 --- /dev/null +++ b/qiboot/src/cpu/s3c2442/s3c24xx-mci.c @@ -0,0 +1,569 @@ +/* + * qi s3c24xx SD card driver + * Author: Andy Green + * based on ----> + * + * u-boot S3C2410 MMC/SD card driver + * (C) Copyright 2006 by OpenMoko, Inc. + * Author: Harald Welte + * + * based on u-boot pxa MMC driver and linux/drivers/mmc/s3c2410mci.c + * (C) 2005-2005 Thomas Kleffel + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#define SDICON (*(u32 *)0x5a000000) +#define SDIPRE (*(u32 *)0x5a000004) +#define SDICARG (*(u32 *)0x5a000008) +#define SDICCON (*(u32 *)0x5a00000c) +#define SDICSTA (*(u32 *)0x5a000010) +#define SDIRSP0 (*(u32 *)0x5a000014) +#define SDIRSP1 (*(u32 *)0x5a000018) +#define SDIRSP2 (*(u32 *)0x5a00001c) +#define SDIRSP3 (*(u32 *)0x5a000020) +#define SDIDTIMER (*(u32 *)0x5a000024) +#define SDIBSIZE (*(u32 *)0x5a000028) +#define SDIDCON (*(u32 *)0x5a00002c) +#define SDIDCNT (*(u32 *)0x5a000030) +#define SDIDSTA (*(u32 *)0x5a000034) +#define SDIFSTA (*(u32 *)0x5a000038) +/* s3c2410 in GTA01 has these two last ones the other way around!!! */ +#define SDIIMSK (*(u32 *)0x5a00003c) +#define SDIDAT (*(u32 *)0x5a000040) +#define SDIDAT2410 (*(u32 *)0x5a00003c) +#define SDIIMSK2410 (*(u32 *)0x5a000040) + +#define CFG_MMC_BASE 0xff000000 + +/* FIXME: anyone who wants to use this on GTA01 / s3c2410 need to + * have this return 1 on that CPU + */ + +int am_i_s3c2410(void) +{ + return 0; +} + +#define CONFIG_MMC_WIDE +#define MMC_BLOCK_SIZE 512 + +/* + * FIXME needs to read cid and csd info to determine block size + * and other parameters + */ +static u8 mmc_buf[MMC_BLOCK_SIZE]; +static mmc_csd_t mmc_csd; +static int mmc_ready = 0; +static int wide = 0; + + +#define CMD_F_RESP 0x01 +#define CMD_F_RESP_LONG 0x02 + +static u32 *mmc_cmd(u16 cmd, u32 arg, u16 flags) +{ + static u32 resp[5]; + + u32 ccon, csta; + u32 csta_rdy_bit = S3C2410_SDICMDSTAT_CMDSENT; + + memset(resp, 0, sizeof(resp)); + +// debug("mmc_cmd CMD%d arg=0x%08x flags=%x\n", cmd, arg, flags); + + SDICSTA = 0xffffffff; + SDIDSTA = 0xffffffff; + SDIFSTA = 0xffffffff; + + SDICARG = arg; + + ccon = cmd & S3C2410_SDICMDCON_INDEX; + ccon |= S3C2410_SDICMDCON_SENDERHOST|S3C2410_SDICMDCON_CMDSTART; + + if (flags & CMD_F_RESP) { + ccon |= S3C2410_SDICMDCON_WAITRSP; + csta_rdy_bit = S3C2410_SDICMDSTAT_RSPFIN; /* 1 << 9 */ + } + + if (flags & CMD_F_RESP_LONG) + ccon |= S3C2410_SDICMDCON_LONGRSP; + + SDICCON = ccon; + + while (1) { + csta = SDICSTA; + if (csta & csta_rdy_bit) + break; + if (csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { + puts("===============> MMC CMD Timeout\n"); + SDICSTA |= S3C2410_SDICMDSTAT_CMDTIMEOUT; + break; + } + } + +// debug("final MMC CMD status 0x%x\n", csta); + + SDICSTA |= csta_rdy_bit; + + if (flags & CMD_F_RESP) { + resp[0] = SDIRSP0; + resp[1] = SDIRSP1; + resp[2] = SDIRSP2; + resp[3] = SDIRSP3; + } + + return resp; +} + +#define FIFO_FILL() ((SDIFSTA & S3C2410_SDIFSTA_COUNTMASK) >> 2) + +static int mmc_block_read(u8 *dst, u32 src, u32 len) +{ + u32 dcon, fifo; + u32 *dst_u32 = (u32 *)dst; + u32 *resp; + + if (len == 0) + return 0; + +// debug("mmc_block_rd dst %lx src %lx len %d\n", (u32)dst, src, len); + + /* set block len */ + resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, len, CMD_F_RESP); + SDIBSIZE = len; + + //SDIPRE = 0xff; + + /* setup data */ + dcon = (len >> 9) & S3C2410_SDIDCON_BLKNUM; + dcon |= S3C2410_SDIDCON_BLOCKMODE; + dcon |= S3C2410_SDIDCON_RXAFTERCMD|S3C2410_SDIDCON_XFER_RXSTART; + if (wide) + dcon |= S3C2410_SDIDCON_WIDEBUS; + + if (!am_i_s3c2410()) + dcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART; + + SDIDCON = dcon; + + /* send read command */ + resp = mmc_cmd(MMC_CMD_READ_BLOCK, src, CMD_F_RESP); + + while (len > 0) { + u32 sdidsta = SDIDSTA; + fifo = FIFO_FILL(); + if (sdidsta & (S3C2410_SDIDSTA_FIFOFAIL| + S3C2410_SDIDSTA_CRCFAIL| + S3C2410_SDIDSTA_RXCRCFAIL| + S3C2410_SDIDSTA_DATATIMEOUT)) { + puts("mmc_block_read: err SDIDSTA=0x"); + print32(sdidsta); + puts("\n"); + return -1; + } + + if (am_i_s3c2410()) { + while (fifo--) { + //debug("dst_u32 = 0x%08x\n", dst_u32); + *(dst_u32++) = SDIDAT2410; + if (len >= 4) + len -= 4; + else { + len = 0; + break; + } + } + } else { + while (fifo--) { + //debug("dst_u32 = 0x%08x\n", dst_u32); + *(dst_u32++) = SDIDAT; + if (len >= 4) + len -= 4; + else { + len = 0; + break; + } + } + } + } + +// debug("waiting for SDIDSTA (currently 0x%08x\n", SDIDSTA); + while (!(SDIDSTA & (1 << 4))) {} +// debug("done waiting for SDIDSTA (currently 0x%08x\n", SDIDSTA); + + SDIDCON = 0; + + if (!(SDIDSTA & S3C2410_SDIDSTA_XFERFINISH)) + puts("mmc_block_read; transfer not finished!\n"); + + return 0; +} + +static int mmc_block_write(u32 dst, u8 *src, int len) +{ + puts("MMC block write not yet supported on S3C2410!\n"); + return -1; +} + + +int s3c24xx_mmc_read(u32 src, u8 *dst, int size) +{ + u32 end, part_start, part_end, part_len, aligned_start, aligned_end; + u32 mmc_block_size, mmc_block_address; + + if (size == 0) + return 0; + + if (!mmc_ready) { + puts("Please initialize the MMC first\n"); + return -1; + } + + mmc_block_size = MMC_BLOCK_SIZE; + mmc_block_address = ~(mmc_block_size - 1); + + src -= CFG_MMC_BASE; + end = src + size; + part_start = ~mmc_block_address & src; + part_end = ~mmc_block_address & end; + aligned_start = mmc_block_address & src; + aligned_end = mmc_block_address & end; + + /* all block aligned accesses */ +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_start) { + part_len = mmc_block_size - part_start; +// debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) + return -1; + + memcpy(dst, mmc_buf+part_start, part_len); + dst += part_len; + src += part_len; + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) { +// debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read((u8 *)(dst), src, mmc_block_size)) < 0) + return -1; + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_end && src < end) { +// debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) + return -1; + + memcpy(dst, mmc_buf, part_end); + } + return 0; +} + +int s3c24xx_mmc_write(u8 *src, u32 dst, int size) +{ + u32 end, part_start, part_end, part_len, aligned_start, aligned_end; + u32 mmc_block_size, mmc_block_address; + + if (size == 0) + return 0; + + if (!mmc_ready) { + puts("Please initialize the MMC first\n"); + return -1; + } + + mmc_block_size = MMC_BLOCK_SIZE; + mmc_block_address = ~(mmc_block_size - 1); + + dst -= CFG_MMC_BASE; + end = dst + size; + part_start = ~mmc_block_address & dst; + part_end = ~mmc_block_address & end; + aligned_start = mmc_block_address & dst; + aligned_end = mmc_block_address & end; + + /* all block aligned accesses */ +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_start) { + part_len = mmc_block_size - part_start; +// debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// (u32)src, dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) + return -1; + + memcpy(mmc_buf+part_start, src, part_len); + if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < 0) + return -1; + + dst += part_len; + src += part_len; + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) { +// debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_write(dst, (u8 *)src, mmc_block_size)) < 0) + return -1; + + } +// debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if (part_end && dst < end) { +// debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", +// src, (u32)dst, end, part_start, part_end, aligned_start, aligned_end); + if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) + return -1; + + memcpy(mmc_buf, src, part_end); + if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) + return -1; + + } + return 0; +} + +u32 s3c24xx_mmc_bread(int dev_num, u32 blknr, u32 blkcnt, void *dst) +{ + int mmc_block_size = MMC_BLOCK_SIZE; + u32 src = blknr * mmc_block_size + CFG_MMC_BASE; + + s3c24xx_mmc_read(src, dst, blkcnt*mmc_block_size); + return blkcnt; +} + +/* MMC_DEFAULT_RCA should probably be just 1, but this may break other code + that expects it to be shifted. */ +static u_int16_t rca = MMC_DEFAULT_RCA >> 16; + +#if 0 +static u32 mmc_size(const struct mmc_csd *csd) +{ + u32 block_len, mult, blocknr; + + block_len = csd->read_bl_len << 12; + mult = csd->c_size_mult1 << 8; + blocknr = (csd->c_size+1) * mult; + + return blocknr * block_len; +} +#endif + +struct sd_cid { + char pnm_0; /* product name */ + char oid_1; /* OEM/application ID */ + char oid_0; + uint8_t mid; /* manufacturer ID */ + char pnm_4; + char pnm_3; + char pnm_2; + char pnm_1; + uint8_t psn_2; /* product serial number */ + uint8_t psn_1; + uint8_t psn_0; /* MSB */ + uint8_t prv; /* product revision */ + uint8_t crc; /* CRC7 checksum, b0 is unused and set to 1 */ + uint8_t mdt_1; /* manufacturing date, LSB, RRRRyyyy yyyymmmm */ + uint8_t mdt_0; /* MSB */ + uint8_t psn_3; /* LSB */ +}; + +static void print_mmc_cid(mmc_cid_t *cid) +{ + puts("MMC found. Card desciption is:\n"); + puts("Manufacturer ID = "); + print8(cid->id[0]); + print8(cid->id[1]); + print8(cid->id[2]); + puts("\nHW/FW Revision = "); + print8(cid->hwrev); + print8(cid->fwrev); + cid->hwrev = cid->fwrev = 0; /* null terminate string */ + puts("Product Name = "); + puts((char *)cid->name); + puts("\nSerial Number = "); + print8(cid->sn[0]); + print8(cid->sn[1]); + print8(cid->sn[2]); + puts("\nMonth = "); + printdec(cid->month); + puts("\nYear = "); + printdec(1997 + cid->year); + puts("\n"); +} + +static void print_sd_cid(const struct sd_cid *cid) +{ + puts("Manufacturer: 0x"); + print8(cid->mid); + puts("OEM \""); + this_board->putc(cid->oid_0); + this_board->putc(cid->oid_1); + puts("\"\nProduct name: \""); + this_board->putc(cid->pnm_0); + this_board->putc(cid->pnm_1); + this_board->putc(cid->pnm_2); + this_board->putc(cid->pnm_3); + this_board->putc(cid->pnm_4); + puts("\", revision "); + printdec(cid->prv >> 4); + puts("."); + printdec(cid->prv & 15); + puts("\nSerial number: "); + printdec(cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 | + cid->psn_3); + puts("\nManufacturing date: "); + printdec(cid->mdt_1 & 15); + puts("/"); + printdec(2000+((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4)); + puts("\nCRC: 0x"); + print8(cid->crc >> 1); + puts(" b0 = "); + print8(cid->crc & 1); + puts("\n"); +} + +int s3c24xx_mmc_init(int verbose) +{ + int retries, rc = -2; + int is_sd = 0; + u32 *resp; + + SDICON = S3C2410_SDICON_FIFORESET | S3C2410_SDICON_CLOCKTYPE; + SDIBSIZE = 512; + if (am_i_s3c2410()) { + /* S3C2410 has some bug that prevents reliable operation at higher speed */ + //SDIPRE = 0x3e; /* SDCLK = PCLK/2 / (SDIPRE+1) = 396kHz */ + SDIPRE = 0x02; /* 2410: SDCLK = PCLK/2 / (SDIPRE+1) = 11MHz */ + SDIDTIMER = 0xffff; + SDIIMSK2410 = 0x0; + } else { + SDIPRE = 0x05; /* 2410: SDCLK = PCLK / (SDIPRE+1) = 11MHz */ + SDIDTIMER = 0x7fffff; + SDIIMSK = 0x0; + } + + udelay(1250000); /* FIXME: 74 SDCLK cycles */ + + mmc_csd.c_size = 0; + + puts("Sending reset...\n"); + + /* reset */ + retries = 10; + resp = mmc_cmd(MMC_CMD_RESET, 0, 0); + + puts("trying to detect SD Card...\n"); + while (retries--) { + udelay(1000000); + resp = mmc_cmd(55, 0x00000000, CMD_F_RESP); + resp = mmc_cmd(41, 0x00300000, CMD_F_RESP); + + if (resp[0] & (1 << 31)) { + is_sd = 1; + break; + } + } + + if (retries < 0 && !is_sd) + return -3; + + /* try to get card id */ + resp = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, CMD_F_RESP|CMD_F_RESP_LONG); + if (resp) { + if (!is_sd) { + /* TODO configure mmc driver depending on card + attributes */ + mmc_cid_t *cid = (mmc_cid_t *)resp; + + if (verbose) + print_mmc_cid(cid); +#if 0 + sprintf((char *) mmc_dev.vendor, + "Man %02x%02x%02x Snr %02x%02x%02x", + cid->id[0], cid->id[1], cid->id[2], + cid->sn[0], cid->sn[1], cid->sn[2]); + sprintf((char *) mmc_dev.product,"%s",cid->name); + sprintf((char *) mmc_dev.revision,"%x %x", + cid->hwrev, cid->fwrev); +#endif + } + else { + struct sd_cid *cid = (struct sd_cid *) resp; + + if (verbose) + print_sd_cid(cid); +#if 0 + sprintf((char *) mmc_dev.vendor, + "Man %02 OEM %c%c \"%c%c%c%c%c\"", + cid->mid, cid->oid_0, cid->oid_1, + cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, + cid->pnm_4); + sprintf((char *) mmc_dev.product, "%d", + cid->psn_0 << 24 | cid->psn_1 << 16 | + cid->psn_2 << 8 | cid->psn_3); + sprintf((char *) mmc_dev.revision, "%d.%d", + cid->prv >> 4, cid->prv & 15); +#endif + } + + + /* MMC exists, get CSD too */ + resp = mmc_cmd(MMC_CMD_SET_RCA, MMC_DEFAULT_RCA, CMD_F_RESP); + if (is_sd) + rca = resp[0] >> 16; + + resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, CMD_F_RESP|CMD_F_RESP_LONG); + if (resp) { + mmc_csd_t *csd = (mmc_csd_t *)resp; + memcpy(&mmc_csd, csd, sizeof(csd)); + rc = 0; + mmc_ready = 1; +#if 0 + /* FIXME add verbose printout for csd */ + printf("READ_BL_LEN=%u, C_SIZE_MULT=%u, C_SIZE=%u\n", + csd->read_bl_len, csd->c_size_mult1, csd->c_size); + printf("size = %u\n", mmc_size(csd)); +#endif + } + } + + resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca<<16, CMD_F_RESP); + +#ifdef CONFIG_MMC_WIDE + if (is_sd) { + resp = mmc_cmd(55, rca<<16, CMD_F_RESP); + resp = mmc_cmd(6, 0x02, CMD_F_RESP); + wide = 1; + } +#endif + + return rc; +} + + diff --git a/qiboot/src/cpu/s3c2442/serial-s3c24xx.c b/qiboot/src/cpu/s3c2442/serial-s3c24xx.c new file mode 100644 index 0000000..0f4ba22 --- /dev/null +++ b/qiboot/src/cpu/s3c2442/serial-s3c24xx.c @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +void serial_init_115200_s3c24xx(const int uart, const int pclk_MHz) +{ + int div = (((54 * pclk_MHz) + 26) / 100) -1; + switch(uart) + { + case UART0: + rULCON0 = 0x3; + rUCON0 = 0x245; + rUFCON0 = 0x0; + rUMCON0 = 0x0; + rUBRDIV0 = div; + break; + case UART1: + rULCON1 = 0x3; + rUCON1 = 0x245; + rUFCON1 = 0x0; + rUMCON1 = 0x0; + rUBRDIV1 = div; + break; + case UART2: + rULCON2 = 0x3; + rUCON2 = 0x245; + rUFCON2 = 0x1; + rUBRDIV2 = div; + break; + default: + break; + } +} +/* + * Output a single byte to the serial port. + */ +void serial_putc_s3c24xx(const int uart, const char c) +{ + switch(uart) + { + case UART0: + while ( !( rUTRSTAT0 & 0x2 ) ); + WrUTXH0(c); + break; + case UART1: + while ( !( rUTRSTAT1 & 0x2 ) ); + WrUTXH1(c); + break; + case UART2: + while ( !( rUTRSTAT2 & 0x2 ) ); + WrUTXH2(c); + break; + default: + break; + } +} diff --git a/qiboot/src/cpu/s3c2442/start.S b/qiboot/src/cpu/s3c2442/start.S new file mode 100644 index 0000000..6ff9194 --- /dev/null +++ b/qiboot/src/cpu/s3c2442/start.S @@ -0,0 +1,315 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define __ASM_MODE__ +#define __ASSEMBLY__ + +#include + +#define S3C2410_MISCCR_nEN_SCLK0 (1 << 17) +#define S3C2410_MISCCR_nEN_SCLK1 (1 << 18) +#define S3C2410_MISCCR_nEN_SCLKE (1 << 19) + + +.globl _start, processor_id, is_jtag + +_start: b start_code +/* if we are injected by JTAG, the script sets _istag content to nonzero */ +is_jtag: + .word 0 + +/* it's at a fixed address (+0x8) so we can breakpoint it in the JTAG script + * we need to go through this hassle because before this moment, SDRAM is not + * working so we can't prep it from JTAG + */ + +_steppingstone_done: + ldr pc, _start_armboot + +_start_armboot: + .word start_qi + +_TEXT_BASE: + .word TEXT_BASE + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end +/* + * we have a stack in steppingstone because we can want to run full memory + * memory tests + */ + + .fill 128 +.globl _ss_stack +_ss_stack: + + +start_code: + /* + * set the cpu to SVC32 mode + */ + mrs r0,cpsr + bic r0,r0,#0x1f + orr r0,r0,#0xd3 + msr cpsr,r0 + +# define pWTCON 0x53000000 + + ldr r0, =pWTCON + mov r1, #0x0 + str r1, [r0] + + /* + * mask all IRQs by setting all bits in the INTMR - default + */ +# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ +# define INTSUBMSK 0x4A00001C +# define INTSUBMSK_val 0x0000ffff + + mov r1, #0xffffffff + ldr r0, =INTMSK + str r1, [r0] + + ldr r1, =INTSUBMSK_val + ldr r0, =INTSUBMSK + str r1, [r0] + + + /* Make sure we get FCLK:HCLK:PCLK = 1:3:6 */ +# define CAMDIVN 0x4C000018 + + ldr r0, =CAMDIVN + mov r1, #0 + str r1, [r0] + + /* Clock asynchronous mode */ + mrc p15, 0, r1, c1, c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 + +#define LOCKTIME 0x4c000000 + + ldr r0, =LOCKTIME + mov r1, #0xffffff + str r1, [r0] + +# define UPLLCON 0x4c000008 +# define MPLLCON_val ((142 << 12) + (7 << 4) + 1) +# define UPLLCON_val (( 88 << 12) + (8 << 4) + 2) + + ldr r0, =UPLLCON + ldr r1, =UPLLCON_val + str r1, [r0] + + /* Page 7-19, seven nops between UPLL and MPLL */ + nop + nop + nop + nop + nop + nop + nop + + ldr r1, =MPLLCON_val + str r1, [r0, #-4] /* MPLLCON */ + +# define CLKDIVN 0x4C000014 /* clock divisor register */ +# define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */ + + /* FCLK:HCLK:PCLK = 1:3:6 */ + ldr r0, =CLKDIVN + mov r1, #CLKDIVN_val + str r1, [r0] + + /* enable only CPU peripheral block clocks we actually use */ + ldr r0, =0x4c00000c /* clkcon */ + ldr r1, =0x3f10 /* uart, pwm, gpio, nand, sdi clocks on */ + str r1, [r0] + + /* gpio UART2 init, H port */ + ldr r0, =0x56000070 + ldr r1, =0x001AAAAA + str r1, [r0] + + /* enable KEEPACT(GPJ8) to make sure PMU keeps us alive */ + ldr r0, =0x56000000 /* GPJ base */ + ldr r1, [r0, #0xd0] /* GPJCON */ + orr r1, r1, #(1 << 16) + str r1, [r0, #0xd0] + + ldr r1, [r0, #0xd4] /* GPJDAT */ + orr r1, r1, #(1 << 8) + str r1, [r0, #0xd4] + + + /* init uart2 */ + ldr r0, =0x50008000 + mov r1, #0x03 + str r1, [r0] + ldr r1, =0x245 + str r1, [r0, #0x04] + mov r1, #0x00 + str r1, [r0, #0x08] + mov r1, #0x00 + str r1, [r0, #0x0c] + mov r1, #0x11 + str r1, [r0, #0x28] + + ldr r0, =0x50008000 + ldr r1, =0x54 + str r1, [r0, #0x20] + +/* reset nand controller, or it is dead to us */ + + mov r1, #0x4E000000 + ldr r2, =0xfff0 @ initial value tacls=3,rph0=7,rph1=7 + ldr r3, [r1, #0] + orr r3, r3, r2 + str r3, [r1, #0] + + ldr r3, [r1, #4] + orr r3, r3, #1 @ enable nand controller + str r3, [r1, #4] + + + /* take sdram out of power down */ + ldr r0, =0x56000080 /* misccr */ + ldr r1, [ r0 ] + bic r1, r1, #(S3C2410_MISCCR_nEN_SCLK0 | S3C2410_MISCCR_nEN_SCLK1 | S3C2410_MISCCR_nEN_SCLKE) + str r1, [ r0 ] + + /* ensure signals stabalise */ + mov r1, #128 +1: subs r1, r1, #1 + bpl 1b + + bl cpu_init_crit + + /* ensure some refresh has happened */ + ldr r1, =0xfffff +1: subs r1, r1, #1 + bpl 1b + + /* capture full EINT situation into gstatus 4 */ + + ldr r0, =0x4A000000 /* SRCPND */ + ldr r1, [ r0 ] + and r1, r1, #0xf + + ldr r0, =0x560000BC /* gstatus4 */ + str r1, [ r0 ] + + ldr r0, =0x560000A8 /* EINTPEND */ + ldr r1, [ r0 ] + ldr r0, =0xfff0 + and r1, r1, r0 + ldr r0, =0x560000BC /* gstatus4 */ + ldr r0, [ r0 ] + orr r1, r1, r0 + ldr r0, =0x560000BC /* gstatus4 */ + str r1, [ r0 ] + + /* test for resume */ + + ldr r1, =0x560000B4 /* gstatus2 */ + ldr r0, [ r1 ] + tst r0, #0x02 /* is this resume from power down */ + /* well, if it was, we are going to jump to + * whatever address we stashed in gstatus3, + * and gstatus4 will hold the wake interrupt + * source for the OS to look at + */ + ldrne pc, [r1, #4] + + + /* >> CFG_VIDEO_LOGO_MAX_SIZE */ +#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ + +stack_setup: + ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ + sub sp, r0, #12 /* leave 3 words for abort-stack */ + +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0x00000000 /* clear */ + +clbss_l: + str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + +/* we are going to jump into the C part of the init now */ +spin: + b _steppingstone_done + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ + +cpu_init_crit: + + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00005000 @ set bits 14, 12 D and I-Cache + mcr p15, 0, r0, c1, c0, 0 + + /* + * before relocating, we have to setup RAM timing + * because memory timing is board-dependend, you will + * find a lowlevel_init.S in your board directory. + */ + mov ip, lr + + bl lowlevel_init + + mov lr, ip + mov pc, lr + diff --git a/qiboot/src/cpu/s3c2442/start_qi.c b/qiboot/src/cpu/s3c2442/start_qi.c new file mode 100644 index 0000000..d7136fd --- /dev/null +++ b/qiboot/src/cpu/s3c2442/start_qi.c @@ -0,0 +1,126 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * Andy Green + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* NOTE this stuff runs in steppingstone context! */ + + +#include +#include "nand_read.h" +#include + +#define stringify2(s) stringify1(s) +#define stringify1(s) #s + + +extern void bootloader_second_phase(void); + +const struct board_api *boards[] = { + &board_api_gta02, + NULL /* always last */ +}; + + +struct board_api const * this_board; +extern int is_jtag; + +void start_qi(void) +{ + int flag = 0; + int board = 0; + + /* + * well, we can be running on this CPU two different ways. + * + * 1) We were copied into steppingstone and TEXT_BASE already + * by JTAG. We don't have to do anything else. JTAG script + * then sets data at address 0x4 to 0xffffffff as a signal we + * are running by JTAG. + * + * 2) We only got our first 4K into steppingstone, we need to copy + * the rest of ourselves into TEXT_BASE. + * + * So we do the copy out of NAND only if we see we did not come up + * under control of JTAG. + */ + + if (!is_jtag) + /* + * We got the first 4KBytes of the bootloader pulled into the + * steppingstone SRAM for free. Now we pull the whole bootloader + * image into SDRAM. + * + * This code and the .S files are arranged by the linker script + * to expect to run from 0x0. But the linker script has told + * everything else to expect to run from 0x33000000+. That's + * why we are going to be able to copy this code and not have it + * crash when we run it from there. + */ + + /* We randomly pull 32KBytes of bootloader */ + if (nand_read_ll((u8 *)TEXT_BASE, 0, 32 * 1024 / 512) < 0) + goto unhappy; + + /* ask all the boards we support in turn if they recognize this + * hardware we are running on, accept the first positive answer + */ + + this_board = boards[board]; + while (!flag && this_board) { + + /* check if it is the right board... */ + if (this_board->is_this_board()) { + flag = 1; + continue; + } + + this_board = boards[board++]; + } + + this_board->port_init(); + set_putc_func(this_board->putc); + + /* stick some hello messages on debug console */ + + puts("\n\n\nQi Bootloader "stringify2(QI_CPU)" " + stringify2(BUILD_HOST)" " + stringify2(BUILD_VERSION)" " + "\n"); + + puts(stringify2(BUILD_DATE) " Copyright (C) 2008 Openmoko, Inc.\n"); + puts("\n Detected: "); + + puts(this_board->name); + puts(", "); + puts((this_board->get_board_variant)()->name); + puts("\n"); + + /* + * jump to bootloader_second_phase() running from DRAM copy + */ + bootloader_second_phase(); + +unhappy: + while(1) + ; + +} diff --git a/qiboot/src/cpu/s3c6410/hs_mmc.c b/qiboot/src/cpu/s3c6410/hs_mmc.c new file mode 100644 index 0000000..485d2a7 --- /dev/null +++ b/qiboot/src/cpu/s3c6410/hs_mmc.c @@ -0,0 +1,650 @@ +#include +#include "hs_mmc.h" +#include +#include + +#define HCLK_OPERATION +#undef DEBUG_HSMMC +#ifdef DEBUG_HSMMC +#define dbg(x...) printf(x) +#else +#define dbg(x...) do { } while (0) +#endif + +//#include +#include +#include +//#include +//#include +//#include + +#include "hs_mmc.h" +#include + +#define SDI_Tx_buffer_HSMMC (0x51000000) +#define SDI_Rx_buffer_HSMMC (0x51000000+(0x300000)) +#define SDI_Compare_buffer_HSMMC (0x51000000+(0x600000)) + +#define Card_OneBlockSize_ver1 512 + +#define MMC_DEFAULT_RCA (1<<16) + +/* Global variables */ + +static u32 HS_DMA_END = 0; +static u32 rca = 0; + +static ulong HCLK; + +int movi_hc = 1; /* sdhc style block indexing */ +enum card_type card_type; + +/* extern functions */ +extern ulong get_HCLK(void); + + +#define s3c_hsmmc_readl(x) *((unsigned int *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) +#define s3c_hsmmc_readw(x) *((unsigned short *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) +#define s3c_hsmmc_readb(x) *((unsigned char *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) + +#define s3c_hsmmc_writel(v,x) *((unsigned int *) (((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v +#define s3c_hsmmc_writew(v,x) *((unsigned short *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v +#define s3c_hsmmc_writeb(v,x) *((unsigned char *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v + +#define readl(x) *((unsigned int *)(x)) +#define writel(v, x) *((unsigned int *)(x)) = v + +#define UNSTUFF_BITS(resp,start,size) \ + ({ \ + const int __size = size; \ + const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ + const int __off = 3 - ((start) / 32); \ + const int __shft = (start) & 31; \ + u32 __res; \ + \ + __res = resp[__off] >> __shft; \ + if (__size + __shft > 32) \ + __res |= resp[__off-1] << ((32 - __shft) & 31); \ + __res & __mask; \ + }) + +static int wait_for_cmd_done (void) +{ + u32 i; + ushort n_int, e_int; + + dbg("wait_for_cmd_done\n"); + for (i = 0; i < 0x20000000; i++) { + n_int = s3c_hsmmc_readw(HM_NORINTSTS); + dbg(" HM_NORINTSTS: %04x\n", n_int); + if (n_int & 0x8000) + /* any error */ + break; + if (n_int & 0x0001) + /* command complete */ + return 0; + } + + e_int = s3c_hsmmc_readw(HM_ERRINTSTS); + s3c_hsmmc_writew(e_int, HM_ERRINTSTS); + s3c_hsmmc_writew(n_int, HM_NORINTSTS); + puts("cmd error1: 0x"); + print32(e_int); + puts(", HM_NORINTSTS: 0x"); + print32(n_int); + puts("\n"); + + return -1; +} + + +static void ClearCommandCompleteStatus(void) +{ + s3c_hsmmc_writew(1 << 0, HM_NORINTSTS); + while (s3c_hsmmc_readw(HM_NORINTSTS) & 0x1) { + s3c_hsmmc_writew(1 << 0, HM_NORINTSTS); + } +} + +static void card_irq_enable(ushort temp) +{ + s3c_hsmmc_writew((s3c_hsmmc_readw(HM_NORINTSTSEN) & 0xFEFF) | (temp << 8), HM_NORINTSTSEN); +} + +void hsmmc_reset (void) +{ + s3c_hsmmc_writeb(0x3, HM_SWRST); +} + +void hsmmc_set_gpio (void) +{ + u32 reg; + + reg = readl(GPGCON) & 0xf0000000; + writel(reg | 0x02222222, GPGCON); + + reg = readl(GPGPUD) & 0xfffff000; + writel(reg, GPGPUD); +} + +static void set_transfer_mode_register (u32 MultiBlk, u32 DataDirection, u32 AutoCmd12En, u32 BlockCntEn, u32 DmaEn) +{ + s3c_hsmmc_writew((s3c_hsmmc_readw(HM_TRNMOD) & ~(0xffff)) | (MultiBlk << 5) + | (DataDirection << 4) | (AutoCmd12En << 2) + | (BlockCntEn << 1) | (DmaEn << 0), HM_TRNMOD); +// dbg("\nHM_TRNMOD = 0x%04x\n", HM_TRNMOD); +} + +static void set_arg_register (u32 arg) +{ + s3c_hsmmc_writel(arg, HM_ARGUMENT); +} + +static void set_blkcnt_register(ushort uBlkCnt) +{ + s3c_hsmmc_writew(uBlkCnt, HM_BLKCNT); +} + +static void SetSystemAddressReg(u32 SysAddr) +{ + s3c_hsmmc_writel(SysAddr, HM_SYSAD); +} + +static void set_blksize_register(ushort uDmaBufBoundary, ushort uBlkSize) +{ + s3c_hsmmc_writew((uDmaBufBoundary << 12) | (uBlkSize), HM_BLKSIZE); +} + +static void ClearErrInterruptStatus(void) +{ + while (s3c_hsmmc_readw(HM_NORINTSTS) & (0x1 << 15)) { + s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTS), HM_NORINTSTS); + s3c_hsmmc_writew(s3c_hsmmc_readw(HM_ERRINTSTS), HM_ERRINTSTS); + } +} + +static void InterruptEnable(ushort NormalIntEn, ushort ErrorIntEn) +{ + ClearErrInterruptStatus(); + s3c_hsmmc_writew(NormalIntEn, HM_NORINTSTSEN); + s3c_hsmmc_writew(ErrorIntEn, HM_ERRINTSTSEN); +} + +static void hsmmc_clock_onoff (int on) +{ + u16 reg16; + + if (on == 0) { + reg16 = s3c_hsmmc_readw(HM_CLKCON) & ~(0x1<<2); + s3c_hsmmc_writew(reg16, HM_CLKCON); + } else { + reg16 = s3c_hsmmc_readw(HM_CLKCON); + s3c_hsmmc_writew(reg16 | (0x1<<2), HM_CLKCON); + + while (1) { + reg16 = s3c_hsmmc_readw(HM_CLKCON); + if (reg16 & (0x1<<3)) /* SD_CLKSRC is Stable */ + break; + } + } +} + +static void set_clock (u32 clksrc, u32 div) +{ + u16 reg16; + u32 i; + + s3c_hsmmc_writel(0xC0004100 | (clksrc << 4), HM_CONTROL2); // rx feedback control + s3c_hsmmc_writel(0x00008080, HM_CONTROL3); // Low clock: 00008080 + s3c_hsmmc_writel(0x3 << 16, HM_CONTROL4); + + s3c_hsmmc_writew(s3c_hsmmc_readw(HM_CLKCON) & ~(0xff << 8), HM_CLKCON); + + /* SDCLK Value Setting + Internal Clock Enable */ + s3c_hsmmc_writew(((div<<8) | 0x1), HM_CLKCON); + + /* CheckInternalClockStable */ + for (i = 0; i < 0x10000; i++) { + reg16 = s3c_hsmmc_readw(HM_CLKCON); + if (reg16 & 0x2) + break; + } + if (i == 0x10000) + puts("internal clock stabilization failed\n"); + + hsmmc_clock_onoff(1); +} + +static void set_cmd_register (ushort cmd, u32 data, u32 flags) +{ + ushort val = (cmd << 8); + + if (cmd == 12) + val |= (3 << 6); + + if (flags & MMC_RSP_136) /* Long RSP */ + val |= 0x01; + else if (flags & MMC_RSP_BUSY) /* R1B */ + val |= 0x03; + else if (flags & MMC_RSP_PRESENT) /* Normal RSP */ + val |= 0x02; + + if (flags & MMC_RSP_OPCODE) + val |= (1<<4); + + if (flags & MMC_RSP_CRC) + val |= (1<<3); + + if (data) + val |= (1<<5); + +// puts("cmdreg = 0x"); +// print32(val); +// puts("\n"); + s3c_hsmmc_writew(val, HM_CMDREG); +} + +static int issue_command (ushort cmd, u32 arg, u32 data, u32 flags) +{ + int i; + +/* puts("### issue_command: "); + printdec(cmd); + puts(" 0x"); + print32(arg); + puts(" "); + printdec(data); + puts(" 0x"); + print32(flags); + puts("\n"); +*/ + /* Check CommandInhibit_CMD */ + for (i = 0; i < 0x1000000; i++) { + if (!(s3c_hsmmc_readl(HM_PRNSTS) & 0x1)) + break; + } + if (i == 0x1000000) { + puts("@@@@@@1 rHM_PRNSTS: "); + printdec(s3c_hsmmc_readl(HM_PRNSTS)); + puts("\n"); + } + + /* Check CommandInhibit_DAT */ + if (flags & MMC_RSP_BUSY) { + for (i = 0; i < 0x1000000; i++) { + if (!(s3c_hsmmc_readl(HM_PRNSTS) & 0x2)) + break; + } + if (i == 0x1000000) { + puts("@@@@@@2 rHM_PRNSTS: "); + print32(s3c_hsmmc_readl(HM_PRNSTS)); + puts("\n"); + } + } + + s3c_hsmmc_writel(arg, HM_ARGUMENT); + + set_cmd_register(cmd, data, flags); + + if (wait_for_cmd_done()) + return 0; + + ClearCommandCompleteStatus(); + + if (!(s3c_hsmmc_readw(HM_NORINTSTS) & 0x8000)) + return 1; + + puts("Command = "); + printdec((s3c_hsmmc_readw(HM_CMDREG) >> 8)); + puts(", Error Stat = 0x"); + print32(s3c_hsmmc_readw(HM_ERRINTSTS)); + return 0; +} + +static int check_card_status(void) +{ + if (!issue_command(MMC_SEND_STATUS, rca<<16, 0, MMC_RSP_R1)) + return 0; + + if (((s3c_hsmmc_readl(HM_RSPREG0) >> 9) & 0xf) == 4) { +// puts("Card is transfer status\n"); + return 1; + } + + return 1; +} + +static void set_hostctl_speed (u8 mode) +{ + u8 reg8; + + reg8 = s3c_hsmmc_readb(HM_HOSTCTL) & ~(0x1<<2); + s3c_hsmmc_writeb(reg8 | (mode<<2), HM_HOSTCTL); +} + +/* return 0: OK + * return -1: error + */ +static int set_bus_width (u32 width) +{ + u8 reg = s3c_hsmmc_readb(HM_HOSTCTL); + u8 bitmode = 0; + + card_irq_enable(0); // Disable sd card interrupt + + + if (!issue_command(MMC_APP_CMD, rca<<16, 0, MMC_RSP_R1)) + return -1; + else { + if (width == 1) { // 1-bits + bitmode = 0; + if (!issue_command(MMC_SWITCH, 0, 0, MMC_RSP_R1B)) + return -1; + } else { // 4-bits + bitmode = 1; + if (!issue_command(MMC_SWITCH, 2, 0, MMC_RSP_R1B)) + return -1; + } + } + + if (bitmode == 2) + reg |= 1 << 5; + else + reg |= bitmode << 1; + + s3c_hsmmc_writeb(reg, HM_HOSTCTL); + card_irq_enable(1); +// puts(" transfer rHM_HOSTCTL(0x28) = 0x"); +// print32(s3c_hsmmc_readb(HM_HOSTCTL)); + + return 0; +} + +static void clock_config (u32 Divisior) +{ + if (100000000 / (Divisior * 2) > 25000000) // Higher than 25MHz, it is necessary to enable high speed mode of the host controller. + set_hostctl_speed(HIGH); + else + set_hostctl_speed(NORMAL); + + hsmmc_clock_onoff(0); // when change the sd clock frequency, need to stop sd clock. + set_clock(SD_EPLL, Divisior); +} + +static void check_dma_int (void) +{ + u32 i; + + for (i = 0; i < 0x10000000; i++) { + if (s3c_hsmmc_readw(HM_NORINTSTS) & 0x0002) { + HS_DMA_END = 1; + s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTS) | 0x0002, HM_NORINTSTS); + return; + } + if (s3c_hsmmc_readw(HM_NORINTSTS) & 0x8000) { + puts("error found: "); + print32(s3c_hsmmc_readw(HM_ERRINTSTS)); + return; + } + } + + puts("check_dma_int: timeout\n"); +} + + +static void print_sd_cid(const struct sd_cid *cid) +{ + puts(" Card Type: "); + switch (card_type) { + case CARDTYPE_NONE: + puts("(None) / "); + break; + case CARDTYPE_MMC: + puts("MMC / "); + break; + case CARDTYPE_SD: + puts("SD / "); + break; + case CARDTYPE_SD20: + puts("SD 2.0 / "); + break; + case CARDTYPE_SDHC: + puts("SD 2.0 SDHC / "); + break; + } + + puts("Mfr: 0x"); + print8(cid->mid); + puts(", OEM \""); + this_board->putc(cid->oid_0); + this_board->putc(cid->oid_1); + puts("\" / "); + + this_board->putc(cid->pnm_0); + this_board->putc(cid->pnm_1); + this_board->putc(cid->pnm_2); + this_board->putc(cid->pnm_3); + this_board->putc(cid->pnm_4); + puts("\", rev "); + printdec(cid->prv >> 4); + puts("."); + printdec(cid->prv & 15); + puts(" / s/n: "); + print32(cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 | + cid->psn_3); + puts(" / date: "); + printdec(cid->mdt_1 & 15); + puts("/"); + printdec(2000 + ((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4)); + puts("\n"); +} + +unsigned int s3c6410_mmc_init (int verbose) +{ + u32 reg; + u32 width; + int resp; + int hcs; + int retries = 50; + u8 response[16]; + unsigned int r1[4]; + struct sd_cid *sd_cid = (struct sd_cid *)response; + struct mmc_csd *csd = (struct mmc_csd *)response; + u8 *p8 = (u8 *)&r1[0]; + unsigned int sd_sectors = 0; + /* we need to shift result by 8 bits spread over 4 x 32-bit regs */ + u8 mangle[] = { 7, 0, 1, 2, 11, 4, 5, 6, 15, 8, 9, 10, 0, 12, 13, 14 }; + int n; + + hsmmc_set_gpio(); + + hsmmc_reset(); + + width = 4; + + HCLK = 33000000; /* FIXME */ + hsmmc_clock_onoff(0); + + reg = readl(SCLK_GATE); + writel(reg | (1<<27), SCLK_GATE); + + set_clock(SD_EPLL, 0x80); + s3c_hsmmc_writeb(0xe, HM_TIMEOUTCON); + set_hostctl_speed(NORMAL); + + InterruptEnable(0xff, 0xff); + +// dbg("HM_NORINTSTS = %x\n", s3c_hsmmc_readw(HM_NORINTSTS)); + + /* MMC_GO_IDLE_STATE */ + issue_command(MMC_GO_IDLE_STATE, 0x00, 0, 0); + + udelay(100000); + udelay(100000); + udelay(100000); + udelay(100000); + + /* SDHC card? */ + + resp = issue_command(SD_SEND_IF_COND, 0x000001aa, + 0, MMC_CMD_BCR | MMC_RSP_R7); + if (resp && ((s3c_hsmmc_readl(HM_RSPREG0) & 0xff) == 0xaa)) { + card_type = CARDTYPE_SD20; /* 2.0 SD, may not be SDHC */ + hcs = 0x40000000; + } + + /* Well, either way let's say hello in SD card protocol */ + + while (retries--) { + + udelay(100000); + udelay(100000); + udelay(100000); + + resp = issue_command(MMC_APP_CMD, 0x00000000, 0, + MMC_RSP_R1); + if (!resp) + continue; + resp = issue_command(SD_APP_OP_COND, hcs | 0x00300000, 0, + MMC_RSP_R3); + if (!resp) + continue; + + if ((s3c_hsmmc_readl(HM_RSPREG0) >> 24) & (1 << 6)) { /* asserts block addressing */ + retries = -2; + card_type = CARDTYPE_SDHC; + } + + if ((s3c_hsmmc_readl(HM_RSPREG0) >> 24) & (1 << 7)) { /* not busy */ + retries = -2; + if (card_type == CARDTYPE_NONE) + card_type = CARDTYPE_SD; + break; + } + } + if (retries == -1) { + puts("no response\n"); + return -2; + } + + if (!issue_command(MMC_ALL_SEND_CID, 0, 0, MMC_RSP_R2)) { + puts("CID broken\n"); + return -3; + } + + r1[0] = s3c_hsmmc_readl(HM_RSPREG3); + r1[1] = s3c_hsmmc_readl(HM_RSPREG2); + r1[2] = s3c_hsmmc_readl(HM_RSPREG1); + r1[3] = s3c_hsmmc_readl(HM_RSPREG0); + + for (n = 0; n < 16; n++) + response[n] = p8[mangle[n]]; + + switch (card_type) { + case CARDTYPE_SD: + case CARDTYPE_SD20: + case CARDTYPE_SDHC: + + if (verbose) + print_sd_cid(sd_cid); + resp = issue_command(SD_SEND_RELATIVE_ADDR, MMC_DEFAULT_RCA, + 0, MMC_RSP_R6); + rca = s3c_hsmmc_readl(HM_RSPREG0) >> 16; + break; + + default: + return 1; + } + + /* grab the CSD */ + + resp = issue_command(MMC_SEND_CSD, rca << 16, 0, MMC_RSP_R2); + if (resp) { + + r1[0] = s3c_hsmmc_readl(HM_RSPREG3); + r1[1] = s3c_hsmmc_readl(HM_RSPREG2); + r1[2] = s3c_hsmmc_readl(HM_RSPREG1); + r1[3] = s3c_hsmmc_readl(HM_RSPREG0); + for (n = 0; n < 16; n++) + response[n] = p8[mangle[n]]; + + switch (card_type) { + case CARDTYPE_SDHC: + puts(" SDHC size: "); + sd_sectors = (UNSTUFF_BITS(((u32 *)&response[0]), 48, 22) + + 1) << 10; + break; + default: + puts(" MMC/SD size: "); + sd_sectors = ((((unsigned long)1 << csd->c_size_mult1) * + (unsigned long)(csd->c_size)) >> 9); + } + printdec(sd_sectors / 2048); + puts(" MiB\n"); + } else + puts("CSD grab broken\n"); + + resp = issue_command(MMC_SELECT_CARD, rca<<16, 0, MMC_RSP_R1); + if (!resp) + return 1; + + /* Operating Clock setting */ + clock_config(2); // Divisor 1 = Base clk /2 ,Divisor 2 = Base clk /4, Divisor 4 = Base clk /8 ... + + while (set_bus_width(width)); + while (!check_card_status()); + + /* MMC_SET_BLOCKLEN */ + while (!issue_command(MMC_SET_BLOCKLEN, 512, 0, MMC_RSP_R1)); + + s3c_hsmmc_writew(0xffff, HM_NORINTSTS); + + return sd_sectors; +} + +unsigned long s3c6410_mmc_bread(int dev_num, unsigned long start_blk, unsigned long blknum, + void *dst) +{ + u32 blksize; //j, , Addr_temp = start_blk; + u32 dma = 0, cmd, multi; //, TotalReadByte, read_blk_cnt = 0; + + HS_DMA_END = 0; + + blksize = Card_OneBlockSize_ver1; + + while (!check_card_status()); + + s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTSEN) & ~(DMA_STS_INT_EN | BLOCKGAP_EVENT_STS_INT_EN), HM_NORINTSTSEN); + s3c_hsmmc_writew((HM_NORINTSIGEN & ~(0xffff)) | TRANSFERCOMPLETE_SIG_INT_EN, HM_NORINTSIGEN); + + SetSystemAddressReg((unsigned long)dst); // AHB System Address For Write + dma = 1; + + set_blksize_register(7, 512); // Maximum DMA Buffer Size, Block Size + set_blkcnt_register(blknum); // Block Numbers to Write + + if (movi_hc) + set_arg_register(start_blk); // Card Start Block Address to Write + else + set_arg_register(start_blk * 512); // Card Start Block Address to Write + + cmd = (blknum > 1) ? 18 : 17; + multi = (blknum > 1); + + set_transfer_mode_register(multi, 1, multi, 1, dma); + set_cmd_register(cmd, 1, MMC_RSP_R1); + + if (wait_for_cmd_done()) { + puts("Command NOT Complete\n"); + return -1; + } else + ClearCommandCompleteStatus(); + + + check_dma_int(); + while (!HS_DMA_END); + + HS_DMA_END = 0; + + return blknum; +} diff --git a/qiboot/src/cpu/s3c6410/hs_mmc.h b/qiboot/src/cpu/s3c6410/hs_mmc.h new file mode 100644 index 0000000..f1218ce --- /dev/null +++ b/qiboot/src/cpu/s3c6410/hs_mmc.h @@ -0,0 +1,40 @@ +#ifndef __HS_MMC_H__ +#define __HS_MMC_H__ + +///////////////////////////////////////////////////////////////////////////////////////////////// +//#define SDHC_MONITOR (*(volatile unsigned *)0x4800004c) +//#define SDHC_SLOT_INT_STAT (*(volatile unsigned *)0x480000fc) + +///////////////////////////////////////////////////////////////////////////////////////////////// +#define SD_HCLK 1 +#define SD_EPLL 2 +#define SD_EXTCLK 3 + +#define NORMAL 0 +#define HIGH 1 + +//Normal Interrupt Signal Enable +#define READWAIT_SIG_INT_EN (1<<10) +#define CARD_SIG_INT_EN (1<<8) +#define CARD_REMOVAL_SIG_INT_EN (1<<7) +#define CARD_INSERT_SIG_INT_EN (1<<6) +#define BUFFER_READREADY_SIG_INT_EN (1<<5) +#define BUFFER_WRITEREADY_SIG_INT_EN (1<<4) +#define DMA_SIG_INT_EN (1<<3) +#define BLOCKGAP_EVENT_SIG_INT_EN (1<<2) +#define TRANSFERCOMPLETE_SIG_INT_EN (1<<1) +#define COMMANDCOMPLETE_SIG_INT_EN (1<<0) + +//Normal Interrupt Status Enable +#define READWAIT_STS_INT_EN (1<<10) +#define CARD_STS_INT_EN (1<<8) +#define CARD_REMOVAL_STS_INT_EN (1<<7) +#define CARD_INSERT_STS_INT_EN (1<<6) +#define BUFFER_READREADY_STS_INT_EN (1<<5) +#define BUFFER_WRITEREADY_STS_INT_EN (1<<4) +#define DMA_STS_INT_EN (1<<3) +#define BLOCKGAP_EVENT_STS_INT_EN (1<<2) +#define TRANSFERCOMPLETE_STS_INT_EN (1<<1) +#define COMMANDCOMPLETE_STS_INT_EN (1<<0) + +#endif /*__HS_MMC_H__*/ diff --git a/qiboot/src/cpu/s3c6410/i2c-bitbang-s3c6410.c b/qiboot/src/cpu/s3c6410/i2c-bitbang-s3c6410.c new file mode 100644 index 0000000..0d1236d --- /dev/null +++ b/qiboot/src/cpu/s3c6410/i2c-bitbang-s3c6410.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * s3c6410-specific i2c + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include + +static char i2c_read_sda_s3c6410(void) +{ + return !!(__REG(GPBDAT) & (1 << 6)); +} + +static void i2c_set_s3c6410(char clock, char data) +{ + if (clock) /* SCL <- input */ + __REG(GPBCON) = (__REG(GPBCON) & ~(3 << (5 * 4))); + else { /* SCL <- output 0 */ + __REG(GPBDAT) = (__REG(GPBDAT) & ~(1 << 5)); + __REG(GPBCON) = (__REG(GPBCON) & ~(3 << (5 * 4))) | (1 << (5 * 4)); + } + if (data) /* SDA <- input */ + __REG(GPBCON) = (__REG(GPBCON) & ~(3 << (6 * 4))); + else { /* SDA <- output 0 */ + __REG(GPBDAT) = (__REG(GPBDAT) & ~(1 << 6)); + __REG(GPBCON) = (__REG(GPBCON) & ~(3 << (6 * 4))) | (1 << (6 * 4)); + } +} + +static void i2c_close_s3c6410(void) +{ + /* set back to hardware I2C ready for Linux */ + __REG(GPBCON) = (__REG(GPBCON) & ~(3 << (5 * 4))) | (2 << (5 * 4)); + __REG(GPBCON) = (__REG(GPBCON) & ~(3 << (6 * 4))) | (2 << (6 * 4)); +} + +static void i2c_spin_s3c6410(void) +{ + int n; + + for (n = 0; n < 1000; n++) + __REG(GPBDAT) = __REG(GPBDAT); +} + +struct i2c_bitbang bb_s3c6410 = { + .read_sda = i2c_read_sda_s3c6410, + .set = i2c_set_s3c6410, + .spin = i2c_spin_s3c6410, + .close = i2c_close_s3c6410, +}; diff --git a/qiboot/src/cpu/s3c6410/om_3d7k-steppingstone.c b/qiboot/src/cpu/s3c6410/om_3d7k-steppingstone.c new file mode 100644 index 0000000..71c57f9 --- /dev/null +++ b/qiboot/src/cpu/s3c6410/om_3d7k-steppingstone.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include + +#define OM_3D7K_DEBUG_UART 3 + +/* out of steppingstone */ +extern const struct board_variant const * get_board_variant_om_3d7k(void); +extern void port_init_om_3d7k(void); + + +int is_this_board_om_3d7k(void) +{ + /* FIXME: find something om_3d7k specific */ + return 1; +} + +static void putc_om_3d7k(char c) +{ + serial_putc_s3c64xx(OM_3D7K_DEBUG_UART, c); +} + +int sd_card_init_om_3d7k(void) +{ + extern int s3c6410_mmc_init(int verbose); + + return s3c6410_mmc_init(1); +} + +int sd_card_block_read_om_3d7k(unsigned char * buf, unsigned long start512, + int blocks512) +{ +unsigned long s3c6410_mmc_bread(int dev_num, unsigned long blknr, unsigned long blkcnt, + void *dst); + + return s3c6410_mmc_bread(0, start512, blocks512, buf); +} + +/* + * our API for bootloader on this machine + */ + +/* for initrd: + * .initramfs_filepath = "boot/initramfs.gz", + * and + * "root=/dev/ram ramdisk_size=6000000" + */ + +static u8 get_ui_keys_om_3d7k(void) +{ + u8 keys; + u8 ret; + static u8 old_keys = 0; /* previous state for debounce */ + static u8 old_ret = 0; /* previous debounced output for edge detect */ + + /* GPN1 is MINUS on OM_3D7K, map to UI_ACTION_ADD_DEBUG, down = 1 */ + keys = !!(__REG(GPMDAT) & (1 << 1)); + + if (keys == old_keys) + ret = keys; + else + ret = old_keys; + + /* edge action */ + if ((ret & 1) && !(old_ret & 1)) + ret |= UI_ACTION_SKIPKERNEL; + + old_keys = keys; + old_ret = ret; + + return ret; +} + +const struct board_api board_api_om_3d7k = { + .name = "OM_3D7K", + .linux_machine_id = 2120, + .linux_mem_start = 0x50000000, + .linux_mem_size = (128 * 1024 * 1024), + .linux_tag_placement = 0x50000000 + 0x100, + .get_board_variant = get_board_variant_om_3d7k, + .is_this_board = is_this_board_om_3d7k, + .port_init = port_init_om_3d7k, + .putc = putc_om_3d7k, + .noboot = "boot/noboot-OM_3D7K", + .append = "boot/append-OM_3D7K", + .get_ui_keys = get_ui_keys_om_3d7k, + .commandline_board = "console=tty0 " + "console=ttySAC3,115200 " + "init=/sbin/init " + "loglevel=8 " + "rootdelay=1 no_console_suspend " + "ro ", + .commandline_board_debug = " loglevel=8", + .kernel_source = { + [0] = { + .name = "SD Card rootfs", + .block_read = sd_card_block_read_om_3d7k, + .filesystem = FS_EXT2, + .partition_index = 2, + .filepath = "boot/uImage-OM_3D7K.bin", + .commandline_append = "root=/dev/mmcblk0p2 ", + }, + [1] = { + .name = "SD Card backup rootfs", + .block_read = sd_card_block_read_om_3d7k, + .filesystem = FS_EXT2, + .partition_index = 3, + .filepath = "boot/uImage-OM_3D7K.bin", + .commandline_append = "root=/dev/mmcblk0p3 ", + }, + }, +}; + diff --git a/qiboot/src/cpu/s3c6410/om_3d7k.c b/qiboot/src/cpu/s3c6410/om_3d7k.c new file mode 100644 index 0000000..badc595 --- /dev/null +++ b/qiboot/src/cpu/s3c6410/om_3d7k.c @@ -0,0 +1,935 @@ +#include +#include +#include +#include +#include +#include + +#define PCF50633_I2C_ADS 0x73 + +const struct pcf50633_init om_3d7k_pcf50633_init[] = { + + { PCF50633_REG_OOCWAKE, 0xd3 }, /* wake from ONKEY,EXTON!,RTC,USB,ADP */ + { PCF50633_REG_OOCTIM1, 0xaa }, /* debounce 14ms everything */ + { PCF50633_REG_OOCTIM2, 0x4a }, + { PCF50633_REG_OOCMODE, 0x55 }, + { PCF50633_REG_OOCCTL, 0x47 }, + + { PCF50633_REG_SVMCTL, 0x08 }, /* 3.10V SYS voltage thresh. */ + { PCF50633_REG_BVMCTL, 0x02 }, /* 2.80V BAT voltage thresh. */ + + { PCF50633_REG_AUTOENA, 0x01 }, /* always on */ + + { PCF50633_REG_DOWN1OUT, 0x17 }, /* 1.2V (0x17 * .025V + 0.625V) */ + + /* all of these are down in 3d7k suspend except MEMLDO */ + + { PCF50633_REG_DOWN1ENA, 0x02 }, /* enabled if GPIO1 = HIGH */ + { PCF50633_REG_DOWN2ENA, 0x02 }, /* enabled if GPIO1 = HIGH */ + { PCF50633_REG_HCLDOENA, 0x00 }, /* Camera 2.8V power off */ + { PCF50633_REG_MEMLDOENA, 0x01 }, /* Memory LDO always ON */ + { PCF50633_REG_LDO1ENA, 0x00 }, /* Gsensor power off */ + { PCF50633_REG_LDO2ENA, 0x00 }, /* Camera 1.5V power off */ + { PCF50633_REG_LDO3ENA, 0x02 }, /* Codec power ON */ + { PCF50633_REG_LDO4ENA, 0x02 }, /* SD power ON */ + { PCF50633_REG_LDO5ENA, 0x00 }, /* BT power off */ + { PCF50633_REG_LDO6ENA, 0x00 }, /* LCM power off */ + + { PCF50633_REG_INT1M, 0x00 }, + { PCF50633_REG_INT2M, 0x00 }, + { PCF50633_REG_INT3M, 0x00 }, + { PCF50633_REG_INT4M, 0x00 }, + { PCF50633_REG_INT5M, 0x00 }, + + { PCF50633_REG_MBCC2, 0x28 }, /* Vbatconid=2.7V, Vmax=4.20V */ + { PCF50633_REG_MBCC3, 0x19 }, /* 25/255 == 98mA pre-charge */ + { PCF50633_REG_MBCC4, 0xff }, /* 255/255 == 1A adapter fast */ + { PCF50633_REG_MBCC5, 0xff }, /* 255/255 == 1A USB fast */ + + { PCF50633_REG_MBCC6, 0x00 }, /* cutoff current 1/32 * Ichg */ + + /* current prototype is pulling > 100mA at startup */ + { PCF50633_REG_MBCC7, 0xc1 }, /* 2.2A max bat curr, USB 500mA */ + + { PCF50633_REG_MBCC8, 0x00 }, + { PCF50633_REG_MBCC1, 0xff }, /* chgena */ + + { PCF50633_REG_BBCCTL, 0x19 }, /* 3V, 200uA, on */ + { PCF50633_REG_OOCSHDWN, 0x04 }, /* defeat 8s death from lowsys on A5 */ + +}; + +static const struct board_variant board_variants[] = { + [0] = { + .name = "OM 3D7K unknown", + .machine_revision = 0 + }, + [1] = { + .name = "OM 3D7K A1", + .machine_revision = 1 + }, + [2] = { + .name = "OM 3D7K A2", + .machine_revision = 2 + }, + [3] = { + .name = "OM 3D7K A3", + .machine_revision = 3 + }, + [4] = { + .name = "OM 3D7K A4", + .machine_revision = 4 + }, + [5] = { + .name = "OM 3D7K A5", + .machine_revision = 5 + }, + [6] = { + .name = "OM 3D7K A6", + .machine_revision = 6 + }, + [7] = { + .name = "OM 3D7K A7", + .machine_revision = 7 + } +}; + +#define S0 0 +#define S1 1 +#define SIN 2 +#define SHOLD 3 + +#define SNP 0 +#define SPD 1 +#define SPU 2 + +void port_init_om_3d7k(void) +{ + int n; + +/* + * We leave iROM up for clock and power otherwise resume fails + */ + + __REG(EINT_MASK) = + (0 << 4) /* PMU interrupt */ + ; + + __REG(PWR_CFG) = + (1 << 17) | /* kill OSCotg clock pad */ + (0 << 0) /* 27MHz osc off */ + ; + + __REG(STOP_MEM_CFG) = + (0 << 6) | /* modem */ + (0 << 5) | /* host IF */ + (1 << 4) | /* OTG */ + (1 << 3) | /* HSMMC */ + (1 << 2) | /* iROM */ + (0 << 1) | /* IRDA */ + (1 << 0) /* NFCON / steppingstone */ + ; + + __REG(NOR_CFG) = + (1 << 31) | /* reserved */ + (1 << 30) | /* iROM */ + (0x1fff << 17) | /* reserved */ + (1 << 16) | /* ETM domain */ + (1 << 15) | /* S domain */ + (1 << 14) | /* F domain / LCD */ + (0 << 13) | /* P domain / 2D, scaler, TV encoder */ + (0 << 12) | /* I domain / JPEG / Camera */ + (1 << 11) | /* reserved */ + (0 << 10) | /* G domain / 3D */ + (0 << 9) | /* V domain / MFC */ + (1 << 8) | /* reserved */ + (0x00 << 0) /* reserved */ + ; + + + __REG(HCLK_GATE) = + (0 << 31) | /* 3D unit */ + (1 << 30) | /* reserved */ + (0 << 29) | /* USB host */ + (0 << 28) | /* "security subsystem" */ + (0 << 27) | /* SDMA1 */ + (0 << 26) | /* SDMA0 */ + (1 << 25) | /* iROM */ + (1 << 24) | /* DDR 1 */ + (1 << 23) | /* reserved */ + (1 << 22) | /* DMC1 */ + (1 << 21) | /* SROM / NAND controller / NAND */ + (0 << 20) | /* USB OTG */ + (0 << 19) | /* HSMMC 2 */ + (0 << 18) | /* HSMMC 1 */ + (1 << 17) | /* HSMMC 0 */ + (0 << 16) | /* MDP */ + (0 << 15) | /* direct host */ + (0 << 14) | /* indirect host */ + (1 << 13) | /* DMA1 */ + (1 << 12) | /* DMA0 */ + (0 << 11) | /* JPEG */ + (0 << 10) | /* camera */ + (0 << 9) | /* scaler */ + (0 << 8) | /* 2D */ + (0 << 7) | /* TV */ + (1 << 6) | /* reserved */ + (1 << 5) | /* POST0 */ + (1 << 4) | /* rotator */ + (1 << 3) | /* LCD controller */ + (1 << 2) | /* TZICs */ + (1 << 1) | /* VICs */ + (0 << 0) /* MFC */ + ; + __REG(PCLK_GATE) = + (0x1f << 28) | /* reserved */ + (0 << 27) | /* I2C1 */ + (0 << 26) | /* IIS2 */ + (1 << 25) | /* reserved */ + (0 << 24) | /* security key */ + (1 << 23) | /* chip ID */ + (0 << 22) | /* SPI1 */ + (0 << 21) | /* SPI0 */ + (0 << 20) | /* HSI RX */ + (0 << 19) | /* HSI TX */ + (1 << 18) | /* GPIO */ + (1 << 17) | /* I2C 0 */ + (1 << 16) | /* IIS1 */ + (1 << 15) | /* IIS0 */ + (0 << 14) | /* AC97 */ + (0 << 13) | /* TZPC */ + (0 << 12) | /* TS ADC */ + (0 << 11) | /* keypad */ + (0 << 10) | /* IRDA */ + (0 << 9) | /* PCM1 */ + (0 << 8) | /* PCM0 */ + (1 << 7) | /* PWM */ + (0 << 6) | /* RTC */ + (1 << 5) | /* WDC */ + (1 << 4) | /* UART3 */ + (1 << 3) | /* UART2 */ + (1 << 2) | /* UART1 */ + (1 << 1) | /* UART0 */ + (0 << 0) /* MFC */ + ; + + __REG(SCLK_GATE) = + (1 << 31) | + (0 << 30) | /* USB Host */ + (0 << 29) | /* HSMMC2 48MHz */ + (0 << 28) | /* HSMMC1 48MHz */ + (0 << 27) | /* HSMMC0 48MHz */ + (0 << 26) | /* HSMMC2 */ + (0 << 25) | /* HSMMC1 */ + (1 << 24) | /* HSMMC0 */ + (0 << 23) | /* SPI1 - 48MHz */ + (0 << 22) | /* SPI0 - 48MHz */ + (0 << 21) | /* SPI1 */ + (0 << 20) | /* SPI0 */ + (0 << 19) | /* TV DAC */ + (0 << 18) | /* TV encoder */ + (0 << 17) | /* scaler 27 */ + (0 << 16) | /* scaler */ + (1 << 15) | /* LCD 27MHz */ + (1 << 14) | /* LCD */ + (1 << 13) | /* camera and LCD */ + (1 << 12) | /* POST0 */ + (1 << 11) | /* AUDIO2 */ + (1 << 10) | /* POST0 again */ + (1 << 9) | /* IIS1 */ + (1 << 8) | /* IIS0 */ + (0 << 7) | /* security */ + (0 << 6) | /* IRDA */ + (1 << 5) | /* UART */ + (1 << 4) | /* reserved */ + (0 << 3) | /* MFC */ + (0 << 2) | /* Cam */ + (0 << 1) | /* JPEG */ + (1 << 0) /* reserved */ + ; + + + /* ---------------------------- Port A ---------------------------- */ + + __REG(GPACON) = + (2 << 0) | /* GPA0 - UART_RXD0 */ + (2 << 4) | /* GPA1 - UART_TXD0 */ + (2 << 8) | /* GPA2 - UART_CTS0 */ + (2 << 12) | /* GPA3 - UART_RTS0 */ + (2 << 16) | /* GPA4 - UART_RXD1 */ + (2 << 20) | /* GPA5 - UART_TXD1 */ + (2 << 24) | /* GPA6 - UART_CTS1 */ + (2 << 28) /* GPA7 - UART_RTS1 */ + ; + + __REG(GPAPUD) = /* pullup inputs */ + 0x2222 + ; + __REG(GPADAT) = 0; /* just for determinism */ + + __REG(GPACONSLP) = + (SIN << 0) | /* GPA0 bluetooth down in suspend*/ + (S0 << 2) | /* GPA1 */ + (SIN << 4) | /* GPA2 */ + (S0 << 6) | /* GPA3 */ + (SIN << 8) | /* GPA4 gsm */ + (SHOLD << 10) | /* GPA5 */ + (SIN << 12) | /* GPA6 */ + (SHOLD << 14) /* GPA7 */ + ; + __REG(GPAPUDSLP) = + (SPD << 0) | /* GPA0 */ + (SNP << 2) | /* GPA1 */ + (SPD << 4) | /* GPA2 */ + (SNP << 6) | /* GPA3 */ + (SPU << 8) | /* GPA4 */ + (SNP << 10) | /* GPA5 */ + (SPU << 12) | /* GPA6 */ + (SNP << 14) /* GPA7 */ + ; + + /* ---------------------------- Port B ---------------------------- */ + + __REG(GPBCON) = + (1 << 0) | /* GPB0 - (NC) output low */ + (1 << 4) | /* GPB1 - (NC) output low */ + (2 << 8) | /* GPB2 - UART_RXD3 */ + (2 << 12) | /* GPB3 - UART_TXD3 */ + (1 << 16) | /* GPB4 - (NC) output low */ + (1 << 20) | /* GPB5 - (I2C BB SCL) OUTPUT */ + (1 << 24) /* GPB6 - (I2C BB SDA) OUTPUT */ + ; + + __REG(GPBPUD) = /* all pullup and pulldown disabled */ + (SPU << (2 * 2)) /* pullup console rx */ + ; + + __REG(GPBDAT) = 0; /* just for determinism */ + + __REG(GPBCONSLP) = + (SHOLD << 0) | /* GPB0 */ + (SHOLD << 2) | /* GPB1 */ + (SIN << 4) | /* GPB2 */ + (SHOLD << 6) | /* GPB3 */ + (SHOLD << 8) | /* GPB4 */ + (SIN << 10) | /* GPB5 ext pullup */ + (SIN << 12) /* GPB6 ext pullup */ + ; + + __REG(GPBPUDSLP) = + (SNP << 0) | /* GPB0 */ + (SNP << 2) | /* GPB1 */ + (SPU << 4) | /* GPB2 */ + (SNP << 6) | /* GPB3 */ + (SNP << 8) | /* GPB4 */ + (SNP << 10) | /* GPB5 */ + (SNP << 12) /* GPB6 */ + ; + + /* ---------------------------- Port C ---------------------------- */ + + __REG(GPCCON) = + (0 << 0) | /* GPC0 - SPI_MISO0 INPUT motion sensor spi */ + (1 << 4) | /* GPC1 - SPI_CLK0 OUTPUT */ + (1 << 8) | /* GPC2 - SPI_MOSI0 OUTPUT */ + (1 << 12) | /* GPC3 - SPI_CS0 OUTPUT */ + (1 << 16) | /* GPC4 - (NC) OUTPUT lcm spi*/ + (1 << 20) | /* GPC5 - SPI_CLK1 OUTPUT */ + (1 << 24) | /* GPC6 - SPI_MOSI1 OUTPUT */ + (1 << 28) /* GPC7 - SPI_CS1 OUTPUT */ + ; + + __REG(GPCPUD) = + (SPD << 0) + ; + __REG(GPCDAT) = 0; /* just for determinism */ + + __REG(GPCCONSLP) = /* both peripherals down in suspend */ + (SIN << 0) | /* GPC0 */ + (S0 << 2) | /* GPC1 */ + (S0 << 4) | /* GPC2 */ + (S0 << 6) | /* GPC3 */ + (SIN << 8) | /* GPC4 */ + (S0 << 10) | /* GPC5 */ + (S0 << 12) | /* GPC6 */ + (S0 << 14) /* GPC7 */ + ; + + __REG(GPCPUDSLP) = + (SPD << 0) | /* GPC0 */ + (SNP << 2) | /* GPC1 */ + (SNP << 4) | /* GPC2 */ + (SNP << 6) | /* GPC3 */ + (SPD << 8) | /* GPC4 */ + (SNP << 10) | /* GPC5 */ + (SNP << 12) | /* GPC6 */ + (SNP << 14) /* GPC7 */ + ; + + /* ---------------------------- Port D ---------------------------- */ + + __REG(GPDCON) = + (3 << 0) | /* GPD0 - I2S_CLK0 */ + (3 << 4) | /* GPD1 - I2S_CDCLK0 */ + (3 << 8) | /* GPD2 - I2S_LRCLK0 */ + (3 << 12) | /* GPD3 - I2S_DI */ + (3 << 16) /* GPD4 - I2S_DO */ + ; + + __REG(GPDPUD) = 0; /* all pullup and pulldown disabled */ + + __REG(GPDDAT) = 0; /* just for determinism */ + + __REG(GPDCONSLP) = + (S0 << 0) | /* GPD0 */ + (S0 << 2) | /* GPD1 */ + (S0 << 4) | /* GPD2 */ + (SIN << 6) | /* GPD3 */ + (S0 << 8) /* GPD4 */ + ; + + __REG(GPDPUDSLP) = + (SNP << 0) | /* GPD0 */ + (SNP << 2) | /* GPD1 */ + (SNP << 4) | /* GPD2 */ + (SPD << 6) | /* GPD3 */ + (SNP << 8) /* GPD4 */ + ; + + /* ---------------------------- Port E ---------------------------- */ + + __REG(GPECON) = + (3 << 0) | /* GPE0 - PCM_SCLK1 */ + (3 << 4) | /* GPE1 - PCM_EXTCLK1 */ + (3 << 8) | /* GPE2 - PCM_FSYNC1 */ + (3 << 12) | /* GPE3 - PCM_SIN */ + (3 << 16) /* GPE4 - PCM_SOUT */ + ; + + __REG(GPEPUD) = 0; /* all pullup and pulldown disabled */ + + __REG(GPEDAT) = 0; /* just for determinism */ + + __REG(GPECONSLP) = + (S0 << 0) | /* GPE0 */ + (S0 << 2) | /* GPE1 */ + (S0 << 4) | /* GPE2 */ + (SIN << 6) | /* GPE3 */ + (S0 << 8) /* GPE4 */ + ; + + __REG(GPEPUDSLP) = + (SNP << 0) | /* GPE0 */ + (SNP << 2) | /* GPE1 */ + (SNP << 4) | /* GPE2 */ + (SPD << 6) | /* GPE3 */ + (SNP << 8) /* GPE4 */ + ; + + /* ---------------------------- Port F ---------------------------- */ + + __REG(GPFCON) = + (2 << 0) | /* GPF0 - CAMIF_CLK */ + (2 << 2) | /* GPF1 - CAMIF_HREF */ + (2 << 4) | /* GPF2 - CAMIF_PCLK */ + (2 << 6) | /* GPF3 - CAMIF_RSTn */ + (2 << 8) | /* GPF4 - CAMIF_VSYNC */ + (2 << 10) | /* GPF5 - CAMIF_YDATA0 */ + (2 << 12) | /* GPF6 - CAMIF_YDATA1 */ + (2 << 14) | /* GPF7 - CAMIF_YDATA2 */ + (2 << 16) | /* GPF8 - CAMIF_YDATA3 */ + (2 << 18) | /* GPF9 - CAMIF_YDATA4 */ + (2 << 20) | /* GPF10 - CAMIF_YDATA5 */ + (2 << 22) | /* GPF11 - CAMIF_YDATA6 */ + (2 << 24) | /* GPF12 - CAMIF_YDATA7 */ + (1 << 26) | /* GPF13 - OUTPUT Vibrator */ + (1 << 28) | /* GPF14 - output not CLKOUT0 */ + (1 << 30) /* GPF15 - OUTPUT CAM_PWRDN */ + ; + + __REG(GPFPUD) = + (SPD << (2 * 12)) | + (SPD << (2 * 11)) | + (SPD << (2 * 10)) | + (SPD << (2 * 9)) | + (SPD << (2 * 8)) | + (SPD << (2 * 7)) | + (SPD << (2 * 6)) | + (SPD << (2 * 5)); /* all cam data pulldown */ + + __REG(GPFDAT) = (1 << 15); /* assert CAM_PWRDN */ + + __REG(GPFCONSLP) = + (S0 << 0) | /* GPF0 */ + (S0 << 2) | /* GPF1 */ + (SIN << 4) | /* GPF2 */ + (S0 << 6) | /* GPF3 */ + (S0 << 8) | /* GPF4 */ + (SIN << 10) | /* GPF5 */ + (SIN << 12) | /* GPF6 */ + (SIN << 14) | /* GPF7 */ + (SIN << 16) | /* GPF8 */ + (SIN << 18) | /* GPF9 */ + (SIN << 20) | /* GPF10 */ + (SIN << 22) | /* GPF11 */ + (SIN << 24) | /* GPF12 */ + (S0 << 26) | /* GPF13 */ + (S0 << 28) | /* GPF14 */ + (S0 << 30) /* GPF15 */ + ; + + __REG(GPFPUDSLP) = + (SPD << 4) | /* GPF2 - pull down */ + (SPD << 10) | /* GPF5 - pull down */ + (SPD << 12) | /* GPF6 - pull down */ + (SPD << 14) | /* GPF7 - pull down */ + (SPD << 16) | /* GPF8 - pull down */ + (SPD << 18) | /* GPF9 - pull down */ + (SPD << 20) | /* GPF10 - pull down */ + (SPD << 22) | /* GPF11 - pull down */ + (SPD << 24) /* GPF12 - pull down */ + ; + + /* ---------------------------- Port G ---------------------------- */ + + __REG(GPGCON) = + (2 << 0) | /* GPG0 - MMC_CLK0 */ + (2 << 4) | /* GPG1 - MMC_CMD0 */ + (2 << 8) | /* GPG2 - MMC_DATA00 */ + (2 << 12) | /* GPG3 - MMC_DATA10 */ + (2 << 16) | /* GPG4 - MMC_DATA20 */ + (2 << 20) | /* GPG5 - MMC_DATA30 */ + (2 << 24) /* GPG6 - (NC) MMC CARD DETECT */ + ; + + __REG(GPGPUD) = (1 << (6 * 2)); /* pull down card detect */ + + __REG(GPGDAT) = 0; /* just for determinism */ + + __REG(GPGCONSLP) = + (SIN << 0) | /* GPG0 - it's not powered*/ + (SIN << 2) | /* GPG1 */ + (SIN << 4) | /* GPG2 */ + (SIN << 6) | /* GPG3 */ + (SIN << 8) | /* GPG4 */ + (SIN << 10) | /* GPG5 */ + (SIN << 12) /* GPG6 */ + ; + + __REG(GPGPUDSLP) = + (SPD << 0) | /* GPG0 - it's not powered*/ + (SPD << 2) | /* GPG1 */ + (SPD << 4) | /* GPG2 */ + (SPD << 6) | /* GPG3 */ + (SPD << 8) | /* GPG4 */ + (SPD << 10) | /* GPG5 */ + (SPD << 12) /* GPG6 */ + ; + + /* ---------------------------- Port H ---------------------------- */ + + __REG(GPHCON0) = + (1 << 0) | /* GPH0 - NC OUT 0 */ + (1 << 4) | /* GPH1 - NC OUT 0 */ + (1 << 8) | /* GPH2 - NC OUT 0 */ + (1 << 12) | /* GPH3 - NC OUT 0 */ + (1 << 16) | /* GPH4 - NC OUT 0 */ + (1 << 20) | /* GPH5 - NC OUT 0 */ + (1 << 24) | /* GPH6 - OUTPUT nBT_RESET */ + (0 << 28) /* GPH7 - INPUT HDQ */ + ; + __REG(GPHCON1) = + (1 << 0) | /* GPH8 - OUTPUT BT PIO5 */ + (0 << 4) /* GPH9 - INPUT LED INT */ + ; + + __REG(GPHPUD) = (SPU << (9 * 2)) | (SPU << (7 * 2)); + + __REG(GPHDAT) = 0; + + __REG(GPHCONSLP) = + (S0 << 0) | /* GPH0 */ + (S0 << 2) | /* GPH1 */ + (S0 << 4) | /* GPH2 */ + (S0 << 6) | /* GPH3 */ + (S0 << 8) | /* GPH4 */ + (S0 << 10) | /* GPH5 */ + (S0 << 12) | /* GPH6 */ + (SIN << 14) | /* GPH7 - INPUT (HDQ) */ + (S0 << 16) | /* GPH8 */ + (SIN << 18) /* GPH9 */ + ; + + __REG(GPHPUDSLP) = (SPU << (7 * 2)) | (SPU << (9 * 2)); + + /* ---------------------------- Port I ---------------------------- */ + + __REG(GPICON) = + (0 << 0) | /* GPI0 - INPUT version b0 */ + (0 << 2) | /* GPI1 - INPUT version b1 */ + (2 << 4) | /* GPI2 - LCD_VD2 */ + (2 << 6) | /* GPI3 - LCD_VD3 */ + (2 << 8) | /* GPI4 - LCD_VD4 */ + (2 << 10) | /* GPI5 - LCD_VD5 */ + (2 << 12) | /* GPI6 - LCD_VD6 */ + (2 << 14) | /* GPI7 - LCD_VD7 */ + (0 << 16) | /* GPI8 - INPUT version b2 */ + (2 << 18) | /* GPI9 - LCD_VD9 */ + (2 << 20) | /* GPI10 - LCD_VD10 */ + (2 << 22) | /* GPI11 - LCD_VD11 */ + (2 << 24) | /* GPI12 - LCD_VD12 */ + (2 << 26) | /* GPI13 - LCD_VD13 */ + (2 << 28) | /* GPI14 - LCD_VD14 */ + (2 << 30) /* GPI15 - LCD_VD15 */ + ; + + __REG(GPIPUD) = 0; /* all pullup and pulldown disabled */ + + __REG(GPIDAT) = 0; /* just for determinism */ + + __REG(GPICONSLP) = + (SIN << 0) | /* GPI0 - input */ + (SIN << 2) | /* GPI1 - input */ + (S0 << 4) | /* GPI2 - input */ + (S0 << 6) | /* GPI3 - input */ + (S0 << 8) | /* GPI4 - input */ + (S0 << 10) | /* GPI5 - input */ + (S0 << 12) | /* GPI6 - input */ + (S0 << 14) | /* GPI7 - input */ + (SIN << 16) | /* GPI8 - input */ + (S0 << 18) | /* GPI9 - input */ + (S0 << 20) | /* GPI10 - input */ + (S0 << 22) | /* GPI11 - input */ + (S0 << 24) | /* GPI12 - input */ + (S0 << 26) | /* GPI13 - input */ + (S0 << 28) | /* GPI14 - input */ + (S0 << 30) /* GPI15 - input */ + ; + + __REG(GPIPUDSLP) = + (1 << 0) | /* GPI0 - pull down */ + (1 << 2) | /* GPI1 - pull down */ + (1 << 16) /* GPI8 - pull down */ + ; + + /* ---------------------------- Port J ---------------------------- */ + + __REG(GPJCON) = + (2 << 0) | /* GPJ0 - LCD_VD16 */ + (2 << 2) | /* GPJ1 - LCD_VD17 */ + (2 << 4) | /* GPJ2 - LCD_VD18 */ + (2 << 6) | /* GPJ3 - LCD_VD19 */ + (2 << 8) | /* GPJ4 - LCD_VD20 */ + (2 << 10) | /* GPJ5 - LCD_VD21 */ + (2 << 12) | /* GPJ6 - LCD_VD22 */ + (2 << 14) | /* GPJ7 - LCD_VD23 */ + (2 << 16) | /* GPJ8 - LCD_HSYNC */ + (2 << 18) | /* GPJ9 - LCD_VSYNC */ + (2 << 20) | /* GPJ10 - LCD_VDEN */ + (2 << 22) /* GPJ11 - LCD_VCLK */ + ; + + __REG(GPJPUD) = 0; /* all pullup and pulldown disabled */ + + __REG(GPJDAT) = 0; /* just for determinism */ + + __REG(GPJCONSLP) = + (S0 << 0) | /* GPJ0 */ + (S0 << 2) | /* GPJ1 */ + (S0 << 4) | /* GPJ2 */ + (S0 << 6) | /* GPJ3 */ + (S0 << 8) | /* GPJ4 */ + (S0 << 10) | /* GPJ5 */ + (S0 << 12) | /* GPJ6 */ + (S0 << 14) | /* GPJ7 */ + (S0 << 16) | /* GPJ8 */ + (S0 << 18) | /* GPJ9 */ + (S0 << 20) | /* GPJ10 */ + (S0 << 22) /* GPJ11 */ + ; + + __REG(GPJPUDSLP) = + 0 + ; + + /* ---------------------------- Port K ---------------------------- */ + + __REG(GPKCON0) = + (1 << 0) | /* GPK0 - OUTPUT NC */ + (1 << 4) | /* GPK1 - OUTPUT NC */ + (1 << 8) | /* GPK2 - OUTPUT (nMODEM_ON) */ + + (1 << 12) | /* GPK3 - OUTPUT (LED_TRIG) */ + (1 << 16) | /* GPK4 - OUTPUT (LED_EN) */ + (0 << 20) | /* GPK5 - OUTPUT NC */ + (1 << 24) | /* GPK6 - OUTPUT (LCD_RESET) */ + (0 << 28) /* GPK7 - OUTPUT NC */ + ; + __REG(GPKCON1) = + (1 << 0) | /* GPK8 - OUTPUT NC */ + (1 << 4) | /* GPK9 - OUTPUT NC */ + (1 << 8) | /* GPK10 - OUTPUT NC */ + (1 << 12) | /* GPK11 - OUTPUT NC */ + (1 << 16) | /* GPK12 - OUTPUT NC */ + (1 << 20) | /* GPK13 - OUTPUT NC */ + (1 << 24) | /* GPK14 - OUTPUT NC */ + (1 << 28) /* GPK15 - OUTPUT NC */ + ; + + __REG(GPKPUD) = 0; + + __REG(GPKDAT) = /* rest output 0 */ + (SHOLD << (2 * 2)) | /* nMODEM_ON */ + (SHOLD << (2 * 3)) | /* LED_TRIG */ + (SHOLD << (2 * 4)) | /* LED_EN */ + (S0 << (2 * 6)) /* LCD_RESET */ + ; + + /* ---------------------------- Port L ---------------------------- */ + + __REG(GPLCON0) = + (1 << 0) | /* GPL0 - OUTPUT (NC) */ + (1 << 4) | /* GPL1 - OUTPUT (NC) */ + (1 << 8) | /* GPL2 - OUTPUT (NC) */ + (1 << 12) | /* GPL3 - OUTPUT (NC) */ + (1 << 16) | /* GPL4 - OUTPUT (NC) */ + (1 << 20) | /* GPL5 - OUTPUT (NC) */ + (1 << 24) | /* GPL6 - OUTPUT (NC) */ + (1 << 28) /* GPL7 - OUTPUT (NC) */ + ; + __REG(GPLCON1) = + (1 << 0) | /* GPL8 - OUTPUT (NC) */ + (1 << 4) | /* GPL9 - OUTPUT (NC) */ + (1 << 8) | /* GPL10 - OUTPUT (NC) */ + (1 << 12) | /* GPL11 - OUTPUT (NC) */ + (1 << 16) | /* GPL12 - OUTPUT (NC) */ + (1 << 20) | /* GPL13 - OUTPUT (NC) */ + (1 << 24) /* GPL14 - OUTPUT (NC) */ + ; + + __REG(GPLPUD) = 0; /* all pullup and pulldown disabled */ + + __REG(GPLDAT) = 0; + + + /* ---------------------------- Port M ---------------------------- */ + + __REG(GPMCON) = + (1 << 0) | /* GPM0 - OUTPUT (TP_RESET) */ + (1 << 4) | /* GPM1 - OUTPUT (NC) */ + (1 << 8) | /* GPM2 - OUTPUT (NC) */ + (1 << 12) | /* GPM3 - OUTPUT (NC) */ + (0 << 16) | /* GPM4 - INPUT (nUSB_FLT) */ + (0 << 20) /* GPM5 - INPUT (nUSB_OC) */ + ; + + __REG(GPMPUD) = (2 << (4 * 2)) | (2 << (5 * 2)); /* Pup on inputs */ + + __REG(GPMDAT) = 0; + + /* ---------------------------- Port N ---------------------------- */ + + __REG(GPNCON) = + (2 << 0) | /* GPN0 - EXINT0 nG1INT1 */ + (2 << 2) | /* GPN1 - EXINT1 KEY_MINUS */ + (2 << 4) | /* GPN2 - EXINT2 KEY_PLUS */ + (2 << 6) | /* GPN3 - EXINT3 PWR_IND */ + (2 << 8) | /* GPN4 - EXINT4 PWR_IRQ */ + (2 << 10) | /* GPN5 - EXINT5 nTOUCH */ + (2 << 12) | /* GPN6 - EXINT6 nJACK_INSERT */ + (1 << 14) | /* GPN7 - EXINT7 NC OUTPUT */ + (2 << 16) | /* GPN8 - EXINT8 nHOLD */ + (2 << 18) | /* GPN9 - EXINT9 WLAN_WAKEUP */ + (2 << 20) | /* GPN10 - EXINT10 nG1INT2 */ + (2 << 22) | /* GPN11 - EXINT11 nIO1 */ + (2 << 24) | /* GPN12 - EXINT12 nONKEYWAKE */ + (0 << 26) | /* GPN13 - INPUT (iROM CFG0) */ + (0 << 28) | /* GPN14 - INPUT (iROM CFG1) */ + (0 << 30) /* GPN15 - INPUT (iROM CFG2) */ + ; + + __REG(GPNPUD) = + (SPD << 0) | /* GPN0 - EXINT0 nG1INT1 */ + (SPU << 2) | /* GPN1 - EXINT1 KEY_MINUS */ + (SPU << 4) | /* GPN2 - EXINT2 KEY_PLUS */ + (SPU << 6) | /* GPN3 - EXINT3 PWR_IND */ + (SNP << 8) | /* GPN4 - EXINT4 PWR_IRQ */ + (SPU << 10) | /* GPN5 - EXINT5 nTOUCH */ + (SNP << 12) | /* GPN6 - EXINT6 nJACK_INSERT */ + (SNP << 14) | /* GPN7 - EXINT7 NC OP */ + (SPU << 16) | /* GPN8 - EXINT8 nHOLD */ + (SPU << 18) | /* GPN9 - EXINT9 BT_WAKEUP */ + (SPD << 20) | /* GPN10 - EXINT10 nG1INT2 */ + (SPD << 22) | /* GPN11 - EXINT11 nIO1 */ + (SPU << 24) | /* GPN12 - EXINT12 nONKEYWAKE */ + (SPD << 26) | /* GPN13 - INPUT (iROM CFG0) */ + (SPD << 28) | /* GPN14 - INPUT (iROM CFG1) */ + (SPD << 30) /* GPN15 - INPUT (iROM CFG2) */ + ; + + __REG(GPNDAT) = 0; + + + /* ---------------------------- Port O ---------------------------- */ + + __REG(GPOCON) = + (2 << 0) | /* GPO0 - XM0CS2 (nNANDCS0) */ + (1 << 2) | /* GPO1 - OUTPUT (nMODEM_RESET) */ + (1 << 4) | /* GPO2 - OUTPUT (NC) */ + (1 << 6) | /* GPO3 - OUTPUT (NC) */ + (1 << 8) | /* GPO4 - OUTPUT (NC) */ + (1 << 10) | /* GPO5 - OUTPUT (NC) */ + (1 << 12) | /* GPO6 - OUTPUT (NC) */ + (1 << 14) | /* GPO7 - OUTPUT (NC) */ + (1 << 16) | /* GPO8 - OUTPUT (NC) */ + (1 << 18) | /* GPO9 - OUTPUT (NC) */ + (1 << 20) | /* GPO10 - OUTPUT (NC) */ + (1 << 22) | /* GPO11 - OUTPUT (NC) */ + (1 << 24) | /* GPO12 - OUTPUT (NC) */ + (1 << 26) | /* GPO13 - OUTPUT (NC) */ + (1 << 28) | /* GPO14 - OUTPUT (NC) */ + (1 << 30) /* GPO15 - OUTPUT (NC) */ + ; + + __REG(GPOPUD) = 0; /* no pulling */ + + __REG(GPODAT) = (1 << 15); /* assert CAM_PWRDN */ + + __REG(GPOCONSLP) = + (SHOLD << 0) | /* GPO0 - hold state */ + (SHOLD << 2) | /* GPO1 - OUTPUT 1 (do not reset modem) */ + (S0 << 4) | /* GPO2 - OUTPUT 0 */ + (S0 << 6) | /* GPO3 - OUTPUT 0 */ + (S0 << 8) | /* GPO4 - OUTPUT 0 */ + (S0 << 10) | /* GPO5 - OUTPUT 0 */ + (S0 << 12) | /* GPO6 - OUTPUT 0 */ + (S0 << 14) | /* GPO7 - OUTPUT 0 */ + (S0 << 16) | /* GPO8 - OUTPUT 0 */ + (S0 << 18) | /* GPO9 - OUTPUT 0 */ + (S0 << 20) | /* GPO10 - OUTPUT 0 */ + (S0 << 22) | /* GPO11 - OUTPUT 0 */ + (S0 << 24) | /* GPO12 - OUTPUT 0 */ + (S0 << 26) | /* GPO13 - OUTPUT 0 */ + (S0 << 28) | /* GPO14 - OUTPUT 0 */ + (S0 << 30) /* GPO15 - OUTPUT 0 */ + ; + + __REG(GPOPUDSLP) = + 0 + ; + + /* ---------------------------- Port P ---------------------------- */ + + __REG(GPPCON) = + (1 << 0) | /* GPP0 - input (NC) */ + (1 << 2) | /* GPP1 - input (NC) */ + (1 << 4) | /* GPP2 - input (NC) */ + (1 << 6) | /* GPP3 - input (NC) */ + (1 << 8) | /* GPP4 - input (NC) */ + (1 << 10) | /* GPP5 - input (NC) */ + (1 << 12) | /* GPP6 - input (NC) */ + (1 << 14) | /* GPP7 - input (NC) */ + (1 << 16) | /* GPP8 - input (NC) */ + (1 << 18) | /* GPP9 - input (NC) */ + (1 << 20) | /* GPP10 - input (NC) */ + (1 << 22) | /* GPP11 - input (NC) */ + (1 << 24) | /* GPP12 - input (NC) */ + (1 << 26) | /* GPP13 - input (NC) */ + (1 << 28) /* GPP14 - input (NC) */ + ; + + __REG(GPPPUD) = 0; /* no pull */ + + __REG(GPPDAT) = 0; + + __REG(GPPCONSLP) = + (S0 << 0) | /* GPP0 - OUTPUT 0 */ + (S0 << 2) | /* GPP1 - OUTPUT 0 */ + (S0 << 4) | /* GPP2 - OUTPUT 0 */ + (S0 << 6) | /* GPP3 - OUTPUT 0 */ + (S0 << 8) | /* GPP4 - OUTPUT 0 */ + (S0 << 10) | /* GPP5 - OUTPUT 0 */ + (S0 << 12) | /* GPP6 - OUTPUT 0 */ + (S0 << 14) | /* GPP7 - OUTPUT 0 */ + (S0 << 16) | /* GPP8 - OUTPUT 0 */ + (S0 << 18) | /* GPP9 - OUTPUT 0 */ + (S0 << 20) | /* GPP10 - OUTPUT 0 */ + (S0 << 22) | /* GPP11 - OUTPUT 0 */ + (S0 << 24) | /* GPP12 - OUTPUT 0 */ + (S0 << 26) | /* GPP13 - OUTPUT 0 */ + (S0 << 28) /* GPP14 - OUTPUT 0 */ + ; + + __REG(GPPPUDSLP) = 0; + + /* ---------------------------- Port Q ---------------------------- */ + + __REG(GPQCON) = + (1 << 0) | /* GPQ0 - OUTPUT (NC) */ + (1 << 2) | /* GPQ1 - OUTPUT (NC) */ + (1 << 4) | /* GPQ2 - OUTPUT (NC) */ + (1 << 6) | /* GPQ3 - OUTPUT (NC) */ + (1 << 8) | /* GPQ4 - OUTPUT (NC) */ + (1 << 10) | /* GPQ5 - OUTPUT (NC) */ + (1 << 12) | /* GPQ6 - OUTPUT (NC) */ + (1 << 14) | /* GPQ7 - OUTPUT (NC) */ + (1 << 16) /* GPQ8 - OUTPUT (NC) */ + ; + + __REG(GPQPUD) = 0; /* no pull */ + + __REG(GPQDAT) = 0; + + __REG(GPQCONSLP) = + (S0 << 0) | /* GPQ0 - OUTPUT 0 */ + (S0 << 2) | /* GPQ1 - OUTPUT 0 */ + (S0 << 4) | /* GPQ2 - OUTPUT 0 */ + (S0 << 6) | /* GPQ3 - OUTPUT 0 */ + (S0 << 8) | /* GPQ4 - OUTPUT 0 */ + (S0 << 10) | /* GPQ5 - OUTPUT 0 */ + (S0 << 12) | /* GPQ6 - OUTPUT 0 */ + (S0 << 14) | /* GPQ7 - OUTPUT 0 */ + (S0 << 16) /* GPQ8 - OUTPUT 0 */ + ; + + __REG(GPQPUDSLP) = 0; + + /* LCD Controller enable */ + + __REG(0x7410800c) = 0; + __REG(0x7f0081a0) = 0xbfc115c1; + + /* + * We have to talk to the PMU a little bit + */ + for (n = 0; n < ARRAY_SIZE(om_3d7k_pcf50633_init); n++) + i2c_write_sync(&bb_s3c6410, PCF50633_I2C_ADS, + om_3d7k_pcf50633_init[n].index, + om_3d7k_pcf50633_init[n].value); + +} + +int om_3d7k_get_pcb_revision(void) +{ + u32 v = __REG(GPIDAT); + /* + * PCB rev is 3 bit code (info from Dkay) + * (b2, b1, b0) = (0,0,1) => pcb rev A1 + * maximum rev = A7 + * bit0 = GPI8 + * bit1 = GPI1 + * bit2 = GPI0 + */ + + return ( + ((v & (1 << 8)) ? 1 : 0) | + ((v & (1 << 1)) ? 2 : 0) | + ((v & (1 << 0)) ? 4 : 0) + ); +} + +const struct board_variant const * get_board_variant_om_3d7k(void) +{ + return &board_variants[om_3d7k_get_pcb_revision()]; +} + diff --git a/qiboot/src/cpu/s3c6410/qi.lds b/qiboot/src/cpu/s3c6410/qi.lds new file mode 100644 index 0000000..22d8546 --- /dev/null +++ b/qiboot/src/cpu/s3c6410/qi.lds @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + __system_ram_start = 0x50000000; + __steppingstone = 0x0c000000; + + /* this text section is magically pulled from the SD Card + * and stored by the iRom at 0x0c000000, then it is jumped into + * by the iRom. So we arrange our early parts needed at 0 in the + * output file, but set to run at 0x0c000000+ + */ + + .text + __steppingstone : + AT (0) + { + src/cpu/s3c6410/start.o (.text .rodata* .data .bss) + src/cpu/s3c6410/start_qi.o (.text .rodata* .data .bss) + src/cpu/s3c6410/serial-s3c64xx.o (.text .rodata* .data .bss) + src/cpu/s3c6410/om_3d7k-steppingstone.o (.text .rodata* .data .bss) + src/cpu/s3c6410/smdk6410-steppingstone.o (.text .rodata* .data .bss) + src/cpu/s3c6410/hs_mmc.o (.text .rodata* .data .bss) + src/utils.o (.text .rodata* .data .bss) + src/memory-test.o (.text .rodata* .data .bss) +/* src/ctype.o (.text .rodata* .data .bss) */ + * (.steppingstone) + } + + . = ALIGN(4); + .everything_else + __system_ram_start + 0x3000000 + SIZEOF(.text) : + AT (SIZEOF(.text)) + { + *(.text .rodata* .data) + } + + + __bss_start = __system_ram_start + 0x03800000; + .bss_6410 + __bss_start (NOLOAD) : + AT (SIZEOF(.text) + SIZEOF(.everything_else)) + { + * (.bss) + } + + _end = .; +} diff --git a/qiboot/src/cpu/s3c6410/serial-s3c64xx.c b/qiboot/src/cpu/s3c6410/serial-s3c64xx.c new file mode 100644 index 0000000..256419b --- /dev/null +++ b/qiboot/src/cpu/s3c6410/serial-s3c64xx.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +/* + * Output a single byte to the serial port. + */ +void serial_putc_s3c64xx(const int uart, const char c) +{ + if (uart >= 4) + return; + + while (!(__REG(0x7F005000 + UTRSTAT_OFFSET + (uart << 10)) & 0x2)) + ; + + __REG(0x7F005000 + UTXH_OFFSET + (uart << 10)) = c; +} diff --git a/qiboot/src/cpu/s3c6410/smdk6410-steppingstone.c b/qiboot/src/cpu/s3c6410/smdk6410-steppingstone.c new file mode 100644 index 0000000..c1d991f --- /dev/null +++ b/qiboot/src/cpu/s3c6410/smdk6410-steppingstone.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#define SMDK6410_DEBUG_UART 0 + +extern const struct board_variant const * get_board_variant_smdk6410(void); + +int is_this_board_smdk6410(void) +{ + /* FIXME: find something smdk6410 specific */ + return 1; +} + +static void putc_smdk6410(char c) +{ + serial_putc_s3c64xx(SMDK6410_DEBUG_UART, c); +} + +int sd_card_init_smdk6410(void) +{ + extern int s3c6410_mmc_init(int verbose); + + return s3c6410_mmc_init(1); +} + +int sd_card_block_read_smdk6410(unsigned char * buf, unsigned long start512, + int blocks512) +{ +unsigned long s3c6410_mmc_bread(int dev_num, unsigned long blknr, + unsigned long blkcnt, void *dst); + + return s3c6410_mmc_bread(0, start512, blocks512, buf); +} + +/* + * our API for bootloader on this machine + */ +const struct board_api board_api_smdk6410 = { + .name = "SMDK6410", + .linux_machine_id = 1866 /* 1626 */, + .linux_mem_start = 0x50000000, + .linux_mem_size = (128 * 1024 * 1024), + .linux_tag_placement = 0x50000000 + 0x100, + .get_board_variant = get_board_variant_smdk6410, + .is_this_board = is_this_board_smdk6410, + .putc = putc_smdk6410, + .commandline_board = "console=ttySAC0,115200 " + "loglevel=3 " + "init=/bin/sh ", + .commandline_board_debug = " loglevel=8", + .noboot = "boot/noboot-SDMK6410", + .append = "boot/append-SMDK6410", + .kernel_source = { + [0] = { + .name = "SD Card rootfs", + .block_read = sd_card_block_read_smdk6410, + .filesystem = FS_EXT2, + .partition_index = 2, + .filepath = "boot/uImage-SMDK6410.bin", + .commandline_append = "root=/dev/mmcblk0p2 " + }, + [1] = { + .name = "SD Card backup rootfs", + .block_read = sd_card_block_read_smdk6410, + .filesystem = FS_EXT2, + .partition_index = 3, + .filepath = "boot/uImage-SMDK6410.bin", + .commandline_append = "root=/dev/mmcblk0p3 " + }, + }, +}; + diff --git a/qiboot/src/cpu/s3c6410/smdk6410.c b/qiboot/src/cpu/s3c6410/smdk6410.c new file mode 100644 index 0000000..63dc3b6 --- /dev/null +++ b/qiboot/src/cpu/s3c6410/smdk6410.c @@ -0,0 +1,27 @@ +#include +#include +#include + +static const struct board_variant board_variants[] = { + [0] = { + .name = "SMDK", + .machine_revision = 0, + }, +}; + +/** + * returns PCB revision information in b0, d8, d9 + * SMDK6410 EVB returns 0x000 + * SMDK6410 returns 0x001 + */ + +int smdk6410_get_pcb_revision(void) +{ + return 0; +} + +const struct board_variant const * get_board_variant_smdk6410(void) +{ + return &board_variants[smdk6410_get_pcb_revision()]; +} + diff --git a/qiboot/src/cpu/s3c6410/start.S b/qiboot/src/cpu/s3c6410/start.S new file mode 100644 index 0000000..be90d57 --- /dev/null +++ b/qiboot/src/cpu/s3c6410/start.S @@ -0,0 +1,487 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define __ASM_MODE__ +#define __ASSEMBLY__ + +#include + +#define TEXT_BASE 0x53000000 + + +#define S3C6410_POP_A 1 + +#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv) + +/* fixed MPLL 533MHz */ +#define MPLL_MDIV 266 +#define MPLL_PDIV 3 +#define MPLL_SDIV 1 + +#define Startup_APLLdiv 0 +#define APLL_MDIV 266 +#define APLL_PDIV 3 +#define APLL_SDIV 1 +#define Startup_PCLKdiv 3 +#define Startup_HCLKdiv 1 +#define Startup_MPLLdiv 1 +#define Startup_HCLKx2div 1 +#define Startup_APLL (12000000/(APLL_PDIV< EXT_UCLK1*/ + + str r1, [r0, #UCON_OFFSET] + + ldr r1, =0x22 + str r1, [r0, #UBRDIV_OFFSET] + + ldr r1, =0x1FFF + str r1, [r0, #UDIVSLOT_OFFSET] + + /* resuming? */ + + ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET) + ldr r1, [r0] + bic r1, r1, #0xfffffff7 + cmp r1, #0x8 + beq wakeup_reset + + /* no, cold boot */ + + ldr r0, =ELFIN_UART_BASE + ELFIN_UART3_OFFSET + ldr r1, =0x55 + str r1, [r0, #UTXH_OFFSET] @'U' + /* >> CFG_VIDEO_LOGO_MAX_SIZE */ +#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ + + + ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ + sub sp, r0, #12 /* leave 3 words for abort-stack */ +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0x00000000 /* clear */ + +clbss_l: + str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + + b _steppingstone_done + + /* resume */ + +wakeup_reset: + + ldr r0, =ELFIN_UART_BASE + ELFIN_UART3_OFFSET + ldr r1, =0x4b4b4b4b + str r1, [r0, #UTXH_OFFSET] + + /*Clear wakeup status register*/ + ldr r0, =(ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET) + ldr r1, [r0] + str r1, [r0] + +#if 0 + /*LED test*/ + ldr r0, =ELFIN_GPIO_BASE + ldr r1, =0x3000 + str r1, [r0, #GPNDAT_OFFSET] +#endif + + /*Load return address and jump to kernel*/ + ldr r0, =(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET) + ldr r1, [r0] /* r1 = physical address of s3c6400_cpu_resume function*/ + mov pc, r1 /*Jump to kernel (sleep-s3c6400.S)*/ + nop + nop + +4: + b 4b diff --git a/qiboot/src/cpu/s3c6410/start_qi.c b/qiboot/src/cpu/s3c6410/start_qi.c new file mode 100644 index 0000000..e85d63b --- /dev/null +++ b/qiboot/src/cpu/s3c6410/start_qi.c @@ -0,0 +1,136 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * Andy Green + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* NOTE this stuff runs in steppingstone context! */ + + +#include +#include +#include + +#define stringify2(s) stringify1(s) +#define stringify1(s) #s + +extern void bootloader_second_phase(void); + +const struct board_api *boards[] = { + &board_api_om_3d7k, + &board_api_smdk6410, + NULL /* always last */ +}; + +struct board_api const * this_board; +extern int is_jtag; + +#include + +void start_qi(void) +{ + int flag = 0; + int board = 0; + unsigned int sd_sectors = 0; + + /* + * well, we can be running on this CPU two different ways. + * + * 1) We were copied into steppingstone and TEXT_BASE already + * by JTAG. We don't have to do anything else. JTAG script + * then sets data at address 0x4 to 0xffffffff as a signal we + * are running by JTAG. + * + * 2) We only got our first 4K into steppingstone, we need to copy + * the rest of ourselves into TEXT_BASE. + * + * So we do the copy out of NAND only if we see we did not come up + * under control of JTAG. + */ + + + /* ask all the boards we support in turn if they recognize this + * hardware we are running on, accept the first positive answer + */ + + this_board = boards[board]; + while (!flag && this_board) + /* check if it is the right board... */ + if (this_board->is_this_board()) + flag = 1; + else + this_board = boards[board++]; + + /* okay, do the critical port and serial init for our board */ + + if (this_board->early_port_init) + this_board->early_port_init(); + + set_putc_func(this_board->putc); + + /* stick some hello messages on debug console */ + + puts("\n\n\nQi Bootloader "stringify2(QI_CPU)" " + stringify2(BUILD_HOST)" " + stringify2(BUILD_VERSION)" " + "\n"); + + puts(stringify2(BUILD_DATE) " Copyright (C) 2008 Openmoko, Inc.\n\n"); + + if (!is_jtag) { + /* + * We got the first 8KBytes of the bootloader pulled into the + * steppingstone SRAM for free. Now we pull the whole bootloader + * image into SDRAM. + * + * This code and the .S files are arranged by the linker script + * to expect to run from 0x0. But the linker script has told + * everything else to expect to run from 0x53000000+. That's + * why we are going to be able to copy this code and not have it + * crash when we run it from there. + */ + + /* We randomly pull 32KBytes of bootloader */ + + extern unsigned int s3c6410_mmc_init(int verbose); + unsigned long s3c6410_mmc_bread(int dev_num, + unsigned long start_blk, unsigned long blknum, + void *dst); + sd_sectors = s3c6410_mmc_init(1); + s3c6410_mmc_bread(0, sd_sectors - 1026 - 16 - (256 * 2), + 32 * 2, (u8 *)0x53000000); + } + + /* all of Qi is in memory now, stuff outside steppingstone too */ + + if (this_board->port_init) + this_board->port_init(); + + puts("\n Detected: "); + puts(this_board->name); + puts(", "); + puts((this_board->get_board_variant)()->name); + puts("\n"); + + /* + * jump to bootloader_second_phase() running from DRAM copy + */ + bootloader_second_phase(); +} diff --git a/qiboot/src/crc32.c b/qiboot/src/crc32.c new file mode 100644 index 0000000..81f1792 --- /dev/null +++ b/qiboot/src/crc32.c @@ -0,0 +1,90 @@ +#include +#include + + +/* original copyright notice for this crc code (it is from U-Boot) --> */ +/* + * This file is derived from crc32.c from the zlib-1.1.3 distribution + * by Jean-loup Gailly and Mark Adler. + */ + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +const unsigned long crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +unsigned long crc32(unsigned long crc, const unsigned char *buf, + unsigned int len) +{ + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8(buf); + len -= 8; + } + if (len) + do { + DO1(buf); + } while (--len); + + return crc ^ 0xffffffffL; +} diff --git a/qiboot/src/ctype.c b/qiboot/src/ctype.c new file mode 100644 index 0000000..cf5a5a6 --- /dev/null +++ b/qiboot/src/ctype.c @@ -0,0 +1,27 @@ +#include + +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ diff --git a/qiboot/src/drivers/glamo-init.c b/qiboot/src/drivers/glamo-init.c new file mode 100644 index 0000000..cf96794 --- /dev/null +++ b/qiboot/src/drivers/glamo-init.c @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2007 by OpenMoko, Inc. + * Author: Harald Welte + * Andy Green + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#define GLAMO_REG(x) (*(volatile unsigned short *)(0x08000000 + x)) + +static void glamo_reg_write(u16 reg, u16 val) +{ + GLAMO_REG(reg) = val; +} + +static u16 glamo_reg_read(u16 reg) +{ + return GLAMO_REG(reg); +} + + +static u16 u16a_gen_init_0x0000[] = { + 0x2020, 0x3650, 0x0002, 0x01FF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x000D, 0x000B, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1801 /*0x1839*/, 0x0000, 0x2000, 0x0001, 0x0100, 0x0000, 0x0000, 0x0000, + 0x05DB, 0x5231, 0x09C3, 0x8261, 0x0003, 0x0000, 0x0000, 0x0000, + 0x000F, 0x101E, 0xC0C3, 0x101E, 0x000F, 0x0001, 0x030F, 0x020F, + 0x080F, 0x0F0F +}; + +static u16 u16a_gen_init_0x0200[] = { + 0x0EF0, 0x07FF, 0x0000, 0x0080, 0x0344, 0x0600, 0x0000, 0x0000, + 0x0000, 0x0000, 0x4000, 0xF00E, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x0873, 0xAFAF, 0x0108, 0x0010, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x1002, 0x6006, 0x00FF, 0x0001, 0x0020, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x3210, 0x5432, 0xE100, 0x01D6 +}; + + +void glamo_core_init(void) +{ + int bp; + + /* power up PLL1 and PLL2 */ + glamo_reg_write(GLAMO_REG_PLL_GEN7, 0x0000); + glamo_reg_write(GLAMO_REG_PLL_GEN3, 0x0400); + + /* enable memory clock and get it out of deep pwrdown */ + glamo_reg_write(GLAMO_REG_CLOCK_MEMORY, + glamo_reg_read(GLAMO_REG_CLOCK_MEMORY) | 8); + glamo_reg_write(GLAMO_REG_MEM_DRAM2, + glamo_reg_read(GLAMO_REG_MEM_DRAM2) & (~(1 << 12))); + glamo_reg_write(GLAMO_REG_MEM_DRAM1, + glamo_reg_read(GLAMO_REG_MEM_DRAM1) & (~(1 << 12))); + /* + * we just fill up the general hostbus and LCD register sets + * with magic values taken from the Linux framebuffer init action + */ + for (bp = 0; bp < ARRAY_SIZE(u16a_gen_init_0x0000); bp++) + glamo_reg_write(0x0 | (bp << 1), + u16a_gen_init_0x0000[bp]); + + for (bp = 0; bp < ARRAY_SIZE(u16a_gen_init_0x0200); bp++) + glamo_reg_write(0x200 | (bp << 1), + u16a_gen_init_0x0200[bp]); + + /* spin until PLL1 lock */ + while (!(glamo_reg_read(GLAMO_REG_PLL_GEN5) & 1)) + ; +} + diff --git a/qiboot/src/drivers/glamo-mmc.c b/qiboot/src/drivers/glamo-mmc.c new file mode 100644 index 0000000..c3b92c3 --- /dev/null +++ b/qiboot/src/drivers/glamo-mmc.c @@ -0,0 +1,851 @@ +/* + * linux/drivers/mmc/host/glamo-mmc.c - Glamo MMC driver + * + * Copyright (C) 2007 OpenMoko, Inc, Andy Green + * Based on the Glamo MCI driver that was --> + * + * Copyright (C) 2007 OpenMoko, Inc, Andy Green + * Based on S3C MMC driver that was: + * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel + * + * and + * + * Based on S3C MMC driver that was (original copyright notice ---->) + * + * (C) Copyright 2006 by OpenMoko, Inc. + * Author: Harald Welte + * + * based on u-boot pxa MMC driver and linux/drivers/mmc/s3c2410mci.c + * (C) 2005-2005 Thomas Kleffel + * + * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include + +#define CONFIG_GLAMO_BASE 0x08000000 + +#define MMC_BLOCK_SIZE_BITS 9 + +#define GLAMO_REG(x) (*(volatile u16 *)(CONFIG_GLAMO_BASE + x)) +#define GLAMO_INTRAM_OFFSET (8 * 1024 * 1024) +#define GLAMO_FB_SIZE ((8 * 1024 * 1024) - 0x10000) +#define GLAMO_START_OF_MMC_INTMEM ((volatile u16 *)(CONFIG_GLAMO_BASE + \ + GLAMO_INTRAM_OFFSET + GLAMO_FB_SIZE)) + +static int ccnt; +//static mmc_csd_t mmc_csd; +static int mmc_ready = 0; +//static int wide = 0; +static enum card_type card_type = CARDTYPE_NONE; + + +#define MULTI_READ_BLOCKS_PER_COMMAND 64 + +int mmc_read(unsigned long src, u8 *dst, int size); + +#define UNSTUFF_BITS(resp,start,size) \ + ({ \ + const int __size = size; \ + const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ + const int __off = 3 - ((start) / 32); \ + const int __shft = (start) & 31; \ + u32 __res; \ + \ + __res = resp[__off] >> __shft; \ + if (__size + __shft > 32) \ + __res |= resp[__off-1] << ((32 - __shft) & 31); \ + __res & __mask; \ + }) + + +static void +glamo_reg_write(u16 val, u16 reg) +{ + GLAMO_REG(reg) = val; +} + +static u16 +glamo_reg_read(u16 reg) +{ + return GLAMO_REG(reg); +} + +unsigned char CRC7(u8 * pu8, int cnt) +{ + u8 crc = 0; + + while (cnt--) { + int n; + u8 d = *pu8++; + for (n = 0; n < 8; n++) { + crc <<= 1; + if ((d & 0x80) ^ (crc & 0x80)) + crc ^= 0x09; + d <<= 1; + } + } + return (crc << 1) | 1; +} + +unsigned long mmc_bread(int dev_num, unsigned long blknr, unsigned long blkcnt, + void *dst) +{ + int ret; + + if (!blkcnt) + return 0; + +/* printf("mmc_bread(%d, %ld, %ld, %p)\n", dev_num, blknr, blkcnt, dst); */ + ret = mmc_read(blknr, dst, blkcnt); + if (ret) + return ret; + + return blkcnt; +} + +/* MMC_DEFAULT_RCA should probably be just 1, but this may break other code + that expects it to be shifted. */ +static u16 rca = MMC_DEFAULT_RCA >> 16; + +static void do_pio_read(u16 *buf, int count_words) +{ + volatile u16 *from_ptr = GLAMO_START_OF_MMC_INTMEM; + + while (count_words--) + *buf++ = *from_ptr++; +} + +static void do_pio_write(u16 *buf, int count_words) +{ + volatile u16 *to_ptr = GLAMO_START_OF_MMC_INTMEM; + + while (count_words--) + *to_ptr++ = *buf++; +} + + +static int mmc_cmd(int opcode, int arg, int flags, + int data_size, int data_blocks, + int will_stop, u16 *resp) +{ + u16 * pu16 = (u16 *)&resp[0]; + u16 * reg_resp = (u16 *)(CONFIG_GLAMO_BASE + GLAMO_REGOFS_MMC + + GLAMO_REG_MMC_CMD_RSP1); + u16 status; + int n; + u8 u8a[6]; + u16 fire = 0; + int cmd_is_stop = 0; + int error = 0; + +#if 0 + printf("mmc_cmd(opcode=%d, arg=0x%08X, flags=0x%x, " + "data_size=%d, data_blocks=%d, will_stop=%d, resp=%p)\n", + opcode, arg, flags, data_size, data_blocks, will_stop, resp); +#endif + switch (opcode) { + case MMC_STOP_TRANSMISSION: + cmd_is_stop = 1; + break; + default: + break; + } + + ccnt++; + + /* this guy has data to read/write? */ + if ((!cmd_is_stop) && (flags & (MMC_DATA_WRITE | MMC_DATA_READ))) { + /* + * the S-Media-internal RAM offset for our MMC buffer + */ + glamo_reg_write((u16)GLAMO_FB_SIZE, + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_WDATADS1); + glamo_reg_write((u16)(GLAMO_FB_SIZE >> 16), + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_WDATADS2); + glamo_reg_write((u16)GLAMO_FB_SIZE, + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_RDATADS1); + glamo_reg_write((u16)(GLAMO_FB_SIZE >> 16), + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_RDATADS2); + + /* set up the block info */ + glamo_reg_write(data_size, GLAMO_REGOFS_MMC + + GLAMO_REG_MMC_DATBLKLEN); + glamo_reg_write(data_blocks, GLAMO_REGOFS_MMC + + GLAMO_REG_MMC_DATBLKCNT); + } + + /* if we can't do it, reject as busy */ + if (!glamo_reg_read(GLAMO_REGOFS_MMC + GLAMO_REG_MMC_RB_STAT1) & + GLAMO_STAT1_MMC_IDLE) + return -1; + + /* create an array in wire order for CRC computation */ + u8a[0] = 0x40 | (opcode & 0x3f); + u8a[1] = (arg >> 24); + u8a[2] = (arg >> 16); + u8a[3] = (arg >> 8); + u8a[4] = arg; + u8a[5] = CRC7(&u8a[0], 5); /* CRC7 on first 5 bytes of packet */ + + /* issue the wire-order array including CRC in register order */ + glamo_reg_write((u8a[4] << 8) | u8a[5], + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_REG1); + glamo_reg_write((u8a[2] << 8) | u8a[3], + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_REG2); + glamo_reg_write((u8a[0] << 8) | u8a[1], + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_REG3); + + /* command index toggle */ + fire |= (ccnt & 1) << 12; + + /* set type of command */ + switch (mmc_cmd_type(flags)) { + case MMC_CMD_BC: + fire |= GLAMO_FIRE_MMC_CMDT_BNR; + break; + case MMC_CMD_BCR: + fire |= GLAMO_FIRE_MMC_CMDT_BR; + break; + case MMC_CMD_AC: + fire |= GLAMO_FIRE_MMC_CMDT_AND; + break; + case MMC_CMD_ADTC: + fire |= GLAMO_FIRE_MMC_CMDT_AD; + break; + } + /* + * if it expects a response, set the type expected + * + * R1, Length : 48bit, Normal response + * R1b, Length : 48bit, same R1, but added card busy status + * R2, Length : 136bit (really 128 bits with CRC snipped) + * R3, Length : 48bit (OCR register value) + * R4, Length : 48bit, SDIO_OP_CONDITION, Reverse SDIO Card + * R5, Length : 48bit, IO_RW_DIRECTION, Reverse SDIO Card + * R6, Length : 48bit (RCA register) + * R7, Length : 48bit (interface condition, VHS(voltage supplied), + * check pattern, CRC7) + */ + switch (mmc_resp_type(flags)) { + case MMC_RSP_R6: /* same index as R7 and R1 */ + fire |= GLAMO_FIRE_MMC_RSPT_R1; + break; + case MMC_RSP_R1B: + fire |= GLAMO_FIRE_MMC_RSPT_R1b; + break; + case MMC_RSP_R2: + fire |= GLAMO_FIRE_MMC_RSPT_R2; + break; + case MMC_RSP_R3: + fire |= GLAMO_FIRE_MMC_RSPT_R3; + break; + /* R4 and R5 supported by chip not defined in linux/mmc/core.h (sdio) */ + } + /* + * From the command index, set up the command class in the host ctrllr + * + * missing guys present on chip but couldn't figure out how to use yet: + * 0x0 "stream read" + * 0x9 "cancel running command" + */ + switch (opcode) { + case MMC_READ_SINGLE_BLOCK: + fire |= GLAMO_FIRE_MMC_CC_SBR; /* single block read */ + break; + case MMC_SWITCH: /* 64 byte payload */ + case 0x33: /* observed issued by MCI */ + case MMC_READ_MULTIPLE_BLOCK: + /* we will get an interrupt off this */ + if (!will_stop) + /* multiblock no stop */ + fire |= GLAMO_FIRE_MMC_CC_MBRNS; + else + /* multiblock with stop */ + fire |= GLAMO_FIRE_MMC_CC_MBRS; + break; + case MMC_WRITE_BLOCK: + fire |= GLAMO_FIRE_MMC_CC_SBW; /* single block write */ + break; + case MMC_WRITE_MULTIPLE_BLOCK: + if (will_stop) + /* multiblock with stop */ + fire |= GLAMO_FIRE_MMC_CC_MBWS; + else + /* multiblock NO stop-- 'RESERVED'? */ + fire |= GLAMO_FIRE_MMC_CC_MBWNS; + break; + case MMC_STOP_TRANSMISSION: + fire |= GLAMO_FIRE_MMC_CC_STOP; /* STOP */ + break; + default: + fire |= GLAMO_FIRE_MMC_CC_BASIC; /* "basic command" */ + break; + } + /* enforce timeout */ + glamo_reg_write(0xfff, GLAMO_REGOFS_MMC + GLAMO_REG_MMC_TIMEOUT); + + /* Generate interrupt on txfer; drive strength max */ + glamo_reg_write((glamo_reg_read(GLAMO_REGOFS_MMC + + GLAMO_REG_MMC_BASIC) & 0xfe) | + 0x0800 | GLAMO_BASIC_MMC_NO_CLK_RD_WAIT | + GLAMO_BASIC_MMC_EN_COMPL_INT | + GLAMO_BASIC_MMC_EN_DR_STR0 | + GLAMO_BASIC_MMC_EN_DR_STR1, + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_BASIC); + + /* send the command out on the wire */ + /* dev_info(&host->pdev->dev, "Using FIRE %04X\n", fire); */ + glamo_reg_write(fire, GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_FIRE); + + /* + * we must spin until response is ready or timed out + * -- we don't get interrupts unless there is a bulk rx + */ + do + status = glamo_reg_read(GLAMO_REGOFS_MMC + + GLAMO_REG_MMC_RB_STAT1); + while ((((status >> 15) & 1) != (ccnt & 1)) || + (!(status & (GLAMO_STAT1_MMC_RB_RRDY | + GLAMO_STAT1_MMC_RTOUT | + GLAMO_STAT1_MMC_DTOUT | + GLAMO_STAT1_MMC_BWERR | + GLAMO_STAT1_MMC_BRERR)))); + + if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT)) + error = -4; + if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) + error = -5; + + if (cmd_is_stop) + return 0; + + if (error) { +#if 0 + puts("cmd 0x"); + print8(opcode); + puts(", arg 0x"); + print8(arg); + puts(", flags 0x"); + print32(flags); + puts("\n"); + puts("Error after cmd: 0x"); + print32(error); + puts("\n"); +#endif + goto done; + } + /* + * mangle the response registers in two different exciting + * undocumented ways discovered by trial and error + */ + if (mmc_resp_type(flags) == MMC_RSP_R2) + /* grab the response */ + for (n = 0; n < 8; n++) /* super mangle power 1 */ + pu16[n ^ 6] = reg_resp[n]; + else + for (n = 0; n < 3; n++) /* super mangle power 2 */ + pu16[n] = (reg_resp[n] >> 8) | + (reg_resp[n + 1] << 8); + /* + * if we don't have bulk data to take care of, we're done + */ + if (!(flags & (MMC_DATA_READ | MMC_DATA_WRITE))) + goto done; + + /* enforce timeout */ + glamo_reg_write(0xfff, GLAMO_REGOFS_MMC + GLAMO_REG_MMC_TIMEOUT); + /* + * spin + */ + while (!(glamo_reg_read(GLAMO_REG_IRQ_STATUS) & GLAMO_IRQ_MMC)) + ; + /* ack this interrupt source */ + glamo_reg_write(GLAMO_IRQ_MMC, GLAMO_REG_IRQ_CLEAR); + + if (status & GLAMO_STAT1_MMC_DTOUT) + error = -1; + if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) + error = -2; + if (status & GLAMO_STAT1_MMC_RTOUT) + error = -5; + if (error) { +// printf("cmd 0x%x, arg 0x%x flags 0x%x\n", opcode, arg, flags); +#if 0 + puts("Error after resp: 0x"); + print32(status); + puts("\n"); +#endif + goto done; + } +#if 0 + if (flags & MMC_DATA_READ) { + volatile u8 * pu8 = (volatile u8 *)GLAMO_START_OF_MMC_INTMEM; + for (n = 0; n < 512; n += 16) { + int n1; + for (n1 = 0; n1 < 16; n1++) { + printf("%02X ", pu8[n + n1]); + } + printf("\n"); + } + } +#endif + return 0; + +done: + return error; +} + +static void glamo_mci_reset(void) +{ + /* reset MMC controller */ + glamo_reg_write(GLAMO_CLOCK_MMC_RESET | GLAMO_CLOCK_MMC_DG_TCLK | + GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK | + GLAMO_CLOCK_MMC_EN_M9CLK, + GLAMO_REG_CLOCK_MMC); + /* and disable reset */ + glamo_reg_write(GLAMO_CLOCK_MMC_DG_TCLK | + GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK | + GLAMO_CLOCK_MMC_EN_M9CLK, + GLAMO_REG_CLOCK_MMC); +} + + + +int mmc_read(unsigned long src, u8 *dst, int size) +{ + int resp; + u8 response[16]; + int size_original = size; + int lump; + + if (((int)dst) & 1) { + puts("Bad align on dst\n"); + return 0; + } + + resp = mmc_cmd(MMC_SET_BLOCKLEN, MMC_BLOCK_SIZE, + MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0, + (u16 *)&response[0]); + if (resp) + return resp; + + while (size) { + /* glamo mmc times out as this increases too much */ + lump = MULTI_READ_BLOCKS_PER_COMMAND; + if (lump > size) + lump = size; + + switch (card_type) { + case CARDTYPE_SDHC: /* block addressing */ + resp = mmc_cmd(MMC_READ_MULTIPLE_BLOCK, + src, + MMC_CMD_ADTC | MMC_RSP_R1 | + MMC_DATA_READ, MMC_BLOCK_SIZE, lump, 1, + (u16 *)&response[0]); + break; + default: /* byte addressing */ + resp = mmc_cmd(MMC_READ_MULTIPLE_BLOCK, src * MMC_BLOCK_SIZE, + MMC_CMD_ADTC | MMC_RSP_R1 | MMC_DATA_READ, + MMC_BLOCK_SIZE, lump, 1, + (u16 *)&response[0]); + break; + } + + if (resp) + return resp; + + /* final speed 16MHz */ + glamo_reg_write((glamo_reg_read(GLAMO_REG_CLOCK_GEN8) & + 0xff00) | 2, GLAMO_REG_CLOCK_GEN8); + + + do_pio_read((u16 *)dst, lump * MMC_BLOCK_SIZE >> 1); + + if (size) + size -= lump; + + dst += lump * MMC_BLOCK_SIZE; + src += lump; + + resp = mmc_cmd(MMC_STOP_TRANSMISSION, 0, + MMC_CMD_AC | MMC_RSP_R1B, 0, 0, 0, + (u16 *)&response[0]); + if (resp) + return resp; + + } + + return size_original; +} + +int mmc_write(u8 *src, unsigned long dst, int size) +{ + int resp; + u8 response[16]; + int size_original = size; + + if ((!size) || (size & (MMC_BLOCK_SIZE - 1))) { + puts("Bad size 0x"); + print32(size); + return 0; + } + + if (((int)dst) & 1) { + puts("Bad align on dst\n"); + return 0; + } + + resp = mmc_cmd(MMC_SET_BLOCKLEN, MMC_BLOCK_SIZE, + MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0, + (u16 *)&response[0]); + + while (size) { + do_pio_write((u16 *)src, MMC_BLOCK_SIZE >> 1); + switch (card_type) { + case CARDTYPE_SDHC: /* block addressing */ + resp = mmc_cmd(MMC_WRITE_BLOCK, + dst >> MMC_BLOCK_SIZE_BITS, + MMC_CMD_ADTC | MMC_RSP_R1 | + MMC_DATA_WRITE, + MMC_BLOCK_SIZE, 1, 0, + (u16 *)&response[0]); + break; + default: /* byte addressing */ + resp = mmc_cmd(MMC_WRITE_BLOCK, dst, + MMC_CMD_ADTC | MMC_RSP_R1 | + MMC_DATA_WRITE, + MMC_BLOCK_SIZE, 1, 0, + (u16 *)&response[0]); + break; + } + if (size >= MMC_BLOCK_SIZE) + size -= MMC_BLOCK_SIZE; + else + size = 0; + dst += MMC_BLOCK_SIZE; + src += MMC_BLOCK_SIZE; + } + return size_original; +} + +#if 0 +static void print_mmc_cid(mmc_cid_t *cid) +{ + puts("MMC found. Card desciption is:\n"); + puts("Manufacturer ID = "); + print8(cid->id[0]); + print8(cid->id[1]); + print8(cid->id[2]); +/* + puts("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev); + cid->hwrev = cid->fwrev = 0; + puts("Product Name = %s\n",cid->name); + printf("Serial Number = %02x%02x%02x\n", + cid->sn[0], cid->sn[1], cid->sn[2]); + printf("Month = %d\n",cid->month); + printf("Year = %d\n",1997 + cid->year); +*/ +} +#endif +static void print_sd_cid(const struct sd_cid *cid) +{ + puts(" Card Type: "); + switch (card_type) { + case CARDTYPE_NONE: + puts("(None) / "); + break; + case CARDTYPE_MMC: + puts("MMC / "); + break; + case CARDTYPE_SD: + puts("SD / "); + break; + case CARDTYPE_SD20: + puts("SD 2.0 / "); + break; + case CARDTYPE_SDHC: + puts("SD 2.0 SDHC / "); + break; + } + + puts("Mfr: 0x"); + print8(cid->mid); + puts(", OEM \""); + this_board->putc(cid->oid_0); + this_board->putc(cid->oid_1); + puts("\" / "); + + this_board->putc(cid->pnm_0); + this_board->putc(cid->pnm_1); + this_board->putc(cid->pnm_2); + this_board->putc(cid->pnm_3); + this_board->putc(cid->pnm_4); + puts("\", rev "); + printdec(cid->prv >> 4); + puts("."); + printdec(cid->prv & 15); + puts(" / s/n: "); + printdec(cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 | + cid->psn_3); + puts(" / date: "); + printdec(cid->mdt_1 & 15); + puts("/"); + printdec(2000 + ((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4)); + puts("\n"); + +/* printf("CRC: 0x%02x, b0 = %d\n", + cid->crc >> 1, cid->crc & 1); */ +} + + +int mmc_init(int verbose) +{ + int retries = 1000, rc = -1; + int resp; + u8 response[16]; +// mmc_cid_t *mmc_cid = (mmc_cid_t *)response; + struct sd_cid *sd_cid = (struct sd_cid *)response; + u32 hcs = 0; + + card_type = CARDTYPE_NONE; + + /* enable engine */ + + glamo_reg_write(GLAMO_CLOCK_MMC_EN_M9CLK | + GLAMO_CLOCK_MMC_EN_TCLK | + GLAMO_CLOCK_MMC_DG_M9CLK | + GLAMO_CLOCK_MMC_DG_TCLK, GLAMO_REG_CLOCK_MMC); + glamo_reg_write(glamo_reg_read(GLAMO_REG_HOSTBUS(2)) | + GLAMO_HOSTBUS2_MMIO_EN_MMC, GLAMO_REG_HOSTBUS(2)); + + /* controller reset */ + + glamo_mci_reset(); + + /* start the clock -- slowly (50MHz / 250 == 195kHz */ + + glamo_reg_write((glamo_reg_read(GLAMO_REG_CLOCK_GEN8) & 0xff00) | 250, + GLAMO_REG_CLOCK_GEN8); + + /* enable clock to divider input */ + + glamo_reg_write(glamo_reg_read( + GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK, + GLAMO_REG_CLOCK_GEN5_1); + + udelay(100000); + + /* set bus width to 1 */ + + glamo_reg_write((glamo_reg_read(GLAMO_REGOFS_MMC + + GLAMO_REG_MMC_BASIC) & + (~GLAMO_BASIC_MMC_EN_4BIT_DATA)), + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_BASIC); + + /* reset */ + + resp = mmc_cmd(MMC_GO_IDLE_STATE, 0, MMC_CMD_BCR, 0, 0, 0, + (u16 *)&response[0]); + + udelay(100000); + udelay(100000); + udelay(100000); + udelay(100000); + + /* SDHC card? */ + + resp = mmc_cmd(SD_SEND_IF_COND, 0x000001aa, + MMC_CMD_BCR | MMC_RSP_R7, 0, 0, 0, + (u16 *)&response[0]); + if (!resp && (response[0] == 0xaa)) { + card_type = CARDTYPE_SD20; /* 2.0 SD, may not be SDHC */ + hcs = 0x40000000; + } + + /* Well, either way let's say hello in SD card protocol */ + + while (retries--) { + + udelay(10000); + + resp = mmc_cmd(MMC_APP_CMD, 0x00000000, + MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0, + (u16 *)&response[0]); + if (resp) + continue; + resp = mmc_cmd(SD_APP_OP_COND, hcs | 0x00300000, + MMC_CMD_BCR | MMC_RSP_R3, 0, 0, 0, + (u16 *)&response[0]); + if (resp) + continue; + + if (response[3] & (1 << 6)) { /* asserts block addressing */ + retries = -2; + card_type = CARDTYPE_SDHC; + } + if (response[3] & (1 << 7)) { /* not busy */ + if (card_type == CARDTYPE_NONE) + card_type = CARDTYPE_SD; + retries = -2; + break; + } + } + if (retries == -1) { + puts("no response\n"); + return 1; + } + + if (card_type == CARDTYPE_NONE) { + retries = 10; + puts("failed to detect SD Card, trying MMC\n"); + do { + resp = mmc_cmd(MMC_SEND_OP_COND, 0x00ffc000, + MMC_CMD_BCR | MMC_RSP_R3, 0, 0, 0, + (u16 *)&response[0]); + udelay(50); + } while (retries-- && !(response[3] & 0x80)); + if (retries >= 0) + card_type = CARDTYPE_MMC; + else + return 1; + } + + /* fill in device description */ +#if 0 + mmc_dev.if_type = IF_TYPE_MMC; + mmc_dev.part_type = PART_TYPE_DOS; + mmc_dev.dev = 0; + mmc_dev.lun = 0; + mmc_dev.type = 0; + mmc_dev.removable = 0; + mmc_dev.block_read = mmc_bread; + mmc_dev.blksz = 512; + mmc_dev.lba = 1 << 16; /* 64K x 512 blocks = 32MB default */ +#endif + /* try to get card id */ + resp = mmc_cmd(MMC_ALL_SEND_CID, hcs, + MMC_CMD_BCR | MMC_RSP_R2, 0, 0, 0, + (u16 *)&response[0]); + if (resp) + return 1; + + switch (card_type) { + case CARDTYPE_MMC: + /* TODO configure mmc driver depending on card + attributes */ +#if 0 + if (verbose) + print_mmc_cid(mmc_cid); + sprintf((char *) mmc_dev.vendor, + "Man %02x%02x%02x Snr %02x%02x%02x", + mmc_cid->id[0], mmc_cid->id[1], mmc_cid->id[2], + mmc_cid->sn[0], mmc_cid->sn[1], mmc_cid->sn[2]); + sprintf((char *) mmc_dev.product, "%s", mmc_cid->name); + sprintf((char *) mmc_dev.revision, "%x %x", + mmc_cid->hwrev, mmc_cid->fwrev); +#endif + /* MMC exists, get CSD too */ + resp = mmc_cmd(MMC_SET_RELATIVE_ADDR, MMC_DEFAULT_RCA, + MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0, + (u16 *)&response[0]); + break; + + case CARDTYPE_SD: + case CARDTYPE_SD20: + case CARDTYPE_SDHC: + + if (verbose) + print_sd_cid(sd_cid); +#if 0 + sprintf((char *) mmc_dev.vendor, + "Man %02 OEM %c%c \"%c%c%c%c%c\"", + sd_cid->mid, sd_cid->oid_0, sd_cid->oid_1, + sd_cid->pnm_0, sd_cid->pnm_1, sd_cid->pnm_2, + sd_cid->pnm_3, sd_cid->pnm_4); + sprintf((char *) mmc_dev.product, "%d", + sd_cid->psn_0 << 24 | sd_cid->psn_1 << 16 | + sd_cid->psn_2 << 8 | sd_cid->psn_3); + sprintf((char *) mmc_dev.revision, "%d.%d", + sd_cid->prv >> 4, sd_cid->prv & 15); +#endif + resp = mmc_cmd(SD_SEND_RELATIVE_ADDR, MMC_DEFAULT_RCA, + MMC_CMD_BCR | MMC_RSP_R6, 0, 0, 0, + (u16 *)&response[0]); + rca = response[2] | (response[3] << 8); + break; + + default: + return 1; + } + + /* grab the CSD */ + + resp = mmc_cmd(MMC_SEND_CSD, rca << 16, + MMC_CMD_AC | MMC_RSP_R2, 0, 0, 0, + (u16 *)&response[0]); + if (!resp) { + mmc_csd_t *csd = (mmc_csd_t *)response; + +// memcpy(&mmc_csd, csd, sizeof(csd)); + rc = 0; + mmc_ready = 1; + /* FIXME add verbose printout for csd */ + /* printf("READ_BL_LEN=%u, C_SIZE_MULT=%u, C_SIZE=%u\n", + csd->read_bl_len, csd->c_size_mult1, + csd->c_size); */ +// mmc_dev.blksz = 512; +// mmc_dev.lba = (((unsigned long)1 << csd->c_size_mult1) * +// (unsigned long)csd->c_size) >> 9; + + switch (card_type) { + case CARDTYPE_SDHC: + puts(" SDHC size: "); + printdec((UNSTUFF_BITS(((u32 *)&response[0]), 48, 22) + + 1) / 2); + break; + default: + puts(" MMC/SD size: "); + printdec((((unsigned long)1 << csd->c_size_mult1) * + (unsigned long)(csd->c_size)) >> 10); + } + puts(" MiB\n"); + } + + resp = mmc_cmd(MMC_SELECT_CARD, rca<<16, MMC_CMD_AC | MMC_RSP_R1, + 0, 0, 0, (u16 *)&response[0]); + if (resp) + return 1; + +#ifdef CONFIG_MMC_WIDE + /* yay 4-bit! */ + if (card_type == CARDTYPE_SD || card_type == CARDTYPE_SDHC) { + resp = mmc_cmd(MMC_APP_CMD, rca<<16, MMC_CMD_AC | MMC_RSP_R1, + 0, 0, 0, (u16 *)&response[0]); + resp = mmc_cmd(MMC_SWITCH, 0x02, MMC_CMD_AC | MMC_RSP_R1B, + 0, 0, 0, (u16 *)&response[0]); + wide = 1; + glamo_reg_write(glamo_reg_read(GLAMO_REGOFS_MMC + + GLAMO_REG_MMC_BASIC) | GLAMO_BASIC_MMC_EN_4BIT_DATA, + GLAMO_REGOFS_MMC + GLAMO_REG_MMC_BASIC); + } +#endif + + /* set the clock to slow until first bulk completes (for slow SDHC) */ + + glamo_reg_write((glamo_reg_read(GLAMO_REG_CLOCK_GEN8) & 0xff00) | 32, + GLAMO_REG_CLOCK_GEN8); + + return rc; +} + + + diff --git a/qiboot/src/drivers/i2c-bitbang.c b/qiboot/src/drivers/i2c-bitbang.c new file mode 100644 index 0000000..436003e --- /dev/null +++ b/qiboot/src/drivers/i2c-bitbang.c @@ -0,0 +1,252 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * Generic i2c bitbang state machine + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include + +void i2c_read(struct i2c_bitbang * bb, unsigned char ads7, unsigned char reg) +{ + bb->data[0] = (ads7 << 1); /* write the register address */ + bb->data[1] = reg; + bb->data[2] = IBCONTROL_DO_START; + bb->data[3] = (ads7 << 1) | 1; /* then issue read cycle to device */ + bb->data[4] = IBCONTROL_DO_READ; + bb->data[5] = IBCONTROL_DO_STOP; + bb->data[6] = IBCONTROL_COMPLETE; + bb->state = IBS_INIT; +} + +void i2c_write(struct i2c_bitbang * bb, unsigned char ads7, unsigned char reg, + unsigned char b) +{ + bb->data[0] = (ads7 << 1); + bb->data[1] = reg; + bb->data[2] = b; + bb->data[3] = IBCONTROL_DO_STOP; + bb->data[4] = IBCONTROL_COMPLETE; + bb->state = IBS_INIT; +} + +int i2c_next_state(struct i2c_bitbang * bb) +{ + switch (bb->state) { + case IBS_INIT: + bb->index = 0; + bb->index_read = 0; + (bb->set)(1, 1); + bb->state = IBS_START1; + break; + + case IBS_START1: + (bb->set)(1, 0); + bb->state = IBS_START2; + break; + + case IBS_START2: + (bb->set)(0, 0); /* start */ + bb->count = 8; + bb->state = IBS_ADS_TX_S; + break; + + /* transmit address or data */ + case IBS_ADS_TX_S: + (bb->set)(0, !!(bb->data[bb->index] & 0x80)); + bb->state = IBS_ADS_TX_H; + break; + case IBS_ADS_TX_H: + (bb->set)(1, !!(bb->data[bb->index] & 0x80)); + bb->state = IBS_ADS_TX_L; + break; + case IBS_ADS_TX_L: + (bb->set)(0, !!(bb->data[bb->index] & 0x80)); + bb->data[bb->index] <<= 1; + bb->count--; + if (bb->count) { + bb->state = IBS_ADS_TX_S; + break; + } + + (bb->set)(0, 1); + bb->state = IBS_ADS_TX_ACK_H; + break; + + case IBS_ADS_TX_ACK_H: + /* we finished... we expect an ack now */ + if ((bb->read_sda)()) + return -1; + + (bb->set)(1, 1); + bb->state = IBS_ADS_TX_ACK_L; + break; + + case IBS_ADS_TX_ACK_L: + (bb->set)(0, 1); + + bb->count = 8; + bb->index++; + switch (bb->data[bb->index]) { + case IBCONTROL_DO_START: + bb->state = IBS_START1; + bb->index++; + break; + case IBCONTROL_DO_STOP: + bb->state = IBS_STOP1; + bb->index++; + break; + case IBCONTROL_DO_READ: + bb->data[bb->index_read] = 0; + bb->state = IBS_DATA_RX_S; + break; + case IBCONTROL_COMPLETE: + return 1; + default: + bb->state = IBS_ADS_TX_S; /* write it out */ + break; + } + break; + + + /* receive data */ + case IBS_DATA_RX_S: + (bb->set)(0, 1); + bb->state = IBS_DATA_RX_H; + break; + + case IBS_DATA_RX_H: + (bb->set)(1, 1); + bb->state = IBS_DATA_RX_L; + break; + + case IBS_DATA_RX_L: + bb->data[bb->index_read] <<= 1; + bb->data[bb->index_read] |= !!(bb->read_sda)(); + bb->count--; + if (bb->count) { + (bb->set)(0, 1); + bb->state = IBS_DATA_RX_S; + break; + } + + /* slave has released SDA now, bang down ACK */ + if (bb->data[bb->index + 1] != IBCONTROL_DO_READ) + (bb->set)(0, 1); + else + (bb->set)(0, 0); + bb->state = IBS_DATA_RX_ACK_H; + break; + + case IBS_DATA_RX_ACK_H: + if (bb->data[bb->index + 1] != IBCONTROL_DO_READ) + (bb->set)(1, 1); /* NAK */ + else + (bb->set)(1, 0); /* ACK */ + bb->state = IBS_DATA_RX_ACK_L; + break; + + case IBS_DATA_RX_ACK_L: + if (bb->data[bb->index + 1] != IBCONTROL_DO_READ) + (bb->set)(0, 1); /* NAK */ + else + (bb->set)(0, 0); /* ACK */ + bb->index_read++; + bb->index++; + switch (bb->data[bb->index]) { + case IBCONTROL_DO_START: + bb->state = IBS_START1; + bb->index++; + break; + case IBCONTROL_DO_STOP: + bb->state = IBS_STOP1; + bb->index++; + break; + case IBCONTROL_DO_READ: + bb->state = IBS_DATA_RX_S; + bb->data[bb->index_read] = 0; + break; + case IBCONTROL_COMPLETE: + return 1; + default: + bb->state = IBS_ADS_TX_S; /* write it out */ + break; + } + break; + + break; + + + case IBS_STOP1: + (bb->set)(0, 0); + bb->state = IBS_STOP2; + break; + + case IBS_STOP2: + (bb->set)(1, 0); + bb->state = IBS_STOP3; + break; + + case IBS_STOP3: + (bb->set)(1, 1); + bb->state = IBS_STOP4; + break; + + case IBS_STOP4: + (bb->set)(1, 1); + return 1; /* done */ + } + + return 0; /* keep going */ +} + +static int i2c_complete_synchronously(struct i2c_bitbang * bb) +{ + int ret = 0; + + while (!ret) { + ret = i2c_next_state(bb); + (bb->spin)(); + } + + if (ret < 0) { + puts("i2c transaction failed "); + printdec(ret); + puts("\n"); + } + return ret; +} + +int i2c_read_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg) +{ + i2c_read(bb, ads7, reg); + if (i2c_complete_synchronously(bb) < 0) + return -1; + + return bb->data[0]; +} + +void i2c_write_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg, unsigned char b) +{ + i2c_write(bb, ads7, reg, b); + i2c_complete_synchronously(bb); +} diff --git a/qiboot/src/fs/dev.c b/qiboot/src/fs/dev.c new file mode 100644 index 0000000..9d4fba3 --- /dev/null +++ b/qiboot/src/fs/dev.c @@ -0,0 +1,133 @@ +/* + * (C) Copyright 2004 + * esd gmbh + * Reinhard Arlt + * + * based on code of fs/reiserfs/dev.c by + * + * (C) Copyright 2003 - 2004 + * Sysgo AG, , Pavel Bartusek + * + * 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. + */ + + +#include +#include +#include + +extern unsigned long partition_offset_blocks; +extern unsigned long partition_length_blocks; + + +int ext2fs_devread(int sector, int filesystem_block_log2, int byte_offset, int byte_len, u8 *buf) +{ + unsigned char sec_buf[SECTOR_SIZE]; + unsigned block_len; + + sector = sector << filesystem_block_log2; + + +/* + * Check partition boundaries + */ + if ((sector < 0) + || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS)) >= + partition_length_blocks)) { + /* errnum = ERR_OUTSIDE_PART; */ + puts(" ** ext2fs_devread() read outside partition sector "); + printdec(sector); + puts("\n"); + return 0; + } + + if (this_board->get_ui_keys) + if ((this_board->get_ui_keys)() & UI_ACTION_SKIPKERNEL) { + puts(" ** skipping \n"); + return 0; + } + +/* + * Get the read to the beginning of a partition. + */ + sector += byte_offset >> SECTOR_BITS; + byte_offset &= SECTOR_SIZE - 1; + + if (byte_offset) { + int minimum = SECTOR_SIZE - byte_offset; + + if (byte_len < minimum) + minimum = byte_len; + + /* read first part which isn't aligned with start of sector */ + if ((this_kernel->block_read)(sec_buf, + partition_offset_blocks + sector, 1) < 0) { + puts(" ** ext2fs_devread() read error **\n"); + return 0; + } + memcpy(buf, sec_buf + byte_offset, + minimum); + buf += minimum; + byte_len -= minimum; + sector++; + } + + if (!byte_len) + return 1; + + /* read sector aligned part */ + block_len = byte_len & ~(SECTOR_SIZE - 1); + + if (block_len == 0) { + u8 p[SECTOR_SIZE]; + + block_len = SECTOR_SIZE; + this_kernel->block_read(p,partition_offset_blocks + sector, 1); + memcpy(buf, p, byte_len); + return 1; + } + + if (this_kernel->block_read(buf, partition_offset_blocks + sector, + block_len / SECTOR_SIZE) < 0) { + puts(" ** ext2fs_devread() read error - block\n"); + printdec(partition_offset_blocks + sector); + puts(" "); + print32(block_len); + puts(" "); + print32(sector); + return 0; + } + block_len = byte_len & ~(SECTOR_SIZE - 1); + buf += block_len; + byte_len -= block_len; + sector += block_len / SECTOR_SIZE; + + if (byte_len) { + /* read rest of data which are not in whole sector */ + if (this_kernel->block_read(sec_buf, + partition_offset_blocks + sector, 1) != 1) { + puts(" ** ext2fs_devread() read error - last part\n"); + printdec(partition_offset_blocks + sector); + puts(" "); + print32(block_len); + puts(" "); + print32(sector); + return 0; + } + memcpy (buf, sec_buf, byte_len); + } + return 1; +} + diff --git a/qiboot/src/fs/ext2.c b/qiboot/src/fs/ext2.c new file mode 100644 index 0000000..2709806 --- /dev/null +++ b/qiboot/src/fs/ext2.c @@ -0,0 +1,940 @@ +/* + *(C) Copyright 2004 + * esd gmbh + * Reinhard Arlt + * + * based on code from grub2 fs/ext2.c and fs/fshelp.c by + * + * GRUB -- GRand Unified Bootloader + * Copyright(C) 2003, 2004 Free Software Foundation, Inc. + * + * 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. + */ + +#include + +#include +#include +#include + +extern int ext2fs_devread(int sector, int log2blksize, int byte_offset, int byte_len, + char *buf); + +/* Magic value used to identify an ext2 filesystem. */ +#define EXT2_MAGIC 0xEF53 +/* Amount of indirect blocks in an inode. */ +#define INDIRECT_BLOCKS 12 +/* Maximum lenght of a pathname. */ +#define EXT2_PATH_MAX 4096 +/* Maximum nesting of symlinks, used to prevent a loop. */ +#define EXT2_MAX_SYMLINKCNT 8 + +/* Filetype used in directory entry. */ +#define FILETYPE_UNKNOWN 0 +#define FILETYPE_REG 1 +#define FILETYPE_DIRECTORY 2 +#define FILETYPE_SYMLINK 7 + +/* Filetype information as used in inodes. */ +#define FILETYPE_INO_MASK 0170000 +#define FILETYPE_INO_REG 0100000 +#define FILETYPE_INO_DIRECTORY 0040000 +#define FILETYPE_INO_SYMLINK 0120000 + +/* Bits used as offset in sector */ +#define DISK_SECTOR_BITS 9 + +/* Log2 size of ext2 block in 512 blocks. */ +#define LOG2_EXT2_BLOCK_SIZE(data)(__le32_to_cpu(data->sblock.log2_block_size) + 1) + +/* Log2 size of ext2 block in bytes. */ +#define LOG2_BLOCK_SIZE(data) (__le32_to_cpu(data->sblock.log2_block_size) + 10) + +/* The size of an ext2 block in bytes. */ +#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data)) + +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_GOOD_OLD_INODE_SIZE 128 +uint32_t ext2_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + +/* The ext2 superblock. */ +struct ext2_sblock { + uint32_t total_inodes; + uint32_t total_blocks; + uint32_t reserved_blocks; + uint32_t free_blocks; + uint32_t free_inodes; + uint32_t first_data_block; + uint32_t log2_block_size; + uint32_t log2_fragment_size; + uint32_t blocks_per_group; + uint32_t fragments_per_group; + uint32_t inodes_per_group; + uint32_t mtime; + uint32_t utime; + uint16_t mnt_count; + uint16_t max_mnt_count; + uint16_t magic; + uint16_t fs_state; + uint16_t error_handling; + uint16_t minor_revision_level; + uint32_t lastcheck; + uint32_t checkinterval; + uint32_t creator_os; + uint32_t revision_level; + uint16_t uid_reserved; + uint16_t gid_reserved; + uint32_t first_inode; + uint16_t inode_size; + uint16_t block_group_number; + uint32_t feature_compatibility; + uint32_t feature_incompat; + uint32_t feature_ro_compat; + uint32_t unique_id[4]; + char volume_name[16]; + char last_mounted_on[64]; + uint32_t compression_info; +}; + +/* The ext2 blockgroup. */ +struct ext2_block_group { + uint32_t block_id; + uint32_t inode_id; + uint32_t inode_table_id; + uint16_t free_blocks; + uint16_t free_inodes; + uint16_t pad; + uint32_t reserved[3]; +}; + +/* The ext2 inode. */ +struct ext2_inode { + uint16_t mode; + uint16_t uid; + uint32_t size; + uint32_t atime; + uint32_t ctime; + uint32_t mtime; + uint32_t dtime; + uint16_t gid; + uint16_t nlinks; + uint32_t blockcnt; /* Blocks of 512 bytes!! */ + uint32_t flags; + uint32_t osd1; + union { + struct datablocks { + uint32_t dir_blocks[INDIRECT_BLOCKS]; + uint32_t indir_block; + uint32_t double_indir_block; + uint32_t tripple_indir_block; + } blocks; + char symlink[60]; + } b; + uint32_t version; + uint32_t acl; + uint32_t dir_acl; + uint32_t fragment_addr; + uint32_t osd2[3]; +}; + +/* The header of an ext2 directory entry. */ +struct ext2_dirent { + uint32_t inode; + uint16_t direntlen; + uint8_t namelen; + uint8_t filetype; +}; + +struct ext2fs_node { + struct ext2_data *data; + struct ext2_inode inode; + int ino; + int inode_read; +}; + +/* Information about a "mounted" ext2 filesystem. */ +struct ext2_data { + struct ext2_sblock sblock; + struct ext2_inode *inode; + struct ext2fs_node diropen; +}; + + +typedef struct ext2fs_node *ext2fs_node_t; + +struct ext2_data *ext2fs_root = NULL; +ext2fs_node_t ext2fs_file = NULL; +int symlinknest = 0; +uint32_t *indir1_block = NULL; +int indir1_size = 0; +int indir1_blkno = -1; +uint32_t *indir2_block = NULL; +int indir2_size = 0; +int indir2_blkno = -1; + + +static int ext2fs_blockgroup + (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) { + return ext2fs_devread + ((__le32_to_cpu(data->sblock.first_data_block) + + 1), LOG2_EXT2_BLOCK_SIZE(data), + group * sizeof(struct ext2_block_group), + sizeof(struct ext2_block_group),(char *) blkgrp); +} + + +static int ext2fs_read_inode + (struct ext2_data *data, int ino, struct ext2_inode *inode) { + struct ext2_block_group blkgrp; + struct ext2_sblock *sblock = &data->sblock; + int inodes_per_block; + int status; + + unsigned int blkno; + unsigned int blkoff; + + /* It is easier to calculate if the first inode is 0. */ + ino--; + status = ext2fs_blockgroup(data, + ino / + __le32_to_cpu(sblock->inodes_per_group), + &blkgrp); + if (status == 0) + return 0; + + inodes_per_block = EXT2_BLOCK_SIZE(data) / ext2_inode_size; + blkno =(ino % __le32_to_cpu(sblock->inodes_per_group)) / + inodes_per_block; + blkoff =(ino % __le32_to_cpu(sblock->inodes_per_group)) % + inodes_per_block; +#ifdef DEBUG + puts("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff); +#endif + /* Read the inode. */ + + status = ext2fs_devread(__le32_to_cpu(blkgrp.inode_table_id) + blkno, + LOG2_EXT2_BLOCK_SIZE(data), + ext2_inode_size * blkoff, + sizeof(struct ext2_inode), (char *)inode); + + return !!status; +} + + +void ext2fs_free_node(ext2fs_node_t node, ext2fs_node_t currroot) { + if ((node != &ext2fs_root->diropen) &&(node != currroot)) { + free(node); + } +} + + +static int ext2fs_read_block(ext2fs_node_t node, int fileblock) { + struct ext2_data *data = node->data; + struct ext2_inode *inode = &node->inode; + int blknr; + int blksz = EXT2_BLOCK_SIZE(data); + int log2_blksz = LOG2_EXT2_BLOCK_SIZE(data); + int status; + + /* Direct blocks. */ + if (fileblock < INDIRECT_BLOCKS) { + blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]); + } + /* Indirect. */ + else if (fileblock <(INDIRECT_BLOCKS +(blksz / 4))) { + if (indir1_block == NULL) { + indir1_block =(uint32_t *) malloc(blksz); + if (indir1_block == NULL) { + puts("** ext2fs read block(indir 1) malloc failed. **\n"); + return -1; + } + indir1_size = blksz; + indir1_blkno = -1; + } + if (blksz != indir1_size) { + free(indir1_block); + indir1_block = NULL; + indir1_size = 0; + indir1_blkno = -1; + indir1_block =(uint32_t *) malloc(blksz); + if (indir1_block == NULL) { + puts("** ext2fs read block(indir 1) malloc failed. **\n"); + return -1; + } + indir1_size = blksz; + } + if ((__le32_to_cpu(inode->b.blocks.indir_block) << + log2_blksz) != indir1_blkno) { + status = ext2fs_devread(__le32_to_cpu(inode->b.blocks.indir_block), log2_blksz, + 0, blksz, + (char *) indir1_block); + if (status == 0) { + puts("** ext2fs read block(indir 1) failed. **\n"); + return 0; + } + indir1_blkno = + __le32_to_cpu(inode->b.blocks. + indir_block) << log2_blksz; + } + blknr = __le32_to_cpu(indir1_block + [fileblock - INDIRECT_BLOCKS]); + } + /* Double indirect. */ + else if (fileblock < + (INDIRECT_BLOCKS +(blksz / 4 *(blksz / 4 + 1)))) { + unsigned int perblock = blksz / 4; + unsigned int rblock = fileblock -(INDIRECT_BLOCKS + + blksz / 4); + + if (indir1_block == NULL) { + indir1_block =(uint32_t *) malloc(blksz); + if (indir1_block == NULL) { + puts("** ext2fs read block(indir 2 1) malloc failed. **\n"); + return -1; + } + indir1_size = blksz; + indir1_blkno = -1; + } + if (blksz != indir1_size) { + free(indir1_block); + indir1_block = NULL; + indir1_size = 0; + indir1_blkno = -1; + indir1_block =(uint32_t *) malloc(blksz); + if (indir1_block == NULL) { + puts("** ext2fs read block(indir 2 1) malloc failed. **\n"); + return -1; + } + indir1_size = blksz; + } + if ((__le32_to_cpu(inode->b.blocks.double_indir_block) << + log2_blksz) != indir1_blkno) { + status = ext2fs_devread(__le32_to_cpu(inode->b.blocks.double_indir_block), log2_blksz, + 0, blksz, + (char *) indir1_block); + if (status == 0) { + puts("** ext2fs read block(indir 2 1) failed. **\n"); + return -1; + } + indir1_blkno = + __le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz; + } + + if (indir2_block == NULL) { + indir2_block =(uint32_t *) malloc(blksz); + if (indir2_block == NULL) { + puts("** ext2fs read block(indir 2 2) malloc failed. **\n"); + return -1; + } + indir2_size = blksz; + indir2_blkno = -1; + } + if (blksz != indir2_size) { + free(indir2_block); + indir2_block = NULL; + indir2_size = 0; + indir2_blkno = -1; + indir2_block =(uint32_t *) malloc(blksz); + if (indir2_block == NULL) { + puts("** ext2fs read block(indir 2 2) malloc failed. **\n"); + return -1; + } + indir2_size = blksz; + } + if ((__le32_to_cpu(indir1_block[rblock / perblock]) << + log2_blksz) != indir2_blkno) { + status = ext2fs_devread(__le32_to_cpu(indir1_block[rblock / perblock]), log2_blksz, + 0, blksz, + (char *) indir2_block); + if (status == 0) { + puts("** ext2fs read block(indir 2 2) failed. **\n"); + return -1; + } + indir2_blkno = + __le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz; + } + blknr = __le32_to_cpu(indir2_block[rblock % perblock]); + } + /* Triple indirect. */ + else { + puts("** ext2fs doesn't support triple indirect blocks. **\n"); + return -1; + } +#ifdef DEBUG + printf("ext2fs_read_block %08x\n", blknr); +#endif + return blknr; +} + + +int ext2fs_read_file(ext2fs_node_t node, int pos, unsigned int len, char *buf) { + int i; + int blockcnt; + int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data); + int blocksize = 1 <<(log2blocksize + DISK_SECTOR_BITS); + unsigned int filesize = __le32_to_cpu(node->inode.size); + int previous_block_number = -1; + int delayed_start = 0; + int delayed_extent = 0; + int delayed_skipfirst = 0; + int delayed_next = 0; + char * delayed_buf = NULL; + int status; + + /* Adjust len so it we can't read past the end of the file. */ + if (len > filesize) { + len = filesize; + } + blockcnt = ((len + pos) + blocksize - 1) / blocksize; + + for(i = pos / blocksize; i < blockcnt; i++) { + int blknr; + int blockoff = pos % blocksize; + int blockend = blocksize; + + int skipfirst = 0; + + blknr = ext2fs_read_block(node, i); + if (blknr < 0) + return -1; + + blknr = blknr << log2blocksize; + + /* Last block. */ + if (i == blockcnt - 1) { + blockend =(len + pos) % blocksize; + + /* The last portion is exactly blocksize. */ + if (!blockend) { + blockend = blocksize; + } + } + + /* First block. */ + if (i == pos / blocksize) { + skipfirst = blockoff; + blockend -= skipfirst; + } + + /* If the block number is 0 this block is not stored on disk but + is zero filled instead. */ + if (blknr) { + int status; + + if (previous_block_number != -1) { + if (delayed_next == blknr) { + delayed_extent += blockend; + delayed_next += blockend >> SECTOR_BITS; + } else { /* spill */ + status = ext2fs_devread(delayed_start, + 0, delayed_skipfirst, + delayed_extent, delayed_buf); + if (status == 0) + return -1; + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_skipfirst = skipfirst; + delayed_buf = buf; + delayed_next = blknr + (blockend >> SECTOR_BITS); + } + } else { + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_skipfirst = skipfirst; + delayed_buf = buf; + delayed_next = blknr + (blockend >> SECTOR_BITS); + } + + } else { + if (previous_block_number != -1) { + /* spill */ + status = ext2fs_devread(delayed_start, + 0, delayed_skipfirst, + delayed_extent, delayed_buf); + if (status == 0) + return -1; + previous_block_number = -1; + } + memset(buf, 0, blocksize - skipfirst); + } + buf += blocksize - skipfirst; + } + + if (previous_block_number != -1) { + /* spill */ + status = ext2fs_devread(delayed_start, + 0, delayed_skipfirst, + delayed_extent, delayed_buf); + if (status == 0) + return -1; + previous_block_number = -1; + } + + return(len); +} + + +static int ext2fs_iterate_dir(ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype) +{ + unsigned int fpos = 0; + int status; + struct ext2fs_node *diro =(struct ext2fs_node *) dir; + +#ifdef DEBUG + if (name != NULL) + printf("Iterate dir %s\n", name); +#endif /* of DEBUG */ + if (!diro->inode_read) { + status = ext2fs_read_inode(diro->data, diro->ino, + &diro->inode); + if (status == 0) { + printdec(diro->ino); + puts("failed to read inode\n"); + return(0); + } + } + + /* Search the file. */ + while (fpos < __le32_to_cpu(diro->inode.size)) { + struct ext2_dirent dirent; + + status = ext2fs_read_file(diro, fpos, + sizeof(struct ext2_dirent), + (char *) &dirent); + if (status < 1) { + puts("ext2fs_read_file ret < 1\n"); + return 0; + } + + if (dirent.namelen != 0) { + char filename[256]; + ext2fs_node_t fdiro; + int type = FILETYPE_UNKNOWN; + + status = ext2fs_read_file(diro, + fpos + sizeof(struct ext2_dirent), + dirent.namelen, filename); + if (status < 1) { + puts("ext2fs_read_file fail 2\n"); + return(0); + } + + fdiro = malloc(sizeof(struct ext2fs_node)); + if (!fdiro) { + puts("malloc fail\n"); + return(0); + } + + + fdiro->data = diro->data; + fdiro->ino = __le32_to_cpu(dirent.inode); + + filename[dirent.namelen] = '\0'; + + if (dirent.filetype != FILETYPE_UNKNOWN) { + fdiro->inode_read = 0; + + if (dirent.filetype == FILETYPE_DIRECTORY) { + type = FILETYPE_DIRECTORY; + } else if (dirent.filetype == + FILETYPE_SYMLINK) { + type = FILETYPE_SYMLINK; + } else if (dirent.filetype == FILETYPE_REG) { + type = FILETYPE_REG; + } + } else { + /* The filetype can not be read from the dirent, get it from inode */ + + status = ext2fs_read_inode(diro->data, + __le32_to_cpu(dirent.inode), + &fdiro->inode); + if (status == 0) { + puts("inner ext2fs_read_inode fail\n"); + free(fdiro); + return(0); + } + fdiro->inode_read = 1; + + if ((__le16_to_cpu(fdiro->inode.mode) & + FILETYPE_INO_MASK) == + FILETYPE_INO_DIRECTORY) { + type = FILETYPE_DIRECTORY; + } else if ((__le16_to_cpu(fdiro->inode.mode) + & FILETYPE_INO_MASK) == + FILETYPE_INO_SYMLINK) { + type = FILETYPE_SYMLINK; + } else if ((__le16_to_cpu(fdiro->inode.mode) + & FILETYPE_INO_MASK) == + FILETYPE_INO_REG) { + type = FILETYPE_REG; + } + } +#ifdef DEBUG + printf("iterate >%s<\n", filename); +#endif /* of DEBUG */ + if ((name != NULL) &&(fnode != NULL) + &&(ftype != NULL)) { + if (strcmp(filename, name) == 0) { + *ftype = type; + *fnode = fdiro; + return 1; + } + } else { + if (fdiro->inode_read == 0) { + status = ext2fs_read_inode(diro->data, + __le32_to_cpu(dirent.inode), + &fdiro->inode); + if (status == 0) { + puts("ext2fs_read_inode 3 fail\n"); + free(fdiro); + return(0); + } + fdiro->inode_read = 1; + } + switch(type) { + case FILETYPE_DIRECTORY: + puts(" "); + break; + case FILETYPE_SYMLINK: + puts(" "); + break; + case FILETYPE_REG: + puts(" "); + break; + default: + puts("< ? > "); + break; + } + printdec(__le32_to_cpu(fdiro->inode.size)); + puts(" "); + puts(filename); + puts("\n"); + } + free(fdiro); + } + fpos += __le16_to_cpu(dirent.direntlen); + } + return 0; +} + + +static char *ext2fs_read_symlink(ext2fs_node_t node) { + char *symlink; + struct ext2fs_node *diro = node; + int status; + + if (!diro->inode_read) { + status = ext2fs_read_inode(diro->data, diro->ino, + &diro->inode); + if (status == 0) { + return(0); + } + } + symlink = malloc(__le32_to_cpu(diro->inode.size) + 1); + if (!symlink) + return(0); + + /* If the filesize of the symlink is bigger than + 60 the symlink is stored in a separate block, + otherwise it is stored in the inode. */ + if (__le32_to_cpu(diro->inode.size) < 60) { + strncpy(symlink, diro->inode.b.symlink, + __le32_to_cpu(diro->inode.size)); + } else { + status = ext2fs_read_file(diro, 0, + __le32_to_cpu(diro->inode.size), + symlink); + if (status == 0) { + free(symlink); + return(0); + } + } + symlink[__le32_to_cpu(diro->inode.size)] = '\0'; + return(symlink); +} + + +int ext2fs_find_file1 + (const char *currpath, + ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) { + char fpath[strlen(currpath) + 1]; + char *name = fpath; + char *next; + int status; + int type = FILETYPE_DIRECTORY; + ext2fs_node_t currnode = currroot; + ext2fs_node_t oldnode = currroot; + + strncpy(fpath, currpath, strlen(currpath) + 1); + + /* Remove all leading slashes. */ + while (*name == '/') + name++; + + if (!*name) { + *currfound = currnode; + return 1; + } + + for(;;) { + int found; + + /* Extract the actual part from the pathname. */ + next = strchr(name, '/'); + if (next) { + /* Remove all leading slashes. */ + while (*next == '/') { + *(next++) = '\0'; + } + } + + /* At this point it is expected that the current node is a directory, check if this is true. */ + if (type != FILETYPE_DIRECTORY) { + ext2fs_free_node(currnode, currroot); + return(0); + } + + oldnode = currnode; + + /* Iterate over the directory. */ + found = ext2fs_iterate_dir(currnode, name, &currnode, &type); + if (found == 0) + return(0); + + if (found == -1) + break; + + /* Read in the symlink and follow it. */ + if (type == FILETYPE_SYMLINK) { + char *symlink; + + /* Test if the symlink does not loop. */ + if (++symlinknest == 8) { + ext2fs_free_node(currnode, currroot); + ext2fs_free_node(oldnode, currroot); + return(0); + } + + symlink = ext2fs_read_symlink(currnode); + ext2fs_free_node(currnode, currroot); + + if (!symlink) { + ext2fs_free_node(oldnode, currroot); + return(0); + } +#ifdef DEBUG + printf("Got symlink >%s<\n", symlink); +#endif /* of DEBUG */ + /* The symlink is an absolute path, go back to the root inode. */ + if (symlink[0] == '/') { + ext2fs_free_node(oldnode, currroot); + oldnode = &ext2fs_root->diropen; + } + + /* Lookup the node the symlink points to. */ + status = ext2fs_find_file1(symlink, oldnode, + &currnode, &type); + + free(symlink); + + if (status == 0) { + ext2fs_free_node(oldnode, currroot); + return(0); + } + } + + ext2fs_free_node(oldnode, currroot); + + /* Found the node! */ + if (!next || *next == '\0') { + *currfound = currnode; + *foundtype = type; + return(1); + } + name = next; + } + return -1; +} + + +int ext2fs_find_file + (const char *path, + ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) { + int status; + int foundtype = FILETYPE_DIRECTORY; + + + symlinknest = 0; + if (!path) + return 0; + + status = ext2fs_find_file1(path, rootnode, foundnode, &foundtype); + if (status == 0) + return 0; + + /* Check if the node that was found was of the expected type. */ + if ((expecttype == FILETYPE_REG) &&(foundtype != expecttype)) { + return 0; + } else if ((expecttype == FILETYPE_DIRECTORY) + &&(foundtype != expecttype)) { + return 0; + } + return 1; +} + + +int ext2fs_ls(char *dirname) { + ext2fs_node_t dirnode; + int status; + + if (ext2fs_root == NULL) + return 0; + + status = ext2fs_find_file(dirname, &ext2fs_root->diropen, &dirnode, + FILETYPE_DIRECTORY); + if (status != 1) { + puts("** Can not find directory. **\n"); + return 1; + } + ext2fs_iterate_dir(dirnode, NULL, NULL, NULL); + ext2fs_free_node(dirnode, &ext2fs_root->diropen); + return 0; +} + + +int ext2fs_open(const char *filename) { + ext2fs_node_t fdiro = NULL; + int status; + int len; + int ret = -1; + + if (ext2fs_root == NULL) + goto fail; + + ext2fs_file = NULL; + status = ext2fs_find_file(filename, &ext2fs_root->diropen, &fdiro, + FILETYPE_REG); + if (status == 0) { + ret = -2; + goto fail; + } + + if (!fdiro->inode_read) { + status = ext2fs_read_inode(fdiro->data, fdiro->ino, + &fdiro->inode); + if (status == 0) { + ret = -3; + goto fail; + } + } + len = __le32_to_cpu(fdiro->inode.size); + ext2fs_file = fdiro; + + return(len); + +fail: + ext2fs_free_node(fdiro, &ext2fs_root->diropen); + return ret; +} + + +int ext2fs_close(void + ) { + if ((ext2fs_file != NULL) &&(ext2fs_root != NULL)) { + ext2fs_free_node(ext2fs_file, &ext2fs_root->diropen); + ext2fs_file = NULL; + } + if (ext2fs_root != NULL) { + free(ext2fs_root); + ext2fs_root = NULL; + } + if (indir1_block != NULL) { + free(indir1_block); + indir1_block = NULL; + indir1_size = 0; + indir1_blkno = -1; + } + if (indir2_block != NULL) { + free(indir2_block); + indir2_block = NULL; + indir2_size = 0; + indir2_blkno = -1; + } + return(0); +} + + +int ext2fs_read(char *buf, unsigned len) { + int status; + + if (ext2fs_root == NULL) + return 0; + + if (ext2fs_file == NULL) + return 0; + + status = ext2fs_read_file(ext2fs_file, 0, len, buf); + return status; +} + + +int ext2fs_mount(void) { + struct ext2_data *data; + int status; + + data = malloc(sizeof(struct ext2_data)); + if (!data) + return 0; + + /* Read the superblock. */ + status = ext2fs_devread(1 * 2, 0, 0, sizeof(struct ext2_sblock), + (char *) &data->sblock); + if (!status) + goto fail; + + /* Make sure this is an ext2 filesystem. */ + if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) + goto fail; + + if (__le32_to_cpu(data->sblock.revision_level) == EXT2_GOOD_OLD_REV) + ext2_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + else + ext2_inode_size = __le16_to_cpu (data->sblock.inode_size); + + data->diropen.data = data; + data->diropen.ino = 2; + data->diropen.inode_read = 1; + data->inode = &data->diropen.inode; + + status = ext2fs_read_inode(data, 2, data->inode); + if (status == 0) + goto fail; + + ext2fs_root = data; + + return 1; + +fail: + puts("Failed to mount ext2 filesystem...\n"); + free(data); + ext2fs_root = NULL; + + return 0; +} + diff --git a/qiboot/src/io.h b/qiboot/src/io.h new file mode 100644 index 0000000..029b7f9 --- /dev/null +++ b/qiboot/src/io.h @@ -0,0 +1,337 @@ +/* + * linux/include/asm-arm/io.h + * + * Copyright (C) 1996-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both + * constant addresses and variable addresses. + * 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture + * specific IO header files. + * 27-Mar-1999 PJB Second parameter of memcpy_toio is const.. + * 04-Apr-1999 PJB Added check_signature. + * 12-Dec-1999 RMK More cleanups + * 18-Jun-2000 RMK Removed virt_to_* and friends definitions + */ +#ifndef __ASM_ARM_IO_H +#define __ASM_ARM_IO_H + +#ifdef __KERNEL__ + +#include +#include +#include +#if 0 /* XXX###XXX */ +#include +#endif /* XXX###XXX */ + +static inline void sync(void) +{ +} + +/* + * Given a physical address and a length, return a virtual address + * that can be used to access the memory range with the caching + * properties specified by "flags". + */ +typedef unsigned long phys_addr_t; + +#define MAP_NOCACHE (0) +#define MAP_WRCOMBINE (0) +#define MAP_WRBACK (0) +#define MAP_WRTHROUGH (0) + +static inline void * +map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) +{ + return (void *)paddr; +} + +/* + * Take down a mapping set up by map_physmem(). + */ +static inline void unmap_physmem(void *vaddr, unsigned long flags) +{ + +} + +/* + * Generic virtual read/write. Note that we don't support half-word + * read/writes. We define __arch_*[bl] here, and leave __arch_*w + * to the architecture specific code. + */ +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getw(a) (*(volatile unsigned short *)(a)) +#define __arch_getl(a) (*(volatile unsigned int *)(a)) + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +extern void __raw_writesb(unsigned int addr, const void *data, int bytelen); +extern void __raw_writesw(unsigned int addr, const void *data, int wordlen); +extern void __raw_writesl(unsigned int addr, const void *data, int longlen); + +extern void __raw_readsb(unsigned int addr, void *data, int bytelen); +extern void __raw_readsw(unsigned int addr, void *data, int wordlen); +extern void __raw_readsl(unsigned int addr, void *data, int longlen); + +#define __raw_writeb(v,a) __arch_putb(v,a) +#define __raw_writew(v,a) __arch_putw(v,a) +#define __raw_writel(v,a) __arch_putl(v,a) + +#define __raw_readb(a) __arch_getb(a) +#define __raw_readw(a) __arch_getw(a) +#define __raw_readl(a) __arch_getl(a) + +#define writeb(v,a) __arch_putb(v,a) +#define writew(v,a) __arch_putw(v,a) +#define writel(v,a) __arch_putl(v,a) + +#define readb(a) __arch_getb(a) +#define readw(a) __arch_getw(a) +#define readl(a) __arch_getl(a) + +/* + * The compiler seems to be incapable of optimising constants + * properly. Spell it out to the compiler in some cases. + * These are only valid for small values of "off" (< 1<<12) + */ +#define __raw_base_writeb(val,base,off) __arch_base_putb(val,base,off) +#define __raw_base_writew(val,base,off) __arch_base_putw(val,base,off) +#define __raw_base_writel(val,base,off) __arch_base_putl(val,base,off) + +#define __raw_base_readb(base,off) __arch_base_getb(base,off) +#define __raw_base_readw(base,off) __arch_base_getw(base,off) +#define __raw_base_readl(base,off) __arch_base_getl(base,off) + +/* + * Now, pick up the machine-defined IO definitions + */ +#if 0 /* XXX###XXX */ +#include +#endif /* XXX###XXX */ + +/* + * IO port access primitives + * ------------------------- + * + * The ARM doesn't have special IO access instructions; all IO is memory + * mapped. Note that these are defined to perform little endian accesses + * only. Their primary purpose is to access PCI and ISA peripherals. + * + * Note that for a big endian machine, this implies that the following + * big endian mode connectivity is in place, as described by numerious + * ARM documents: + * + * PCI: D0-D7 D8-D15 D16-D23 D24-D31 + * ARM: D24-D31 D16-D23 D8-D15 D0-D7 + * + * The machine specific io.h include defines __io to translate an "IO" + * address to a memory address. + * + * Note that we prevent GCC re-ordering or caching values in expressions + * by introducing sequence points into the in*() definitions. Note that + * __raw_* do not guarantee this behaviour. + * + * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space. + */ +#ifdef __io +#define outb(v,p) __raw_writeb(v,__io(p)) +#define outw(v,p) __raw_writew(cpu_to_le16(v),__io(p)) +#define outl(v,p) __raw_writel(cpu_to_le32(v),__io(p)) + +#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; }) +#define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; }) +#define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; }) + +#define outsb(p,d,l) __raw_writesb(__io(p),d,l) +#define outsw(p,d,l) __raw_writesw(__io(p),d,l) +#define outsl(p,d,l) __raw_writesl(__io(p),d,l) + +#define insb(p,d,l) __raw_readsb(__io(p),d,l) +#define insw(p,d,l) __raw_readsw(__io(p),d,l) +#define insl(p,d,l) __raw_readsl(__io(p),d,l) +#endif + +#define outb_p(val,port) outb((val),(port)) +#define outw_p(val,port) outw((val),(port)) +#define outl_p(val,port) outl((val),(port)) +#define inb_p(port) inb((port)) +#define inw_p(port) inw((port)) +#define inl_p(port) inl((port)) + +#define outsb_p(port,from,len) outsb(port,from,len) +#define outsw_p(port,from,len) outsw(port,from,len) +#define outsl_p(port,from,len) outsl(port,from,len) +#define insb_p(port,to,len) insb(port,to,len) +#define insw_p(port,to,len) insw(port,to,len) +#define insl_p(port,to,len) insl(port,to,len) + +/* + * ioremap and friends. + * + * ioremap takes a PCI memory address, as specified in + * linux/Documentation/IO-mapping.txt. If you want a + * physical address, use __ioremap instead. + */ +extern void * __ioremap(unsigned long offset, size_t size, unsigned long flags); +extern void __iounmap(void *addr); + +/* + * Generic ioremap support. + * + * Define: + * iomem_valid_addr(off,size) + * iomem_to_phys(off) + */ +#ifdef iomem_valid_addr +#define __arch_ioremap(off,sz,nocache) \ + ({ \ + unsigned long _off = (off), _size = (sz); \ + void *_ret = (void *)0; \ + if (iomem_valid_addr(_off, _size)) \ + _ret = __ioremap(iomem_to_phys(_off),_size,0); \ + _ret; \ + }) + +#define __arch_iounmap __iounmap +#endif + +#define ioremap(off,sz) __arch_ioremap((off),(sz),0) +#define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1) +#define iounmap(_addr) __arch_iounmap(_addr) + +/* + * DMA-consistent mapping functions. These allocate/free a region of + * uncached, unwrite-buffered mapped memory space for use with DMA + * devices. This is the "generic" version. The PCI specific version + * is in pci.h + */ +extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); +extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); +extern void consistent_sync(void *vaddr, size_t size, int rw); + +/* + * String version of IO memory access ops: + */ +extern void _memcpy_fromio(void *, unsigned long, size_t); +extern void _memcpy_toio(unsigned long, const void *, size_t); +extern void _memset_io(unsigned long, int, size_t); + +extern void __readwrite_bug(const char *fn); + +/* + * If this architecture has PCI memory IO, then define the read/write + * macros. These should only be used with the cookie passed from + * ioremap. + */ +#ifdef __mem_pci + +#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; }) +#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) +#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) + +#define writeb(v,c) __raw_writeb(v,__mem_pci(c)) +#define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c)) +#define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c)) + +#define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l)) +#define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l)) +#define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l)) + +#define eth_io_copy_and_sum(s,c,l,b) \ + eth_copy_and_sum((s),__mem_pci(c),(l),(b)) + +static inline int +check_signature(unsigned long io_addr, const unsigned char *signature, + int length) +{ + int retval = 0; + do { + if (readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + +#elif !defined(readb) + +#define readb(addr) (__readwrite_bug("readb"),0) +#define readw(addr) (__readwrite_bug("readw"),0) +#define readl(addr) (__readwrite_bug("readl"),0) +#define writeb(v,addr) __readwrite_bug("writeb") +#define writew(v,addr) __readwrite_bug("writew") +#define writel(v,addr) __readwrite_bug("writel") + +#define eth_io_copy_and_sum(a,b,c,d) __readwrite_bug("eth_io_copy_and_sum") + +#define check_signature(io,sig,len) (0) + +#endif /* __mem_pci */ + +/* + * If this architecture has ISA IO, then define the isa_read/isa_write + * macros. + */ +#ifdef __mem_isa + +#define isa_readb(addr) __raw_readb(__mem_isa(addr)) +#define isa_readw(addr) __raw_readw(__mem_isa(addr)) +#define isa_readl(addr) __raw_readl(__mem_isa(addr)) +#define isa_writeb(val,addr) __raw_writeb(val,__mem_isa(addr)) +#define isa_writew(val,addr) __raw_writew(val,__mem_isa(addr)) +#define isa_writel(val,addr) __raw_writel(val,__mem_isa(addr)) +#define isa_memset_io(a,b,c) _memset_io(__mem_isa(a),(b),(c)) +#define isa_memcpy_fromio(a,b,c) _memcpy_fromio((a),__mem_isa(b),(c)) +#define isa_memcpy_toio(a,b,c) _memcpy_toio(__mem_isa((a)),(b),(c)) + +#define isa_eth_io_copy_and_sum(a,b,c,d) \ + eth_copy_and_sum((a),__mem_isa(b),(c),(d)) + +static inline int +isa_check_signature(unsigned long io_addr, const unsigned char *signature, + int length) +{ + int retval = 0; + do { + if (isa_readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + +#else /* __mem_isa */ + +#define isa_readb(addr) (__readwrite_bug("isa_readb"),0) +#define isa_readw(addr) (__readwrite_bug("isa_readw"),0) +#define isa_readl(addr) (__readwrite_bug("isa_readl"),0) +#define isa_writeb(val,addr) __readwrite_bug("isa_writeb") +#define isa_writew(val,addr) __readwrite_bug("isa_writew") +#define isa_writel(val,addr) __readwrite_bug("isa_writel") +#define isa_memset_io(a,b,c) __readwrite_bug("isa_memset_io") +#define isa_memcpy_fromio(a,b,c) __readwrite_bug("isa_memcpy_fromio") +#define isa_memcpy_toio(a,b,c) __readwrite_bug("isa_memcpy_toio") + +#define isa_eth_io_copy_and_sum(a,b,c,d) \ + __readwrite_bug("isa_eth_io_copy_and_sum") + +#define isa_check_signature(io,sig,len) (0) + +#endif /* __mem_isa */ +#endif /* __KERNEL__ */ +#endif /* __ASM_ARM_IO_H */ diff --git a/qiboot/src/memory-test.c b/qiboot/src/memory-test.c new file mode 100644 index 0000000..4cdc8cc --- /dev/null +++ b/qiboot/src/memory-test.c @@ -0,0 +1,145 @@ +#include +#include + +int memory_test_const32(void * start, unsigned int length, u32 value) +{ + int errors = 0; + u32 * p = (u32 *)start; + u32 * pend = (u32 *)(start + length); + int count = length >> 2; + + puts("."); + + while (p < pend) + *p++ = value; + + p = (u32 *)start; + count = length >> 2; + + while (count--) + if (*p++ != value) { + puts("*** Error "); + print32((long)p - 4); + errors++; + } + + return errors; +} + +int memory_test_ads(void * start, unsigned int length, u32 mask) +{ + int errors = 0; + u32 * p = (u32 *)start; + u32 * pend = (u32 *)(start + length); + + puts("."); + + while (p < pend) + if ((u32)p & mask) + *p++ = 0xffffffff; + else + *p++ = 0; + + p = (u32 *)start; + + while (p < pend) { + if ((u32)p & mask) { + if (*p++ != 0xffffffff) { + puts("*** Error "); + print32((long)p - 4); + errors++; + } + } else { + if (*p++) { + puts("*** Error "); + print32((long)p - 4); + errors++; + } + } + } + return errors; +} + +int memory_test_walking1(void * start, unsigned int length) +{ + int errors = 0; + u32 value = 1; + + while (value) { + errors += memory_test_const32(start, length, value); + value <<= 1; + } + + return errors; +} + +/* negative runs == run forever */ + +void __memory_test(void * start, unsigned int length) +{ + int errors = 0; + int series = 0; + int mask; + + puts("\nMemory Testing 0x"); + print32((u32)start); + puts(" length "); + printdec(length >> 20); + puts(" MB\n"); + + while (1) { + puts(" Test series "); + printdec(series + 1); + puts(" "); + + /* these are looking at data issues, they flood the whole + * array with the same data + */ + + errors += memory_test_const32(start, length, 0x55555555); + errors += memory_test_const32(start, length, 0xaaaaaaaa); + errors += memory_test_const32(start, length, 0x55aa55aa); + errors += memory_test_const32(start, length, 0xaa55aa55); + errors += memory_test_const32(start, length, 0x00ff00ff); + errors += memory_test_const32(start, length, 0xff00ff00); + errors += memory_test_walking1(start, length); + + /* this is looking at addressing issues, it floods only + * addresses meeting a walking mask with 0xffffffff (the rest + * is zeroed), and makes sure all the bits are only seen where + * they were placed + */ + + mask = 1; + while (! (length & mask)) { + errors += memory_test_ads(start, length, mask); + mask = mask << 1; + } + + puts(" Total errors: "); + printdec(errors); + puts("\n"); + + series++; + } +} + + +void memory_test(void * start, unsigned int length) +{ + /* it's a small steppingstone stack from start.S */ + extern int _ss_stack; + + /* + * we won't be coming back from this, so just force our local stack to + * steppingstone out of the way of main memory test action + * + * then jump into the actual test + */ + asm volatile ( + "mov sp, %0\n" + : : "r" (&_ss_stack) + ); + + __memory_test(start, length); +} diff --git a/qiboot/src/part.h b/qiboot/src/part.h new file mode 100644 index 0000000..b22a637 --- /dev/null +++ b/qiboot/src/part.h @@ -0,0 +1,138 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _PART_H +#define _PART_H + +#include + +typedef struct block_dev_desc { + int if_type; /* type of the interface */ + int dev; /* device number */ + unsigned char part_type; /* partition type */ + unsigned char target; /* target SCSI ID */ + unsigned char lun; /* target LUN */ + unsigned char type; /* device type */ + unsigned char removable; /* removable device */ +#ifdef CONFIG_LBA48 + unsigned char lba48; /* device can use 48bit addr (ATA/ATAPI v7) */ +#endif + lbaint_t lba; /* number of blocks */ + unsigned long blksz; /* block size */ + char vendor [40+1]; /* IDE model, SCSI Vendor */ + char product[20+1]; /* IDE Serial no, SCSI product */ + char revision[8+1]; /* firmware revision */ + unsigned long (*block_read)(int dev, + unsigned long start, + lbaint_t blkcnt, + void *buffer); + unsigned long (*block_write)(int dev, + unsigned long start, + lbaint_t blkcnt, + const void *buffer); + void *priv; /* driver private struct pointer */ +}block_dev_desc_t; + +/* Interface types: */ +#define IF_TYPE_UNKNOWN 0 +#define IF_TYPE_IDE 1 +#define IF_TYPE_SCSI 2 +#define IF_TYPE_ATAPI 3 +#define IF_TYPE_USB 4 +#define IF_TYPE_DOC 5 +#define IF_TYPE_MMC 6 +#define IF_TYPE_SD 7 +#define IF_TYPE_SATA 8 + +/* Part types */ +#define PART_TYPE_UNKNOWN 0x00 +#define PART_TYPE_MAC 0x01 +#define PART_TYPE_DOS 0x02 +#define PART_TYPE_ISO 0x03 +#define PART_TYPE_AMIGA 0x04 + +/* + * Type string for U-Boot bootable partitions + */ +#define BOOT_PART_TYPE "U-Boot" /* primary boot partition type */ +#define BOOT_PART_COMP "PPCBoot" /* PPCBoot compatibility type */ + +/* device types */ +#define DEV_TYPE_UNKNOWN 0xff /* not connected */ +#define DEV_TYPE_HARDDISK 0x00 /* harddisk */ +#define DEV_TYPE_TAPE 0x01 /* Tape */ +#define DEV_TYPE_CDROM 0x05 /* CD-ROM */ +#define DEV_TYPE_OPDISK 0x07 /* optical disk */ + +typedef struct disk_partition { + ulong start; /* # of first block in partition */ + ulong size; /* number of blocks in partition */ + ulong blksz; /* block size in bytes */ + uchar name[32]; /* partition name */ + uchar type[32]; /* string type description */ +} disk_partition_t; + +/* Misc _get_dev functions */ +block_dev_desc_t* get_dev(char* ifname, int dev); +block_dev_desc_t* ide_get_dev(int dev); +block_dev_desc_t* sata_get_dev(int dev); +block_dev_desc_t* scsi_get_dev(int dev); +block_dev_desc_t* usb_stor_get_dev(int dev); +block_dev_desc_t* mmc_get_dev(int dev); +block_dev_desc_t* systemace_get_dev(int dev); + +/* disk/part.c */ +int get_partition_info (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); +void print_part (block_dev_desc_t *dev_desc); +void init_part (block_dev_desc_t *dev_desc); +void dev_print(block_dev_desc_t *dev_desc); + + +#ifdef CONFIG_MAC_PARTITION +/* disk/part_mac.c */ +int get_partition_info_mac (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); +void print_part_mac (block_dev_desc_t *dev_desc); +int test_part_mac (block_dev_desc_t *dev_desc); +#endif + +#ifdef CONFIG_DOS_PARTITION +/* disk/part_dos.c */ +int get_partition_info_dos (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); +void print_part_dos (block_dev_desc_t *dev_desc); +int test_part_dos (block_dev_desc_t *dev_desc); +#endif + +#ifdef CONFIG_ISO_PARTITION +/* disk/part_iso.c */ +int get_partition_info_iso (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); +void print_part_iso (block_dev_desc_t *dev_desc); +int test_part_iso (block_dev_desc_t *dev_desc); +#endif + +#ifdef CONFIG_AMIGA_PARTITION +/* disk/part_amiga.c */ +int get_partition_info_amiga (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); +void print_part_amiga (block_dev_desc_t *dev_desc); +int test_part_amiga (block_dev_desc_t *dev_desc); +#endif + +#endif /* _PART_H */ diff --git a/qiboot/src/phase2.c b/qiboot/src/phase2.c new file mode 100644 index 0000000..4a7ff18 --- /dev/null +++ b/qiboot/src/phase2.c @@ -0,0 +1,495 @@ +/* + * (C) Copyright 2008 Openmoko, Inc. + * Author: Andy Green + * + * Parse the U-Boot header and Boot Linux + * based on various code from U-Boot + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "blink_led.h" +#include +#define __ARM__ +#include +#include +#include + + +typedef void (*the_kernel_fn)(int zero, int arch, uint params); + +unsigned long partition_offset_blocks = 0; +unsigned long partition_length_blocks = 0; + +struct kernel_source const * this_kernel = 0; + +static const int INITRD_OFFSET = (8 * 1024 * 1024); + + +int raise(int n) +{ + return 0; +} + +static void indicate(enum ui_indication ui_indication) +{ + if (this_board->set_ui_indication) + (this_board->set_ui_indication)(ui_indication); +} + +static int read_file(const char * filepath, u8 * destination, int size) +{ + int len = size; + int ret; + + switch (this_kernel->filesystem) { + case FS_EXT2: + if (!ext2fs_mount()) { + puts("Unable to mount ext2 filesystem\n"); + indicate(UI_IND_MOUNT_FAIL); + return -2; /* death */ + } + puts(" EXT2 open: "); + puts(filepath); + len = ext2fs_open(filepath); + if (len < 0) { + puts(" Open failed\n"); + return -1; + } + puts(" OK\n"); + ret = ext2fs_read((char *)destination, size); + if (ret < 0) { + puts(" Read failed\n"); + return -1; + } + break; + + case FS_FAT: + /* FIXME */ + case FS_RAW: + /* any filename-related request in raw filesystem will fail */ + if (filepath) + return -1; + puts(" RAW open: +"); + printdec(partition_offset_blocks); + puts(" 512-byte blocks\n"); + if (this_kernel->block_read(destination, + partition_offset_blocks, size >> 9) < 0) { + puts("Bad kernel header\n"); + return -1; + } + break; + } + + return len; +} + +static int do_block_init(void) +{ + static void * last_block_init = NULL; + static int last_block_init_result = 0; + int fresh = 0; + + /* if this device needs initializing, try to init it */ + if (!this_kernel->block_init) + return 1; /* happy */ + + /* + * cache result to limit attempts for same + * block device to one time + */ + if (this_kernel->block_init != last_block_init) { + last_block_init = this_kernel->block_init; + last_block_init_result = (this_kernel->block_init)(); + fresh = 1; + } + + if (last_block_init_result) { + puts("block device init failed\n"); + if (fresh) + indicate(UI_IND_MOUNT_FAIL); + + return 0; /* failed */ + } + last_block_init = this_kernel->block_init; + + return 1; /* happy */ +} + +static int do_partitions(void *kernel_dram) +{ + unsigned char *p = kernel_dram; + + /* if there's a partition table implied, parse it, otherwise + * just use a fixed offset + */ + if (!this_kernel->partition_index) { + partition_offset_blocks = + this_kernel->offset_blocks512_if_no_partition; + return 1; + } + + if ((int)this_kernel->block_read(kernel_dram, 0, 4) < 0) { + puts("Bad partition read\n"); + indicate(UI_IND_MOUNT_FAIL); + return 0; + } + + if ((p[0x1fe] != 0x55) || (p[0x1ff] != 0xaa)) { + puts("partition signature missing\n"); + indicate(UI_IND_MOUNT_FAIL); + return 0; + } + + p += 0x1be + 8 + (0x10 * (this_kernel->partition_index - 1)); + + partition_offset_blocks = (((u32)p[3]) << 24) | + (((u32)p[2]) << 16) | + (((u32)p[1]) << 8) | + p[0]; + partition_length_blocks = (((u32)p[7]) << 24) | + (((u32)p[6]) << 16) | + (((u32)p[5]) << 8) | + p[4]; + + puts(" Partition: "); + printdec(this_kernel->partition_index); + puts(" start +"); + printdec(partition_offset_blocks); + puts(" 512-byte blocks, size "); + printdec(partition_length_blocks / 2048); + puts(" MiB\n"); + + return 1; +} + +static void do_params(unsigned initramfs_len, + const char *commandline_rootfs_append) +{ + const struct board_variant * board_variant = + (this_board->get_board_variant)(); + const char *p; + char * cmdline; + struct tag *params = (struct tag *)this_board->linux_tag_placement; + + /* eat leading white space */ + for (p = this_board->commandline_board; *p == ' '; p++); + + /* first tag */ + params->hdr.tag = ATAG_CORE; + params->hdr.size = tag_size(tag_core); + params->u.core.flags = 0; + params->u.core.pagesize = 0; + params->u.core.rootdev = 0; + params = tag_next(params); + + /* revision tag */ + params->hdr.tag = ATAG_REVISION; + params->hdr.size = tag_size(tag_revision); + params->u.revision.rev = board_variant->machine_revision; + params = tag_next(params); + + /* memory tags */ + params->hdr.tag = ATAG_MEM; + params->hdr.size = tag_size(tag_mem32); + params->u.mem.start = this_board->linux_mem_start; + params->u.mem.size = this_board->linux_mem_size; + params = tag_next(params); + + if (this_kernel->initramfs_filepath) { + /* INITRD2 tag */ + params->hdr.tag = ATAG_INITRD2; + params->hdr.size = tag_size(tag_initrd); + params->u.initrd.start = this_board->linux_mem_start + + INITRD_OFFSET; + params->u.initrd.size = initramfs_len; + params = tag_next(params); + } + + /* kernel commandline */ + + cmdline = params->u.cmdline.cmdline; + + /* start with the fixed device part of the commandline */ + + cmdline += strlen(strcpy(cmdline, p)); + + /* if the board itself needs a computed commandline, add it now */ + + if (this_board->append_device_specific_cmdline) + cmdline = (this_board->append_device_specific_cmdline)(cmdline); + + /* If he is giving an append commandline for this rootfs, apply that */ + + if (this_kernel->commandline_append) + cmdline += strlen(strcpy(cmdline, + this_kernel->commandline_append)); + if (commandline_rootfs_append[0]) + cmdline += strlen(strcpy(cmdline, + commandline_rootfs_append)); + + /* deal with any trailing newlines that hitched a ride */ + + while (*(cmdline - 1) == '\n') + cmdline--; + + *cmdline = '\0'; + + /* + * if he's still holding down the UI_ACTION_SKIPKERNEL key + * now we finished loading the kernel, take it to mean he wants + * to have the debugging options added to the commandline + */ + + if (this_board->commandline_board_debug && this_board->get_ui_debug) + if ((this_board->get_ui_debug)()) + cmdline += strlen(strcpy(cmdline, this_board-> + commandline_board_debug)); + + params->hdr.tag = ATAG_CMDLINE; + params->hdr.size = (sizeof(struct tag_header) + + strlen(params->u.cmdline.cmdline) + 1 + 4) >> 2; + + puts(" Cmdline: "); + puts(params->u.cmdline.cmdline); + puts("\n"); + + params = tag_next(params); + + /* needs to always be the last tag */ + params->hdr.tag = ATAG_NONE; + params->hdr.size = 0; +} + +static int do_crc(const image_header_t *hdr, const void *kernel_dram) +{ + unsigned long crc; + + /* + * It's good for now to know that our kernel is intact from + * the storage before we jump into it and maybe crash silently + * even though it costs us some time + */ + crc = crc32(0, kernel_dram + sizeof(image_header_t), + __be32_to_cpu(hdr->ih_size)); + if (crc == __be32_to_cpu(hdr->ih_dcrc)) + return 1; + + puts("\nKernel CRC ERROR: read 0x"); + print32(crc); + puts(" vs hdr CRC 0x"); + print32(__be32_to_cpu(hdr->ih_dcrc)); + puts("\n"); + + return 0; +} + +static the_kernel_fn load_uimage(void *kernel_dram) +{ + image_header_t *hdr; + u32 kernel_size; + + hdr = (image_header_t *)kernel_dram; + + if (__be32_to_cpu(hdr->ih_magic) != IH_MAGIC) { + puts("bad magic "); + print32(hdr->ih_magic); + puts("\n"); + return NULL; + } + + puts(" Found: \""); + puts((const char *)hdr->ih_name); + puts("\"\n Size: "); + printdec(__be32_to_cpu(hdr->ih_size) >> 10); + puts(" KiB\n"); + + kernel_size = ((__be32_to_cpu(hdr->ih_size) + + sizeof(image_header_t) + 2048) & ~(2048 - 1)); + + if (read_file(this_kernel->filepath, kernel_dram, kernel_size) < 0) { + indicate(UI_IND_KERNEL_PULL_FAIL); + return NULL; + } + + indicate(UI_IND_KERNEL_PULL_OK); + + if (!do_crc(hdr, kernel_dram)) + return NULL; + + return (the_kernel_fn) (((char *)hdr) + sizeof(image_header_t)); +} + +static the_kernel_fn load_zimage(void *kernel_dram) +{ + u32 magic = *(u32 *) (kernel_dram + 0x24); + u32 size = *(u32 *) (kernel_dram + 0x2c); + int got; + + if (magic != 0x016f2818) { + puts("bad magic "); + print32(magic); + puts("\n"); + return NULL; + } + + puts(" Size: "); + printdec(size >> 10); + puts(" KiB\n"); + + got = read_file(this_kernel->filepath, kernel_dram, size); + if (got < 0) { + indicate(UI_IND_KERNEL_PULL_FAIL); + return NULL; + } + + if (got != size) { + puts("short kernel\n"); + return NULL; + } + + indicate(UI_IND_KERNEL_PULL_OK); + + return (the_kernel_fn) kernel_dram; +} + +static void try_this_kernel(void) +{ + the_kernel_fn the_kernel; + unsigned int initramfs_len = 0; + static char commandline_rootfs_append[512] = ""; + int ret; + void * kernel_dram = (void *)this_board->linux_mem_start + 0x8000; + + partition_offset_blocks = 0; + partition_length_blocks = 0; + + puts("\nTrying kernel: "); + puts(this_kernel->name); + puts("\n"); + + indicate(UI_IND_MOUNT_PART); + + if (!do_block_init()) + return; + + if (!do_partitions(kernel_dram)) + return; + + /* does he want us to skip this? */ + + ret = read_file(this_board->noboot, kernel_dram, 512); + if (ret != -1) { + /* -2 (mount fail) should make us give up too */ + if (ret >= 0) { + puts(" (Skipping on finding "); + puts(this_board->noboot); + puts(")\n"); + indicate(UI_IND_SKIPPING); + } + return; + } + + /* is there a commandline append file? */ + + commandline_rootfs_append[0] = '\0'; + read_file(this_board->append, (u8 *)commandline_rootfs_append, 512); + + indicate(UI_IND_KERNEL_PULL); + + /* pull the kernel image */ + + if (read_file(this_kernel->filepath, kernel_dram, 4096) < 0) + return; + + the_kernel = load_uimage(kernel_dram); + if (!the_kernel) + the_kernel = load_zimage(kernel_dram); + if (!the_kernel) + return; + + /* initramfs if needed */ + + if (this_kernel->initramfs_filepath) { + indicate(UI_IND_INITRAMFS_PULL); + initramfs_len = read_file(this_kernel->initramfs_filepath, + (u8 *)this_board->linux_mem_start + INITRD_OFFSET, + 16 * 1024 * 1024); + if (initramfs_len < 0) { + puts("initramfs load failed\n"); + indicate(UI_IND_INITRAMFS_PULL_FAIL); + return; + } + indicate(UI_IND_INITRAMFS_PULL_OK); + } + + do_params(initramfs_len, commandline_rootfs_append); + + /* give board implementation a chance to shut down + * anything it may have going on, leave GPIO set for Linux + */ + if (this_board->close) + (this_board->close)(); + + puts("Starting --->\n\n"); + indicate(UI_IND_KERNEL_START); + + /* + * ooh that's it, we're gonna try boot this image! + * never mind the cache, Linux will take care of it + */ + the_kernel(0, this_board->linux_machine_id, + this_board->linux_tag_placement); + + /* we won't come back here no matter what */ +} + +void bootloader_second_phase(void) +{ + /* give device a chance to print device-specific things */ + + if (this_board->post_serial_init) + (this_board->post_serial_init)(); + + /* we try the possible kernels for this board in order */ + + for (this_kernel = this_board->kernel_source; this_kernel->name; + this_kernel++) + try_this_kernel(); + + /* none of the kernels worked out */ + + puts("\nNo usable kernel image found\n"); + + /* + * sit there doing a memory test in this case. + * + * This phase 2 code will get destroyed but it's OK, we won't be + * coming back and the whole memory test and dependency functions are + * in phase 1 / steppingstone, so we can test entire memory range. + * + * It means we just boot with SD Card with kernel(s) renamed or removed + * to provoke memory test. + */ + + indicate(UI_IND_MEM_TEST); + + memory_test((void *)this_board->linux_mem_start, + this_board->linux_mem_size); + +} diff --git a/qiboot/src/serial.h b/qiboot/src/serial.h new file mode 100644 index 0000000..c10a386 --- /dev/null +++ b/qiboot/src/serial.h @@ -0,0 +1,112 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * + * Configuation settings for the FIC Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#define UART0 0 +#define UART1 1 +#define UART2 2 + +#define rGPHCON (*(volatile unsigned *)0x56000070) /*UART 0 Line control*/ + +#define rULCON0 (*(volatile unsigned *)0x50000000) /*UART 0 Line control*/ +#define rUCON0 (*(volatile unsigned *)0x50000004) /*UART 0 Control*/ +#define rUFCON0 (*(volatile unsigned *)0x50000008) /*UART 0 FIFO control*/ +#define rUMCON0 (*(volatile unsigned *)0x5000000c) /*UART 0 Modem control*/ +#define rUTRSTAT0 (*(volatile unsigned *)0x50000010) /*UART 0 Tx/Rx status*/ +#define rUERSTAT0 (*(volatile unsigned *)0x50000014) /*UART 0 Rx error status*/ +#define rUFSTAT0 (*(volatile unsigned *)0x50000018) /*UART 0 FIFO status*/ +#define rUMSTAT0 (*(volatile unsigned *)0x5000001c) /*UART 0 Modem status*/ +#define rUBRDIV0 (*(volatile unsigned *)0x50000028) /*UART 0 Baud rate divisor*/ + +#define rULCON1 (*(volatile unsigned *)0x50004000) /*UART 1 Line control*/ +#define rUCON1 (*(volatile unsigned *)0x50004004) /*UART 1 Control*/ +#define rUFCON1 (*(volatile unsigned *)0x50004008) /*UART 1 FIFO control*/ +#define rUMCON1 (*(volatile unsigned *)0x5000400c) /*UART 1 Modem control*/ +#define rUTRSTAT1 (*(volatile unsigned *)0x50004010) /*UART 1 Tx/Rx status*/ +#define rUERSTAT1 (*(volatile unsigned *)0x50004014) /*UART 1 Rx error status*/ +#define rUFSTAT1 (*(volatile unsigned *)0x50004018) /*UART 1 FIFO status*/ +#define rUMSTAT1 (*(volatile unsigned *)0x5000401c) /*UART 1 Modem status*/ +#define rUBRDIV1 (*(volatile unsigned *)0x50004028) /*UART 1 Baud rate divisor*/ + +#define rULCON2 (*(volatile unsigned *)0x50008000) /*UART 2 Line control*/ +#define rUCON2 (*(volatile unsigned *)0x50008004) /*UART 2 Control*/ +#define rUFCON2 (*(volatile unsigned *)0x50008008) /*UART 2 FIFO control*/ +#define rUTRSTAT2 (*(volatile unsigned *)0x50008010) /*UART 2 Tx/Rx status*/ +#define rUERSTAT2 (*(volatile unsigned *)0x50008014) /*UART 2 Rx error status*/ +#define rUFSTAT2 (*(volatile unsigned *)0x50008018) /*UART 2 FIFO status*/ +#define rUBRDIV2 (*(volatile unsigned *)0x50008028) /*UART 2 Baud rate divisor*/ + +#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch) +#define RdURXH0() (*(volatile unsigned char *)0x50000024) +#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004020)=(unsigned char)(ch) +#define RdURXH1() (*(volatile unsigned char *)0x50004024) +#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008020)=(unsigned char)(ch) +#define RdURXH2() (*(volatile unsigned char *)0x50008024) + + + +// I/O PORT +#define rGPACON (*(volatile unsigned *)0x56000000) +#define rGPADAT (*(volatile unsigned *)0x56000004) + +#define rGPBCON (*(volatile unsigned *)0x56000010) +#define rGPBDAT (*(volatile unsigned *)0x56000014) +#define rGPBUP (*(volatile unsigned *)0x56000018) + +#define rGPCCON (*(volatile unsigned *)0x56000020) +#define rGPCDAT (*(volatile unsigned *)0x56000024) +#define rGPCUP (*(volatile unsigned *)0x56000028) + +#define rGPDCON (*(volatile unsigned *)0x56000030) +#define rGPDDAT (*(volatile unsigned *)0x56000034) +#define rGPDUP (*(volatile unsigned *)0x56000038) + +#define rGPECON (*(volatile unsigned *)0x56000040) +#define rGPEDAT (*(volatile unsigned *)0x56000044) +#define rGPEUP (*(volatile unsigned *)0x56000048) + +#define rGPFCON (*(volatile unsigned *)0x56000050) +#define rGPFDAT (*(volatile unsigned *)0x56000054) +#define rGPFUP (*(volatile unsigned *)0x56000058) + +#define rGPGCON (*(volatile unsigned *)0x56000060) +#define rGPGDAT (*(volatile unsigned *)0x56000064) +#define rGPGUP (*(volatile unsigned *)0x56000068) + +#define rGPHCON (*(volatile unsigned *)0x56000070) +#define rGPHDAT (*(volatile unsigned *)0x56000074) +#define rGPHUP (*(volatile unsigned *)0x56000078) + +#define rGPJCON (*(volatile unsigned *)0x560000d0) //Port J control +#define rGPJDAT (*(volatile unsigned *)0x560000d4) //Port J data +#define rGPJUP (*(volatile unsigned *)0x560000d8) //Port J data + +void port_init(void); +void serial_init (const int uart); +void serial_putc (const int uart,const char c); +int printk(const char *fmt, ...); +int puts(const char *string); + +#endif diff --git a/qiboot/src/start.S b/qiboot/src/start.S new file mode 100644 index 0000000..bbc8186 --- /dev/null +++ b/qiboot/src/start.S @@ -0,0 +1,332 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define __ASM_MODE__ +#include + +#define S3C2410_MISCCR_nEN_SCLK0 (1 << 17) +#define S3C2410_MISCCR_nEN_SCLK1 (1 << 18) +#define S3C2410_MISCCR_nEN_SCLKE (1 << 19) + + + +.globl _start, processor_id, is_jtag + +_start: b start_code +/* if we are injected by JTAG, the script sets _istag content to nonzero */ +is_jtag: + .word 0 + +/* it's at a fixed address (+0x8) so we can breakpoint it in the JTAG script + * we need to go through this hassle because before this moment, SDRAM is not + * working so we can't prep it from JTAG + */ + +_steppingstone_done: + ldr pc, _start_armboot + +_start_armboot: + .word start_qi + +_TEXT_BASE: + .word TEXT_BASE + +processor_id: + .word 0 + .word 0x41129200 /* s3c2442 ID */ + .word 0x410fb760 /* s3c6410 ID */ + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +start_code: + /* + * set the cpu to SVC32 mode + */ + mrs r0,cpsr + bic r0,r0,#0x1f + orr r0,r0,#0xd3 + msr cpsr,r0 + + /* + * detect processor we are running on + * s3c2442: 0x4112920x + * s3c6410: 0x410fb76x + */ + MRC p15, 0 ,r0, c0, c0, 0 + ldr r1, =processor_id + str r0, [r1] + ldr r2, [r1, #4] + + and r0, #0xfffffff0 + cmp r0, r2 + beq startup_2442 + + /* 6410 startup */ +startup_6410: + + mov r0, #0 + str r0, [r1] + + /* 2442 startup */ +startup_2442: +# define pWTCON 0x53000000 + + ldr r0, =pWTCON + mov r1, #0x0 + str r1, [r0] + + /* + * mask all IRQs by setting all bits in the INTMR - default + */ +# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ +# define INTSUBMSK 0x4A00001C +# define INTSUBMSK_val 0x0000ffff + + mov r1, #0xffffffff + ldr r0, =INTMSK + str r1, [r0] + + ldr r1, =INTSUBMSK_val + ldr r0, =INTSUBMSK + str r1, [r0] + + + /* Make sure we get FCLK:HCLK:PCLK = 1:3:6 */ +# define CAMDIVN 0x4C000018 + + ldr r0, =CAMDIVN + mov r1, #0 + str r1, [r0] + + /* Clock asynchronous mode */ + mrc p15, 0, r1, c1, c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 + +#define LOCKTIME 0x4c000000 + + ldr r0, =LOCKTIME + mov r1, #0xffffff + str r1, [r0] + +# define UPLLCON 0x4c000008 +# define MPLLCON_val ((142 << 12) + (7 << 4) + 1) +# define UPLLCON_val (( 88 << 12) + (8 << 4) + 2) + + ldr r0, =UPLLCON + ldr r1, =UPLLCON_val + str r1, [r0] + + /* Page 7-19, seven nops between UPLL and MPLL */ + nop + nop + nop + nop + nop + nop + nop + + ldr r1, =MPLLCON_val + str r1, [r0, #-4] /* MPLLCON */ + +# define CLKDIVN 0x4C000014 /* clock divisor register */ +# define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */ + + /* FCLK:HCLK:PCLK = 1:3:6 */ + ldr r0, =CLKDIVN + mov r1, #CLKDIVN_val + str r1, [r0] + + /* enable only CPU peripheral block clocks we actually use */ + ldr r0, =0x4c00000c /* clkcon */ + ldr r1, =0x3f10 /* uart, pwm, gpio, nand, sdi clocks on */ + str r1, [r0] + + /* gpio UART2 init, H port */ + ldr r0, =0x56000070 + ldr r1, =0x001AAAAA + str r1, [r0] + + /* enable KEEPACT(GPJ8) to make sure PMU keeps us alive */ + ldr r0, =0x56000000 /* GPJ base */ + ldr r1, [r0, #0xd0] /* GPJCON */ + orr r1, r1, #(1 << 16) + str r1, [r0, #0xd0] + + ldr r1, [r0, #0xd4] /* GPJDAT */ + orr r1, r1, #(1 << 8) + str r1, [r0, #0xd4] + + + /* init uart2 */ + ldr r0, =0x50008000 + mov r1, #0x03 + str r1, [r0] + ldr r1, =0x245 + str r1, [r0, #0x04] + mov r1, #0x00 + str r1, [r0, #0x08] + mov r1, #0x00 + str r1, [r0, #0x0c] + mov r1, #0x11 + str r1, [r0, #0x28] + + ldr r0, =0x50008000 + ldr r1, =0x54 + str r1, [r0, #0x20] + +/* reset nand controller, or it is dead to us */ + + mov r1, #0x4E000000 + ldr r2, =0xfff0 @ initial value tacls=3,rph0=7,rph1=7 + ldr r3, [r1, #0] + orr r3, r3, r2 + str r3, [r1, #0] + + ldr r3, [r1, #4] + orr r3, r3, #1 @ enable nand controller + str r3, [r1, #4] + + + /* take sdram out of power down */ + ldr r0, =0x56000080 /* misccr */ + ldr r1, [ r0 ] + bic r1, r1, #(S3C2410_MISCCR_nEN_SCLK0 | S3C2410_MISCCR_nEN_SCLK1 | S3C2410_MISCCR_nEN_SCLKE) + str r1, [ r0 ] + + /* ensure signals stabalise */ + mov r1, #128 +1: subs r1, r1, #1 + bpl 1b + + bl cpu_init_crit + + /* ensure some refresh has happened */ + ldr r1, =0xfffff +1: subs r1, r1, #1 + bpl 1b + + /* capture full EINT situation into gstatus 4 */ + + ldr r0, =0x4A000000 /* SRCPND */ + ldr r1, [ r0 ] + and r1, r1, #0xf + + ldr r0, =0x560000BC /* gstatus4 */ + str r1, [ r0 ] + + ldr r0, =0x560000A8 /* EINTPEND */ + ldr r1, [ r0 ] + ldr r0, =0xfff0 + and r1, r1, r0 + ldr r0, =0x560000BC /* gstatus4 */ + ldr r0, [ r0 ] + orr r1, r1, r0 + ldr r0, =0x560000BC /* gstatus4 */ + str r1, [ r0 ] + + /* test for resume */ + + ldr r1, =0x560000B4 /* gstatus2 */ + ldr r0, [ r1 ] + tst r0, #0x02 /* is this resume from power down */ + /* well, if it was, we are going to jump to + * whatever address we stashed in gstatus3, + * and gstatus4 will hold the wake interrupt + * source for the OS to look at + */ + ldrne pc, [r1, #4] + + + /* >> CFG_VIDEO_LOGO_MAX_SIZE */ +#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ + +stack_setup: + ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ + sub sp, r0, #12 /* leave 3 words for abort-stack */ + +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0x00000000 /* clear */ + +clbss_l: + str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + +/* we are going to jump into the C part of the init now */ +spin: + b _steppingstone_done + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ + +cpu_init_crit: + + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + mcr p15, 0, r0, c1, c0, 0 + + /* + * before relocating, we have to setup RAM timing + * because memory timing is board-dependend, you will + * find a lowlevel_init.S in your board directory. + */ + mov ip, lr + + bl lowlevel_init + + mov lr, ip + mov pc, lr + diff --git a/qiboot/src/utils-phase2.c b/qiboot/src/utils-phase2.c new file mode 100644 index 0000000..bbbd672 --- /dev/null +++ b/qiboot/src/utils-phase2.c @@ -0,0 +1,134 @@ +/* + * (C) Copyright 2008 Openmoko, Inc. + * Author: Andy Green + * + * Little utils for print and strings + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +extern void (*putc_func)(char); + +/* + * malloc pool needs to be in phase 2 bss section, we have phase 1 bss in + * steppingstone to allow full memory range testing in C + */ +u8 malloc_pool[MALLOC_POOL_EXTENT]; +void * malloc_pointer = &malloc_pool[0]; + + +/* improbably simple malloc and free for small and non-intense allocation + * just moves the allocation ptr forward each time and ignores free + */ + +void *malloc(size_t size) +{ + void *p = malloc_pointer; + + malloc_pointer += (size & ~3) + 4; + + if (((u8 *)malloc_pointer - &malloc_pool[0]) > sizeof(malloc_pool)) { + puts("Ran out of malloc pool\n"); + while (1) + ; + } + + return p; +} + +void free(void *ptr) +{ +} + +char *strncpy(char *dest, const char *src, size_t n) +{ + char * dest_orig = dest; + + while (*src && n--) + *dest++ = *src++; + + if (n) + *dest = '\0'; + + return dest_orig; +} + + +int strcmp(const char *s1, const char *s2) +{ + while (1) { + if (*s1 != *s2) + return *s1 - *s2; + if (!*s1) + return 0; + s1++; + s2++; + } +} + +char *strchr(const char *s, int c) +{ + while ((*s) && (*s != c)) + s++; + + if (*s == c) + return (char *)s; + + return NULL; +} + +void hexdump(unsigned char *start, int len) +{ + int n; + + while (len > 0) { + print32((int)start); + (putc_func)(':'); + (putc_func)(' '); + for (n = 0; n < 16; n++) { + print8(*start++); + (putc_func)(' '); + } + (putc_func)('\n'); + len -= 16; + } +} + +void setnybble(char *p, unsigned char n) +{ + if (n < 10) + *p = '0' + n; + else + *p = 'a' + n - 10; +} + +void set8(char *p, unsigned char n) +{ + setnybble(p, (n >> 4) & 15); + setnybble(p + 1, n & 15); +} + +void set32(char *p, unsigned int u) +{ + set8(p, u >> 24); + set8(p + 2, u >> 16); + set8(p + 4, u >> 8); + set8(p + 6, u); +} + diff --git a/qiboot/src/utils.c b/qiboot/src/utils.c new file mode 100644 index 0000000..82f3e4a --- /dev/null +++ b/qiboot/src/utils.c @@ -0,0 +1,150 @@ +/* + * (C) Copyright 2008 Openmoko, Inc. + * Author: Andy Green + * + * Little utils for print and strings + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +void (*putc_func)(char) = NULL; + + +void set_putc_func(void (*p)(char)) +{ + putc_func = p; +} + +size_t strlen(const char *s) +{ + size_t n = 0; + + while (*s++) + n++; + + return n; +} + +char *strcpy(char *dest, const char *src) +{ + char * dest_orig = dest; + + while (*src) + *dest++ = *src++; + *dest = '\0'; + + return dest_orig; +} + +int puts(const char *string) +{ + while (*string) + (putc_func)(*string++); + + return 1; +} + +/* done like this to avoid needing statics in steppingstone */ +void printnybble(unsigned char n) +{ + if (n < 10) + (putc_func)('0' + n); + else + (putc_func)('a' + n - 10); +} + +void print8(unsigned char n) +{ + printnybble((n >> 4) & 15); + printnybble(n & 15); +} + +void print32(unsigned int u) +{ + print8(u >> 24); + print8(u >> 16); + print8(u >> 8); + print8(u); +} + +void printdec(int n) +{ + int d[] = { + 1 * 1000 * 1000 * 1000, + 100 * 1000 * 1000, + 10 * 1000 * 1000, + 1 * 1000 * 1000, + 100 * 1000, + 10 * 1000, + 1 * 1000, + 100, + 10, + 1, + 0 + }; + int flag = 0; + int div = 0; + + if (n < 0) { + (putc_func)('-'); + n = -n; + } + + while (d[div]) { + int r = 0; + while (n >= d[div]) { + r++; + n -= d[div]; + } + if (r || flag || (d[div] == 1)) { + (putc_func)('0' + r); + flag = 1; + } + div++; + } +} + +void *memcpy(void *dest, const void *src, size_t n) +{ + u8 const * ps = src; + u8 * pd = dest; + + while (n--) + *pd++ = *ps++; + + return dest; +} + +void *memset(void *s, int c, size_t n) +{ + u8 * p = s; + + while (n--) + *p++ = c; + + return s; +} + +int q; + +void udelay(int n) +{ + while (n--) + q+=n * q; +} diff --git a/qiboot/tools/Makefile b/qiboot/tools/Makefile new file mode 100644 index 0000000..e2a5409 --- /dev/null +++ b/qiboot/tools/Makefile @@ -0,0 +1,39 @@ +#(C) Copyright 2007 OpenMoko, Inc. +# Author: xiangfu liu +# +# Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone +# +# 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., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +include ../config.mk + +CC = ${HOSTCC} +CFLAGS = -Wall +C_SRCS = $(wildcard *.c) +C_OBJS = $(patsubst %.c,%.o, $(C_SRCS)) +SRCS = ${C_SRCS} +OBJS = ${C_OBJS} +TARGET = mkudfu + +%.o: %.c + CC $(CFLAGS) -o $@ $< + +all:${TARGET} + +${TARGET}:${SRCS} + +clean: + @rm -f *.o *~ ${TARGET} diff --git a/qiboot/tools/mkudfu.c b/qiboot/tools/mkudfu.c new file mode 100644 index 0000000..57ac294 --- /dev/null +++ b/qiboot/tools/mkudfu.c @@ -0,0 +1,314 @@ +/* + * USB DFU file trailer tool + * (C) Copyright by OpenMoko, Inc. + * Author: Harald Welte + * + * based on mkimage.c, copyright information as follows: + * + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * All rights reserved. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#ifndef __WIN32__ +#include /* for host / network byte order conversions */ +#endif +#include +#include +#include +#include + +#if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__) +#include +#endif + +#ifdef __WIN32__ +typedef unsigned int __u32; + +#define SWAP_LONG(x) \ + ((__u32)( \ + (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ + (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ + (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ + (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#define ntohl(a) SWAP_LONG(a) +#define htonl(a) SWAP_LONG(a) +#endif /* __WIN32__ */ + +#ifndef O_BINARY /* should be define'd on __WIN32__ */ +#define O_BINARY 0 +#endif + +#include "usb_dfu_trailer.h" + +extern int errno; + +#ifndef MAP_FAILED +#define MAP_FAILED (-1) +#endif + +static char *cmdname; + +static char *datafile; +static char *imagefile; + + +static void usage() +{ + fprintf (stderr, "%s - create / display u-boot DFU trailer\n", cmdname); + fprintf (stderr, "Usage: %s -l image\n" + " -l ==> list image header information\n" + " %s -v VID -p PID -r REV -d data_file image\n", + cmdname, cmdname); + fprintf (stderr, " -v ==> set vendor ID to 'VID'\n" + " -p ==> set product ID system to 'PID'\n" + " -r ==> set hardware revision to 'REV'\n" + " -d ==> use 'data_file' as input file\n" + ); + exit (EXIT_FAILURE); +} + +static void print_trailer(struct uboot_dfu_trailer *trailer) +{ + printf("===> DFU Trailer information:\n"); + printf("Trailer Vers.: %d\n", trailer->version); + printf("Trailer Length: %d\n", trailer->length); + printf("VendorID: 0x%04x\n", trailer->vendor); + printf("ProductID: 0x%04x\n", trailer->product); + printf("HW Revision: 0x%04x\n", trailer->revision); +} + +static void copy_file (int ifd, const char *datafile, int pad) +{ + int dfd; + struct stat sbuf; + unsigned char *ptr; + int tail; + int zero = 0; + int offset = 0; + int size; + + if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + cmdname, datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (fstat(dfd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + cmdname, datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + ptr = (unsigned char *)mmap(0, sbuf.st_size, + PROT_READ, MAP_SHARED, dfd, 0); + if (ptr == (unsigned char *)MAP_FAILED) { + fprintf (stderr, "%s: Can't read %s: %s\n", + cmdname, datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + size = sbuf.st_size - offset; + if (write(ifd, ptr + offset, size) != size) { + fprintf (stderr, "%s: Write error on %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (pad && ((tail = size % 4) != 0)) { + + if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { + fprintf (stderr, "%s: Write error on %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + } + + (void) munmap((void *)ptr, sbuf.st_size); + (void) close (dfd); +} + + +int main(int argc, char **argv) +{ + int ifd; + int lflag = 0; + struct stat sbuf; + u_int16_t opt_vendor, opt_product, opt_revision; + struct uboot_dfu_trailer _hdr, _mirror, *hdr = &_hdr; + + opt_vendor = opt_product = opt_revision = 0; + + cmdname = *argv; + + while (--argc > 0 && **++argv == '-') { + while (*++*argv) { + switch (**argv) { + case 'l': + lflag = 1; + break; + case 'v': + if (--argc <= 0) + usage (); + opt_vendor = strtoul(*++argv, NULL, 16); + goto NXTARG; + case 'p': + if (--argc <= 0) + usage (); + opt_product = strtoul(*++argv, NULL, 16); + goto NXTARG; + case 'r': + if (--argc <= 0) + usage (); + opt_revision = strtoul(*++argv, NULL, 16); + goto NXTARG; + case 'd': + if (--argc <= 0) + usage (); + datafile = *++argv; + goto NXTARG; + case 'h': + usage(); + break; + default: + usage(); + } + } +NXTARG: ; + } + + if (argc != 1) + usage(); + + imagefile = *argv; + + if (lflag) + ifd = open(imagefile, O_RDONLY|O_BINARY); + else + ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); + + if (ifd < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (lflag) { + unsigned char *ptr; + /* list header information of existing image */ + if (fstat(ifd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if ((unsigned)sbuf.st_size < sizeof(struct uboot_dfu_trailer)) { + fprintf (stderr, + "%s: Bad size: \"%s\" is no valid image\n", + cmdname, imagefile); + exit (EXIT_FAILURE); + } + + ptr = (unsigned char *)mmap(0, sbuf.st_size, + PROT_READ, MAP_SHARED, ifd, 0); + if ((caddr_t)ptr == (caddr_t)-1) { + fprintf (stderr, "%s: Can't read %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + dfu_trailer_mirror(hdr, ptr+sbuf.st_size); + + if (hdr->magic != UBOOT_DFU_TRAILER_MAGIC) { + fprintf (stderr, + "%s: Bad Magic Number: \"%s\" is no valid image\n", + cmdname, imagefile); + exit (EXIT_FAILURE); + } + + /* for multi-file images we need the data part, too */ + print_trailer(hdr); + + (void) munmap((void *)ptr, sbuf.st_size); + (void) close (ifd); + + exit (EXIT_SUCCESS); + } + + /* if we're not listing: */ + + copy_file (ifd, datafile, 0); + + memset (hdr, 0, sizeof(struct uboot_dfu_trailer)); + + /* Build new header */ + hdr->version = UBOOT_DFU_TRAILER_V1; + hdr->magic = UBOOT_DFU_TRAILER_MAGIC; + hdr->length = sizeof(struct uboot_dfu_trailer); + hdr->vendor = opt_vendor; + hdr->product = opt_product; + hdr->revision = opt_revision; + + print_trailer(hdr); + dfu_trailer_mirror(&_mirror, (unsigned char *)hdr+sizeof(*hdr)); + + if (write(ifd, &_mirror, sizeof(struct uboot_dfu_trailer)) + != sizeof(struct uboot_dfu_trailer)) { + fprintf (stderr, "%s: Write error on %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + /* We're a bit of paranoid */ +#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) + (void) fdatasync (ifd); +#else + (void) fsync (ifd); +#endif + + if (fstat(ifd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + /* We're a bit of paranoid */ +#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) + (void) fdatasync (ifd); +#else + (void) fsync (ifd); +#endif + + if (close(ifd)) { + fprintf (stderr, "%s: Write error on %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +} diff --git a/qiboot/tools/usb_dfu_trailer.h b/qiboot/tools/usb_dfu_trailer.h new file mode 100644 index 0000000..3903b85 --- /dev/null +++ b/qiboot/tools/usb_dfu_trailer.h @@ -0,0 +1,31 @@ +#ifndef _USB_DFU_TRAILER_H +#define _USB_DFU_TRAILER_H + +/* trailer handling for DFU files */ + +#define UBOOT_DFU_TRAILER_V1 1 +#define UBOOT_DFU_TRAILER_MAGIC 0x19731978 +struct uboot_dfu_trailer { + u_int32_t magic; + u_int16_t version; + u_int16_t length; + u_int16_t vendor; + u_int16_t product; + u_int32_t revision; +} __attribute__((packed)); + +/* we mirror the trailer because we want it to be longer in later versions + * while keeping backwards compatibility */ +static inline void dfu_trailer_mirror(struct uboot_dfu_trailer *trailer, + unsigned char *eof) +{ + int i; + int len = sizeof(struct uboot_dfu_trailer); + unsigned char *src = eof - len; + unsigned char *dst = (unsigned char *) trailer; + + for (i = 0; i < len; i++) + dst[len-1-i] = src[i]; +} + +#endif /* _USB_DFU_TRAILER_H */