1
0
mirror of git://projects.qi-hardware.com/xburst-tools.git synced 2024-11-26 03:16:15 +02:00

Merge /home/xiangfu/workspace/qi-boot

This commit is contained in:
xiangfu 2009-06-30 12:46:07 +08:00
commit 1c8765eb8a
88 changed files with 18149 additions and 0 deletions

283
qiboot/6410-partition-sd.sh Executable file
View File

@ -0,0 +1,283 @@
#!/bin/sh
# 6410 SD Boot formatter
# (C) 2008 Openmoko, Inc
# Author: Andy Green <andy@openmoko.com>
# 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 <andy@openmoko.com>"
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") '<device> <card> <bootloader> <partition>'
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"

93
qiboot/Makefile Normal file
View File

@ -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)

149
qiboot/README Normal file
View File

@ -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/<uImage-device>.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-<device>, 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-<device>,
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 <device> 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-<devicename>.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-<devicename>,
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.

12
qiboot/build Executable file
View File

@ -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

22
qiboot/config.mk Normal file
View File

@ -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

7
qiboot/dfu-qi Executable file
View File

@ -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

34
qiboot/gta02-qi.ocd Executable file
View File

@ -0,0 +1,34 @@
# gta02 Qi script
# Andy Green <andy@openmoko.com>
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
#

80
qiboot/include/ext2.h Normal file
View File

@ -0,0 +1,80 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
*
* (C) Copyright 2003 Sysgo Real-Time Solutions, AG <www.elinos.com>
* Pavel Bartusek <pba@sysgo.de>
*
* 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);

220
qiboot/include/fat.h Normal file
View File

@ -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 <asm/byteorder.h>
#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_ */

View File

@ -0,0 +1 @@
extern void glamo_core_init(void);

149
qiboot/include/glamo-mmc.h Normal file
View File

@ -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 <Complex> 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__ */

628
qiboot/include/glamo-regs.h Normal file
View File

@ -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 <laforge@openmoko.org>
* 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 */

View File

@ -0,0 +1,3 @@
#include <i2c-bitbang.h>
extern struct i2c_bitbang bb_s3c24xx;

View File

@ -0,0 +1,3 @@
#include <i2c-bitbang.h>
extern struct i2c_bitbang bb_s3c6410;

View File

@ -0,0 +1,102 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* 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 */

570
qiboot/include/image.h Normal file
View File

@ -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_<os>()
* 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__ */

View File

@ -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 <tolkien@mizi.com>
* 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 <Complex> 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 */

120
qiboot/include/linux-mmc.h Normal file
View File

@ -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 <linux/list.h>
#include <linux/interrupt.h>
#include <linux/device.h>
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

110
qiboot/include/mmc.h Normal file
View File

@ -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__ */

View File

@ -0,0 +1,30 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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 <qi.h>
extern const struct board_api board_api_gta01;
#endif
#define TEXT_BASE 0x33000000
#endif /* __CONFIG_H */

View File

@ -0,0 +1,32 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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 <qi.h>
extern const struct board_api board_api_gta02;
#endif
#define TEXT_BASE 0x33000000
#endif /* __CONFIG_H */

View File

@ -0,0 +1,28 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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 <qi.h>
extern const struct board_api board_api_om_3d7k;
#endif
#define TEXT_BASE_OM_3D7K 0x53000000

View File

@ -0,0 +1,6 @@
#ifndef __ASM_MODE__
#include <qi.h>
extern const struct board_api board_api_smdk6410;
#endif
#define TEXT_BASE_SMDK6410 0x53000000

260
qiboot/include/pcf50606.h Normal file
View File

@ -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 <laforge@openmoko.org>
*
*/
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 */

392
qiboot/include/pcf50633.h Normal file
View File

@ -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 <laforge@openmoko.org>
*
*/
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 */

View File

@ -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

45
qiboot/include/qi-ctype.h Normal file
View File

@ -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)

144
qiboot/include/qi.h Normal file
View File

@ -0,0 +1,144 @@
/*
* (C) Copyright 2008 Openmoko, Inc.
* Author: Andy Green <andy@openmoko.org>
*
* 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 <stdarg.h>
#include <qi-ctype.h>
#include <asm/byteorder.h>
#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

View File

@ -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 <mmc.h>
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_ */

View File

@ -0,0 +1,110 @@
/* linux/include/asm/arch-s3c2410/regs-sdi.h
*
* Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
* 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 */

1394
qiboot/include/s3c6410.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,72 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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

View File

@ -0,0 +1,72 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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

269
qiboot/include/setup.h Normal file
View File

@ -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

View File

@ -0,0 +1,6 @@
#ifndef __ASM_MODE__
#include <qi.h>
extern const struct board_api board_api_smdk6410;
#endif
#define TEXT_BASE_SMDK6410 0x53000000

View File

@ -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

90
qiboot/src/blink_led.c Normal file
View File

@ -0,0 +1,90 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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<time;i++);
return 0;
}
int set_GPB(void)
{
GPBCON = 0x5;
GPBDW = 0xffff;
return 0;
}
int orange_on(int times)
{
int count=0;
set_GPB();
for(count=0;count<times;count++)
{
ORANGE_ON();
delay(0xfffff);
ORANGE_OFF() ;
delay(0xfffff);
}
return 0;
}
int blue_on(int times)
{
int count=0;
set_GPB();
for(count=0;count<times;count++)
{
BLUE_ON();
delay(0xfffff);
BLUE_OFF();
delay(0xfffff);
}
return 0;
}
int blink_led(void)
{
set_GPB();
while(1)
{
ORANGE_ON();
delay(0xfffff);
ORANGE_OFF() ;
delay(0xfffff);
BLUE_ON();
delay(0xfffff);
BLUE_OFF();
delay(0xfffff);
}
return 0;
}

39
qiboot/src/blink_led.h Normal file
View File

@ -0,0 +1,39 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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 */

681
qiboot/src/common.h Normal file
View File

@ -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 <config.h>
#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/string.h>
#include <asm/ptrace.h>
#include <stdarg.h>
#if defined(CONFIG_PCI) && (defined(CONFIG_4xx) && !defined(CONFIG_AP1000))
#include <pci.h>
#endif
#if defined(CONFIG_8xx)
#include <asm/8xx_immap.h>
#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 <asm/5xx_immap.h>
#elif defined(CONFIG_MPC5xxx)
#include <mpc5xxx.h>
#elif defined(CONFIG_MPC512X)
#include <mpc512x.h>
#include <asm/immap_512x.h>
#elif defined(CONFIG_MPC8220)
#include <asm/immap_8220.h>
#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 <asm/immap_8260.h>
#endif
#ifdef CONFIG_MPC86xx
#include <mpc86xx.h>
#include <asm/immap_86xx.h>
#endif
#ifdef CONFIG_MPC85xx
#include <mpc85xx.h>
#include <asm/immap_85xx.h>
#endif
#ifdef CONFIG_MPC83XX
#include <mpc83xx.h>
#include <asm/immap_83xx.h>
#endif
#ifdef CONFIG_4xx
#include <ppc4xx.h>
#endif
#ifdef CONFIG_HYMOD
#include <board/hymod/hymod.h>
#endif
#ifdef CONFIG_ARM
#define asmlinkage /* nothing */
#endif
#ifdef CONFIG_BLACKFIN
#include <asm/blackfin.h>
#endif
#include <part.h>
#include <flash.h>
#include <image.h>
#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 <asm/u-boot.h> /* boot information for Linux kernel */
#include <asm/global_data.h> /* 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 <asm/mach-types.h>
# include <asm/setup.h>
# include <asm/u-boot-arm.h> /* ARM version to be fixed! */
#endif /* CONFIG_ARM */
#ifdef CONFIG_I386 /* x86 version to be fixed! */
# include <asm/u-boot-i386.h>
#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)/.../<eth> */
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 <status_led.h>
#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_ */

View File

@ -0,0 +1,312 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include <neo_gta01.h>
#include <serial-s3c24xx.h>
#include <ports-s3c24xx.h>
#include <s3c24xx-mci.h>
#include <i2c-bitbang-s3c24xx.h>
#include <pcf50606.h>
#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 ",
},
},
};

View File

@ -0,0 +1,68 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include <i2c-bitbang.h>
#include <ports-s3c24xx.h>
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,
};

View File

@ -0,0 +1,162 @@
/*
* Memory Setup stuff - taken from blob memsetup.S
*
* Modified for the FIC Neo1973 GTA01 by Harald Welte <laforge@openmoko.org>
*
* 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 <config.h>
* #include <version.h>
*/
#define __ASM_MODE__
#include <neo_gta01.h>
/*
*
* Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
*
* Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com>
*
*/
#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

View File

@ -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 <hwang@mizi.com>
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*/
/* NOTE this stuff runs in steppingstone context! */
/* the API refers to 512-byte blocks */
#include <qi.h>
#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;
}

View File

@ -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 <hwang@mizi.com>
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*/
#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 */

View File

@ -0,0 +1,63 @@
/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@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
*/
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 = .;
}

View File

@ -0,0 +1,579 @@
/*
* qi s3c24xx SD card driver
* Author: Andy Green <andy@openmoko.com>
* based on ---->
*
* u-boot S3C2410 MMC/SD card driver
* (C) Copyright 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*
* 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 <qi.h>
#include <mmc.h>
#include <s3c24xx-regs-sdi.h>
#include <string.h>
#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;
}

View File

@ -0,0 +1,77 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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 <qi.h>
#include <serial-s3c24xx.h>
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;
}
}

View File

@ -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 <neo_gta01.h>
#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

View File

@ -0,0 +1,131 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
* Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include "nand_read.h"
#include <neo_gta01.h>
#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)
;
}

View File

@ -0,0 +1,740 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* (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 <qi.h>
#include <neo_gta02.h>
#include <serial-s3c24xx.h>
#include <ports-s3c24xx.h>
#include <i2c-bitbang-s3c24xx.h>
#include <pcf50633.h>
#include <glamo-init.h>
#include <string.h>
#include <ext2.h>
#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 ",
},
},
};

View File

@ -0,0 +1,68 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include <i2c-bitbang.h>
#include <ports-s3c24xx.h>
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,
};

View File

@ -0,0 +1,162 @@
/*
* Memory Setup stuff - taken from blob memsetup.S
*
* Modified for the FIC Neo1973 GTA01 by Harald Welte <laforge@openmoko.org>
*
* 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 <config.h>
* #include <version.h>
*/
#define __ASM_MODE__
#include <neo_gta02.h>
/*
*
* Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
*
* Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com>
*
*/
#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

View File

@ -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 <hwang@mizi.com>
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*/
/* NOTE this stuff runs in steppingstone context! */
/* the API refers to 512-byte blocks */
#include <qi.h>
#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;
}

View File

@ -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 <hwang@mizi.com>
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*/
#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 */

View File

@ -0,0 +1,65 @@
/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@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
*/
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 = .;
}

View File

@ -0,0 +1,569 @@
/*
* qi s3c24xx SD card driver
* Author: Andy Green <andy@openmoko.com>
* based on ---->
*
* u-boot S3C2410 MMC/SD card driver
* (C) Copyright 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*
* 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 <qi.h>
#include <mmc.h>
#include <s3c24xx-regs-sdi.h>
#include <string.h>
#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;
}

View File

@ -0,0 +1,77 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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 <qi.h>
#include <serial-s3c24xx.h>
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;
}
}

View File

@ -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 <neo_gta02.h>
#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

View File

@ -0,0 +1,126 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
* Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include "nand_read.h"
#include <neo_gta02.h>
#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)
;
}

View File

@ -0,0 +1,650 @@
#include <qi.h>
#include "hs_mmc.h"
#include <string.h>
#include <glamo-mmc.h>
#define HCLK_OPERATION
#undef DEBUG_HSMMC
#ifdef DEBUG_HSMMC
#define dbg(x...) printf(x)
#else
#define dbg(x...) do { } while (0)
#endif
//#include <linux-mmc.h>
#include <linux-mmc-protocol.h>
#include <s3c6410.h>
//#include <linux/mmc/protocol.h>
//#include <asm/io.h>
//#include <movi.h>
#include "hs_mmc.h"
#include <mmc.h>
#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;
}

View File

@ -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__*/

View File

@ -0,0 +1,69 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include <i2c-bitbang.h>
#include <s3c6410.h>
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,
};

View File

@ -0,0 +1,114 @@
#include <qi.h>
#include <neo_om_3d7k.h>
#include <s3c6410.h>
#include <serial-s3c64xx.h>
#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 ",
},
},
};

View File

@ -0,0 +1,935 @@
#include <qi.h>
#include <neo_om_3d7k.h>
#include <s3c6410.h>
#include <serial-s3c64xx.h>
#include <i2c-bitbang-s3c6410.h>
#include <pcf50633.h>
#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()];
}

View File

@ -0,0 +1,75 @@
/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@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
*/
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 = .;
}

View File

@ -0,0 +1,38 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include <s3c6410.h>
/*
* 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;
}

View File

@ -0,0 +1,73 @@
#include <qi.h>
#include <neo_smdk6410.h>
#include <serial-s3c64xx.h>
#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 "
},
},
};

View File

@ -0,0 +1,27 @@
#include <qi.h>
#include <neo_smdk6410.h>
#include <serial-s3c64xx.h>
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()];
}

View File

@ -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 <s3c6410.h>
#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<<APLL_SDIV)*APLL_MDIV)
#define Startup_HCLK (Startup_APLL/(Startup_HCLKx2div+1)/(Startup_HCLKdiv+1))
#define CLK_DIV_VAL ((Startup_PCLKdiv<<12)|(Startup_HCLKx2div<<9)|(Startup_HCLKdiv<<8)|(Startup_MPLLdiv<<4)|Startup_APLLdiv)
#define APLL_VAL set_pll(APLL_MDIV, APLL_PDIV, APLL_SDIV)
#define MPLL_VAL set_pll(MPLL_MDIV, MPLL_PDIV, MPLL_SDIV)
#if S3C6410_POP_A
#define DMC1_MEM_CFG 0x00210011 /* Supports one CKE control, Chip1, Burst4, Row/Column bit */
#define DMC1_MEM_CFG2 0xB41
#define DMC1_CHIP0_CFG 0x150FC
#define DMC1_CHIP1_CFG 0x154FC
#define DMC_DDR_32_CFG 0x0 /* 32bit, DDR */
/* Memory Parameters */
/* DDR Parameters */
#define DDR_tREFRESH 5865 /* ns */
#define DDR_tRAS 50 /* ns (min: 45ns)*/
#define DDR_tRC 68 /* ns (min: 67.5ns)*/
#define DDR_tRCD 23 /* ns (min: 22.5ns)*/
#define DDR_tRFC 133 /* ns (min: 80ns)*/
#define DDR_tRP 23 /* ns (min: 22.5ns)*/
#define DDR_tRRD 20 /* ns (min: 15ns)*/
#define DDR_tWR 20 /* ns (min: 15ns)*/
#define DDR_tXSR 125 /* ns (min: 120ns)*/
#define DDR_CASL 3 /* CAS Latency 3 */
#else
#define DMC1_MEM_CFG 0x00010012 /* Supports one CKE control, Chip1, Burst4, Row/Column bit */
#define DMC1_MEM_CFG2 0xB45
#define DMC1_CHIP0_CFG 0x150F8
#define DMC_DDR_32_CFG 0x0 /* 32bit, DDR */
/* Memory Parameters */
/* DDR Parameters */
#define DDR_tREFRESH 7800 /* ns */
#define DDR_tRAS 45 /* ns (min: 45ns)*/
#define DDR_tRC 68 /* ns (min: 67.5ns)*/
#define DDR_tRCD 23 /* ns (min: 22.5ns)*/
#define DDR_tRFC 80 /* ns (min: 80ns)*/
#define DDR_tRP 23 /* ns (min: 22.5ns)*/
#define DDR_tRRD 15 /* ns (min: 15ns)*/
#define DDR_tWR 15 /* ns (min: 15ns)*/
#define DDR_tXSR 120 /* ns (min: 120ns)*/
#define DDR_CASL 3 /* CAS Latency 3 */
#endif
/*
* mDDR memory configuration
*/
#define DMC_DDR_BA_EMRS 2
#define DMC_DDR_MEM_CASLAT 3
#define DMC_DDR_CAS_LATENCY (DDR_CASL<<1) //6 Set Cas Latency to 3
#define DMC_DDR_t_DQSS 1 // Min 0.75 ~ 1.25
#define DMC_DDR_t_MRD 2 //Min 2 tck
#define DMC_DDR_t_RAS (((Startup_HCLK / 1000 * DDR_tRAS) - 1) / 1000000 + 1) //7, Min 45ns
#define DMC_DDR_t_RC (((Startup_HCLK / 1000 * DDR_tRC) - 1) / 1000000 + 1) //10, Min 67.5ns
#define DMC_DDR_t_RCD (((Startup_HCLK / 1000 * DDR_tRCD) - 1) / 1000000 + 1) //4,5(TRM), Min 22.5ns
#define DMC_DDR_schedule_RCD ((DMC_DDR_t_RCD - 3) << 3)
#define DMC_DDR_t_RFC (((Startup_HCLK / 1000 * DDR_tRFC) - 1) / 1000000 + 1) //11,18(TRM) Min 80ns
#define DMC_DDR_schedule_RFC ((DMC_DDR_t_RFC - 3) << 5)
#define DMC_DDR_t_RP (((Startup_HCLK / 1000 * DDR_tRP) - 1) / 1000000 + 1) //4, 5(TRM) Min 22.5ns
#define DMC_DDR_schedule_RP ((DMC_DDR_t_RP - 3) << 3)
#define DMC_DDR_t_RRD (((Startup_HCLK / 1000 * DDR_tRRD) - 1) / 1000000 + 1) //3, Min 15ns
#define DMC_DDR_t_WR (((Startup_HCLK / 1000 * DDR_tWR) - 1) / 1000000 + 1) //Min 15ns
#define DMC_DDR_t_WTR 2
#define DMC_DDR_t_XP 2 //1tck + tIS(1.5ns)
#define DMC_DDR_t_XSR (((Startup_HCLK / 1000 * DDR_tXSR) - 1) / 1000000 + 1) //17, Min 120ns
#define DMC_DDR_t_ESR DMC_DDR_t_XSR
#define DMC_DDR_REFRESH_PRD (((Startup_HCLK / 1000 * DDR_tREFRESH) - 1) / 1000000) // TRM 2656
#define DMC_DDR_USER_CONFIG 1 // 2b01 : mDDR
.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
/*
* 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 @ Enable I and D-Cache
mcr p15, 0, r0, c1, c0, 0
/* Peri port setup */
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)
/* SDRAM */
ldr r0, =ELFIN_MEM_SYS_CFG @Memory sussystem address 0x7e00f120
mov r1, #0xd @ Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1
str r1, [r0]
ldr r0, =ELFIN_DMC1_BASE @DMC1 base address 0x7e001000
ldr r1, =0x04
str r1, [r0, #INDEX_DMC_MEMC_CMD]
ldr r1, =DMC_DDR_REFRESH_PRD
str r1, [r0, #INDEX_DMC_REFRESH_PRD]
ldr r1, =DMC_DDR_CAS_LATENCY
str r1, [r0, #INDEX_DMC_CAS_LATENCY]
ldr r1, =DMC_DDR_t_DQSS
str r1, [r0, #INDEX_DMC_T_DQSS]
ldr r1, =DMC_DDR_t_MRD
str r1, [r0, #INDEX_DMC_T_MRD]
ldr r1, =DMC_DDR_t_RAS
str r1, [r0, #INDEX_DMC_T_RAS]
ldr r1, =DMC_DDR_t_RC
str r1, [r0, #INDEX_DMC_T_RC]
ldr r1, =DMC_DDR_t_RCD
ldr r2, =DMC_DDR_schedule_RCD
orr r1, r1, r2
str r1, [r0, #INDEX_DMC_T_RCD]
ldr r1, =DMC_DDR_t_RFC
ldr r2, =DMC_DDR_schedule_RFC
orr r1, r1, r2
str r1, [r0, #INDEX_DMC_T_RFC]
ldr r1, =DMC_DDR_t_RP
ldr r2, =DMC_DDR_schedule_RP
orr r1, r1, r2
str r1, [r0, #INDEX_DMC_T_RP]
ldr r1, =DMC_DDR_t_RRD
str r1, [r0, #INDEX_DMC_T_RRD]
ldr r1, =DMC_DDR_t_WR
str r1, [r0, #INDEX_DMC_T_WR]
ldr r1, =DMC_DDR_t_WTR
str r1, [r0, #INDEX_DMC_T_WTR]
ldr r1, =DMC_DDR_t_XP
str r1, [r0, #INDEX_DMC_T_XP]
ldr r1, =DMC_DDR_t_XSR
str r1, [r0, #INDEX_DMC_T_XSR]
ldr r1, =DMC_DDR_t_ESR
str r1, [r0, #INDEX_DMC_T_ESR]
ldr r1, =DMC1_MEM_CFG
str r1, [r0, #INDEX_DMC_MEMORY_CFG]
ldr r1, =DMC1_MEM_CFG2
str r1, [r0, #INDEX_DMC_MEMORY_CFG2]
ldr r1, =DMC1_CHIP0_CFG
str r1, [r0, #INDEX_DMC_CHIP_0_CFG]
ldr r1, =DMC_DDR_32_CFG
str r1, [r0, #INDEX_DMC_USER_CONFIG]
@DMC0 DDR Chip 0 configuration direct command reg
ldr r1, =DMC_NOP0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@Precharge All
ldr r1, =DMC_PA0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@Auto Refresh 2 time
ldr r1, =DMC_AR0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@MRS
ldr r1, =DMC_mDDR_EMR0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@Mode Reg
ldr r1, =DMC_mDDR_MR0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
#if S3C6410_POP_A
ldr r1, =DMC1_CHIP1_CFG
str r1, [r0, #INDEX_DMC_CHIP_1_CFG]
@DMC0 DDR Chip 0 configuration direct command reg
ldr r1, =DMC_NOP1
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@Precharge All
ldr r1, =DMC_PA1
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@Auto Refresh 2 time
ldr r1, =DMC_AR1
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@MRS
ldr r1, =DMC_mDDR_EMR1
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
@Mode Reg
ldr r1, =DMC_mDDR_MR1
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
#endif
@Enable DMC1
mov r1, #0x0
str r1, [r0, #INDEX_DMC_MEMC_CMD]
1:
ldr r1, [r0, #INDEX_DMC_MEMC_STATUS]
mov r2, #0x3
and r1, r1, r2
cmp r1, #0x1
bne 1b
nop
ldr r0, =ELFIN_CLOCK_POWER_BASE @0x7e00f000
ldr r1, [r0, #OTHERS_OFFSET]
mov r2, #0x40
orr r1, r1, r2
str r1, [r0, #OTHERS_OFFSET]
nop
nop
nop
nop
nop
ldr r2, =0x80
orr r1, r1, r2
str r1, [r0, #OTHERS_OFFSET]
2:
ldr r1, [r0, #OTHERS_OFFSET]
ldr r2, =0xf00
and r1, r1, r2
cmp r1, #0xf00
bne 2b
mov r1, #0xff00
orr r1, r1, #0xff
str r1, [r0, #APLL_LOCK_OFFSET]
str r1, [r0, #MPLL_LOCK_OFFSET]
str r1, [r0, #EPLL_LOCK_OFFSET]
/* CLKUART(=66.5Mhz) = CLKUART_input(532/2=266Mhz) / (UART_RATIO(3)+1) */
/* CLKUART(=50Mhz) = CLKUART_input(400/2=200Mhz) / (UART_RATIO(3)+1) */
/* Now, When you use UART CLK SRC by EXT_UCLK1, We support 532MHz & 400MHz value */
ldr r1, [r0, #CLK_DIV2_OFFSET]
bic r1, r1, #0x70000
orr r1, r1, #0x30000
str r1, [r0, #CLK_DIV2_OFFSET]
ldr r1, [r0, #CLK_DIV0_OFFSET] /*Set Clock Divider*/
bic r1, r1, #0x30000
bic r1, r1, #0xff00
bic r1, r1, #0xff
ldr r2, =CLK_DIV_VAL
orr r1, r1, r2
str r1, [r0, #CLK_DIV0_OFFSET]
ldr r1, =APLL_VAL
str r1, [r0, #APLL_CON_OFFSET]
ldr r1, =MPLL_VAL
str r1, [r0, #MPLL_CON_OFFSET]
ldr r1, =0x80200203 /* FOUT of EPLL is 96MHz */
str r1, [r0, #EPLL_CON0_OFFSET]
ldr r1, =0x0
str r1, [r0, #EPLL_CON1_OFFSET]
ldr r1, [r0, #CLK_SRC_OFFSET] /* APLL, MPLL, EPLL select to Fout */
ldr r2, =0x2007
orr r1, r1, r2
str r1, [r0, #CLK_SRC_OFFSET]
/* wait at least 200us to stablize all clock */
mov r1, #0x10000
3: subs r1, r1, #1
bne 3b
ldr r1, [r0, #OTHERS_OFFSET]
orr r1, r1, #0x20
str r1, [r0, #OTHERS_OFFSET]
/* set GPIO to enable UART */
@ GPIO setting for UART
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x2222
str r1, [r0, #GPBCON_OFFSET]
ldr r0, =ELFIN_UART_BASE + ELFIN_UART3_OFFSET @0x7F005c00 uart 3
mov r1, #0x0
str r1, [r0, #UFCON_OFFSET]
str r1, [r0, #UMCON_OFFSET]
mov r1, #0x3 @was 0.
str r1, [r0, #ULCON_OFFSET]
ldr r1, =0xe45 /* UARTCLK SRC = 11 => 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

View File

@ -0,0 +1,136 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
* Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include <neo_om_3d7k.h>
#include <neo_smdk6410.h>
#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 <serial-s3c64xx.h>
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();
}

90
qiboot/src/crc32.c Normal file
View File

@ -0,0 +1,90 @@
#include <qi.h>
#include <string.h>
/* 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;
}

27
qiboot/src/ctype.c Normal file
View File

@ -0,0 +1,27 @@
#include <qi-ctype.h>
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 */

View File

@ -0,0 +1,103 @@
/*
* (C) Copyright 2007 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
* Andy Green <andy@openmoko.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <qi.h>
#include <glamo-regs.h>
#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))
;
}

View File

@ -0,0 +1,851 @@
/*
* linux/drivers/mmc/host/glamo-mmc.c - Glamo MMC driver
*
* Copyright (C) 2007 OpenMoko, Inc, Andy Green <andy@openmoko.com>
* Based on the Glamo MCI driver that was -->
*
* Copyright (C) 2007 OpenMoko, Inc, Andy Green <andy@openmoko.com>
* Based on S3C MMC driver that was:
* Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
*
* and
*
* Based on S3C MMC driver that was (original copyright notice ---->)
*
* (C) Copyright 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*
* 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 <tk@maintech.de>
*
* 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 <qi.h>
#include <mmc.h>
#include <glamo-regs.h>
#include <glamo-mmc.h>
#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;
}

View File

@ -0,0 +1,252 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: Andy Green <andy@openmoko.com>
*
* 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 <qi.h>
#include <i2c-bitbang.h>
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);
}

133
qiboot/src/fs/dev.c Normal file
View File

@ -0,0 +1,133 @@
/*
* (C) Copyright 2004
* esd gmbh <www.esd-electronics.com>
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
*
* based on code of fs/reiserfs/dev.c by
*
* (C) Copyright 2003 - 2004
* Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <qi.h>
#include <ext2.h>
#include <string.h>
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;
}

940
qiboot/src/fs/ext2.c Normal file
View File

@ -0,0 +1,940 @@
/*
*(C) Copyright 2004
* esd gmbh <www.esd-electronics.com>
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
*
* 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 <qi.h>
#include <ext2.h>
#include <malloc.h>
#include <string.h>
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("<DIR> ");
break;
case FILETYPE_SYMLINK:
puts("<SYM> ");
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;
}

337
qiboot/src/io.h Normal file
View File

@ -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 <linux/types.h>
#include <asm/byteorder.h>
#include <asm/memory.h>
#if 0 /* XXX###XXX */
#include <asm/arch/hardware.h>
#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 <asm/arch/io.h>
#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 */

145
qiboot/src/memory-test.c Normal file
View File

@ -0,0 +1,145 @@
#include <qi.h>
#include <string.h>
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);
}

138
qiboot/src/part.h Normal file
View File

@ -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 <ide.h>
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 */

495
qiboot/src/phase2.c Normal file
View File

@ -0,0 +1,495 @@
/*
* (C) Copyright 2008 Openmoko, Inc.
* Author: Andy Green <andy@openmoko.org>
*
* 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 <qi.h>
#include <neo_gta02.h>
#include "blink_led.h"
#include <string.h>
#define __ARM__
#include <image.h>
#include <setup.h>
#include <ext2.h>
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);
}

112
qiboot/src/serial.h Normal file
View File

@ -0,0 +1,112 @@
/*
* (C) Copyright 2007 OpenMoko, Inc.
* Author: xiangfu liu <xiangfu@openmoko.org>
*
* 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

332
qiboot/src/start.S Normal file
View File

@ -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 <neo_gta02.h>
#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

134
qiboot/src/utils-phase2.c Normal file
View File

@ -0,0 +1,134 @@
/*
* (C) Copyright 2008 Openmoko, Inc.
* Author: Andy Green <andy@openmoko.org>
*
* 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 <qi.h>
#include <string.h>
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);
}

150
qiboot/src/utils.c Normal file
View File

@ -0,0 +1,150 @@
/*
* (C) Copyright 2008 Openmoko, Inc.
* Author: Andy Green <andy@openmoko.org>
*
* 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 <qi.h>
#include <string.h>
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;
}

39
qiboot/tools/Makefile Normal file
View File

@ -0,0 +1,39 @@
#(C) Copyright 2007 OpenMoko, Inc.
# Author: xiangfu liu <xiangfu@openmoko.org>
#
# 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}

314
qiboot/tools/mkudfu.c Normal file
View File

@ -0,0 +1,314 @@
/*
* USB DFU file trailer tool
* (C) Copyright by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*
* 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __WIN32__
#include <netinet/in.h> /* for host / network byte order conversions */
#endif
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__)
#include <inttypes.h>
#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);
}

View File

@ -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 */