LIBS += drivers/spi/libspi.a
ifeq ($(CPU),mpc83xx)
LIBS += drivers/qe/qe.a
+ LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.a
endif
ifeq ($(CPU),mpc85xx)
LIBS += drivers/qe/qe.a
LIBS += api/libapi.a
LIBS += post/libpost.a
+ ifeq ($(SOC),omap3)
+ LIBS += $(CPUDIR)/omap-common/libomap-common.a
+ endif
+ ifeq ($(SOC),omap4)
+ LIBS += $(CPUDIR)/omap-common/libomap-common.a
+ endif
+
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) $(TIMESTAMP_FILE) $(VERSION_FILE)
ONENAND_BIN ?= $(obj)onenand_ipl/onenand-ipl-2k.bin
endif
+ifeq ($(CONFIG_MMC_U_BOOT),y)
+MMC_IPL = mmc_ipl
+U_BOOT_MMC = $(obj)u-boot-mmc.bin
+MMC_BIN ?= $(obj)mmc_ipl/mmc-ipl-16k.bin
+endif
+
+ifeq ($(CONFIG_RECOVERY_U_BOOT),y)
+RECOVERY_BLOCK = recovery
+U_BOOT_RECOVERY = $(obj)u-boot-recovery.bin
+RECOVERY_BIN ?= $(obj)recovery/recovery.bin
+export RECOVERY_BLOCK
+endif
+
__OBJS := $(subst $(obj),,$(OBJS))
__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
#########################################################################
# Always append ALL so that arch config.mk's can add custom ones
-ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)
+ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) $(U_BOOT_MMC) $(U_BOOT_RECOVERY)
all: $(ALL)
$(U_BOOT_ONENAND): $(ONENAND_IPL) $(obj)u-boot.bin
cat $(ONENAND_BIN) $(obj)u-boot.bin > $(obj)u-boot-onenand.bin
+$(MMC_IPL): $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk
+ $(MAKE) -C mmc_ipl/board/$(BOARDDIR) all
+
+$(U_BOOT_MMC): $(MMC_IPL) $(obj)u-boot.bin
+ cat $(MMC_BIN) $(obj)u-boot.bin > $(obj)u-boot-mmc.bin
+
+$(RECOVERY_BLOCK): $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk $(ONENAND_IPL)
+ $(MAKE) -C recovery all
+
+$(U_BOOT_RECOVERY): $(RECOVERY_BLOCK) $(obj)u-boot.bin
+ cat $(RECOVERY_BIN) $(obj)u-boot.bin > $(obj)u-boot-recovery.bin
+
$(VERSION_FILE):
@( printf '#define U_BOOT_VERSION "U-Boot %s%s"\n' "$(U_BOOT_VERSION)" \
'$(shell $(TOPDIR)/tools/setlocalversion $(TOPDIR))' ) > $@.tmp
fi
@$(MKCONFIG) -n $@ -a nhk8815 arm arm926ejs nhk8815 st nomadik
+ex1_config : unconfig
+ @mkdir -p $(obj)include
+ @echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h
+ @$(MKCONFIG) $(@:_config=) arm arm926ejs ex1 samsung drime3
+ @echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk
+
xtract_omap1610xxx = $(subst _cs0boot,,$(subst _cs3boot,,$(subst _cs_autoboot,,$(subst _config,,$1))))
omap1610inn_config \
@board/armltd/versatile/split_by_variant.sh $@
#########################################################################
- ## ARM CORTEX Systems
++## ARMv7 Systems
+#########################################################################
+
+smdkc100_config: unconfig
+ @echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h
- @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 smdkc100 samsung s5pc1xx
++ @$(MKCONFIG) $(@:_config=) arm armv7 smdkc100 samsung s5pc1xx
+ @echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk
+ @echo "ONENAND_BIN = $(obj)onenand_ipl/onenand-ipl-16k.bin" >> $(obj)include/config.mk
+
+s5pc1xx_universal_mmc_config \
+s5pc1xx_universal_config: unconfig
+ @if [ "$(findstring mmc,$@)" ] ; then \
+ echo "#define CONFIG_MMC_U_BOOT" > $(obj)include/config.h ; \
+ else \
+ echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h ; \
+ fi;
- @$(MKCONFIG) -a s5pc1xx_universal arm arm_cortexa8 universal samsung s5pc1xx
++ @$(MKCONFIG) -a s5pc1xx_universal arm armv7 universal samsung s5pc1xx
+ @if [ "$(findstring mmc,$@)" ] ; then \
+ echo "CONFIG_MMC_U_BOOT = y" >> $(obj)include/config.mk ; \
+ else \
+ echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk ; \
+ echo "ONENAND_BIN = $(obj)onenand_ipl/onenand-ipl-16k.bin" >> $(obj)include/config.mk ; \
+ echo "CONFIG_RECOVERY_U_BOOT = y" >> $(obj)include/config.mk ; \
+ fi;
+
+s5pc1xx_p1p2_config: unconfig
+ @echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h
- @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 p1p2 samsung s5pc1xx
++ @$(MKCONFIG) $(@:_config=) arm armv7 p1p2 samsung s5pc1xx
+ @echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk
+ @echo "ONENAND_BIN = $(obj)onenand_ipl/onenand-ipl-16k.bin" >> $(obj)include/config.mk
+
+#########################################################################
## XScale Systems
#########################################################################
fi;
@$(MKCONFIG) -n $@ -a trizepsiv arm pxa trizepsiv
+ vpac270_nor_config \
+ vpac270_onenand_config : unconfig
+ @mkdir -p $(obj)include
+ @if [ "$(findstring onenand,$@)" ] ; then \
+ echo "#define CONFIG_ONENAND_U_BOOT" \
+ >>$(obj)include/config.h ; \
+ fi;
+ @$(MKCONFIG) -n $@ -a vpac270 arm pxa vpac270
+
#########################################################################
## ARM1136 Systems
#########################################################################
@$(MKCONFIG) smdk6400 arm arm1176 smdk6400 samsung s3c64xx
@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
+smdk6442_config: unconfig
+ @echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h
+ @$(MKCONFIG) $(@:_config=) arm arm1176 smdk6442 samsung s5p64xx
+ @echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk
+ @echo "ONENAND_BIN = $(obj)onenand_ipl/onenand-ipl-8k.bin" >> $(obj)include/config.mk
+
#========================================================================
# MIPS
#========================================================================
$(obj)board/netstar/{eeprom,crcek,crcit,*.srec,*.bin} \
$(obj)board/trab/trab_fkt $(obj)board/voiceblue/eeprom \
$(obj)board/armltd/{integratorap,integratorcp}/u-boot.lds \
- $(obj)arch/blackfin/lib/u-boot.lds \
$(obj)u-boot.lds \
$(obj)arch/blackfin/cpu/bootrom-asm-offsets.[chs]
@rm -f $(obj)include/bmp_logo.h
@rm -f $(obj)onenand_ipl/onenand-{ipl,ipl.bin,ipl.map}
@rm -f $(ONENAND_BIN)
@rm -f $(obj)onenand_ipl/u-boot.lds
+ @rm -f $(obj)mmc_ipl/mmc-{ipl,ipl.bin,ipl.map}
+ @rm -f $(MMC_BIN)
+ @rm -f $(obj)mmc_ipl/u-boot.lds
+ @rm -f $(obj)recovery/{recovery,recovery.map}
@rm -f $(TIMESTAMP_FILE) $(VERSION_FILE)
@find $(OBJTREE) -type f \
\( -name 'core' -o -name '*.bak' -o -name '*~' \
@rm -f $(obj)include/asm/proc $(obj)include/asm/arch $(obj)include/asm
@[ ! -d $(obj)nand_spl ] || find $(obj)nand_spl -name "*" -type l -print | xargs rm -f
@[ ! -d $(obj)onenand_ipl ] || find $(obj)onenand_ipl -name "*" -type l -print | xargs rm -f
+ @[ ! -d $(obj)mmc_ipl ] || find $(obj)mmc_ipl -name "*" -type l -print | xargs rm -f
+ @[ ! -d $(obj)recovery ] || find $(obj)recovery -name "*" -type l -print | xargs rm -f
+ @[ ! -d $(obj)api_examples ] || find $(obj)api_examples -name "*" -type l -print | xargs rm -f
ifeq ($(OBJTREE),$(SRCTREE))
mrproper \
#include <asm/arch/sys_proto.h>
#endif
-static void cache_flush(void);
+void cache_flush(void);
int cleanup_before_linux(void)
{
return 0;
}
-static void cache_flush(void)
+void cache_flush(void)
{
asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
}
SOBJS = cache.o
SOBJS += reset.o
-COBJS += clock.o
-COBJS += cpu_info.o
-COBJS += sromc.o
-COBJS += timer.o
+COBJS-y += clock.o
+COBJS-y += cpu_info.o
+COBJS-y += sromc.o
+COBJS-y += timer.o
+COBJS-$(CONFIG_CMD_SLEEP) += sleep.o
+COBJS-$(CONFIG_CMD_SLEEP) += sleep_asm.o
+COBJS-$(CONFIG_SOFT_I2C) += i2c-gpio.o
+COBJS-$(CONFIG_CMD_USBDOWN) += usb-hs-otg.o usb_downloader.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
-OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))
+OBJS := $(addprefix $(obj),$(COBJS-y) $(SOBJS))
all: $(obj).depend $(LIB)
/* Default is s5pc100 */
unsigned int s5pc1xx_cpu_id = 0xC100;
+/* Default is EVT1 */
+unsigned int s5pc1xx_cpu_rev = 1;
#ifdef CONFIG_ARCH_CPU_INIT
int arch_cpu_init(void)
{
s5pc1xx_cpu_id = readl(S5PC1XX_PRO_ID);
s5pc1xx_cpu_id = 0xC000 | ((s5pc1xx_cpu_id & 0x00FFF000) >> 12);
-
+#ifndef CONFIG_RECOVERY_BLOCK
s5pc1xx_clock_init();
-
+#endif
return 0;
}
#endif
#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
+#ifndef CONFIG_RECOVERY_BLOCK
char buf[32];
printf("CPU:\tS5P%X@%sMHz\n",
s5pc1xx_cpu_id, strmhz(buf, get_arm_clk()));
-
+#endif
return 0;
}
#endif
--- /dev/null
+/*
+ * Copyright (C) 2009 Samsung Electronics
+ * Minkyu Kang <mk7.kang@samsung.com>
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/gpio.h>
+#include <i2c-gpio.h>
+#include <i2c.h>
+
+static struct i2c_gpio_bus *i2c_gpio;
+
+void i2c_gpio_init(struct i2c_gpio_bus *bus, int len, int index)
+{
+ int i;
+ struct s5p_gpio_bank *bank;
+
+ i2c_gpio = bus;
+
+ /* init all i2c gpio buses */
+ for (i = 0; i < len; i++) {
+ bank = (struct s5p_gpio_bank *)i2c_gpio[i].bus->gpio_base;
+
+ if (!bank)
+ continue;
+
+ /* SDA */
+ gpio_direction_output(bank,
+ i2c_gpio[i].bus->sda_pin, 1);
+
+ /* SCL */
+ gpio_direction_output(bank,
+ i2c_gpio[i].bus->scl_pin, 1);
+ }
+
+ /* set default bus */
+ i2c_set_bus_num(index);
+}
+
+void i2c_gpio_set(int line, int value)
+{
+ struct s5p_gpio_bank *bank;
+ unsigned int bus_index;
+
+ bus_index = i2c_get_bus_num();
+
+ bank = (struct s5p_gpio_bank *)i2c_gpio[bus_index].bus->gpio_base;
+ if (!bank)
+ return;
+
+ if (line)
+ line = i2c_gpio[bus_index].bus->sda_pin;
+ else
+ line = i2c_gpio[bus_index].bus->scl_pin;
+
+ gpio_set_value(bank, line, value);
+}
+
+int i2c_gpio_get(void)
+{
+ struct s5p_gpio_bank *bank;
+ unsigned int bus_index;
+
+ bus_index = i2c_get_bus_num();
+
+ bank = (struct s5p_gpio_bank *)i2c_gpio[bus_index].bus->gpio_base;
+ if (!bank)
+ return 0;
+
+ return gpio_get_value(bank, i2c_gpio[bus_index].bus->sda_pin);
+}
+
+void i2c_gpio_dir(int dir)
+{
+ struct s5p_gpio_bank *bank;
+ unsigned int bus_index;
+
+ bus_index = i2c_get_bus_num();
+
+ bank = (struct s5p_gpio_bank *)i2c_gpio[bus_index].bus->gpio_base;
+ if (!bank)
+ return;
+
+ if (dir) {
+ gpio_direction_output(bank,
+ i2c_gpio[bus_index].bus->sda_pin, 0);
+ } else {
+ gpio_direction_input(bank,
+ i2c_gpio[bus_index].bus->sda_pin);
+ }
+}
--- /dev/null
+/*
+ * Sleep command for S5PC110
+ *
+ * Copyright (C) 2005-2008 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * 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 <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <serial.h>
+#include <stdio_dev.h>
+#include <onenand_uboot.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+#include "sleep.h"
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+struct stack {
+ u32 irq[3];
+ u32 abt[3];
+ u32 und[3];
+} ____cacheline_aligned;
+
+static struct stack stacks[1];
+
+enum {
+ SLEEP_WFI,
+ SLEEP_REGISTER,
+};
+
+static void __board_sleep_init(void) { }
+
+void board_sleep_init(void)
+ __attribute__((weak, alias("__board_sleep_init")));
+
+extern void board_sleep_init_late(void);
+
+struct regs_to_save {
+ unsigned int start_address;
+ unsigned int size;
+};
+
+static struct regs_to_save core_save[] = {
+ { .start_address = 0xE0100200, .size = 7 },
+ { .start_address = 0xE0100280, .size = 2 },
+ { .start_address = 0xE0100300, .size = 8 },
+ { .start_address = 0xE0100460, .size = 5 },
+ { .start_address = 0xE0100480, .size = 3 },
+ { .start_address = 0xE0100500, .size = 1 },
+ { .start_address = 0xE0107008, .size = 1 },
+ { .start_address = 0xE0103000, .size = 3 }, /* DCGIDC_MAP* */
+ { .start_address = 0xE0103020, .size = 2 }, /* DCGPREF_MAP* */
+ { .start_address = 0xE0103040, .size = 1 }, /* DVCIDX_MAP */
+ { .start_address = 0xE0103060, .size = 2 }, /* FREQ_CPU/DPM */
+ { .start_address = 0xE0103080, .size = 1 }, /* DVSEMCLK_EN */
+ { .start_address = 0xE0103084, .size = 1 }, /* MAXPERF */
+};
+
+static unsigned int buf_core_save[7 + 2 + 8 + 5 + 3 + 1 + 1 +
+ 3 + 2 + 1 + 2 + 1 + 1];
+
+static struct regs_to_save gpio_save[] = {
+ { .start_address = 0xE0200000, .size = 6 },
+ { .start_address = 0xE0200020, .size = 6 },
+ { .start_address = 0xE0200040, .size = 6 },
+ { .start_address = 0xE0200060, .size = 6 },
+ { .start_address = 0xE0200080, .size = 6 },
+ { .start_address = 0xE02000A0, .size = 6 },
+ { .start_address = 0xE02000C0, .size = 6 },
+ { .start_address = 0xE02000E0, .size = 6 },
+ { .start_address = 0xE0200100, .size = 6 },
+ { .start_address = 0xE0200120, .size = 6 },
+ { .start_address = 0xE0200140, .size = 6 },
+ { .start_address = 0xE0200160, .size = 6 },
+ { .start_address = 0xE0200180, .size = 6 },
+ { .start_address = 0xE02001A0, .size = 6 },
+ { .start_address = 0xE02001C0, .size = 6 },
+ { .start_address = 0xE02001E0, .size = 6 },
+ { .start_address = 0xE0200200, .size = 6 },
+ { .start_address = 0xE0200220, .size = 6 },
+ { .start_address = 0xE0200240, .size = 6 },
+ { .start_address = 0xE0200260, .size = 6 },
+ { .start_address = 0xE0200280, .size = 6 },
+ { .start_address = 0xE02002A0, .size = 6 },
+ { .start_address = 0xE02002C0, .size = 6 },
+ { .start_address = 0xE02002E0, .size = 6 },
+ { .start_address = 0xE0200300, .size = 6 },
+ { .start_address = 0xE0200320, .size = 6 },
+ { .start_address = 0xE0200340, .size = 6 },
+ { .start_address = 0xE0200360, .size = 6 },
+ { .start_address = 0xE0200380, .size = 6 },
+ { .start_address = 0xE02003A0, .size = 6 },
+ { .start_address = 0xE02003C0, .size = 6 },
+ { .start_address = 0xE02003E0, .size = 6 },
+ { .start_address = 0xE0200400, .size = 6 },
+ { .start_address = 0xE0200420, .size = 6 },
+ { .start_address = 0xE0200440, .size = 6 },
+ { .start_address = 0xE0200460, .size = 6 },
+ { .start_address = 0xE0200480, .size = 6 },
+ { .start_address = 0xE02004A0, .size = 6 },
+ { .start_address = 0xE02004C0, .size = 6 },
+ { .start_address = 0xE02004E0, .size = 6 },
+ { .start_address = 0xE0200500, .size = 6 },
+ { .start_address = 0xE0200520, .size = 6 },
+ { .start_address = 0xE0200540, .size = 6 },
+ { .start_address = 0xE0200560, .size = 6 },
+ { .start_address = 0xE0200580, .size = 6 },
+ { .start_address = 0xE02005A0, .size = 6 },
+ { .start_address = 0xE02005C0, .size = 6 },
+ { .start_address = 0xE02005E0, .size = 6 },
+ { .start_address = 0xE0200608, .size = 2 },
+ { .start_address = 0xE0200628, .size = 2 },
+ { .start_address = 0xE0200648, .size = 2 },
+ { .start_address = 0xE0200700, .size = 22 },
+ { .start_address = 0xE0200900, .size = 22 },
+ { .start_address = 0xE0200A00, .size = 22 },
+};
+
+static unsigned int buf_gpio_save[6 * 8 * 6 + 2 * 3 + 22 * 3];
+
+static struct regs_to_save irq_save[] = {
+ { .start_address = 0xF200000C, .size = 2 },
+ { .start_address = 0xF2000018, .size = 1 },
+ { .start_address = 0xF210000C, .size = 2 },
+ { .start_address = 0xF2100018, .size = 1 },
+ { .start_address = 0xF220000C, .size = 2 },
+ { .start_address = 0xF2200018, .size = 1 },
+ { .start_address = 0xF230000C, .size = 2 },
+ { .start_address = 0xF2300018, .size = 1 },
+};
+
+static unsigned int buf_irq_save[(2 + 1) * 4];
+
+static struct regs_to_save sromc_save[] = {
+ { .start_address = 0xE8000000, .size = 7 },
+};
+
+static unsigned int buf_sromc_save[7];
+
+static struct regs_to_save uart_save[] = {
+ { .start_address = 0xE2900000, .size = 4 },
+ { .start_address = 0xE2900028, .size = 2 },
+ { .start_address = 0xE2900038, .size = 1 },
+ { .start_address = 0xE2900400, .size = 4 },
+ { .start_address = 0xE2900428, .size = 2 },
+ { .start_address = 0xE2900438, .size = 1 },
+ { .start_address = 0xE2900800, .size = 4 },
+ { .start_address = 0xE2900828, .size = 2 },
+ { .start_address = 0xE2900838, .size = 1 },
+ { .start_address = 0xE2900C00, .size = 4 },
+ { .start_address = 0xE2900C28, .size = 2 },
+ { .start_address = 0xE2900C38, .size = 1 },
+};
+static unsigned int buf_uart_save[(4 + 2 + 1) * 4];
+
+static struct regs_to_save power_setting_save[] = {
+ { .start_address = S5PC110_OSC_CON, .size = 1}, /* OSC_CON */
+ { .start_address = S5PC110_PWR_CFG, .size = 5}, /* PWR_CFG ~ NORMAL_CFG */
+ { .start_address = S5PC110_IDLE_CFG, .size = 1},
+ { .start_address = S5PC110_STOP_CFG, .size = 2}, /* ~ STOP_MEM_CFG */
+ { .start_address = S5PC110_SLEEP_CFG, .size = 1},
+
+ { .start_address = S5PC110_OSC_FREQ, .size = 3}, /* ~ PWR_STABLE */
+ { .start_address = S5PC110_MTC_STABLE, .size = 2}, /* ~ CLAMP_STABLE */
+ { .start_address = S5PC110_OTHERS, .size = 1},
+ { .start_address = S5PC110_MIE_CONTROL, .size = 2}, /* ~ HDMI_CONTROL */
+ { .start_address = S5PC110_USB_PHY_CON, .size = 5}, /* ~ PS_HOLD_CONTROL */
+ { .start_address = S5PC110_INFORM0, .size = 8}, /* ~ INFORM7 */
+};
+static unsigned int buf_power_setting_save[1 + 5 + 1 + 2 + 1 +
+ 3 + 2 + 1 + 2 + 5 + 8];
+
+static struct regs_to_save clock_setting_save[] = {
+ { .start_address = S5PC110_APLL_LOCK, .size = 1},
+ { .start_address = S5PC110_MPLL_LOCK, .size = 1},
+ { .start_address = S5PC110_EPLL_LOCK, .size = 1},
+ { .start_address = S5PC110_VPLL_LOCK, .size = 1},
+ { .start_address = S5PC110_APLL_CON, .size = 1},
+ { .start_address = S5PC110_MPLL_CON, .size = 1},
+ { .start_address = S5PC110_EPLL_CON, .size = 1},
+ { .start_address = S5PC110_VPLL_CON, .size = 1},
+};
+static unsigned int buf_clock_setting_save[8];
+
+static unsigned int reg_others;
+
+void s5pc110_save_reg(struct regs_to_save *list,
+ unsigned int *buf, int length)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < list[i].size; j++) {
+ *buf = readl((unsigned int *)
+ (list[i].start_address+j * 4));
+ buf++;
+ }
+ }
+}
+
+void s5pc110_save_regs(void)
+{
+ reg_others = readl(S5PC110_OTHERS);
+ s5pc110_save_reg(gpio_save, buf_gpio_save, ARRAY_SIZE(gpio_save));
+ s5pc110_save_reg(irq_save, buf_irq_save, ARRAY_SIZE(irq_save));
+ s5pc110_save_reg(core_save, buf_core_save, ARRAY_SIZE(core_save));
+ s5pc110_save_reg(sromc_save, buf_sromc_save, ARRAY_SIZE(sromc_save));
+ s5pc110_save_reg(uart_save, buf_uart_save, ARRAY_SIZE(uart_save));
+
+ s5pc110_save_reg(power_setting_save, buf_power_setting_save,
+ ARRAY_SIZE(power_setting_save));
+ s5pc110_save_reg(clock_setting_save, buf_clock_setting_save,
+ ARRAY_SIZE(clock_setting_save));
+}
+
+void s5pc110_restore_reg(struct regs_to_save *list,
+ unsigned int *buf, int length)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < list[i].size; j++) {
+ writel(*buf, (unsigned int *)
+ (list[i].start_address+j * 4));
+
+ if (s5pc1xx_get_cpu_rev() == 0) {
+ unsigned int tmp;
+ tmp = readl((unsigned int *)
+ (list[i].start_address+j * 4));
+ }
+
+ buf++;
+ }
+ }
+
+}
+
+void s5pc110_restore_regs(void)
+{
+ s5pc110_restore_reg(uart_save, buf_uart_save, ARRAY_SIZE(uart_save));
+ s5pc110_restore_reg(sromc_save, buf_sromc_save, ARRAY_SIZE(sromc_save));
+ s5pc110_restore_reg(core_save, buf_core_save, ARRAY_SIZE(core_save));
+ s5pc110_restore_reg(irq_save, buf_irq_save, ARRAY_SIZE(irq_save));
+ s5pc110_restore_reg(gpio_save, buf_gpio_save, ARRAY_SIZE(gpio_save));
+
+ s5pc110_restore_reg(power_setting_save, buf_power_setting_save,
+ ARRAY_SIZE(power_setting_save));
+ s5pc110_restore_reg(clock_setting_save, buf_clock_setting_save,
+ ARRAY_SIZE(clock_setting_save));
+}
+
+void s5pc110_wakeup(void)
+{
+ struct mtd_info *mtd = &onenand_mtd;
+ struct onenand_chip *onenand_chip= mtd->priv;
+
+ struct stack *stk = &stacks[0];
+ __asm__ (
+ "msr cpsr_c, %1\n\t"
+ "add sp, %0, %2\n\t"
+ "msr cpsr_c, %3\n\t"
+ "add sp, %0, %4\n\t"
+ "msr cpsr_c, %5\n\t"
+ "add sp, %0, %6\n\t"
+ "msr cpsr_c, %7"
+ :
+ : "r" (stk),
+ "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+ "I" (offsetof(struct stack, irq[0])),
+ "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+ "I" (offsetof(struct stack, abt[0])),
+ "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+ "I" (offsetof(struct stack, und[0])),
+ "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+ : "r14");
+
+ s5pc110_restore_regs();
+
+ reg_others |= (1 << 31); /* GPIO */
+ reg_others |= (1 << 30); /* CF I/O */
+ reg_others |= (1 << 29); /* MMC */
+ reg_others |= (1 << 28); /* UART */
+ writel(reg_others, S5PC110_OTHERS);
+
+ printf("Wakeup Source: (0x%08x) ", readl(S5PC110_WAKEUP_STAT));
+ if (readl(S5PC110_WAKEUP_STAT) | 0x01) {
+ printf("/ Pending EINT: 0X %2.2X %2.2X %2.2X %2.2X",
+ readl(0xE0200F4C),
+ readl(0xE0200F48),
+ readl(0xE0200F44),
+ readl(0xE0200F40));
+ }
+ puts("\n");
+
+ timer_init();
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+ /* init_func_i2c */
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+#ifdef CONFIG_SERIAL_MULTI
+ serial_initialize();
+#endif
+ stdio_init_resume(); /* get the devices list going. */
+
+#if defined(CONFIG_CMD_ONENAND)
+ /* unlock all */
+ onenand_chip->unlock_all(mtd);
+#endif
+
+ return;
+}
+
+static int s5pc110_sleep(int mode)
+{
+ unsigned long regs_save[16];
+ unsigned int value;
+ int i;
+
+ puts("Entering s5pc110_sleep();\n");
+
+ board_sleep_init();
+
+ value = readl(S5PC110_WAKEUP_MASK);
+ value |= (1 << 15);
+ value |= (1 << 14);
+ value |= (1 << 13);
+ value |= (1 << 12);
+ value |= (1 << 11);
+ value |= (1 << 10);
+ value |= (1 << 9);
+ value |= (1 << 5);
+ value |= (1 << 4);
+ value |= (1 << 3);
+ value |= (1 << 2);
+ value |= (1 << 1);
+
+ value &= ~(1 << 2); /* RTC_TICK. To check temperature while charging */
+ value &= ~(1 << 1);
+
+ writel(value, S5PC110_WAKEUP_MASK);
+ printf("WAKEUP_MASK = 0x%8.8x (%8.8x)\n", value, readl(S5PC110_WAKEUP_MASK));
+
+ value = readl(S5PC110_EINT_WAKEUP_MASK);
+ value = 0xFFFFFFFF;
+ value &= ~(1 << 7); /* AP_PMIC_IRQ */
+ value &= ~(1 << 22); /* nPOWER */
+ /* value &= ~(1 << 23);*/ /* JACK_nINT */
+ value &= ~(1 << 24); /* KBR(0) */
+ value &= ~(1 << 25); /* KBR(1) */
+ /* value &= ~(1 << 28);*/ /* T-Flash */
+ writel(value, S5PC110_EINT_WAKEUP_MASK);
+ value = readl(S5PC110_EINT_WAKEUP_MASK);
+ for (i = 0; i < 4; i++)
+ value = readl(0xE0200F40 + i * 4);
+
+ s5pc110_save_regs();
+
+ board_sleep_init_late();
+
+ writel((unsigned long) s5pc110_cpu_resume, S5PC110_INFORM0);
+
+ value = readl(S5PC110_SLEEP_CFG);
+ value &= ~(1 << 0); /* OSC_EN off */
+ value &= ~(1 << 1); /* USBOSC_EN off */
+ writel(value, S5PC110_SLEEP_CFG);
+
+ value = readl(S5PC110_PWR_CFG);
+ value &= ~S5PC110_CFG_STANDBYWFI_MASK;
+ if (mode == SLEEP_WFI) {
+ if (s5pc1xx_get_cpu_rev() == 0) {
+ puts("ERRATA MODE\n");
+ value |= S5PC110_CFG_STANDBYWFI_IGNORE;
+ } else {
+ value |= S5PC110_CFG_STANDBYWFI_SLEEP;
+ }
+ } else {
+ value |= S5PC110_CFG_STANDBYWFI_IGNORE;
+ }
+
+ writel(value, S5PC110_PWR_CFG);
+
+ /* F2000000: VICIRQSTATUS-irq0 */
+ writel(0xffffffff, 0xF2000000 + 0x14); /* VIC_INT_ENABLE_CLEAR */
+ writel(0xffffffff, 0xF2100000 + 0x14);
+ writel(0xffffffff, 0xF2200000 + 0x14);
+ writel(0xffffffff, 0xF2300000 + 0x14);
+ writel(0xffffffff, 0xF2000000 + 0x1c); /* VIC_INT_SOFT_CLEAR */
+ writel(0xffffffff, 0xF2100000 + 0x1c);
+ writel(0xffffffff, 0xF2200000 + 0x1c);
+ writel(0xffffffff, 0xF2300000 + 0x1c);
+
+ /* Clear all EINT PENDING bit */
+ writel(0xff, 0xE0200000 + 0xF40);
+ value = readl(0xE0200000 + 0xF40);
+ writel(0xff, 0xE0200000 + 0xF44);
+ value = readl(0xE0200000 + 0xF44);
+ writel(0xff, 0xE0200000 + 0xF48);
+ value = readl(0xE0200000 + 0xF48);
+ writel(0xff, 0xE0200000 + 0xF4C);
+ value = readl(0xE0200000 + 0xF4C);
+
+ value = readl(S5PC110_WAKEUP_STAT);
+ writel(value, S5PC110_WAKEUP_STAT);
+
+
+ value = readl(S5PC110_OTHERS);
+ value |= S5PC110_OTHERS_SYSCON_INT_DISABLE;
+ writel(value, S5PC110_OTHERS);
+
+ s5pc110_sleep_save_phys = (unsigned int) regs_save;
+
+ value = readl(S5PC110_OTHERS);
+ value |= 1;
+ writel(value, S5PC110_OTHERS);
+
+ /* cache flush */
+ asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
+ l2_cache_disable();
+ invalidate_dcache(get_device_type());
+
+ if (s5pc110_cpu_save(regs_save) == 0) {
+ /* cache flush */
+ asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
+ l2_cache_disable();
+ invalidate_dcache(get_device_type());
+
+ if (mode == SLEEP_WFI) {
+ if (s5pc1xx_get_cpu_rev() == 0) {
+ puts("Warn: Entering SLEEP_WFI mode with"
+ "EVT0_ERRATA. \n");
+ puts("Warn: This sleep will probably fail\n");
+ }
+
+ value = readl(S5PC110_PWR_CFG);
+ value &= ~S5PC110_CFG_STANDBYWFI_MASK;
+ value |= S5PC110_CFG_STANDBYWFI_SLEEP;
+ writel(value, S5PC110_PWR_CFG);
+
+ asm ("b 1f\n\t"
+ ".align 5\n\t"
+ "1:\n\t"
+ "mcr p15, 0, %0, c7, c10, 5\n\t"
+ "mcr p15, 0, %0, c7, c10, 4\n\t"
+ ".word 0xe320f003" :: "r" (value));
+
+ } else { /* SLEEP_REGISTER */
+ value = (1 << 2);
+ writel(value, S5PC110_PWR_MODE);
+
+ while (1)
+ ;
+ }
+ }
+
+
+ s5pc110_wakeup();
+
+#if 0
+ writel(0, S5PC110_EINT_WAKEUP_MASK);
+ readl(S5PC110_EINT_WAKEUP_MASK);
+#endif
+
+ for (i = 0; i < 4; i++)
+ readl(0xE0200F40 + i * 4);
+
+ value = readl(S5PC110_WAKEUP_STAT);
+ writel(0xFFFF & value, S5PC110_WAKEUP_STAT);
+ readl(S5PC110_WAKEUP_STAT);
+
+ board_sleep_resume();
+ return value;
+}
+
+int do_sleep(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int mode = SLEEP_WFI;
+
+ if (argc >= 2) {
+ int arg = argv[1][0]-'0';
+
+ switch(arg) {
+ case 0:
+ break;
+ case 1:
+ mode = SLEEP_REGISTER;
+ break;
+ }
+ }
+
+ if (cpu_is_s5pc110())
+ return s5pc110_sleep(mode);
+
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD(
+ sleep, CONFIG_SYS_MAXARGS, 1, do_sleep,
+ "S5PC110 sleep",
+ "0 - Sleep with SLEEP_WFI mode\n"
+ "sleep 1 - Sleep with SLEEP_REGISTER mode\n"
+);
--- /dev/null
+/*
+ * Copied and modified from linux/arch/arm/plat-s5pc11x/pm.c
+ * Copyright (c) 2004,2009 Simtec Electronics
+ * boyko.lee <boyko.lee@samsung.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
+ *
+ * Parts based on arch/arm/mach-pxa/pm.c
+ *
+ * Thanks to Dimitry Andric for debugging
+*/
+
+#ifndef __S5PC110_SLEEP_H
+#define __S5PC110_SLEEP_H
+
+#include <common.h>
+#include <asm/ptrace.h>
+
+/*
+ * PSR bits
+ */
+/* #define USR26_MODE 0x00000000 */
+/* #define FIQ26_MODE 0x00000001 */
+/* #define IRQ26_MODE 0x00000002 */
+/* #define SVC26_MODE 0x00000003 */
+/* #define USR_MODE 0x00000010 */
+/* #define FIQ_MODE 0x00000011 */
+/* #define IRQ_MODE 0x00000012 */
+/* #define SVC_MODE 0x00000013 */
+/* #define ABT_MODE 0x00000017 */
+/* #define UND_MODE 0x0000001b */
+/* #define SYSTEM_MODE 0x0000001f */
+#define MODE32_BIT 0x00000010
+/* #define MODE_MASK 0x0000001f */
+#define PSR_T_BIT 0x00000020
+#define PSR_F_BIT 0x00000040
+#define PSR_I_BIT 0x00000080
+#define PSR_A_BIT 0x00000100
+#define PSR_J_BIT 0x01000000
+#define PSR_Q_BIT 0x08000000
+#define PSR_V_BIT 0x10000000
+#define PSR_C_BIT 0x20000000
+#define PSR_Z_BIT 0x40000000
+#define PSR_N_BIT 0x80000000
+
+#ifndef __ASSEMBLY__
+extern void board_sleep_resume(void);
+extern int s5pc110_cpu_save(unsigned long *saveblk);
+extern void s5pc110_cpu_resume(void);
+extern unsigned int s5pc110_sleep_return_addr;
+extern unsigned int s5pc110_sleep_save_phys;
+
+#endif
+
+#endif
--- /dev/null
+/* linux/arch/arm/plat-s3c64xx/sleep.S
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C6410 Power Manager (Suspend-To-RAM) support
+ *
+ * Based on PXA/SA1100 sleep code by:
+ * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
+ * Cliff Brake, (c) 2001
+ *
+ * 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 <asm/assembler.h>
+#include <asm/ptrace.h>
+#define ENTRY(name) \
+ .global name; \
+ .align 4,0x90; \
+name:
+
+#include "sleep.h"
+#define SWRESET_VALUE 0xE0102000
+
+/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
+ * reset the UART configuration, only enable if you really need this!
+*/
+ .text
+
+ /* s5pc110_cpu_save
+ *
+ * save enough of the CPU state to allow us to re-start
+ * pm.c code. as we store items like the sp/lr, we will
+ * end up returning from this function when the cpu resumes
+ * so the return value is set to mark this.
+ *
+ * This arangement means we avoid having to flush the cache
+ * from this code.
+ *
+ * entry:
+ * r0 = pointer to save block
+ *
+ * exit:
+ * r0 = 0 => we stored everything
+ * 1 => resumed from sleep
+ */
+
+ENTRY(s5pc110_cpu_save)
+
+ stmfd sp!, { r3 - r12, lr }
+
+ mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
+ mrc p15, 0, r5, c3, c0, 0 @ Domain ID
+ mrc p15, 0, r6, c2, c0, 0 @ Translation Table BASE0
+ mrc p15, 0, r7, c2, c0, 1 @ Translation Table BASE1
+ mrc p15, 0, r8, c2, c0, 2 @ Translation Table Control
+ mrc p15, 0, r9, c1, c0, 0 @ Control register
+ mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register
+ mrc p15, 0, r11, c1, c0, 2 @ Co-processor access controls
+ mrc p15, 0, r12, c10, c2, 0 @ Read PRRR
+ mrc p15, 0, r3, c10, c2, 1 @ READ NMRR
+
+ stmia r0, { r3 - r13 }
+
+ mov r0, #0
+ ldmfd sp, { r3 - r12, pc }
+
+ @@ return to the caller, after having the MMU
+ @@ turned on, this restores the last bits from the
+ @@ stack
+ .align 4
+resume_without_mmu:
+ mov r0, #1
+
+ ldmfd sp!, { r3 - r12, pc }
+
+ .ltorg
+
+ @@ the next bits sit in the .data segment, even though they
+ @@ happen to be code... the s5pc110_sleep_save_phys needs to be
+ @@ accessed by the resume code before it can restore the MMU.
+ @@ This means that the variable has to be close enough for the
+ @@ code to read it... since the .text segment needs to be RO,
+ @@ the data segment can be the only place to put this code.
+
+ .data
+
+
+
+ .global s5pc110_sleep_save_phys
+s5pc110_sleep_save_phys:
+ .word 0
+
+
+ /* sleep magic, to allow the bootloader to check for an valid
+ * image to resume to. Must be the first word before the
+ * s5pc110_cpu_resume entry.
+ */
+
+ .word 0x2bedf00d
+
+ /* s5pc110_cpu_resume
+ *
+ * resume code entry for bootloader to call
+ *
+ * we must put this code here in the data segment as we have no
+ * other way of restoring the stack pointer after sleep, and we
+ * must not write to the code segment (code is read-only)
+ */
+
+ENTRY(s5pc110_cpu_resume)
+ mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+ msr cpsr_c, r0
+
+ @@ load UART to allow us to print the two characters for
+ @@ resume debug
+
+ mov r1, #0
+ mcr p15, 0, r1, c8, c7, 0 @@ invalidate TLBs
+ mcr p15, 0, r1, c7, c5, 0 @@ invalidate I Cache
+
+ ldr r0, s5pc110_sleep_save_phys @ address of restore block
+ ldmia r0, { r3 - r13 }
+
+ mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
+ mcr p15, 0, r5, c3, c0, 0 @ Domain ID
+
+ mcr p15, 0, r8, c2, c0, 2 @ Translation Table Control
+ mcr p15, 0, r7, c2, c0, 1 @ Translation Table BASE1
+ mcr p15, 0, r6, c2, c0, 0 @ Translation Table BASE0
+
+ mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register
+
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0 @ Invalidate I & D TLB
+
+ mov r0, #0 @ restore copro access controls
+ mcr p15, 0, r11, c1, c0, 2 @ Co-processor access controls
+ mcr p15, 0, r0, c7, c5, 4
+
+ mcr p15, 0, r12, c10, c2, 0 @ write PRRR
+ mcr p15, 0, r3, c10, c2, 1 @ write NMRR
+
+ ldr r2, =resume_without_mmu
+ mov pc, r2
+
+ .ltorg
+
/* set prescaler : 16 */
/* set divider : 2 */
- writel((PRESCALER_1 & 0xff) << 8, &timer->tcfg0);
- writel((MUX_DIV_2 & 0xf) << MUX4_DIV_SHIFT, &timer->tcfg1);
+ val = readl(&timer->tcfg0);
+ val &= ~(0xff << 8);
+ val |= (PRESCALER_1 & 0xff) << 8;
+ writel(val, &timer->tcfg0);
+ val = readl(&timer->tcfg1);
+ val &= ~(0xf << MUX4_DIV_SHIFT);
+ val |= (MUX_DIV_2 & 0xF) << MUX4_DIV_SHIFT;
+ writel(val, &timer->tcfg1);
if (count_value == 0) {
/* reset initial value */
unsigned long get_timer(unsigned long base)
{
- return get_timer_masked() - base;
+ return (get_timer_masked()/2000 - base);
}
void set_timer(unsigned long t)
/* delay x useconds */
void __udelay(unsigned long usec)
{
- unsigned long tmo, tmp;
+ unsigned long tmo, tmp, now, until;
if (usec >= 1000) {
/*
}
/* get current timestamp */
- tmp = get_timer(0);
+ tmp = get_timer_masked();
/* if setting this fordward will roll time stamp */
/* reset "advancing" timestamp to 0, set lastdec value */
/* else, set advancing stamp wake up time */
- if ((tmo + tmp + 1) < tmp)
+ until = tmo + tmp + count_value;
+ if (until < tmp) {
reset_timer_masked();
+ tmp = get_timer_masked();
+ tmo += tmp;
+
+ }
else
tmo += tmp;
- /* loop till event */
- while (get_timer_masked() < tmo)
+ /* loop till event */ /* FIX: consider the overflow case */
+ while ((now = get_timer_masked()) < tmo && now >= tmp)
; /* nop */
}
--- /dev/null
+/*
+ * Copyright (C) 2009 Samsung Electronics
+ * Minkyu Kang <mk7.kang@samsung.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 <common.h>
+
+#include <command.h>
+#include <asm/errno.h>
+#include <asm/arch/power.h>
+#include "usb-hs-otg.h"
+
+u32 remode_wakeup;
+u16 config_value;
+
+int s5p_receive_done;
+int s5p_usb_connected;
+
+USB_OPMODE op_mode = USB_CPU;
+USB_SPEED speed = USB_HIGH;
+/*
+USB_OPMODE op_mode = USB_DMA;
+USB_SPEED speed = USB_FULL;
+*/
+
+otg_dev_t otg;
+get_status_t get_status;
+get_intf_t get_intf;
+
+enum EP_INDEX {
+ EP0, EP1, EP2, EP3, EP4
+};
+
+/*------------------------------------------------*/
+/* EP0 state */
+enum EP0_STATE {
+ EP0_STATE_INIT = 0,
+ EP0_STATE_GD_DEV_0 = 11,
+ EP0_STATE_GD_DEV_1 = 12,
+ EP0_STATE_GD_DEV_2 = 13,
+ EP0_STATE_GD_CFG_0 = 21,
+ EP0_STATE_GD_CFG_1 = 22,
+ EP0_STATE_GD_CFG_2 = 23,
+ EP0_STATE_GD_CFG_3 = 24,
+ EP0_STATE_GD_CFG_4 = 25,
+ EP0_STATE_GD_STR_I0 = 30,
+ EP0_STATE_GD_STR_I1 = 31,
+ EP0_STATE_GD_STR_I2 = 32,
+ EP0_STATE_GD_DEV_QUALIFIER = 33,
+ EP0_STATE_INTERFACE_GET = 34,
+ EP0_STATE_GET_STATUS0 = 35,
+ EP0_STATE_GET_STATUS1 = 36,
+ EP0_STATE_GET_STATUS2 = 37,
+ EP0_STATE_GET_STATUS3 = 38,
+ EP0_STATE_GET_STATUS4 = 39,
+ EP0_STATE_GD_OTHER_SPEED = 40,
+ EP0_STATE_GD_CFG_ONLY_0 = 41,
+ EP0_STATE_GD_CFG_ONLY_1 = 42,
+ EP0_STATE_GD_IF_ONLY_0 = 44,
+ EP0_STATE_GD_IF_ONLY_1 = 45,
+ EP0_STATE_GD_EP0_ONLY_0 = 46,
+ EP0_STATE_GD_EP1_ONLY_0 = 47,
+ EP0_STATE_GD_EP2_ONLY_0 = 48,
+ EP0_STATE_GD_EP3_ONLY_0 = 49,
+ EP0_STATE_GD_OTHER_SPEED_HIGH_1 = 51,
+ EP0_STATE_GD_OTHER_SPEED_HIGH_2 = 52,
+ EP0_STATE_GD_OTHER_SPEED_HIGH_3 = 53
+};
+
+/*definitions related to CSR setting */
+
+/* OTG_GOTGCTL*/
+#define B_SESSION_VALID (0x1 << 19)
+#define A_SESSION_VALID (0x1 << 18)
+
+/* OTG_GAHBCFG*/
+#define PTXFE_HALF (0<<8)
+#define PTXFE_ZERO (1<<8)
+#define NPTXFE_HALF (0<<7)
+#define NPTXFE_ZERO (1<<7)
+#define MODE_SLAVE (0<<5)
+#define MODE_DMA (1<<5)
+#define BURST_SINGLE (0<<1)
+#define BURST_INCR (1<<1)
+#define BURST_INCR4 (3<<1)
+#define BURST_INCR8 (5<<1)
+#define BURST_INCR16 (7<<1)
+#define GBL_INT_UNMASK (1<<0)
+#define GBL_INT_MASK (0<<0)
+
+/* OTG_GRSTCTL*/
+#define AHB_MASTER_IDLE (1u<<31)
+#define CORE_SOFT_RESET (0x1<<0)
+
+/* OTG_GINTSTS/OTG_GINTMSK core interrupt register */
+#define INT_RESUME (1u<<31)
+#define INT_DISCONN (0x1<<29)
+#define INT_CONN_ID_STS_CNG (0x1<<28)
+#define INT_OUT_EP (0x1<<19)
+#define INT_IN_EP (0x1<<18)
+#define INT_ENUMDONE (0x1<<13)
+#define INT_RESET (0x1<<12)
+#define INT_SUSPEND (0x1<<11)
+#define INT_TX_FIFO_EMPTY (0x1<<5)
+#define INT_RX_FIFO_NOT_EMPTY (0x1<<4)
+#define INT_SOF (0x1<<3)
+#define INT_DEV_MODE (0x0<<0)
+#define INT_HOST_MODE (0x1<<1)
+#define INT_OTG (0x1<<2)
+
+/* OTG_GRXSTSP STATUS*/
+#define GLOBAL_OUT_NAK (0x1<<17)
+#define OUT_PKT_RECEIVED (0x2<<17)
+#define OUT_TRNASFER_COMPLETED (0x3<<17)
+#define SETUP_TRANSACTION_COMPLETED (0x4<<17)
+#define SETUP_PKT_RECEIVED (0x6<<17)
+
+/* OTG_DCTL device control register */
+#define NORMAL_OPERATION (0x1<<0)
+#define SOFT_DISCONNECT (0x1<<1)
+#define TEST_J_MODE (TEST_J<<4)
+#define TEST_K_MODE (TEST_K<<4)
+#define TEST_SE0_NAK_MODE (TEST_SE0_NAK<<4)
+#define TEST_PACKET_MODE (TEST_PACKET<<4)
+#define TEST_FORCE_ENABLE_MODE (TEST_FORCE_ENABLE<<4)
+#define TEST_CONTROL_FIELD (0x7<<4)
+
+/* OTG_DAINT device all endpoint interrupt register */
+#define INT_IN_EP0 (0x1<<0)
+#define INT_IN_EP1 (0x1<<1)
+#define INT_IN_EP3 (0x1<<3)
+#define INT_OUT_EP0 (0x1<<16)
+#define INT_OUT_EP2 (0x1<<18)
+#define INT_OUT_EP4 (0x1<<20)
+
+/* OTG_DIEPCTL0/OTG_DOEPCTL0 */
+#define DEPCTL_EPENA (0x1<<31)
+#define DEPCTL_EPDIS (0x1<<30)
+#define DEPCTL_SNAK (0x1<<27)
+#define DEPCTL_CNAK (0x1<<26)
+#define DEPCTL_CTRL_TYPE (EP_TYPE_CONTROL<<18)
+#define DEPCTL_ISO_TYPE (EP_TYPE_ISOCHRONOUS<<18)
+#define DEPCTL_BULK_TYPE (EP_TYPE_BULK<<18)
+#define DEPCTL_INTR_TYPE (EP_TYPE_INTERRUPT<<18)
+#define DEPCTL_USBACTEP (0x1<<15)
+
+/*ep0 enable, clear nak, next ep0, max 64byte */
+#define EPEN_CNAK_EP0_64 (DEPCTL_EPENA|DEPCTL_CNAK|(CONTROL_EP<<11)|(0<<0))
+
+/*ep0 enable, clear nak, next ep0, 8byte */
+#define EPEN_CNAK_EP0_8 (DEPCTL_EPENA|DEPCTL_CNAK|(CONTROL_EP<<11)|(3<<0))
+
+/* DIEPCTLn/DOEPCTLn */
+#define BACK2BACK_SETUP_RECEIVED (0x1<<6)
+#define INTKN_TXFEMP (0x1<<4)
+#define NON_ISO_IN_EP_TIMEOUT (0x1<<3)
+#define CTRL_OUT_EP_SETUP_PHASE_DONE (0x1<<3)
+#define AHB_ERROR (0x1<<2)
+#define TRANSFER_DONE (0x1<<0)
+
+/* codes representing languages */
+const u8 string_desc0[] = {
+ 4, STRING_DESCRIPTOR, LANGID_US_L, LANGID_US_H,
+};
+
+#ifdef CONFIG_SAMSUNG_USB
+const u8 string_desc1[] = /* Manufacturer */
+{
+ (0x14 + 2), STRING_DESCRIPTOR,
+ 'S', 0x0, '/', 0x0, 'W', 0x0, ' ', 0x0, 'C', 0x0,
+ 'e', 0x0, 'n', 0x0, 't', 0x0, 'e', 0x0, 'r', 0x0,
+};
+#else
+const u8 string_desc1[] = /* Manufacturer */
+{
+ (0x14 + 2), STRING_DESCRIPTOR,
+ 'S', 0x0, 'y', 0x0, 's', 0x0, 't', 0x0, 'e', 0x0,
+ 'm', 0x0, ' ', 0x0, 'M', 0x0, 'C', 0x0, 'U', 0x0,
+};
+#endif
+
+#ifdef CONFIG_SAMSUNG_USB
+const u8 string_desc2[] = /* Product */
+{
+ (0x24 + 2), STRING_DESCRIPTOR,
+ 'S', 0x0, 'A', 0x0, 'M', 0x0, 'S', 0x0, 'U', 0x0,
+ 'N', 0x0, 'G', 0x0, ' ', 0x0, 'S', 0x0, 'L', 0x0,
+ 'P', 0x0, ' ', 0x0, 'D', 0x0, 'R', 0x0, 'I', 0x0,
+ 'V', 0x0, 'E', 0x0, 'R', 0x0
+};
+#else
+const u8 string_desc2[] = /* Product */
+{
+ (0x2a + 2), STRING_DESCRIPTOR,
+ 'S', 0x0, 'E', 0x0, 'C', 0x0, ' ', 0x0, 'S', 0x0,
+ '3', 0x0, 'C', 0x0, '6', 0x0, '4', 0x0, '0', 0x0,
+ '0', 0x0, 'X', 0x0, ' ', 0x0, 'T', 0x0, 'e', 0x0,
+ 's', 0x0, 't', 0x0, ' ', 0x0, 'B', 0x0, '/', 0x0,
+ 'D', 0x0
+};
+#endif
+
+/* setting the device qualifier descriptor and a string descriptor */
+const u8 qualifier_desc[] = {
+ 0x0a, /* 0 desc size */
+ 0x06, /* 1 desc type (DEVICE_QUALIFIER) */
+ 0x00, /* 2 USB release */
+ 0x02, /* 3 => 2.00 */
+ 0xFF, /* 4 class */
+ 0x00, /* 5 subclass */
+ 0x00, /* 6 protocol */
+ 64, /* 7 max pack size */
+ 0x01, /* 8 number of other-speed configuration */
+ 0x00, /* 9 reserved */
+};
+
+const u8 config_full[] = {
+ 0x09, /* 0 desc size */
+ 0x07, /* 1 desc type (other speed) */
+ 0x20, /* 2 Total length of data returned */
+ 0x00, /* 3 */
+ 0x01, /* 4 Number of interfaces */
+ 0x01, /* 5 value to use to select configuration */
+ 0x00, /* 6 index of string desc */
+ /* 7 same as configuration desc */
+ CONF_ATTR_DEFAULT | CONF_ATTR_SELFPOWERED,
+ 0x19, /* 8 same as configuration desc */
+
+};
+
+const u8 config_full_total[] = {
+ 0x09, 0x07, 0x20, 0x00, 0x01, 0x01, 0x00, 0xC0, 0x19,
+ 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00,
+ 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
+ 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00
+};
+
+const u8 config_high[] = {
+ 0x09, /* 0 desc size */
+ 0x07, /* 1 desc type (other speed) */
+ 0x20, /* 2 Total length of data returned */
+ 0x00, /* 3 */
+ 0x01, /* 4 Number of interfaces */
+ 0x01, /* 5 value to use to select configuration */
+ 0x00, /* 6 index of string desc */
+ /* 7 same as configuration desc */
+ CONF_ATTR_DEFAULT | CONF_ATTR_SELFPOWERED,
+ 0x19, /* 8 same as configuration desc */
+
+};
+
+const u8 config_high_total[] = {
+ 0x09, 0x07, 0x20, 0x00, 0x01, 0x01, 0x00, 0xC0, 0x19,
+ 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00,
+ 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00,
+ 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00
+};
+
+/* Descriptor size */
+enum DESCRIPTOR_SIZE {
+ DEVICE_DESC_SIZE = sizeof(device_desc_t),
+ STRING_DESC0_SIZE = sizeof(string_desc0),
+ STRING_DESC1_SIZE = sizeof(string_desc1),
+ STRING_DESC2_SIZE = sizeof(string_desc2),
+ CONFIG_DESC_SIZE = sizeof(config_desc_t),
+ INTERFACE_DESC_SIZE = sizeof(intf_desc_t),
+ ENDPOINT_DESC_SIZE = sizeof(ep_desc_t),
+ DEVICE_QUALIFIER_SIZE = sizeof(qualifier_desc),
+ OTHER_SPEED_CFG_SIZE = 9
+};
+
+/*32 <cfg desc>+<if desc>+<endp0 desc>+<endp1 desc>*/
+#define CONFIG_DESC_TOTAL_SIZE \
+ (CONFIG_DESC_SIZE+INTERFACE_DESC_SIZE+ENDPOINT_DESC_SIZE*2)
+
+static unsigned int phy_base;
+static unsigned int otg_base;
+
+static inline void s5p_usb_init_base(void)
+{
+ if (cpu_is_s5pc110()) {
+ phy_base = S5PC110_PHY_BASE;
+ otg_base = S5PC110_OTG_BASE;
+ } else {
+ phy_base = S5PC100_PHY_BASE;
+ otg_base = S5PC100_OTG_BASE;
+ }
+}
+
+static inline int s5pc1xx_phy_read_reg(int offset)
+{
+ return readl(phy_base + offset);
+}
+
+static inline void s5pc1xx_phy_write_reg(int value, int offset)
+{
+ writel(value, phy_base + offset);
+}
+
+static inline int s5pc1xx_otg_read_reg(int offset)
+{
+ return readl(otg_base + offset);
+}
+
+static inline void s5pc1xx_otg_write_reg(int value, int offset)
+{
+ writel(value, otg_base + offset);
+}
+
+static void s5p_usb_init_phy(void)
+{
+ if (cpu_is_s5pc110()) {
+ s5pc1xx_phy_write_reg(0xA0, OTG_PHYPWR);
+ s5pc1xx_phy_write_reg(0x3, OTG_PHYCTRL);
+ } else {
+ s5pc1xx_phy_write_reg(0x0, OTG_PHYPWR);
+#ifdef CONFIG_OTG_CLK_OSCC
+ s5pc1xx_phy_write_reg(0x22, OTG_PHYCTRL);
+#else
+ s5pc1xx_phy_write_reg(0x2, OTG_PHYCTRL);
+#endif
+ }
+
+ s5pc1xx_phy_write_reg(0x1, OTG_RSTCON);
+ udelay(20);
+ s5pc1xx_phy_write_reg(0x0, OTG_RSTCON);
+ udelay(20);
+}
+
+int s5p_usb_detect_irq(void)
+{
+ u32 status;
+ status = s5pc1xx_otg_read_reg(OTG_GINTSTS);
+ return (status & 0x800c3810);
+}
+
+void s5p_usb_clear_irq(void)
+{
+ s5pc1xx_otg_write_reg(0xffffffff, OTG_GINTSTS);
+}
+
+static void s5p_usb_core_soft_reset(void)
+{
+ u32 tmp;
+
+ s5pc1xx_otg_write_reg(CORE_SOFT_RESET, OTG_GRSTCTL);
+
+ do {
+ tmp = s5pc1xx_otg_read_reg(OTG_GRSTCTL);
+ } while (!(tmp & AHB_MASTER_IDLE));
+}
+
+static void s5p_usb_wait_cable_insert(void)
+{
+ u32 tmp;
+ int ucFirst = 1;
+
+ do {
+ udelay(50);
+
+ tmp = s5pc1xx_otg_read_reg(OTG_GOTGCTL);
+
+ if (tmp & (B_SESSION_VALID | A_SESSION_VALID)) {
+ break;
+ } else if (ucFirst == 1) {
+ puts("Insert a OTG cable into the connector!\n");
+ ucFirst = 0;
+ }
+ } while (1);
+}
+
+static void s5p_usb_init_core(void)
+{
+ s5pc1xx_otg_write_reg(PTXFE_HALF | NPTXFE_HALF | MODE_SLAVE |
+ BURST_SINGLE | GBL_INT_UNMASK, OTG_GAHBCFG);
+
+ s5pc1xx_otg_write_reg(
+ 0x0 << 15 /* PHY Low Power Clock sel */
+ | 0x1 << 14 /* Non-Periodic TxFIFO Rewind Enable */
+ | 0x5 << 10 /* Turnaround time */
+ | 0x0 << 9 /* 0:HNP disable, 1:HNP enable */
+ | 0x0 << 8 /* 0:SRP disable, 1:SRP enable */
+ | 0x0 << 7 /* ULPI DDR sel */
+ | 0x0 << 6 /* 0: high speed utmi+, 1: full speed serial */
+ | 0x0 << 4 /* 0: utmi+, 1:ulpi */
+ | 0x1 << 3 /* phy i/f 0:8bit, 1:16bit */
+ | 0x7 << 0, /* HS/FS Timeout* */
+ OTG_GUSBCFG);
+}
+
+static void s5p_usb_check_current_mode(u8 *pucMode)
+{
+ u32 tmp;
+
+ tmp = s5pc1xx_otg_read_reg(OTG_GINTSTS);
+ *pucMode = tmp & 0x1;
+}
+
+static void s5p_usb_soft_disconnect(int set)
+{
+ u32 tmp;
+
+ tmp = s5pc1xx_otg_read_reg(OTG_DCTL);
+ if (set)
+ tmp |= SOFT_DISCONNECT;
+ else
+ tmp &= ~SOFT_DISCONNECT;
+ s5pc1xx_otg_write_reg(tmp, OTG_DCTL);
+}
+
+static void s5p_usb_init_device(void)
+{
+ s5pc1xx_otg_write_reg(1 << 18 | otg.speed << 0, OTG_DCFG);
+
+ s5pc1xx_otg_write_reg(INT_RESUME | INT_OUT_EP | INT_IN_EP |
+ INT_ENUMDONE | INT_RESET | INT_SUSPEND |
+ INT_RX_FIFO_NOT_EMPTY, OTG_GINTMSK);
+}
+
+int s5p_usbctl_init(void)
+{
+ u8 ucMode;
+ u32 reg;
+
+ s5p_usb_init_base();
+
+ if (cpu_is_s5pc110()) {
+ reg = readl(S5PC110_USB_PHY_CON);
+ reg |= (1 << 0); /* USB PHY0 enable */
+ writel(reg, S5PC110_USB_PHY_CON);
+ } else {
+ reg = readl(S5PC100_OTHERS);
+ reg |= (1 << 16); /* unmask usb signal */
+ writel(reg, S5PC100_OTHERS);
+ }
+
+ otg.speed = speed;
+ otg.set_config = 0;
+ otg.ep0_state = EP0_STATE_INIT;
+ otg.ep0_substate = 0;
+
+ s5p_usb_init_phy();
+ s5p_usb_core_soft_reset();
+ s5p_usb_wait_cable_insert();
+ s5p_usb_init_core();
+ s5p_usb_check_current_mode(&ucMode);
+
+ if (ucMode == INT_DEV_MODE) {
+ s5p_usb_soft_disconnect(1);
+ udelay(10);
+ s5p_usb_soft_disconnect(0);
+ s5p_usb_init_device();
+ return 0;
+ } else {
+ puts("Error : Current Mode is Host\n");
+ return 0;
+ }
+}
+
+static void s5p_usb_set_inep_xfersize(EP_TYPE type, u32 pktcnt, u32 xfersize)
+{
+ if (type == EP_TYPE_CONTROL) {
+ s5pc1xx_otg_write_reg((pktcnt << 19) | (xfersize << 0),
+ OTG_DIEPTSIZ0);
+ } else if (type == EP_TYPE_BULK) {
+ s5pc1xx_otg_write_reg((1 << 29) | (pktcnt << 19) |
+ (xfersize << 0), OTG_DIEPTSIZ_IN);
+ }
+}
+
+static void s5p_usb_set_outep_xfersize(EP_TYPE type, u32 pktcnt, u32 xfersize)
+{
+ if (type == EP_TYPE_CONTROL) {
+ s5pc1xx_otg_write_reg((1 << 29) | (pktcnt << 19) |
+ (xfersize << 0), OTG_DOEPTSIZ0);
+ } else if (type == EP_TYPE_BULK) {
+ s5pc1xx_otg_write_reg((pktcnt << 19) | (xfersize << 0),
+ OTG_DOEPTSIZ_OUT);
+ }
+}
+
+/* works on both aligned and unaligned buffers */
+static void s5p_usb_write_ep0_fifo(u8 *buf, int num)
+{
+ int i;
+ u32 Wr_Data = 0;
+
+ for (i = 0; i < num; i += 4) {
+ Wr_Data = ((*(buf + 3)) << 24) |
+ ((*(buf + 2)) << 16) |
+ ((*(buf + 1)) << 8) |
+ *buf;
+ s5pc1xx_otg_write_reg(Wr_Data, OTG_EP0_FIFO);
+ buf += 4;
+ }
+}
+
+/* optimized fifo access routines, warning: only aligned buffers are supported */
+static inline void s5p_usb_write_in_fifo(u8 *buf, int num)
+{
+ u32 fifo = otg_base + OTG_IN_FIFO;
+ u32 *p = (u32 *)buf;
+ int i;
+
+ for (i = 0; i < num; i += 4)
+ writel(*p++, fifo);
+}
+
+static inline void s5p_usb_read_out_fifo(u8 *buf, int num)
+{
+ u32 fifo = otg_base + OTG_OUT_FIFO;
+ u32 *p = (u32 *)buf;
+ int i;
+
+ for (i = 0; i < num; i += 4)
+ *p++ = readl(fifo);
+}
+
+static void s5p_usb_get_desc(void)
+{
+ switch (otg.dev_req.wValue_H) {
+ case DEVICE_DESCRIPTOR:
+ otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
+ otg.dev_req.wLength_L);
+ otg.ep0_state = EP0_STATE_GD_DEV_0;
+ break;
+
+ case CONFIGURATION_DESCRIPTOR:
+ otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
+ otg.dev_req.wLength_L);
+
+ if (otg.req_length > CONFIG_DESC_SIZE)
+ otg.ep0_state = EP0_STATE_GD_CFG_0;
+ else
+ otg.ep0_state = EP0_STATE_GD_CFG_ONLY_0;
+ break;
+
+ case STRING_DESCRIPTOR:
+ switch (otg.dev_req.wValue_L) {
+ case 0:
+ otg.ep0_state = EP0_STATE_GD_STR_I0;
+ break;
+ case 1:
+ otg.ep0_state = EP0_STATE_GD_STR_I1;
+ break;
+ case 2:
+ otg.ep0_state = EP0_STATE_GD_STR_I2;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case ENDPOINT_DESCRIPTOR:
+ switch (otg.dev_req.wValue_L & 0xf) {
+ case 0:
+ otg.ep0_state = EP0_STATE_GD_EP0_ONLY_0;
+ break;
+ case 1:
+ otg.ep0_state = EP0_STATE_GD_EP1_ONLY_0;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case DEVICE_QUALIFIER:
+ otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
+ otg.dev_req.wLength_L);
+ otg.ep0_state = EP0_STATE_GD_DEV_QUALIFIER;
+ break;
+
+ case OTHER_SPEED_CONFIGURATION:
+ otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
+ otg.dev_req.wLength_L);
+ otg.ep0_state = EP0_STATE_GD_OTHER_SPEED;
+ break;
+ }
+}
+
+static void s5p_usb_clear_feature(void)
+{
+ switch (otg.dev_req.bmRequestType) {
+ case DEVICE_RECIPIENT:
+ if (otg.dev_req.wValue_L == 1)
+ remode_wakeup = 0;
+ break;
+
+ case ENDPOINT_RECIPIENT:
+ if (otg.dev_req.wValue_L == 0) {
+ if ((otg.dev_req.wIndex_L & 0x7f) == CONTROL_EP)
+ get_status.ep_ctrl = 0;
+
+ /* IN Endpoint */
+ if ((otg.dev_req.wIndex_L & 0x7f) == BULK_IN_EP)
+ get_status.ep_in = 0;
+
+ /* OUT Endpoint */
+ if ((otg.dev_req.wIndex_L & 0x7f) == BULK_OUT_EP)
+ get_status.ep_out = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+}
+
+static void s5p_usb_set_feature(void)
+{
+ switch (otg.dev_req.bmRequestType) {
+ case DEVICE_RECIPIENT:
+ if (otg.dev_req.wValue_L == 1)
+ remode_wakeup = 1;
+ break;
+
+ case ENDPOINT_RECIPIENT:
+ if (otg.dev_req.wValue_L == 0) {
+ if ((otg.dev_req.wIndex_L & 0x7f) == CONTROL_EP)
+ get_status.ep_ctrl = 1;
+
+ if ((otg.dev_req.wIndex_L & 0x7f) == BULK_IN_EP)
+ get_status.ep_in = 1;
+
+ if ((otg.dev_req.wIndex_L & 0x7f) == BULK_OUT_EP)
+ get_status.ep_out = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ otg.ep0_state = EP0_STATE_INIT;
+}
+
+static void s5p_usb_get_status(void)
+{
+ switch (otg.dev_req.bmRequestType) {
+ case (0x80): /*device */
+ get_status.Device = ((u8) remode_wakeup << 1) | 0x1;
+ otg.ep0_state = EP0_STATE_GET_STATUS0;
+ break;
+
+ case (0x81): /*interface */
+ get_status.Interface = 0;
+ otg.ep0_state = EP0_STATE_GET_STATUS1;
+ break;
+
+ case (0x82): /*endpoint */
+ if ((otg.dev_req.wIndex_L & 0x7f) == CONTROL_EP)
+ otg.ep0_state = EP0_STATE_GET_STATUS2;
+
+ if ((otg.dev_req.wIndex_L & 0x7f) == BULK_IN_EP)
+ otg.ep0_state = EP0_STATE_GET_STATUS3;
+
+ if ((otg.dev_req.wIndex_L & 0x7f) == BULK_OUT_EP)
+ otg.ep0_state = EP0_STATE_GET_STATUS4;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void s5p_usb_ep0_int_hndlr(void)
+{
+ u16 i;
+ u32 buf[2] = {0x0000, };
+ u16 addr;
+
+ if (otg.ep0_state == EP0_STATE_INIT) {
+ for (i = 0; i < 2; i++)
+ buf[i] = s5pc1xx_otg_read_reg(OTG_EP0_FIFO);
+
+ otg.dev_req.bmRequestType = buf[0];
+ otg.dev_req.bRequest = buf[0] >> 8;
+ otg.dev_req.wValue_L = buf[0] >> 16;
+ otg.dev_req.wValue_H = buf[0] >> 24;
+ otg.dev_req.wIndex_L = buf[1];
+ otg.dev_req.wIndex_H = buf[1] >> 8;
+ otg.dev_req.wLength_L = buf[1] >> 16;
+ otg.dev_req.wLength_H = buf[1] >> 24;
+
+ switch (otg.dev_req.bRequest) {
+ case STANDARD_SET_ADDRESS:
+ /* Set Address Update bit */
+ addr = (otg.dev_req.wValue_L);
+ s5pc1xx_otg_write_reg(1 << 18 | addr << 4 | otg.speed << 0,
+ OTG_DCFG);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case STANDARD_SET_DESCRIPTOR:
+ break;
+
+ case STANDARD_SET_CONFIGURATION:
+ /* Configuration value in configuration descriptor */
+ config_value = otg.dev_req.wValue_L;
+ otg.set_config = 1;
+ otg.ep0_state = EP0_STATE_INIT;
+
+ s5p_usb_connected = 1;
+ break;
+
+ case STANDARD_GET_CONFIGURATION:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+
+ /*ep0 enable, clear nak, next ep0, 8byte */
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5pc1xx_otg_write_reg(config_value, OTG_EP0_FIFO);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case STANDARD_GET_DESCRIPTOR:
+ s5p_usb_get_desc();
+ break;
+
+ case STANDARD_CLEAR_FEATURE:
+ s5p_usb_clear_feature();
+ break;
+
+ case STANDARD_SET_FEATURE:
+ s5p_usb_set_feature();
+ break;
+
+ case STANDARD_GET_STATUS:
+ s5p_usb_get_status();
+ break;
+
+ case STANDARD_GET_INTERFACE:
+ otg.ep0_state = EP0_STATE_INTERFACE_GET;
+ break;
+
+ case STANDARD_SET_INTERFACE:
+ get_intf.AlternateSetting = otg.dev_req.wValue_L;
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case STANDARD_SYNCH_FRAME:
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, otg.ctrl_max_pktsize);
+
+ /*clear nak, next ep0, 64byte */
+ s5pc1xx_otg_write_reg(((1 << 26) | (CONTROL_EP << 11) | (0 << 0)),
+ OTG_DIEPCTL0);
+}
+
+static void s5p_usb_set_otherspeed_conf_desc(u32 length)
+{
+ /* Standard device descriptor */
+ if (length == 9) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 9);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &config_full, 9);
+ } else if (length == 32) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 32);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &config_full_total, 32);
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+}
+
+static void s5p_usb_transfer_ep0(void)
+{
+ switch (otg.ep0_state) {
+ case EP0_STATE_INIT:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 0);
+
+ /*ep0 enable, clear nak, next ep0, 8byte */
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ break;
+
+ case EP0_STATE_GD_DEV_0:
+ /*ep0 enable, clear nak, next ep0, max 64byte */
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ if (otg.req_length < DEVICE_DESC_SIZE) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ otg.req_length);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.dev)),
+ otg.req_length);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ DEVICE_DESC_SIZE);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.dev)),
+ DEVICE_DESC_SIZE);
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_DEV_1:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ if (otg.req_length < (2 * FS_CTRL_PKT_SIZE)) {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.dev)) +
+ FS_CTRL_PKT_SIZE,
+ otg.req_length - FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ } else {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.dev)) +
+ FS_CTRL_PKT_SIZE, FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_GD_DEV_2;
+ }
+ break;
+
+ case EP0_STATE_GD_DEV_2:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ if (otg.req_length < DEVICE_DESC_SIZE) {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.dev)) +
+ (2 * FS_CTRL_PKT_SIZE),
+ otg.req_length - 2 * FS_CTRL_PKT_SIZE);
+ } else {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.dev)) +
+ (2 * FS_CTRL_PKT_SIZE),
+ DEVICE_DESC_SIZE - 2 * FS_CTRL_PKT_SIZE);
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_CFG_0:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ if (otg.req_length < CONFIG_DESC_TOTAL_SIZE) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ otg.req_length);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)),
+ otg.req_length);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ CONFIG_DESC_TOTAL_SIZE);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)),
+ CONFIG_DESC_TOTAL_SIZE);
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_CFG_1:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ if (otg.req_length < (2 * FS_CTRL_PKT_SIZE)) {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)) +
+ FS_CTRL_PKT_SIZE,
+ (otg.req_length - FS_CTRL_PKT_SIZE));
+ otg.ep0_state = EP0_STATE_INIT;
+ } else {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)) +
+ FS_CTRL_PKT_SIZE, FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_GD_CFG_2;
+ }
+ break;
+
+ case EP0_STATE_GD_CFG_2:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ if (otg.req_length < (3 * FS_CTRL_PKT_SIZE)) {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)) +
+ (2 * FS_CTRL_PKT_SIZE),
+ otg.req_length - 2 * FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ } else {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)) +
+ (2 * FS_CTRL_PKT_SIZE), FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_GD_CFG_3;
+ }
+ break;
+
+ case EP0_STATE_GD_CFG_3:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ if (otg.req_length < (4 * FS_CTRL_PKT_SIZE)) {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)) +
+ (3 * FS_CTRL_PKT_SIZE),
+ otg.req_length - 3 * FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ } else {
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)) +
+ (3 * FS_CTRL_PKT_SIZE), FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_GD_CFG_4;
+ }
+ break;
+
+ case EP0_STATE_GD_CFG_4:
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_DEV_QUALIFIER:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ if (otg.req_length < 10) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ otg.req_length);
+ s5p_usb_write_ep0_fifo((u8 *)qualifier_desc,
+ otg.req_length);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 10);
+ s5p_usb_write_ep0_fifo((u8 *)qualifier_desc, 10);
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_OTHER_SPEED:
+ s5p_usb_set_otherspeed_conf_desc(otg.req_length);
+ break;
+
+ case EP0_STATE_GD_OTHER_SPEED_HIGH_1:
+ if (otg.req_length == 9) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &config_high) + 8, 1);
+ otg.ep0_state = EP0_STATE_INIT;
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 8);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &config_high) + 8, 8);
+ otg.ep0_state = EP0_STATE_GD_OTHER_SPEED_HIGH_2;
+ }
+ break;
+
+ case EP0_STATE_GD_OTHER_SPEED_HIGH_2:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 8);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &config_high) + 16, 8);
+ otg.ep0_state = EP0_STATE_GD_OTHER_SPEED_HIGH_3;
+ break;
+
+ case EP0_STATE_GD_OTHER_SPEED_HIGH_3:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 8);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &config_high) + 24, 8);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_CFG_ONLY_0:
+ if (otg.req_length < CONFIG_DESC_SIZE) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ otg.req_length);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)),
+ otg.req_length);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ CONFIG_DESC_SIZE);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)),
+ CONFIG_DESC_SIZE);
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_CFG_ONLY_1:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.config)) +
+ FS_CTRL_PKT_SIZE,
+ CONFIG_DESC_SIZE - FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_IF_ONLY_0:
+ if (otg.req_length < INTERFACE_DESC_SIZE) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ otg.req_length);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.intf)),
+ otg.req_length);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1,
+ INTERFACE_DESC_SIZE);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.intf)),
+ INTERFACE_DESC_SIZE);
+ }
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_IF_ONLY_1:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.intf)) +
+ FS_CTRL_PKT_SIZE,
+ INTERFACE_DESC_SIZE - FS_CTRL_PKT_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_EP0_ONLY_0:
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, ENDPOINT_DESC_SIZE);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.ep1)),
+ ENDPOINT_DESC_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_EP1_ONLY_0:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, ENDPOINT_DESC_SIZE);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo(((u8 *) &(otg.desc.ep2)),
+ ENDPOINT_DESC_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_STR_I0:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, STRING_DESC0_SIZE);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *)string_desc0, STRING_DESC0_SIZE);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GD_STR_I1:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, sizeof(string_desc1));
+ if ((otg.ep0_substate * otg.ctrl_max_pktsize +
+ otg.ctrl_max_pktsize) < sizeof(string_desc1)) {
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+
+ s5p_usb_write_ep0_fifo((u8 *)string_desc1 +
+ (otg.ep0_substate * otg.ctrl_max_pktsize),
+ otg.ctrl_max_pktsize);
+ otg.ep0_state = EP0_STATE_GD_STR_I1;
+ otg.ep0_substate++;
+ } else {
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+
+ s5p_usb_write_ep0_fifo((u8 *)string_desc1 +
+ (otg.ep0_substate * otg.ctrl_max_pktsize),
+ sizeof(string_desc1) - (otg.ep0_substate *
+ otg.ctrl_max_pktsize));
+ otg.ep0_state = EP0_STATE_INIT;
+ otg.ep0_substate = 0;
+ }
+ break;
+
+ case EP0_STATE_GD_STR_I2:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, sizeof(string_desc2));
+ if ((otg.ep0_substate * otg.ctrl_max_pktsize +
+ otg.ctrl_max_pktsize) < sizeof(string_desc2)) {
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+
+ s5p_usb_write_ep0_fifo((u8 *) string_desc2 +
+ (otg.ep0_substate * otg.ctrl_max_pktsize),
+ otg.ctrl_max_pktsize);
+ otg.ep0_state = EP0_STATE_GD_STR_I2;
+ otg.ep0_substate++;
+ } else {
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_64, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) string_desc2 +
+ (otg.ep0_substate * otg.ctrl_max_pktsize),
+ sizeof(string_desc2) - (otg.ep0_substate *
+ otg.ctrl_max_pktsize));
+ otg.ep0_state = EP0_STATE_INIT;
+ otg.ep0_substate = 0;
+ }
+ break;
+
+ case EP0_STATE_INTERFACE_GET:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &get_intf, 1);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GET_STATUS0:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &get_status, 1);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GET_STATUS1:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &get_status + 1, 1);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GET_STATUS2:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &get_status + 2, 1);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GET_STATUS3:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &get_status + 3, 1);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ case EP0_STATE_GET_STATUS4:
+ s5p_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
+ s5pc1xx_otg_write_reg(EPEN_CNAK_EP0_8, OTG_DIEPCTL0);
+ s5p_usb_write_ep0_fifo((u8 *) &get_status + 4, 1);
+ otg.ep0_state = EP0_STATE_INIT;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void s5p_usb_tx(char *tx_data, int tx_size)
+{
+ otg.up_ptr = (u8 *) tx_data;
+ otg.up_addr = (u32) tx_data;
+ otg.up_size = tx_size;
+
+ if (otg.op_mode == USB_CPU) {
+ if (otg.up_size > otg.bulkin_max_pktsize) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_BULK, 1,
+ otg.bulkin_max_pktsize);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_BULK, 1, otg.up_size);
+ }
+
+ /*ep1 enable, clear nak, bulk, usb active, max pkt */
+ s5pc1xx_otg_write_reg(1u << 31 | 1 << 26 | 2 << 18 | 1 << 15 |
+ otg.bulkin_max_pktsize << 0, OTG_DIEPCTL_IN);
+
+ s5p_usb_write_in_fifo(otg.up_ptr, otg.up_size);
+ } else if ((otg.op_mode == USB_DMA) && (otg.up_size > 0)) {
+ u32 pktcnt, remainder;
+
+ s5pc1xx_otg_write_reg(MODE_DMA | BURST_INCR4 | GBL_INT_UNMASK,
+ OTG_GAHBCFG);
+ s5pc1xx_otg_write_reg(INT_RESUME | INT_OUT_EP | INT_IN_EP |
+ INT_ENUMDONE | INT_RESET | INT_SUSPEND,
+ OTG_GINTMSK);
+
+ s5pc1xx_otg_write_reg((u32) otg.up_ptr, OTG_DIEPDMA_IN);
+
+ pktcnt = (u32) (otg.up_size / otg.bulkin_max_pktsize);
+ remainder = (u32) (otg.up_size % otg.bulkin_max_pktsize);
+ if (remainder != 0)
+ pktcnt += 1;
+
+ if (pktcnt > 1023) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_BULK, 1023,
+ otg.bulkin_max_pktsize * 1023);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_BULK, pktcnt,
+ otg.up_size);
+ }
+
+ /*ep1 enable, clear nak, bulk, usb active, next ep1, max pkt */
+ s5pc1xx_otg_write_reg(1u << 31 | 1 << 26 | 2 << 18 | 1 << 15 |
+ BULK_IN_EP << 11 | otg.bulkin_max_pktsize << 0,
+ OTG_DIEPCTL_IN);
+ }
+}
+
+static void s5p_usb_int_bulkout(u32 fifo_cnt_byte)
+{
+ s5p_usb_read_out_fifo((u8 *)otg.dn_ptr, fifo_cnt_byte);
+ otg.dn_ptr += fifo_cnt_byte;
+
+ s5p_usb_set_outep_xfersize(EP_TYPE_BULK, 1,
+ otg.bulkout_max_pktsize);
+
+ /*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt */
+ s5pc1xx_otg_write_reg(1u << 31 | 1 << 26 | 2 << 18 | 1 << 15 |
+ otg.bulkout_max_pktsize << 0, OTG_DOEPCTL_OUT);
+
+ if (((u32)otg.dn_ptr - otg.dn_addr) >= (otg.dn_filesize))
+ s5p_receive_done = 1;
+}
+
+static void s5p_usb_dma_in_done(void)
+{
+ s32 remain_cnt;
+
+ otg.up_ptr = (u8 *)s5pc1xx_otg_read_reg(OTG_DIEPDMA_IN);
+ remain_cnt = otg.up_size - ((u32) otg.up_ptr - otg.up_addr);
+
+ if (remain_cnt > 0) {
+ u32 pktcnt, remainder;
+ pktcnt = (u32)(remain_cnt / otg.bulkin_max_pktsize);
+ remainder = (u32)(remain_cnt % otg.bulkin_max_pktsize);
+
+ if (remainder != 0)
+ pktcnt += 1;
+
+ if (pktcnt > 1023) {
+ s5p_usb_set_inep_xfersize(EP_TYPE_BULK, 1023,
+ otg.bulkin_max_pktsize * 1023);
+ } else {
+ s5p_usb_set_inep_xfersize(EP_TYPE_BULK, pktcnt,
+ remain_cnt);
+ }
+
+ /*ep1 enable, clear nak, bulk, usb active, next ep1, max pkt */
+ s5pc1xx_otg_write_reg(1u << 31 | 1 << 26 | 2 << 18 | 1 << 15 |
+ BULK_IN_EP << 11 | otg.bulkin_max_pktsize << 0,
+ OTG_DIEPCTL_IN);
+
+ s5p_receive_done = 1;
+ }
+}
+
+static void s5p_usb_dma_out_done(void)
+{
+ s32 remain_cnt;
+
+ otg.dn_ptr = (u8 *)s5pc1xx_otg_read_reg(OTG_DOEPDMA_OUT);
+
+ remain_cnt = otg.dn_filesize - ((u32) otg.dn_ptr - otg.dn_addr + 8);
+
+ if (remain_cnt > 0) {
+ u32 pktcnt, remainder;
+ pktcnt = (u32)(remain_cnt / otg.bulkout_max_pktsize);
+ remainder = (u32)(remain_cnt % otg.bulkout_max_pktsize);
+
+ if (remainder != 0)
+ pktcnt += 1;
+
+ if (pktcnt > 1023) {
+ s5p_usb_set_outep_xfersize(EP_TYPE_BULK, 1023,
+ otg.bulkout_max_pktsize * 1023);
+ } else {
+ s5p_usb_set_outep_xfersize(EP_TYPE_BULK, pktcnt,
+ remain_cnt);
+ }
+
+ /*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt 64 */
+ s5pc1xx_otg_write_reg(1u << 31 | 1 << 26 | 2 << 18 | 1 << 15 |
+ otg.bulkout_max_pktsize << 0, OTG_DOEPCTL_OUT);
+ } else {
+ udelay(500); /*for FPGA ??? */
+ }
+}
+
+static void s5p_usb_set_all_outep_nak(int set)
+{
+ u8 i;
+ u32 tmp;
+
+ for (i = 0; i < 16; i++) {
+ tmp = s5pc1xx_otg_read_reg(OTG_DOEPCTL0 + 0x20 * i);
+ if (set)
+ tmp |= DEPCTL_SNAK;
+ else
+ tmp |= (DEPCTL_EPENA | DEPCTL_CNAK);
+ s5pc1xx_otg_write_reg(tmp, OTG_DOEPCTL0 + 0x20 * i);
+ }
+}
+
+static void s5p_usb_set_max_pktsize(USB_SPEED speed)
+{
+ otg.speed = USB_HIGH;
+ otg.ctrl_max_pktsize = HS_CTRL_PKT_SIZE;
+ otg.bulkin_max_pktsize = HS_BULK_PKT_SIZE;
+ otg.bulkout_max_pktsize = HS_BULK_PKT_SIZE;
+}
+
+static void s5p_usb_set_endpoint(void)
+{
+ /* Unmask OTG_DAINT source */
+ s5pc1xx_otg_write_reg(0xff, OTG_DIEPINT0);
+ s5pc1xx_otg_write_reg(0xff, OTG_DOEPINT0);
+ s5pc1xx_otg_write_reg(0xff, OTG_DIEPINT_IN);
+ s5pc1xx_otg_write_reg(0xff, OTG_DOEPINT_OUT);
+
+ /* Init For Ep0 */
+ /*MPS:64bytes */
+ s5pc1xx_otg_write_reg(((1 << 26) | (CONTROL_EP << 11) | (0 << 0)),
+ OTG_DIEPCTL0);
+ /*ep0 enable, clear nak */
+ s5pc1xx_otg_write_reg((1u << 31) | (1 << 26) | (0 << 0),
+ OTG_DOEPCTL0);
+}
+
+static void s5p_usb_set_descriptors(void)
+{
+#if defined (CONFIG_SAMSUNG_USB)
+ otg.desc.dev.bLength = DEVICE_DESC_SIZE;
+ otg.desc.dev.bDescriptorType = DEVICE_DESCRIPTOR;
+ otg.desc.dev.bDeviceClass = 0xFF;
+ otg.desc.dev.bDeviceSubClass = 0x0;
+ otg.desc.dev.bDeviceProtocol = 0x0;
+ otg.desc.dev.bMaxPacketSize0 = otg.ctrl_max_pktsize;
+ otg.desc.dev.idVendorL = 0xE8;
+ otg.desc.dev.idVendorH = 0x04;
+ otg.desc.dev.idProductL = 0x04;
+ otg.desc.dev.idProductH = 0x12;
+ otg.desc.dev.iManufacturer = 0x0;
+ otg.desc.dev.iProduct = 0x2;
+ otg.desc.dev.iSerialNumber = 0x0;
+ otg.desc.dev.bNumConfigurations = 0x1;
+ otg.desc.dev.bcdUSBL = 0x00;
+ otg.desc.dev.bcdUSBH = 0x02;
+
+ otg.desc.config.bLength = CONFIG_DESC_SIZE;
+ otg.desc.config.bDescriptorType = CONFIGURATION_DESCRIPTOR;
+ otg.desc.config.wTotalLengthL = CONFIG_DESC_TOTAL_SIZE;
+ otg.desc.config.wTotalLengthH = 0;
+ otg.desc.config.bNumInterfaces = 1;
+ otg.desc.config.bConfigurationValue = 1;
+ otg.desc.config.iConfiguration = 0;
+ otg.desc.config.bmAttributes = CONF_ATTR_DEFAULT | CONF_ATTR_SELFPOWERED;
+ otg.desc.config.maxPower = 50;
+#else
+ otg.desc.dev.bLength = DEVICE_DESC_SIZE;
+ otg.desc.dev.bDescriptorType = DEVICE_DESCRIPTOR;
+ otg.desc.dev.bDeviceClass = 0xFF;
+ otg.desc.dev.bDeviceSubClass = 0x0;
+ otg.desc.dev.bDeviceProtocol = 0x0;
+ otg.desc.dev.bMaxPacketSize0 = otg.ctrl_max_pktsize;
+ otg.desc.dev.idVendorL = 0xE8;
+ otg.desc.dev.idVendorH = 0x04;
+ otg.desc.dev.idProductL = 0x34;
+ otg.desc.dev.idProductH = 0x12;
+ otg.desc.dev.bcdDeviceL = 0x00;
+ otg.desc.dev.bcdDeviceH = 0x01;
+ otg.desc.dev.iManufacturer = 0x1;
+ otg.desc.dev.iProduct = 0x2;
+ otg.desc.dev.iSerialNumber = 0x0;
+ otg.desc.dev.bNumConfigurations = 0x1;
+ otg.desc.dev.bcdUSBL = 0x00;
+ otg.desc.dev.bcdUSBH = 0x02;
+
+ otg.desc.config.bLength = CONFIG_DESC_SIZE;
+ otg.desc.config.bDescriptorType = CONFIGURATION_DESCRIPTOR;
+ otg.desc.config.wTotalLengthL = CONFIG_DESC_TOTAL_SIZE;
+ otg.desc.config.wTotalLengthH = 0;
+ otg.desc.config.bNumInterfaces = 1;
+ otg.desc.config.bConfigurationValue = 1;
+ otg.desc.config.iConfiguration = 0;
+ otg.desc.config.bmAttributes = CONF_ATTR_DEFAULT | CONF_ATTR_SELFPOWERED;
+ otg.desc.config.maxPower = 25;
+#endif
+ otg.desc.intf.bLength = INTERFACE_DESC_SIZE;
+ otg.desc.intf.bDescriptorType = INTERFACE_DESCRIPTOR;
+ otg.desc.intf.bInterfaceNumber = 0x0;
+ otg.desc.intf.bAlternateSetting = 0x0;
+ otg.desc.intf.bNumEndpoints = 2;
+ otg.desc.intf.bInterfaceClass = 0xff;
+ otg.desc.intf.bInterfaceSubClass = 0xff;
+ otg.desc.intf.bInterfaceProtocol = 0xff;
+ otg.desc.intf.iInterface = 0x0;
+
+ otg.desc.ep1.bLength = ENDPOINT_DESC_SIZE;
+ otg.desc.ep1.bDescriptorType = ENDPOINT_DESCRIPTOR;
+ otg.desc.ep1.bEndpointAddress = BULK_IN_EP | EP_ADDR_IN;
+ otg.desc.ep1.bmAttributes = EP_ATTR_BULK;
+ otg.desc.ep1.wMaxPacketSizeL = (u8)otg.bulkin_max_pktsize;
+ otg.desc.ep1.wMaxPacketSizeH = (u8)(otg.bulkin_max_pktsize >> 8);
+ otg.desc.ep1.bInterval = 0x0;
+
+ otg.desc.ep2.bLength = ENDPOINT_DESC_SIZE;
+ otg.desc.ep2.bDescriptorType = ENDPOINT_DESCRIPTOR;
+ otg.desc.ep2.bEndpointAddress = BULK_OUT_EP | EP_ADDR_OUT;
+ otg.desc.ep2.bmAttributes = EP_ATTR_BULK;
+ otg.desc.ep2.wMaxPacketSizeL = (u8)otg.bulkout_max_pktsize;
+ otg.desc.ep2.wMaxPacketSizeH = (u8)(otg.bulkout_max_pktsize >> 8);
+ otg.desc.ep2.bInterval = 0x0;
+}
+
+static void s5p_usb_set_opmode(USB_OPMODE mode)
+{
+ otg.op_mode = mode;
+
+ s5pc1xx_otg_write_reg(INT_RESUME | INT_OUT_EP | INT_IN_EP | INT_ENUMDONE |
+ INT_RESET | INT_SUSPEND | INT_RX_FIFO_NOT_EMPTY,
+ OTG_GINTMSK);
+
+ s5pc1xx_otg_write_reg(MODE_SLAVE | BURST_SINGLE | GBL_INT_UNMASK,
+ OTG_GAHBCFG);
+
+ s5p_usb_set_outep_xfersize(EP_TYPE_BULK, 1, otg.bulkout_max_pktsize);
+ s5p_usb_set_inep_xfersize(EP_TYPE_BULK, 1, 0);
+
+ /*bulk out ep enable, clear nak, bulk, usb active, next ep3, max pkt */
+ s5pc1xx_otg_write_reg(1u << 31 | 1 << 26 | 2 << 18 | 1 << 15 |
+ otg.bulkout_max_pktsize << 0, OTG_DOEPCTL_OUT);
+
+ /*bulk in ep enable, clear nak, bulk, usb active, next ep1, max pkt */
+ s5pc1xx_otg_write_reg(0u << 31 | 1 << 26 | 2 << 18 | 1 << 15 |
+ otg.bulkin_max_pktsize << 0, OTG_DIEPCTL_IN);
+}
+
+static void s5p_usb_reset(void)
+{
+ s5p_usb_set_all_outep_nak(1);
+
+ otg.ep0_state = EP0_STATE_INIT;
+ s5pc1xx_otg_write_reg(((1 << BULK_OUT_EP) | (1 << CONTROL_EP)) << 16 |
+ ((1 << BULK_IN_EP) | (1 << CONTROL_EP)), OTG_DAINTMSK);
+ s5pc1xx_otg_write_reg(CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR |
+ TRANSFER_DONE, OTG_DOEPMSK);
+ s5pc1xx_otg_write_reg(INTKN_TXFEMP | NON_ISO_IN_EP_TIMEOUT | AHB_ERROR |
+ TRANSFER_DONE, OTG_DIEPMSK);
+
+ /* Rx FIFO Size */
+ s5pc1xx_otg_write_reg(RX_FIFO_SIZE, OTG_GRXFSIZ);
+
+ /* Non Periodic Tx FIFO Size */
+ s5pc1xx_otg_write_reg(NPTX_FIFO_SIZE << 16 | NPTX_FIFO_START_ADDR << 0,
+ OTG_GNPTXFSIZ);
+
+ s5p_usb_set_all_outep_nak(0);
+
+ /*clear device address */
+ s5pc1xx_otg_write_reg(s5pc1xx_otg_read_reg(OTG_DCFG) & ~(0x7f << 4),
+ OTG_DCFG);
+}
+
+static int s5p_usb_set_init(void)
+{
+ u32 status;
+
+ status = s5pc1xx_otg_read_reg(OTG_DSTS);
+
+ /* Set if Device is High speed or Full speed */
+ if (((status & 0x6) >> 1) == USB_HIGH) {
+ s5p_usb_set_max_pktsize(USB_HIGH);
+ } else if (((status & 0x6) >> 1) == USB_FULL) {
+ puts("Error: Don't support Full_Speed\n");
+ return 0;
+ } else {
+ puts("Error: Neither High_Speed nor Full_Speed\n");
+ return 0;
+ }
+
+ s5p_usb_set_endpoint();
+ s5p_usb_set_descriptors();
+ s5p_usb_set_opmode(op_mode);
+
+ return 1;
+}
+
+static void s5p_usb_pkt_receive(void)
+{
+ u32 rx_status;
+ u32 fifo_cnt_byte;
+
+ rx_status = s5pc1xx_otg_read_reg(OTG_GRXSTSP);
+
+ if ((rx_status & (0xf << 17)) == SETUP_PKT_RECEIVED) {
+ s5p_usb_ep0_int_hndlr();
+ } else if ((rx_status & (0xf << 17)) == OUT_PKT_RECEIVED) {
+ fifo_cnt_byte = (rx_status & 0x7ff0) >> 4;
+
+ if ((rx_status & BULK_OUT_EP) && (fifo_cnt_byte)) {
+ s5p_usb_int_bulkout(fifo_cnt_byte);
+ if (otg.op_mode == USB_CPU) {
+ s5pc1xx_otg_write_reg(INT_RESUME | INT_OUT_EP |
+ INT_IN_EP | INT_ENUMDONE | INT_RESET |
+ INT_SUSPEND | INT_RX_FIFO_NOT_EMPTY,
+ OTG_GINTMSK);
+ }
+ return;
+ }
+
+ }
+}
+
+static void s5p_usb_transfer(void)
+{
+ u32 ep_int;
+ u32 check_dma;
+ u32 ep_int_status;
+
+ ep_int = s5pc1xx_otg_read_reg(OTG_DAINT);
+
+ if (ep_int & (1 << CONTROL_EP)) {
+ ep_int_status = s5pc1xx_otg_read_reg(OTG_DIEPINT0);
+
+ if (ep_int_status & INTKN_TXFEMP) {
+ u32 uNTxFifoSpace;
+ do {
+ uNTxFifoSpace = s5pc1xx_otg_read_reg(OTG_GNPTXSTS)
+ & 0xffff;
+ } while (uNTxFifoSpace < otg.ctrl_max_pktsize);
+
+ s5p_usb_transfer_ep0();
+ }
+
+ s5pc1xx_otg_write_reg(ep_int_status, OTG_DIEPINT0);
+ }
+
+ if (ep_int & ((1 << CONTROL_EP) << 16)) {
+ ep_int_status = s5pc1xx_otg_read_reg(OTG_DOEPINT0);
+
+ s5p_usb_set_outep_xfersize(EP_TYPE_CONTROL, 1, 8);
+ s5pc1xx_otg_write_reg(1u << 31 | 1 << 26, OTG_DOEPCTL0);
+
+ s5pc1xx_otg_write_reg(ep_int_status, OTG_DOEPINT0);
+ }
+
+ if (ep_int & (1 << BULK_IN_EP)) {
+ ep_int_status = s5pc1xx_otg_read_reg(OTG_DIEPINT_IN);
+
+ s5pc1xx_otg_write_reg(ep_int_status, OTG_DIEPINT_IN);
+ check_dma = s5pc1xx_otg_read_reg(OTG_GAHBCFG);
+
+ if ((check_dma & MODE_DMA) && (ep_int_status & TRANSFER_DONE))
+ s5p_usb_dma_in_done();
+ }
+
+ if (ep_int & ((1 << BULK_OUT_EP) << 16)) {
+ ep_int_status = s5pc1xx_otg_read_reg(OTG_DOEPINT_OUT);
+
+ s5pc1xx_otg_write_reg(ep_int_status, OTG_DOEPINT_OUT);
+ check_dma = s5pc1xx_otg_read_reg(OTG_GAHBCFG);
+
+ if ((check_dma & MODE_DMA) && (ep_int_status & TRANSFER_DONE))
+ s5p_usb_dma_out_done();
+ }
+}
+
+void s5p_udc_int_hndlr(void)
+{
+ u32 int_status;
+ int tmp;
+
+ int_status = s5pc1xx_otg_read_reg(OTG_GINTSTS);
+ s5pc1xx_otg_write_reg(int_status, OTG_GINTSTS);
+
+ if (int_status & INT_RESET) {
+ s5pc1xx_otg_write_reg(INT_RESET, OTG_GINTSTS);
+ s5p_usb_reset();
+ }
+
+ if (int_status & INT_ENUMDONE) {
+ s5pc1xx_otg_write_reg(INT_ENUMDONE, OTG_GINTSTS);
+
+ tmp = s5p_usb_set_init();
+ if (tmp == 0)
+ return;
+ }
+
+ if (int_status & INT_RESUME)
+ s5pc1xx_otg_write_reg(INT_RESUME, OTG_GINTSTS);
+
+ if (int_status & INT_SUSPEND)
+ s5pc1xx_otg_write_reg(INT_SUSPEND, OTG_GINTSTS);
+
+ if (int_status & INT_RX_FIFO_NOT_EMPTY) {
+ s5pc1xx_otg_write_reg(INT_RESUME | INT_OUT_EP | INT_IN_EP |
+ INT_ENUMDONE | INT_RESET | INT_SUSPEND,
+ OTG_GINTMSK);
+
+ s5p_usb_pkt_receive();
+
+ s5pc1xx_otg_write_reg(INT_RESUME | INT_OUT_EP | INT_IN_EP |
+ INT_ENUMDONE | INT_RESET | INT_SUSPEND |
+ INT_RX_FIFO_NOT_EMPTY, OTG_GINTMSK);
+ }
+
+ if ((int_status & INT_IN_EP) || (int_status & INT_OUT_EP))
+ s5p_usb_transfer();
+}
--- /dev/null
+/*
+ * (C) Copyright 2007
+ * Byungjae Lee, Samsung Erectronics, bjlee@samsung.com.
+ * - only support for S3C6400
+ *
+ * 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 __USBD_HS_OTG_H__
+#define __USBD_HS_OTG_H__
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/arch/usb-hs-otg.h>
+
+#define make_word_c(w) __constant_cpu_to_le16(w)
+#define make_word(w) __cpu_to_le16(w)
+
+#define CONTROL_EP 0
+#define BULK_IN_EP 1
+#define BULK_OUT_EP 2
+#define INTR_IN_EP 3
+
+#define FS_CTRL_PKT_SIZE 8
+#define FS_BULK_PKT_SIZE 64
+
+#define HS_CTRL_PKT_SIZE 64
+#define HS_BULK_PKT_SIZE 512
+
+#define RX_FIFO_SIZE 512
+#define NPTX_FIFO_START_ADDR RX_FIFO_SIZE
+#define NPTX_FIFO_SIZE 512
+#define PTX_FIFO_SIZE 512
+
+/* string descriptor */
+#define LANGID_US_L (0x09)
+#define LANGID_US_H (0x04)
+
+/* Feature Selectors */
+#define EP_STALL 0
+#define DEVICE_REMOTE_WAKEUP 1
+#define TEST_MODE 2
+
+/* Test Mode Selector*/
+#define TEST_J 1
+#define TEST_K 2
+#define TEST_SE0_NAK 3
+#define TEST_PACKET 4
+#define TEST_FORCE_ENABLE 5
+
+#define OTG_DIEPCTL_IN (OTG_DIEPCTL0 + 0x20 * BULK_IN_EP)
+#define OTG_DIEPINT_IN (OTG_DIEPINT0 + 0x20 * BULK_IN_EP)
+#define OTG_DIEPTSIZ_IN (OTG_DIEPTSIZ0 + 0x20 * BULK_IN_EP)
+#define OTG_DIEPDMA_IN (OTG_DIEPDMA0 + 0x20 * BULK_IN_EP)
+#define OTG_DOEPCTL_OUT (OTG_DOEPCTL0 + 0x20 * BULK_OUT_EP)
+#define OTG_DOEPINT_OUT (OTG_DOEPINT0 + 0x20 * BULK_OUT_EP)
+#define OTG_DOEPTSIZ_OUT (OTG_DOEPTSIZ0 + 0x20 * BULK_OUT_EP)
+#define OTG_DOEPDMA_OUT (OTG_DOEPDMA0 + 0x20 * BULK_OUT_EP)
+#define OTG_IN_FIFO (OTG_EP0_FIFO + 0x1000 * BULK_IN_EP)
+#define OTG_OUT_FIFO (OTG_EP0_FIFO + 0x1000 * BULK_OUT_EP)
+
+typedef struct {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bcdUSBL;
+ u8 bcdUSBH;
+ u8 bDeviceClass;
+ u8 bDeviceSubClass;
+ u8 bDeviceProtocol;
+ u8 bMaxPacketSize0;
+ u8 idVendorL;
+ u8 idVendorH;
+ u8 idProductL;
+ u8 idProductH;
+ u8 bcdDeviceL;
+ u8 bcdDeviceH;
+ u8 iManufacturer;
+ u8 iProduct;
+ u8 iSerialNumber;
+ u8 bNumConfigurations;
+} __attribute__ ((packed)) device_desc_t;
+
+typedef struct {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 wTotalLengthL;
+ u8 wTotalLengthH;
+ u8 bNumInterfaces;
+ u8 bConfigurationValue;
+ u8 iConfiguration;
+ u8 bmAttributes;
+ u8 maxPower;
+} __attribute__ ((packed)) config_desc_t;
+
+typedef struct {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bInterfaceNumber;
+ u8 bAlternateSetting;
+ u8 bNumEndpoints;
+ u8 bInterfaceClass;
+ u8 bInterfaceSubClass;
+ u8 bInterfaceProtocol;
+ u8 iInterface;
+} __attribute__ ((packed)) intf_desc_t;
+
+typedef struct {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+ u8 wMaxPacketSizeL;
+ u8 wMaxPacketSizeH;
+ u8 bInterval;
+} __attribute__ ((packed)) ep_desc_t;
+
+typedef struct {
+ u8 bLength;
+ u8 bDescriptorType;
+ u16 bString[30];
+} __attribute__ ((packed)) string_desc_t;
+
+typedef struct {
+ u8 bmRequestType;
+ u8 bRequest;
+ u8 wValue_L;
+ u8 wValue_H;
+ u8 wIndex_L;
+ u8 wIndex_H;
+ u8 wLength_L;
+ u8 wLength_H;
+} __attribute__ ((packed)) device_req_t;
+
+typedef struct {
+ device_desc_t dev;
+ config_desc_t config;
+ intf_desc_t intf;
+ ep_desc_t ep1;
+ ep_desc_t ep2;
+ ep_desc_t ep3;
+ ep_desc_t ep4;
+} __attribute__ ((packed)) descriptors_t;
+
+typedef struct {
+ u8 Device;
+ u8 Interface;
+ u8 ep_ctrl;
+ u8 ep_in;
+ u8 ep_out;
+} __attribute__ ((packed)) get_status_t;
+
+typedef struct {
+ u8 AlternateSetting;
+} __attribute__ ((packed)) get_intf_t;
+
+typedef enum {
+ USB_CPU, USB_DMA
+} USB_OPMODE;
+
+typedef enum {
+ USB_HIGH, USB_FULL, USB_LOW
+} USB_SPEED;
+
+typedef enum {
+ EP_TYPE_CONTROL, EP_TYPE_ISOCHRONOUS, EP_TYPE_BULK, EP_TYPE_INTERRUPT
+} EP_TYPE;
+
+typedef struct {
+ descriptors_t desc;
+ device_req_t dev_req;
+
+ u32 ep0_state;
+ u32 ep0_substate;
+ USB_OPMODE op_mode;
+ USB_SPEED speed;
+ u32 ctrl_max_pktsize;
+ u32 bulkin_max_pktsize;
+ u32 bulkout_max_pktsize;
+ u32 dn_addr;
+ u32 dn_filesize;
+ u32 up_addr;
+ u32 up_size;
+ u8 *dn_ptr;
+ u8 *up_ptr;
+ u32 set_config;
+ u32 req_length;
+} __attribute__ ((packed)) otg_dev_t;
+
+enum DEV_REQUEST_DIRECTION {
+ HOST_TO_DEVICE = 0x00,
+ DEVICE_TO_HOST = 0x80
+};
+
+enum DEV_REQUEST_TYPE {
+ STANDARD_TYPE = 0x00,
+ CLASS_TYPE = 0x20,
+ VENDOR_TYPE = 0x40,
+ RESERVED_TYPE = 0x60
+};
+
+enum DEV_REQUEST_RECIPIENT {
+ DEVICE_RECIPIENT = 0,
+ INTERFACE_RECIPIENT = 1,
+ ENDPOINT_RECIPIENT = 2,
+ OTHER_RECIPIENT = 3
+};
+
+enum DESCRIPTOR_TYPE {
+ DEVICE_DESCRIPTOR = 1,
+ CONFIGURATION_DESCRIPTOR = 2,
+ STRING_DESCRIPTOR = 3,
+ INTERFACE_DESCRIPTOR = 4,
+ ENDPOINT_DESCRIPTOR = 5,
+ DEVICE_QUALIFIER = 6,
+ OTHER_SPEED_CONFIGURATION = 7,
+ INTERFACE_POWER = 8
+};
+
+enum CONFIG_ATTRIBUTES {
+ CONF_ATTR_DEFAULT = 0x80,
+ CONF_ATTR_REMOTE_WAKEUP = 0x20,
+ CONF_ATTR_SELFPOWERED = 0x40
+};
+
+enum ENDPOINT_ATTRIBUTES {
+ EP_ADDR_IN = 0x80,
+ EP_ADDR_OUT = 0x00,
+ EP_ATTR_CONTROL = 0x0,
+ EP_ATTR_ISOCHRONOUS = 0x1,
+ EP_ATTR_BULK = 0x2,
+ EP_ATTR_INTERRUPT = 0x3
+};
+
+enum STANDARD_REQUEST_CODE {
+ STANDARD_GET_STATUS = 0,
+ STANDARD_CLEAR_FEATURE = 1,
+ STANDARD_RESERVED_1 = 2,
+ STANDARD_SET_FEATURE = 3,
+ STANDARD_RESERVED_2 = 4,
+ STANDARD_SET_ADDRESS = 5,
+ STANDARD_GET_DESCRIPTOR = 6,
+ STANDARD_SET_DESCRIPTOR = 7,
+ STANDARD_GET_CONFIGURATION = 8,
+ STANDARD_SET_CONFIGURATION = 9,
+ STANDARD_GET_INTERFACE = 10,
+ STANDARD_SET_INTERFACE = 11,
+ STANDARD_SYNCH_FRAME = 12
+};
+
+int s5p_usbctl_init(void);
+void s5p_udc_int_hndlr(void);
+void s5p_usb_tx(char *tx_data, int tx_size);
+int s5p_usb_detect_irq(void);
+void s5p_usb_clear_irq(void);
+
+/* in usbd-otg-hs.c */
+extern unsigned int s5p_usbd_dn_addr;
+extern unsigned int s5p_usbd_dn_cnt;
+extern int s5p_got_header;
+extern int s5p_receive_done;
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2009 Samsung Electronics
+ * Minkyu Kang <mk7.kang@samsung.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 <common.h>
+#include "usbd.h"
+#include "usb-hs-otg.h"
+#ifdef CONFIG_S5PC1XXFB
+#include <fbutils.h>
+#endif
+
+#define TX_DATA_LEN 4
+#define RX_DATA_LEN 64
+
+static char tx_data[TX_DATA_LEN] = "MPL";
+static char rx_data[RX_DATA_LEN];
+
+extern int s5p_receive_done;
+extern int s5p_usb_connected;
+extern otg_dev_t otg;
+
+static int __usb_board_init(void)
+{
+ return 0;
+}
+
+int usb_board_init(void) __attribute__((weak, alias("__usb_board_init")));
+
+extern int s5p_no_lcd_support(void);
+extern void s5pc_fimd_lcd_off(unsigned int win_id);
+extern void s5pc_fimd_window_off(unsigned int win_id);
+
+void s5pc1xx_wdt_reset(void)
+{
+ unsigned long wdt_base;
+
+ if (cpu_is_s5pc110())
+ wdt_base = S5PC110_WATCHDOG_BASE;
+ else
+ wdt_base = S5PC100_WATCHDOG_BASE;
+
+ /*
+ * WTCON
+ * Watchdog timer[5] : 0(disable) / 1(enable)
+ * Reset[0] : 0(disable) / 1(enable)
+ */
+ writel((1 << 5) | (1 << 0), wdt_base);
+}
+
+/* clear download informations */
+static void s5p_usb_clear_dnfile_info(void)
+{
+ otg.dn_addr = 0;
+ otg.dn_filesize = 0;
+ otg.dn_ptr = 0;
+}
+
+/* start the usb controller */
+static void usb_init(void)
+{
+ if (usb_board_init()) {
+ puts("Failed to usb_board_init\n");
+ return;
+ }
+
+#ifdef CONFIG_S5PC1XXFB
+ if (!s5p_no_lcd_support()) {
+ init_font();
+ set_font_color(FONT_WHITE);
+ fb_printf("Ready to USB Connection\n");
+ }
+#endif
+
+ s5p_usbctl_init();
+
+ printf("USB Start!! - %s Speed\n",
+ otg.speed ? "Full" : "High");
+
+ while (!s5p_usb_connected) {
+ if (s5p_usb_detect_irq()) {
+ s5p_udc_int_hndlr();
+ s5p_usb_clear_irq();
+ }
+ }
+
+ s5p_usb_clear_dnfile_info();
+
+ puts("Connected!!\n");
+
+#ifdef CONFIG_S5PC1XXFB
+ if (!s5p_no_lcd_support()) {
+ fb_printf("Download Start\n");
+ draw_progress(40, 0, FONT_WHITE);
+ }
+#endif
+}
+
+static void usb_stop(void)
+{
+#ifdef CONFIG_S5PC1XXFB
+ if (!s5p_no_lcd_support()) {
+ exit_font();
+
+ /* it uses fb3 as default window. */
+ s5pc_fimd_lcd_off(3);
+ s5pc_fimd_window_off(3);
+ }
+#endif
+}
+
+/*
+ * receive the packet from host PC
+ * return received size
+ */
+static int usb_receive_packet(void)
+{
+ while (1) {
+ if (s5p_usb_detect_irq()) {
+ s5p_udc_int_hndlr();
+ s5p_usb_clear_irq();
+ }
+
+ if (s5p_receive_done) {
+ s5p_receive_done = 0;
+ return otg.dn_filesize;
+ }
+ }
+}
+
+/* setup the download informations */
+static void recv_setup(char *addr, int len)
+{
+ s5p_usb_clear_dnfile_info();
+
+ otg.dn_addr = (u32)addr;
+ otg.dn_ptr = (u8 *) addr;
+ otg.dn_filesize = len;
+}
+
+#ifdef CONFIG_GENERIC_MMC
+#include <mmc.h>
+extern int s5p_no_mmc_support(void);
+
+static void usbd_set_mmc_dev(struct usbd_ops *usbd)
+{
+ struct mmc *mmc;
+
+ if (s5p_no_mmc_support())
+ return;
+
+ usbd->mmc_dev = 0;
+ /* FIXME */
+ usbd->mmc_max = 0x8000;
+
+ mmc = find_mmc_device(usbd->mmc_dev);
+ mmc_init(mmc);
+
+ usbd->mmc_blk = mmc->read_bl_len;
+
+ if (mmc->high_capacity)
+ usbd->mmc_total = mmc->capacity;
+ else
+ usbd->mmc_total = mmc->capacity / mmc->read_bl_len;
+}
+#endif
+
+#ifdef CONFIG_S5PC1XXFB
+static void set_progress(int progress)
+{
+ draw_progress(40, progress, FONT_WHITE);
+}
+#endif
+/*
+ * This function is interfaced between
+ * USB Device Controller and USB Downloader
+ */
+struct usbd_ops *usbd_set_interface(struct usbd_ops *usbd)
+{
+ usbd->usb_init = usb_init;
+ usbd->usb_stop = usb_stop;
+ usbd->send_data = s5p_usb_tx;
+ usbd->recv_data = usb_receive_packet;
+ usbd->recv_setup = recv_setup;
+ usbd->tx_data = tx_data;
+ usbd->rx_data = rx_data;
+ usbd->tx_len = TX_DATA_LEN;
+ usbd->rx_len = RX_DATA_LEN;
+ usbd->ram_addr = CONFIG_SYS_DOWN_ADDR;
+#ifdef CONFIG_S5PC1XXFB
+ if (!s5p_no_lcd_support())
+ usbd->set_progress = set_progress;
+#endif
+#ifdef CONFIG_GENERIC_MMC
+ usbd_set_mmc_dev(usbd);
+#endif
+ usbd->cpu_reset = s5pc1xx_wdt_reset;
+
+ return usbd;
+}
.globl _start
_start: b reset
+#if !defined(CONFIG_PRELOADER) && !defined(CONFIG_RECOVERY_BLOCK)
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
_irq: .word irq
_fiq: .word fiq
_pad: .word 0x12345678 /* now 16*4=64 */
+#else
+ . = _start + 64
+#endif
.global _end_vect
_end_vect:
orr r0, r0, #0xd3
msr cpsr,r0
+#if !defined(CONFIG_PRELOADER) && !defined(CONFIG_RECOVERY_BLOCK)
#if (CONFIG_OMAP34XX)
/* Copy vectors to mask ROM indirect addr */
adr r0, _start @ r0 <- current position of code
bl cpy_clk_code @ put dpll adjust code behind vectors
#endif /* NAND Boot */
#endif
+#endif /* CONFIG_PRELOADER || CONFIG_RECOVERY_BLOCK */
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+#if !defined(CONFIG_RECOVERY_BLOCK)
bl cpu_init_crit
#endif
+#endif
-#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+#if !defined(CONFIG_SKIP_RELOCATE_UBOOT) || !defined(CONFIG_PRELOADER) || !defined(CONFIG_RECOVERY_BLOCK)
relocate: @ relocate U-Boot to RAM
adr r0, _start @ r0 <- current position of code
ldr r1, _TEXT_BASE @ test if we run from flash or RAM
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot
+#if defined(CONFIG_PRELOADER)
+ sub sp, r0, #128 @ leave 32 words for abort-stack
+#else
sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 @ leave 3 words for abort-stack
+#endif /* CONFIG_PRELOADER */
bic sp, sp, #7 @ 8-byte alignment for ABI compliance
+#if !defined(CONFIG_PRELOADER) && !defined(CONFIG_RECOVERY_BLOCK)
/* Clear BSS (if any). Is below tx (watch load addr - need space) */
clear_bss:
ldr r0, _bss_start @ find start of bss segment
cmp r0, r1 @ are we at the end yet
add r0, r0, #4 @ increment clear index pointer
bne clbss_l @ keep clearing till at end
+#endif /* CONFIG_PRELOADER || CONFIG_RECOVERY_BLOCK */
ldr pc, _start_armboot @ jump to C code
+#if defined(CONFIG_ONENAND_IPL)
+_start_armboot: .word start_oneboot
+#elif defined(CONFIG_MMC_IPL)
+_start_armboot: .word start_mmcboot
+#elif defined(CONFIG_RECOVERY_BLOCK)
+_start_armboot: .word start_recovery_boot
+#else
_start_armboot: .word start_armboot
+#endif
/*************************************************************************
*
*************************************************************************/
cpu_init_crit:
+#if !defined(CONFIG_RECOVERY_BLOCK)
/*
* Invalidate L1 I/D
*/
bl lowlevel_init @ go setup pll,mux,memory
mov lr, ip @ restore link
mov pc, lr @ back to my caller
+#endif
+
+#if !defined(CONFIG_PRELOADER) && !defined(CONFIG_RECOVERY_BLOCK)
/*
*************************************************************************
*
bl do_fiq
#endif
+#endif /* CONFIG_PRELOADER || CONFIG_RECOVERY_BLOCK */
--- /dev/null
- pmic, CONFIG_SYS_MAXARGS, 1, do_pmic,
+/*
+ * Copyright (C) 2009 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ * Minkyu Kang <mk7.kang@samsung.com>
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/power.h>
+#include <asm/arch/mem.h>
+#include <asm/arch/hs_otg.h>
+#include <asm/arch/regs-otg.h>
+#include <asm/arch/rtc.h>
+#include <asm/arch/adc.h>
+#include <asm/errno.h>
+#include <fbutils.h>
+#include <lcd.h>
+#include <bmp_layout.h>
+
+#include "animation_frames.h"
+#include "gpio_setting.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define C100_MACH_START 3000
+#define C110_MACH_START 3100
+
+static unsigned int board_rev;
+static unsigned int battery_soc;
+static struct s5pc110_gpio *s5pc110_gpio;
+
+enum {
+ I2C_2,
+ I2C_GPIO3,
+ I2C_PMIC,
+ I2C_GPIO5,
+ I2C_GPIO6,
+ I2C_GPIO7,
+ I2C_GPIO10,
+};
+
+/*
+ * i2c 2
+ * SDA: GPD1[4]
+ * SCL: GPD1[5]
+ */
+static struct i2c_gpio_bus_data i2c_2 = {
+ .sda_pin = 4,
+ .scl_pin = 5,
+};
+
+/*
+ * i2c gpio3
+ * SDA: GPJ3[6]
+ * SCL: GPJ3[7]
+ */
+static struct i2c_gpio_bus_data i2c_gpio3 = {
+ .sda_pin = 6,
+ .scl_pin = 7,
+};
+
+/*
+ * i2c pmic
+ * SDA: GPJ4[0]
+ * SCL: GPJ4[3]
+ */
+static struct i2c_gpio_bus_data i2c_pmic = {
+ .sda_pin = 0,
+ .scl_pin = 3,
+};
+
+/*
+ * i2c gpio5
+ * SDA: MP05[3]
+ * SCL: MP05[2]
+ */
+static struct i2c_gpio_bus_data i2c_gpio5 = {
+ .sda_pin = 3,
+ .scl_pin = 2,
+};
+
+/*
+ * i2c gpio6
+ * SDA: GPJ3[4]
+ * SCL: GPJ3[5]
+ */
+static struct i2c_gpio_bus_data i2c_gpio6 = {
+ .sda_pin = 4,
+ .scl_pin = 5,
+};
+
+/*
+ * i2c gpio7 - goni
+ * SDA: MP05[1]
+ * SCL: MP05[0]
+ */
+static struct i2c_gpio_bus_data i2c_gpio7 = {
+ .sda_pin = 1,
+ .scl_pin = 0,
+};
+
+/*
+ * i2c gpio7 - cypress
+ * SDA: MP05[6]
+ * SCL: MP05[4]
+ */
+static struct i2c_gpio_bus_data i2c_cypress_gpio7 = {
+ .sda_pin = 6,
+ .scl_pin = 4,
+};
+
+/*
+ * i2c gpio10
+ * SDA: GPJ3[0]
+ * SCL: GPJ3[1]
+ */
+static struct i2c_gpio_bus_data i2c_gpio10 = {
+ .sda_pin = 0,
+ .scl_pin = 1,
+};
+
+
+static struct i2c_gpio_bus i2c_gpio[] = {
+ {
+ .bus = &i2c_2,
+ }, {
+ .bus = &i2c_gpio3,
+ }, {
+ .bus = &i2c_pmic,
+ }, {
+ .bus = &i2c_gpio5,
+ }, {
+ .bus = &i2c_gpio6,
+ }, {
+ .bus = &i2c_gpio7,
+ }, {
+ .bus = &i2c_gpio10,
+ },
+};
+
+u32 get_board_rev(void)
+{
+ return board_rev;
+}
+
+static int hwrevision(int rev)
+{
+ return (board_rev & 0xf) == rev;
+}
+
+enum {
+ MACH_UNIVERSAL,
+ MACH_TICKERTAPE,
+ MACH_CHANGED,
+ MACH_P1P2, /* Don't remove it */
+ MACH_GEMINUS,
+ MACH_CYPRESS,
+
+ MACH_WMG160 = 160,
+
+ MACH_PSEUDO_END,
+};
+
+#define SPLIT_SCREEN_FEATURE 0x100
+
+/* board is MACH_AQUILA and board is like below. */
+#define J1_B2_BOARD 0x0200
+#define LIMO_UNIVERSAL_BOARD 0x0400
+#define LIMO_REAL_BOARD 0x0800
+#define MEDIA_BOARD 0x1000
+#define BAMBOO_BOARD 0x2000
+
+/* board is MACH_GONI and board is like below */
+#define S1_BOARD 0x1000
+#define HAYDN_BOARD 0x2000
+#define KESSLER_BOARD 0x4000
+#define SDK_BOARD 0x8000
+
+#define BOARD_MASK 0xFF00
+
+static int c110_machine_id(void)
+{
+ return gd->bd->bi_arch_number - C110_MACH_START;
+}
+
+static int mach_is_aquila(void)
+{
+ return gd->bd->bi_arch_number == MACH_TYPE_AQUILA;
+}
+
+static int mach_is_tickertape(void)
+{
+ return c110_machine_id() == MACH_TICKERTAPE;
+}
+
+static int mach_is_geminus(void)
+{
+ return c110_machine_id() == MACH_GEMINUS;
+}
+
+static int mach_is_cypress(void)
+{
+ return c110_machine_id() == MACH_CYPRESS;
+}
+
+static int board_is_limo_universal(void)
+{
+ return mach_is_aquila() && (board_rev & LIMO_UNIVERSAL_BOARD);
+}
+
+static int board_is_limo_real(void)
+{
+ return mach_is_aquila() && (board_rev & LIMO_REAL_BOARD);
+}
+
+static int board_is_bamboo(void)
+{
+ return mach_is_aquila() && (board_rev & BAMBOO_BOARD);
+}
+
+static int board_is_media(void)
+{
+ return mach_is_aquila() && (board_rev & MEDIA_BOARD);
+}
+
+static int board_is_j1b2(void)
+{
+ return mach_is_aquila() && (board_rev & J1_B2_BOARD);
+}
+
+/* Kessler */
+static int mach_is_goni(void)
+{
+ return gd->bd->bi_arch_number == MACH_TYPE_GONI;
+}
+
+static int board_is_sdk(void)
+{
+ return mach_is_goni() && (board_rev & SDK_BOARD);
+}
+
+static int board_is_s1(void)
+{
+ return mach_is_goni() && (board_rev & S1_BOARD);
+}
+
+
+static int board_is_haydn(void)
+{
+ return mach_is_goni() && (board_rev & HAYDN_BOARD);
+}
+
+/* DLNA Dongle */
+static int mach_is_wmg160(void)
+{
+ return c110_machine_id() == MACH_WMG160;
+}
+
+#ifdef CONFIG_AVS_TEST
+static int board_has_AVS(void)
+{
+ return board_is_sdk() && hwrevision(6);
+}
+#else
+static int board_has_AVS(void)
+{
+ return 0;
+}
+#endif
+
+static void check_battery(int mode);
+static void check_micro_usb(int intr);
+
+void i2c_init_board(void)
+{
+ struct s5pc110_gpio *gpio = (struct s5pc110_gpio *)S5PC110_GPIO_BASE;
+ int num_bus;
+
+ if (cpu_is_s5pc100())
+ return;
+
+ num_bus = ARRAY_SIZE(i2c_gpio);
+
+ if (mach_is_aquila()) {
+ i2c_gpio[I2C_GPIO6].bus->gpio_base = 0;
+ i2c_gpio[I2C_GPIO7].bus->gpio_base = 0;
+ } else if (mach_is_goni()) {
+ i2c_gpio[I2C_GPIO7].bus->gpio_base =
+ (unsigned int)&gpio->gpio_mp0_5;
+ } else if (mach_is_cypress()) {
+ i2c_gpio[I2C_GPIO7].bus = &i2c_cypress_gpio7;
+ i2c_gpio[I2C_GPIO7].bus->gpio_base =
+ (unsigned int)&gpio->gpio_mp0_5;
+ } else {
+ i2c_gpio[I2C_GPIO7].bus->gpio_base = 0;
+ }
+
+ if (board_has_AVS()) { /* no I2C2. it's used by AVS-IEM */
+ static int printed = 0;
+ struct s5p_gpio_bank *bank =
+ (struct s5p_gpio_bank *)(&gpio->gpio_d1);
+ /* set GPD1CON[4], [5] as IEM_SPWI/SCLK */
+ gpio_cfg_pin(bank, 4, 0x2); /* IEM_SCLK */
+ gpio_cfg_pin(bank, 5, 0x2); /* IEM_SPWI */
+
+ i2c_gpio[I2C_2].bus->gpio_base = 0;
+ if (!printed) {
+ puts("(I2C2 Diabled. AVS Mode) ");
+ printed = 1;
+ }
+ } else
+ i2c_gpio[I2C_2].bus->gpio_base = (unsigned int)&gpio->gpio_d1;
+
+ i2c_gpio[I2C_GPIO3].bus->gpio_base = (unsigned int)&gpio->gpio_j3;
+ i2c_gpio[I2C_PMIC].bus->gpio_base = (unsigned int)&gpio->gpio_j4;
+ i2c_gpio[I2C_GPIO5].bus->gpio_base = (unsigned int)&gpio->gpio_mp0_5;
+ i2c_gpio[I2C_GPIO6].bus->gpio_base = (unsigned int)&gpio->gpio_j3;
+
+ i2c_gpio_init(i2c_gpio, num_bus, I2C_PMIC);
+
+ /* Reset on fsa9480 early */
+ check_micro_usb(1);
+ /* Reset on max17040 early */
+ if (battery_soc == 0)
+ check_battery(1);
+}
+
+#ifdef CONFIG_MISC_INIT_R
+#define DEV_INFO_LEN 256
+static char device_info[DEV_INFO_LEN];
+static int display_info;
+
+static void empty_device_info_buffer(void)
+{
+ memset(device_info, 0x0, DEV_INFO_LEN);
+}
+
+static void dprintf(const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char buf[128];
+
+ va_start(args, fmt);
+ i = vsprintf(buf, fmt, args);
+ va_end(args);
+
+ buf[127] = 0;
+
+ if ((strlen(device_info) + strlen(buf)) > (DEV_INFO_LEN - 1)) {
+ puts("Flushing device info...\n");
+ puts(device_info);
+ empty_device_info_buffer();
+ }
+ strncat(device_info, buf, 127);
+ puts(buf);
+}
+
+#ifdef CONFIG_S5PC1XXFB
+static void display_device_info(void)
+{
+ if (!display_info)
+ return;
+
+ init_font();
+ set_font_xy(0, 450);
+ set_font_color(FONT_WHITE);
+ fb_printf(device_info);
+ exit_font();
+
+ memset(device_info, 0x0, DEV_INFO_LEN);
+
+ udelay(5 * 1000 * 1000);
+}
+#endif
+
+static const char *board_name[] = {
+ "Universal",
+ "TickerTape",
+ "Goni",
+ "P1P2", /* Don't remove it */
+ "Geminus",
+ "Cypress",
+ "Limo SDK",
+};
+
+enum {
+ MEM_4G1G1G,
+ MEM_4G2G1G,
+ MEM_4G3G1G,
+ MEM_4G4G1G,
+};
+
+static char feature_buffer[32];
+
+static char *display_features(int board, int board_rev)
+{
+ int count = 0;
+ char *buf = feature_buffer;
+ char *name = NULL;
+
+ if (board == MACH_TYPE_AQUILA) {
+ if (board_rev & SPLIT_SCREEN_FEATURE)
+ name = "SplitScreen";
+ if (board_rev & J1_B2_BOARD)
+ name = "J1 B2";
+ /* Limo Real or Universal */
+ if (board_rev & LIMO_REAL_BOARD)
+ name = "Limo Real";
+ else if (board_rev & LIMO_UNIVERSAL_BOARD)
+ name = "Limo Universal";
+ if (board_rev & MEDIA_BOARD)
+ name = "Media";
+ if (board_rev & BAMBOO_BOARD)
+ name = "Bamboo";
+ } else if (board == MACH_TYPE_GONI) {
+ if (board_rev & SDK_BOARD) {
+ if (hwrevision(9)) {
+ name = "Kessler";
+ } else {
+ name = "SLP SDK";
+ if (hwrevision(3))
+ strcat(name, " 4.3inch");
+ else if (hwrevision(4))
+ strcat(name, " 4.5inch");
+ }
+ }
+ if (board_rev & S1_BOARD)
+ name = "S1";
+ if (board_rev & HAYDN_BOARD)
+ name = "Haydn";
+ }
+ if (name)
+ count += sprintf(buf + count, " - %s", name);
+
+ return buf;
+}
+
+static char *get_board_name(int board)
+{
+ if (board == MACH_TYPE_AQUILA)
+ return "Aquila";
+ else if (board == MACH_TYPE_GONI)
+ return "Goni";
+ else if (board == MACH_WMG160)
+ return "WMG160";
+ return (char *) board_name[board];
+}
+
+static void check_board_revision(int board, int rev)
+{
+ if (board == MACH_TYPE_AQUILA) {
+ /* Limo Real or Universal */
+ if (rev & LIMO_UNIVERSAL_BOARD)
+ board_rev &= ~J1_B2_BOARD;
+ if (rev & LIMO_REAL_BOARD)
+ board_rev &= ~(J1_B2_BOARD |
+ LIMO_UNIVERSAL_BOARD);
+ if (rev & MEDIA_BOARD)
+ board_rev &= ~(J1_B2_BOARD |
+ LIMO_UNIVERSAL_BOARD);
+ if (rev & BAMBOO_BOARD)
+ board_rev &= ~(J1_B2_BOARD |
+ LIMO_UNIVERSAL_BOARD |
+ LIMO_REAL_BOARD |
+ MEDIA_BOARD);
+ } else if (board == MACH_TYPE_GONI) {
+ if (rev & KESSLER_BOARD)
+ board_rev &= ~(J1_B2_BOARD |
+ LIMO_UNIVERSAL_BOARD);
+ if (rev & SDK_BOARD)
+ board_rev &= ~(J1_B2_BOARD |
+ LIMO_UNIVERSAL_BOARD);
+ if (rev & S1_BOARD)
+ board_rev &= ~(J1_B2_BOARD | LIMO_UNIVERSAL_BOARD |
+ LIMO_REAL_BOARD);
+ if (rev & HAYDN_BOARD)
+ board_rev &= ~(J1_B2_BOARD | LIMO_UNIVERSAL_BOARD |
+ LIMO_REAL_BOARD);
+ } else {
+ board_rev &= ~BOARD_MASK;
+ }
+}
+
+static unsigned int get_hw_revision(struct s5p_gpio_bank *bank, int hwrev3)
+{
+ unsigned int rev;
+
+ gpio_direction_input(bank, 2);
+ gpio_direction_input(bank, 3);
+ gpio_direction_input(bank, 4);
+ gpio_direction_input(bank, hwrev3);
+
+ gpio_set_pull(bank, 2, GPIO_PULL_NONE); /* HWREV_MODE0 */
+ gpio_set_pull(bank, 3, GPIO_PULL_NONE); /* HWREV_MODE1 */
+ gpio_set_pull(bank, 4, GPIO_PULL_NONE); /* HWREV_MODE2 */
+ gpio_set_pull(bank, hwrev3, GPIO_PULL_NONE); /* HWREV_MODE3 */
+
+ rev = gpio_get_value(bank, 2);
+ rev |= (gpio_get_value(bank, 3) << 1);
+ rev |= (gpio_get_value(bank, 4) << 2);
+ rev |= (gpio_get_value(bank, hwrev3) << 3);
+
+ return rev;
+}
+
+static void check_hw_revision(void)
+{
+ unsigned int board = MACH_UNIVERSAL; /* Default is Universal */
+
+ if (cpu_is_s5pc100()) {
+ struct s5pc100_gpio *gpio =
+ (struct s5pc100_gpio *)S5PC100_GPIO_BASE;
+
+ board_rev = get_hw_revision(&gpio->gpio_j0, 0);
+
+ /* C100 TickerTape */
+ if (board_rev == 3)
+ board = MACH_TICKERTAPE;
+ } else {
+ struct s5pc110_gpio *gpio =
+ (struct s5pc110_gpio *)S5PC110_GPIO_BASE;
+ int hwrev3 = 1;
+
+ board_rev = 0;
+
+ /*
+ * Note Check 'Aquila' board first
+ *
+ * TT: TickerTape
+ * SS: SplitScreen
+ * LRA: Limo Real Aquila
+ * LUA: Limo Universal Aquila
+ * OA: Old Aquila
+ * CYP: Cypress
+ * BB: Bamboo
+ *
+ * ADDR = 0xE0200000 + OFF
+ *
+ * OFF Universal BB LRA LUA OA TT SS CYP
+ * J1: 0x0264 0x10 0x10 0x00 0x00 0x00 0x00 0x00
+ * J2: 0x0284 0x01 0x10 0x00
+ * H1: 0x0C24 W 0x28 0xA8 0x1C 0x0F
+ * H3: 0x0C64 0x03 0x07 0x0F
+ * D1: 0x00C4 0x0F 0x3F 0x3F 0x0F 0xXC 0x3F
+ * I: 0x0224 0x02 0x00 0x08
+ * MP03: 0x0324 0x9x 0xbx 0x9x
+ * MP05: 0x0364 0x80 0x88
+ */
+
+ /* C110 Aquila */
+ if (gpio_get_value(&gpio->gpio_j1, 4) == 0) {
+ board = MACH_TYPE_AQUILA;
+ board_rev |= J1_B2_BOARD;
+
+ gpio_set_pull(&gpio->gpio_j2, 6, GPIO_PULL_NONE);
+ gpio_direction_input(&gpio->gpio_j2, 6);
+
+ /* Check board */
+ if (gpio_get_value(&gpio->gpio_h1, 2) == 0)
+ board_rev |= LIMO_UNIVERSAL_BOARD;
+
+ if (gpio_get_value(&gpio->gpio_h3, 2) == 0)
+ board_rev |= LIMO_REAL_BOARD;
+
+ if (gpio_get_value(&gpio->gpio_j2, 6) == 1)
+ board_rev |= MEDIA_BOARD;
+
+ /* set gpio to default value. */
+ gpio_set_pull(&gpio->gpio_j2, 6, GPIO_PULL_DOWN);
+ gpio_direction_output(&gpio->gpio_j2, 6, 0);
+ }
+
+ /* Workaround: C110 Aquila Rev0.6 */
+ if (board_rev == 6) {
+ board = MACH_TYPE_AQUILA;
+ board_rev |= LIMO_REAL_BOARD;
+ }
+
+ /* C110 Aquila Bamboo */
+ if (gpio_get_value(&gpio->gpio_j2, 0) == 1) {
+ board = MACH_TYPE_AQUILA;
+ board_rev |= BAMBOO_BOARD;
+ }
+
+ /* C110 TickerTape */
+ if (gpio_get_value(&gpio->gpio_d1, 0) == 0 &&
+ gpio_get_value(&gpio->gpio_d1, 1) == 0)
+ board = MACH_TICKERTAPE;
+
+ /* WMG160 - GPH3[0:4] = 0x00 */
+ if (board == MACH_TICKERTAPE) {
+ int i, wmg160 = 1;
+
+ for (i = 0; i < 4; i++) {
+ if (gpio_get_value(&gpio->gpio_h3, i) != 0) {
+ wmg160 = 0;
+ break;
+ }
+ }
+ if (wmg160) {
+ board = MACH_WMG160;
+ hwrev3 = 7;
+ }
+ }
+
+ /* C110 Geminus for rev0.0 */
+ gpio_set_pull(&gpio->gpio_j1, 2, GPIO_PULL_NONE);
+ gpio_direction_input(&gpio->gpio_j1, 2);
+ if (gpio_get_value(&gpio->gpio_j1, 2) == 1) {
+ board = MACH_GEMINUS;
+ if ((board_rev & ~BOARD_MASK) == 3)
+ board_rev &= ~0xff;
+ }
+ gpio_set_pull(&gpio->gpio_j1, 2, GPIO_PULL_DOWN);
+ gpio_direction_output(&gpio->gpio_j1, 2, 0);
+
+ /* C110 Geminus for rev0.1 ~ */
+ gpio_set_pull(&gpio->gpio_j0, 6, GPIO_PULL_NONE);
+ gpio_direction_input(&gpio->gpio_j0, 6);
+ if (gpio_get_value(&gpio->gpio_j0, 6) == 1) {
+ board = MACH_GEMINUS;
+ hwrev3 = 7;
+ }
+ gpio_set_pull(&gpio->gpio_j0, 6, GPIO_PULL_DOWN);
+
+ /* Kessler MP0_5[6] == 1 */
+ gpio_direction_input(&gpio->gpio_mp0_5, 6);
+ if (gpio_get_value(&gpio->gpio_mp0_5, 6) == 1) {
+ /* Cypress: Do this for cypress */
+ gpio_set_pull(&gpio->gpio_j2, 2, GPIO_PULL_NONE);
+ gpio_direction_input(&gpio->gpio_j2, 2);
+ if (gpio_get_value(&gpio->gpio_j2, 2) == 1) {
+ board = MACH_CYPRESS;
+ gpio_direction_output(&gpio->gpio_mp0_5, 6, 0);
+ } else {
+ board = MACH_TYPE_GONI;
+ board_rev |= KESSLER_BOARD;
+#if 0
+ /* workaround: temporarily use sdk rev0.5 */
+ board_rev |= SDK_BOARD;
+
+#endif
+ /* Limo SDK MP0_5[4] == 1 */
+ gpio_direction_input(&gpio->gpio_mp0_5, 4);
+ if (gpio_get_value(&gpio->gpio_mp0_5, 4) == 1) {
+ board_rev &= ~KESSLER_BOARD;
+
+ /* Haydn MP0_4[0] == 1 */
+ gpio_direction_input(&gpio->gpio_mp0_4, 0);
+ if (gpio_get_value(&gpio->gpio_mp0_4, 0) == 1)
+ board_rev |= HAYDN_BOARD;
+ else
+ board_rev |= SDK_BOARD;
+ }
+
+ }
+ gpio_set_pull(&gpio->gpio_j2, 2, GPIO_PULL_DOWN);
+ hwrev3 = 7;
+ } else {
+ gpio_direction_output(&gpio->gpio_mp0_5, 6, 0);
+ /* Goni S1 board detection */
+ if (board == MACH_TICKERTAPE) {
+ board = MACH_TYPE_GONI;
+ board_rev |= S1_BOARD;
+ hwrev3 = 7;
+ }
+ }
+
+ board_rev |= get_hw_revision(&gpio->gpio_j0, hwrev3);
+ }
+
+ /* Set machine id */
+ if (board < MACH_PSEUDO_END) {
+ if (cpu_is_s5pc110())
+ gd->bd->bi_arch_number = C110_MACH_START + board;
+ else
+ gd->bd->bi_arch_number = C100_MACH_START + board;
+ } else {
+ gd->bd->bi_arch_number = board;
+ }
+
+ /* Architecture Common settings */
+ if (cpu_is_s5pc110()) {
+ setenv("mtdparts", MTDPARTS_DEFAULT_4KB);
+ } else {
+ setenv("bootk", "onenand read 0x30007FC0 0x60000 0x300000; "
+ "bootm 0x30007FC0");
+ setenv("updatek", "onenand erase 0x60000 0x300000; "
+ "onenand write 0x31008000 0x60000 0x300000");
+ }
+}
+
+static void show_hw_revision(void)
+{
+ int board;
+
+ /*
+ * Workaround for Rev 0.3 + CP Ver ES 3.1
+ * it's Rev 0.4
+ */
+ if (board_is_limo_real()) {
+ if (hwrevision(0)) {
+ /* default is Rev 0.4 */
+ board_rev &= ~0xf;
+ board_rev |= 0x4;
+ }
+ }
+
+ if (mach_is_goni() || mach_is_aquila())
+ board = gd->bd->bi_arch_number;
+ else if (cpu_is_s5pc110())
+ board = gd->bd->bi_arch_number - C110_MACH_START;
+ else
+ board = gd->bd->bi_arch_number - C100_MACH_START;
+
+ check_board_revision(board, board_rev);
+
+ /* Set CPU Revision */
+ if (mach_is_aquila()) {
+ if (board_is_limo_real()) {
+ if ((board_rev & 0xf) < 8)
+ s5pc1xx_set_cpu_rev(0);
+ }
+ else if (board_is_bamboo())
+ s5pc1xx_set_cpu_rev(0);
+ } else if (mach_is_goni()) {
+ if (board_is_sdk() &&
+ (hwrevision(2) || hwrevision(4) || hwrevision(5) || hwrevision(6)))
+ s5pc1xx_set_cpu_rev(2); /* EVT1-Fused */
+ else
+ s5pc1xx_set_cpu_rev(1);
+ } else if (mach_is_geminus()) {
+ if ((board_rev & 0xf) < 1)
+ s5pc1xx_set_cpu_rev(0);
+ } else if (mach_is_cypress()) {
+ s5pc1xx_set_cpu_rev(1);
+ } else if (mach_is_wmg160()) {
+ if (hwrevision(5))
+ s5pc1xx_set_cpu_rev(0);
+ else
+ s5pc1xx_set_cpu_rev(2);
+ } else {
+ s5pc1xx_set_cpu_rev(0);
+ }
+
+ if (cpu_is_s5pc110())
+ writel(0xc1100000 | (0xffff & (s5pc1xx_get_cpu_rev() ? 1 : 0)),
+ S5PC110_INFORM3);
+
+ empty_device_info_buffer();
+ dprintf("HW Revision:\t%x (%s%s) %s\n",
+ board_rev, get_board_name(board),
+ display_features(board, board_rev),
+ s5pc1xx_get_cpu_rev() ? "" : "EVT0");
+}
+
+static void check_auto_burn(void)
+{
+ unsigned long magic_base = CONFIG_SYS_SDRAM_BASE + 0x02000000;
+ unsigned int count = 0;
+ char buf[64];
+
+ if (readl(magic_base) == 0x426f6f74) { /* ASICC: Boot */
+ puts("Auto burning bootloader\n");
+ count += sprintf(buf + count, "run updateb; ");
+ }
+ if (readl(magic_base + 0x04) == 0x4b65726e) { /* ASICC: Kern */
+ puts("Auto burning kernel\n");
+ count += sprintf(buf + count, "run updatek; ");
+ }
+
+ if (count) {
+ count += sprintf(buf + count, "reset");
+ setenv("bootcmd", buf);
+ }
+
+ /* Clear the magic value */
+ writel(0xa5a55a5a, magic_base);
+ writel(0xa5a55a5a, magic_base + 0x4);
+}
+
+static void pmic_pin_init(void)
+{
+ unsigned int reg, value;
+
+ if (cpu_is_s5pc100())
+ return;
+
+ /* AP_PS_HOLD: XEINT_0: GPH0[0]
+ * Note: Don't use GPIO PS_HOLD it doesn't work
+ */
+ reg = S5PC110_PS_HOLD_CONTROL;
+ value = readl(reg);
+ value |= S5PC110_PS_HOLD_DIR_OUTPUT |
+ S5PC110_PS_HOLD_DATA_HIGH |
+ S5PC110_PS_HOLD_OUT_EN;
+ writel(value, reg);
+
+ /* nPOWER: XEINT_22: GPH2[6] interrupt mode */
+ gpio_cfg_pin(&s5pc110_gpio->gpio_h2, 6, GPIO_IRQ);
+ gpio_set_pull(&s5pc110_gpio->gpio_h2, 6, GPIO_PULL_UP);
+}
+
+static void enable_ldos(void)
+{
+ if (cpu_is_s5pc100())
+ return;
+
+ /* TOUCH_EN: XMMC3DATA_3: GPG3[6] output high */
+ gpio_direction_output(&s5pc110_gpio->gpio_g3, 6, 1);
+}
+
+static void enable_t_flash(void)
+{
+ if (!(board_is_limo_universal() || board_is_limo_real()))
+ return;
+
+ /* T_FLASH_EN : XM0ADDR_13: MP0_5[4] output high */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_5, 4, 1);
+}
+
+static void setup_limo_real_gpios(void)
+{
+ if (!board_is_limo_real())
+ return;
+
+ /*
+ * Note: Please write GPIO alphabet order
+ */
+ /* CODEC_LDO_EN: XVVSYNC_LDI: GPF3[4] output high */
+ gpio_direction_output(&s5pc110_gpio->gpio_f3, 4, 1);
+
+ if (hwrevision(0))
+ /* RESET_REQ_N: XM0BEN_1: MP0_2[1] output high */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_2, 1, 1);
+ else
+ /* RESET_REQ_N: XM0CSn_2: MP0_1[2] output high */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_1, 2, 1);
+
+ /* T_FLASH_DETECT: EINT28: GPH3[4] interrupt mode */
+ gpio_cfg_pin(&s5pc110_gpio->gpio_h3, 4, GPIO_IRQ);
+ gpio_set_pull(&s5pc110_gpio->gpio_h3, 4, GPIO_PULL_UP);
+}
+
+static void setup_media_gpios(void)
+{
+ if (!board_is_media())
+ return;
+
+ /*
+ * Note: Please write GPIO alphabet order
+ */
+ /* RESET_REQ_N: XM0CSn_2: MP0_1[2] output high */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_1, 2, 1);
+
+ /* T_FLASH_DETECT: EINT28: GPH3[4] interrupt mode */
+ gpio_cfg_pin(&s5pc110_gpio->gpio_h3, 4, GPIO_IRQ);
+ gpio_set_pull(&s5pc110_gpio->gpio_h3, 4, GPIO_PULL_UP);
+}
+
+#define KBR3 (1 << 3)
+#define KBR2 (1 << 2)
+#define KBR1 (1 << 1)
+#define KBR0 (1 << 0)
+
+static void check_keypad(void)
+{
+ unsigned int reg, value;
+ unsigned int col_num, row_num;
+ unsigned int col_mask;
+ unsigned int col_mask_shift;
+ unsigned int row_state[4];
+ unsigned int i;
+ unsigned int auto_download = 0;
+
+ if (mach_is_wmg160())
+ return;
+
+ if (cpu_is_s5pc100()) {
+ struct s5pc100_gpio *gpio =
+ (struct s5pc100_gpio *)S5PC100_GPIO_BASE;
+
+ row_num = 3;
+ col_num = 3;
+
+ /* Set GPH2[2:0] to KP_COL[2:0] */
+ gpio_cfg_pin(&gpio->gpio_h2, 0, 0x3);
+ gpio_cfg_pin(&gpio->gpio_h2, 1, 0x3);
+ gpio_cfg_pin(&gpio->gpio_h2, 2, 0x3);
+
+ /* Set GPH3[2:0] to KP_ROW[2:0] */
+ gpio_cfg_pin(&gpio->gpio_h3, 0, 0x3);
+ gpio_cfg_pin(&gpio->gpio_h3, 1, 0x3);
+ gpio_cfg_pin(&gpio->gpio_h3, 2, 0x3);
+
+ reg = S5PC100_KEYPAD_BASE;
+ col_mask = S5PC1XX_KEYIFCOL_MASK;
+ col_mask_shift = 0;
+ } else {
+ if (board_is_limo_real() || board_is_limo_universal()) {
+ row_num = 2;
+ col_num = 3;
+ } else {
+ row_num = 4;
+ col_num = 4;
+ }
+
+ for (i = 0; i < row_num; i++) {
+ if (board_is_sdk() && (hwrevision(3) || hwrevision(4)) && i == 0) {
+ continue;
+ }
+ /* Set GPH3[3:0] to KP_ROW[3:0] */
+ gpio_cfg_pin(&s5pc110_gpio->gpio_h3, i, 0x3);
+ gpio_set_pull(&s5pc110_gpio->gpio_h3, i, GPIO_PULL_UP);
+ }
+
+ for (i = 0; i < col_num; i++)
+ /* Set GPH2[3:0] to KP_COL[3:0] */
+ gpio_cfg_pin(&s5pc110_gpio->gpio_h2, i, 0x3);
+
+ reg = S5PC110_KEYPAD_BASE;
+ col_mask = S5PC110_KEYIFCOLEN_MASK;
+ col_mask_shift = 8;
+ }
+
+ /* KEYIFCOL reg clear */
+ writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
+
+ /* key_scan */
+ for (i = 0; i < col_num; i++) {
+ value = col_mask;
+ value &= ~(1 << i) << col_mask_shift;
+
+ writel(value, reg + S5PC1XX_KEYIFCOL_OFFSET);
+ udelay(1000);
+
+ value = readl(reg + S5PC1XX_KEYIFROW_OFFSET);
+ row_state[i] = ~value & ((1 << row_num) - 1);
+ if (row_state[i])
+ printf("[%d col] row_state: 0x%x\n", i, row_state[i]);
+ }
+
+ /* KEYIFCOL reg clear */
+ writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
+
+ if (mach_is_aquila() || mach_is_goni()) {
+ /* volume down */
+ if (row_state[1] & 0x2)
+ display_info = 1;
+ if (board_is_sdk() && hwrevision(0)) {
+ /* home & volume down */
+ if ((row_state[1] & 0x1) && (row_state[1] & 0x2))
+ auto_download = 1;
+ } else if (board_is_sdk() && hwrevision(2)) {
+ /* cam full shot & volume down */
+ if ((row_state[1] & 0x6) && (row_state[2] & 0x4))
+ auto_download = 1;
+ } else if (board_is_sdk() && (hwrevision(3) || hwrevision(4))) {
+ /* cam full shot & volume down */
+ if ((row_state[1] & 0x6) && (row_state[2] & 0x4))
+ auto_download = 1;
+ } else {
+ /* cam full shot & volume down */
+ if ((row_state[0] & 0x1) && (row_state[1] & 0x2))
+ auto_download = 1;
+ }
+ } else if (mach_is_geminus())
+ /* volume down & home */
+ if ((row_state[1] & 0x2) && (row_state[2] & 0x1))
+ auto_download = 1;
+
+ if (auto_download)
+ setenv("bootcmd", "usbdown");
+}
+
+static void check_battery(int mode)
+{
+ unsigned char val[2];
+ unsigned char addr = 0x36; /* max17040 fuel gauge */
+
+ i2c_set_bus_num(I2C_GPIO3);
+
+ if (mach_is_aquila()) {
+ if (board_is_j1b2())
+ return;
+ } else if (mach_is_goni()) {
+ i2c_set_bus_num(I2C_GPIO7);
+ } else if (mach_is_cypress()) {
+ i2c_set_bus_num(I2C_GPIO7);
+ } else if (mach_is_geminus()) {
+ if (hwrevision(1))
+ i2c_set_bus_num(I2C_GPIO7);
+ } else
+ return;
+
+ if (i2c_probe(addr)) {
+ puts("Can't found max17040 fuel gauge\n");
+ return;
+ }
+
+ /* mode 0: check mode / 1: enable mode */
+ if (mode) {
+ val[0] = 0x54;
+ val[1] = 0x00;
+ i2c_write(addr, 0xfe, 1, val, 2);
+ } else {
+ i2c_read(addr, 0x04, 1, val, 1);
+ dprintf("battery:\t%d%%\n", val[0]);
+ battery_soc = val[0];
+ }
+}
+
+static void check_mhl(void)
+{
+ unsigned char val[2];
+ unsigned char addr = 0x39; /* SIL9230 */
+
+ /* MHL Power enable */
+ /* HDMI_EN : GPJ2[2] XMSMDATA_2 output mode */
+ gpio_direction_output(&s5pc110_gpio->gpio_j2, 2, 1);
+
+ /* MHL_RST : MP0_4[7] XM0ADDR_7 output mode */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_4, 7, 0);
+
+ /* 10ms required after reset */
+ udelay(10000);
+
+ /* output enable */
+ gpio_set_value(&s5pc110_gpio->gpio_mp0_4, 7, 1);
+
+ i2c_set_bus_num(I2C_GPIO5);
+
+ /* set usb path */
+ if (i2c_probe(addr)) {
+ puts("Can't found MHL Chip\n");
+ return;
+ }
+
+ /*
+ * System Control #1
+ * set to Normal operation
+ */
+ val[0] = 0x35;
+ i2c_write((0x72 >> 1), 0x08, 1, val, 1);
+ i2c_read((0x72 >> 1), 0x08, 1, val, 1);
+
+ /*
+ * MHL TX Control #1
+ * TERM_MODE [7:6]
+ * 00 = MHL termination ON
+ * 11 = MHL termination OFF
+ */
+ val[0] = 0xd0;
+ i2c_write((0x72 >> 1), 0xa0, 1, val, 1);
+ i2c_read((0x72 >> 1), 0xa0, 1, val, 1);
+}
+
+static int max8998_probe(void)
+{
+ unsigned char addr = 0xCC >> 1;
+
+ i2c_set_bus_num(I2C_PMIC);
+
+ if (i2c_probe(addr)) {
+ puts("Can't found max8998\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define CHARGER_ANIMATION_FRAME 6
+static void max8998_clear_interrupt(void)
+{
+ unsigned char addr, val[2];
+ addr = 0xCC >> 1;
+
+ if (max8998_probe())
+ return;
+
+ i2c_read(addr, 0x00, 1, val, 1);
+ i2c_read(addr, 0x01, 1, val, 1);
+ i2c_read(addr, 0x02, 1, val, 1);
+ i2c_read(addr, 0x03, 1, val, 1);
+}
+
+static int max8998_power_key(void)
+{
+ unsigned char addr, val[2];
+ addr = 0xCC >> 1;
+
+ if (max8998_probe())
+ return 0;
+
+ /* Accessing IRQ1 register */
+ i2c_read(addr, 0x00, 1, val, 1);
+ if (val[0] & (1 << 6))
+ return 1;
+
+ return 0;
+}
+
+static int max8998_has_ext_power_source(void)
+{
+ unsigned char addr, val[2];
+ addr = 0xCC >> 1;
+
+ if (max8998_probe())
+ return 0;
+
+ /* Accessing STATUS2 register */
+ i2c_read(addr, 0x09, 1, val, 1);
+ if (val[0] & (1 << 5))
+ return 1;
+
+ return 0;
+}
+
+struct thermister_stat {
+ short centigrade;
+ unsigned short adc;
+};
+
+static struct thermister_stat adc_to_temperature_data[] = {
+ { .centigrade = -20, .adc = 1856, },
+ { .centigrade = -15, .adc = 1799, },
+ { .centigrade = -10, .adc = 1730, },
+ { .centigrade = -5, .adc = 1649, },
+ { .centigrade = 0, .adc = 1556, },
+ { .centigrade = 5, .adc = 1454, },
+ { .centigrade = 10, .adc = 1343, },
+ { .centigrade = 15, .adc = 1227, },
+ { .centigrade = 20, .adc = 1109, },
+ { .centigrade = 25, .adc = 992, },
+ { .centigrade = 30, .adc = 880, },
+ { .centigrade = 35, .adc = 773, },
+ { .centigrade = 40, .adc = 675, },
+ { .centigrade = 45, .adc = 586, },
+ { .centigrade = 50, .adc = 507, },
+ { .centigrade = 55, .adc = 436, },
+ { .centigrade = 58, .adc = 399, },
+ { .centigrade = 63, .adc = 343, },
+ { .centigrade = 65, .adc = 322, },
+};
+
+#ifndef USHRT_MAX
+#define USHRT_MAX 0xFFFFU
+#endif
+static int adc_to_temperature_centigrade(unsigned short adc)
+{
+ int i;
+ int approximation;
+ /* low_*: Greatest Lower Bound,
+ * * * * high_*: Smallest Upper Bound */
+ int low_temp = 0, high_temp = 0;
+ unsigned short low_adc = 0, high_adc = USHRT_MAX;
+ for (i = 0; i < ARRAY_SIZE(adc_to_temperature_data); i++) {
+ if (adc_to_temperature_data[i].adc <= adc &&
+ adc_to_temperature_data[i].adc >= low_adc) {
+ low_temp = adc_to_temperature_data[i].centigrade;
+ low_adc = adc_to_temperature_data[i].adc;
+ }
+ if (adc_to_temperature_data[i].adc >= adc &&
+ adc_to_temperature_data[i].adc <= high_adc) {
+ high_temp = adc_to_temperature_data[i].centigrade;
+ high_adc = adc_to_temperature_data[i].adc;
+ }
+ }
+
+ /* Linear approximation between cloest low and high,
+ * which is the weighted average of the two. */
+
+ /* The following equation is correct only when the two are different */
+ if (low_adc == high_adc)
+ return low_temp;
+ if (ARRAY_SIZE(adc_to_temperature_data) < 2)
+ return 20; /* The room temperature */
+ if (low_adc == 0)
+ return high_temp;
+ if (high_adc == USHRT_MAX)
+ return low_temp;
+
+ approximation = low_temp * (adc - low_adc) +
+ high_temp * (high_adc - adc);
+ approximation /= high_adc - low_adc;
+
+ return approximation;
+}
+
+static unsigned short get_adc_value(int channel)
+{
+ struct s5pc110_adc *adc = (struct s5pc110_adc *) S5PC110_ADC_BASE;
+ unsigned short ret = 0;
+ unsigned int reg;
+ int ldonum = 8;
+ char buf[64];
+ unsigned int loop = 0;
+
+ if (mach_is_goni())
+ ldonum = 4;
+ else if (mach_is_geminus())
+ ldonum = 4;
+ else if (mach_is_wmg160())
+ ldonum = 4;
+ else if (mach_is_cypress())
+ ldonum = 8;
+ else if (mach_is_tickertape())
+ ldonum = 8;
+ else if (mach_is_aquila())
+ ldonum = 8;
+ /*
+ else if (mach_is_p1p2())
+ ldonum = 4;
+ */
+
+ sprintf(buf, "pmic ldo %d on", ldonum);
+ run_command(buf, 0);
+
+ writel(channel & 0xF, &adc->adcmux);
+ writel((1 << 14) | (49 << 6), &adc->adccon);
+ writel(1000 & 0xffff, &adc->adcdly);
+ writel(readl(&adc->adccon) | (1 << 16), &adc->adccon); /* 12 bit */
+ udelay(10);
+ writel(readl(&adc->adccon) | (1 << 0), &adc->adccon); /* Enable */
+ udelay(10);
+
+ do {
+ udelay(1);
+ reg = readl(&adc->adccon);
+ } while (!(reg & (1 << 15)) && (loop++ < 1000));
+
+ ret = readl(&adc->adcdat0) & 0xFFF;
+ sprintf(buf, "pmic ldo %d off", ldonum);
+ run_command(buf, 0);
+
+ return ret;
+}
+
+static int adc_get_average_ambient_temperature(void)
+{
+ if (mach_is_goni()) {
+ unsigned short min = USHRT_MAX;
+ unsigned short max = 0;
+ unsigned int sum = 0;
+ unsigned int measured = 0;
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ unsigned short measurement = get_adc_value(6);
+ sum += measurement;
+ measured++;
+ if (min > measurement)
+ min = measurement;
+ if (max < measurement)
+ max = measurement;
+ }
+ if (measured >= 3) {
+ measured -= 2;
+ sum -= min;
+ sum -= max;
+ }
+ sum /= measured;
+ printf("Average Ambient Temperature = %d(ADC=%d)\n",
+ adc_to_temperature_centigrade(sum), sum);
+ return adc_to_temperature_centigrade(sum);
+ }
+
+ return 20; /* 20 Centigrade */
+}
+
+enum temperature_level {
+ _TEMP_OK,
+ _TEMP_OK_HIGH,
+ _TEMP_OK_LOW,
+ _TEMP_TOO_HIGH,
+ _TEMP_TOO_LOW,
+};
+
+static enum temperature_level temperature_check(void)
+{
+ int temp = adc_get_average_ambient_temperature();
+ if (temp < -5)
+ return _TEMP_TOO_LOW;
+ if (temp < 0)
+ return _TEMP_OK_LOW;
+ if (temp > 63)
+ return _TEMP_TOO_HIGH;
+ if (temp > 58)
+ return _TEMP_OK_HIGH;
+ return _TEMP_OK;
+}
+
+extern void lcd_display_clear(void);
+extern int lcd_display_bitmap(ulong bmp_image, int x, int y);
+
+static void charger_en(int enable)
+{
+ /* 0: disable
+ * 600: 600mA
+ * 475: 475mA
+ */
+ unsigned char addr = 0xCC >> 1; /* max8998 */
+ unsigned char val[2];
+
+ if (max8998_probe())
+ return;
+
+ if (!enable) {
+ puts("Disable the charger.\n");
+ i2c_read(addr, 0x0D, 1, val, 1);
+ val[0] &= ~(0x1);
+ val[0] |= 0x1;
+ i2c_write(addr, 0x0D, 1, val, 1);
+ } else {
+ i2c_read(addr, 0x0C, 1, val, 1);
+ val[0] &= ~(0x7 << 0);
+ val[0] &= ~(0x7 << 5);
+ if (enable == 600) {
+ val[0] |= 5; /* 600mA */
+ val[0] |= (3 << 5); /* Stop at 150mA (25%) */
+ } else { /* Assume 475 mA */
+ enable = 475;
+ val[0] |= 2; /* 475mA */
+ val[0] |= (4 << 5); /* Stop at 142.5mA (30%) */
+ }
+ i2c_write(addr, 0x0C, 1, val, 1);
+
+ i2c_read(addr, 0x0D, 1, val, 1);
+ val[0] &= ~(0x1);
+ i2c_write(addr, 0x0D, 1, val, 1);
+ printf("Enable the charger @ %dmA\n", enable);
+ }
+}
+
+void lcd_power_on(unsigned int onoff);
+extern int do_sleep (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern int drv_lcd_init_resume (void);
+
+static void into_charge_mode(void)
+{
+ unsigned int level;
+ int i, j;
+ bmp_image_t *bmp;
+ unsigned long len;
+ ulong bmp_addr[CHARGER_ANIMATION_FRAME];
+ unsigned int reg, wakeup_stat;
+ int charger_speed = 600;
+
+ max8998_clear_interrupt();
+
+ puts("Charge Mode\n");
+ charger_en(charger_speed);
+
+#ifdef CONFIG_S5PC1XXFB
+ init_font();
+
+ /* TODO: write the image-text for the charger */
+
+ level = battery_soc * CHARGER_ANIMATION_FRAME / 100;
+ if (level >= CHARGER_ANIMATION_FRAME)
+ level = CHARGER_ANIMATION_FRAME - 1;
+
+ for (i = 0; i < CHARGER_ANIMATION_FRAME; i++)
+ bmp_addr[i] = (ulong)battery_charging_animation[i];
+
+ lcd_display_clear();
+ for (i = 0; i < 3; i++) {
+ for (j = level; j < CHARGER_ANIMATION_FRAME; j++) {
+ int k;
+
+ bmp = gunzip_bmp(bmp_addr[j], &len);
+ lcd_display_bitmap((ulong)bmp, 140, 202);
+ free(bmp);
+
+ for (k = 0; k < 10; k++) {
+ if (max8998_power_key()) {
+ lcd_display_clear();
+ goto restore_screen;
+ } else if (!max8998_has_ext_power_source()) {
+ lcd_display_clear();
+ goto restore_screen;
+ } else {
+ udelay(100 * 1000);
+ }
+ }
+ }
+ }
+ exit_font();
+
+ /* Disable the display to prevent flickering */
+ /* TODO: how to reenable the display later? */
+ lcd_power_on(0);
+#endif
+
+ do {
+ struct s5pc110_rtc *rtc = (struct s5pc110_rtc *)S5PC110_RTC_BASE;
+ unsigned int org, org_ip3;
+ enum temperature_level previous_state = _TEMP_OK;
+
+ empty_device_info_buffer();
+ if (max8998_power_key())
+ break;
+ else if (!max8998_has_ext_power_source())
+ break;
+
+ /* Enable RTC, SYSTIMER, ADC at CLKGATE IP3 */
+ org_ip3 = readl(0xE010046C);
+ writel(org_ip3 | (1 << 15) | (1 << 16) | (1 << 24), 0xE010046C);
+
+ reg = org = readl(&rtc->rtccon);
+ reg |= (1 << 0);
+ writel(reg, &rtc->rtccon);
+
+ reg = readl(&rtc->rtccon);
+ writel(reg | (1 << 3), &rtc->rtccon);
+ udelay(10);
+ writel(reg & ~(1 << 3), &rtc->rtccon);
+ udelay(10);
+
+ reg = readl(&rtc->rtccon);
+ reg &= ~((1 << 8) | (0xF << 4));
+ reg |= (1 << 8) | (0xD << 4); /* D: 4 Hz, 9: 64 Hz */
+ writel(reg, &rtc->rtccon);
+
+ reg = 15 * 4 - 1; /* 15 sec */
+ writel(reg, &rtc->ticcnt);
+
+ /* EVT0: sleep 1, EVT1: sleep */
+ if (cpu_is_s5pc110()) {
+ char *name = "dummy";
+ char *usage = "N/A";
+ char *help = NULL;
+ cmd_tbl_t ctt;
+ ctt.name = name;
+ ctt.usage = usage;
+ ctt.help = help;
+
+ if (s5pc1xx_get_cpu_rev() == 0) {
+ char *argv[] = {"1", "1"};
+ wakeup_stat = do_sleep(&ctt, 0, 2, argv);
+ } else {
+ char *argv[] = {"0", "0"};
+ wakeup_stat = do_sleep(&ctt, 0, 1, argv);
+ }
+ } else {
+ puts("\n\n\nERROR: this is not S5PC110.\n\n\n");
+ return;
+ }
+
+ /* Check TEMP HIGH/LOW */
+ switch (temperature_check()) {
+ case _TEMP_OK:
+ charger_en(charger_speed);
+ previous_state = _TEMP_OK;
+ break;
+ case _TEMP_TOO_LOW:
+ charger_en(0);
+ previous_state = _TEMP_TOO_LOW;
+ break;
+ case _TEMP_TOO_HIGH:
+ charger_en(0);
+ previous_state = _TEMP_TOO_HIGH;
+ break;
+ case _TEMP_OK_LOW:
+ if (previous_state == _TEMP_TOO_LOW) {
+ charger_en(0);
+ } else {
+ charger_en(charger_speed);
+ previous_state = _TEMP_OK;
+ }
+ break;
+ case _TEMP_OK_HIGH:
+ if (previous_state == _TEMP_TOO_HIGH) {
+ charger_en(0);
+ } else {
+ charger_en(charger_speed);
+ previous_state = _TEMP_OK;
+ }
+ break;
+ }
+
+ writel(org, &rtc->rtccon);
+ writel(org_ip3, 0xE010046C);
+
+ } while (wakeup_stat == 0x04); /* RTC TICK */
+
+#ifdef CONFIG_S5PC1XXFB
+restore_screen:
+ /* TODO: Reenable logo display (not working yet) */
+ lcd_power_on(1);
+ drv_lcd_init_resume();
+#endif
+}
+
+#define S5PC110_RST_STAT 0xE010A000
+
+#define SWRESET (1 << 3)
+#define WDTRESET (1 << 2)
+#define WARMRESET (1 << 1)
+#define EXTRESET (1 << 0)
+
+static int get_reset_status(void)
+{
+ return readl(S5PC110_RST_STAT) & 0xf;
+}
+
+static int fsa9480_probe(void)
+{
+ unsigned char addr = 0x25;
+
+ if (cpu_is_s5pc100())
+ return 1;
+
+ if (board_is_limo_real()) {
+ if (hwrevision(0) || hwrevision(1))
+ return 1;
+ }
+
+ i2c_set_bus_num(I2C_PMIC);
+
+ if (mach_is_goni()) {
+ i2c_set_bus_num(I2C_GPIO6);
+ } else if (mach_is_cypress()) {
+ i2c_set_bus_num(I2C_GPIO6);
+ } else if (mach_is_geminus()) {
+ if (hwrevision(1))
+ i2c_set_bus_num(I2C_GPIO6);
+ } else if (mach_is_wmg160()) {
+ i2c_set_bus_num(I2C_GPIO6);
+ }
+
+ if (i2c_probe(addr)) {
+ puts("Can't found fsa9480\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static void check_micro_usb(int intr)
+{
+ unsigned char addr;
+ unsigned char val[2];
+ static int started_charging_once = 0;
+ char *path;
+
+ if (fsa9480_probe())
+ return;
+
+ addr = 0x25; /* fsa9480 */
+
+ /* Clear Interrupt */
+ if (intr) {
+ i2c_read(addr, 0x03, 1, val, 2);
+ return;
+ }
+
+ /* Read Device Type 1 */
+ i2c_read(addr, 0x0a, 1, val, 1);
+
+#define FSA_DEV1_CHARGER (1 << 6)
+#define FSA_DEV1_UART (1 << 3)
+#define FSA_DEV1_USB (1 << 2)
+#define FSA_DEV2_JIG_USB_OFF (1 << 1)
+#define FSA_DEV2_JIG_USB_ON (1 << 0)
+
+ /*
+ * If USB, use default 475mA
+ * If Charger, use 600mA and go to charge mode
+ */
+ if ((val[0] & FSA_DEV1_CHARGER) && !started_charging_once) {
+ started_charging_once = 1;
+
+ /* If it's full, do not charge. */
+ if (battery_soc < 100)
+ into_charge_mode();
+ else
+ charger_en(0);
+ } else if (val[0] & FSA_DEV1_USB) {
+ if (battery_soc < 100)
+ charger_en(475); /* enable charger and keep booting */
+ else
+ charger_en(0);
+ }
+
+ /* If reset status is watchdog reset then skip it */
+ if (!(get_reset_status() & WDTRESET)) {
+ /* If Factory Mode is Boot ON-USB, go to download mode */
+ i2c_read(addr, 0x07, 1, val, 1);
+
+#define FSA_ADC_FAC_USB_OFF 0x18
+#define FSA_ADC_FAC_USB_ON 0x19
+#define FSA_ADC_FAC_UART 0x1d
+
+ if (val[0] == FSA_ADC_FAC_USB_ON ||
+ val[0] == FSA_ADC_FAC_USB_OFF)
+ setenv("bootcmd", "usbdown");
+ }
+
+ path = getenv("usb");
+
+ if (!strncmp(path, "cp", 2))
+ run_command("microusb cp", 0);
+}
+
+static void micro_usb_switch(int path)
+{
+ unsigned char addr;
+ unsigned char val[2];
+
+ if (fsa9480_probe())
+ return;
+
+ addr = 0x25; /* fsa9480 */
+
+ if (path)
+ val[0] = 0x90; /* VAUDIO */
+ else
+ val[0] = (1 << 5) | (1 << 2); /* DHOST */
+
+ i2c_write(addr, 0x13, 1, val, 1); /* MANSW1 */
+
+ i2c_read(addr, 0x2, 1, val, 1);
+ val[0] &= ~(1 << 2); /* Manual switching */
+ i2c_write(addr, 0x2, 1, val, 1);
+}
+
+#define MAX8998_REG_ONOFF1 0x11
+#define MAX8998_REG_ONOFF2 0x12
+#define MAX8998_REG_ONOFF3 0x13
+#define MAX8998_REG_ONOFF4 0x14
+#define MAX8998_REG_LDO7 0x21
+#define MAX8998_REG_LDO17 0x29
+/* ONOFF1 */
+#define MAX8998_LDO3 (1 << 2)
+/* ONOFF2 */
+#define MAX8998_LDO6 (1 << 7)
+#define MAX8998_LDO7 (1 << 6)
+#define MAX8998_LDO8 (1 << 5)
+#define MAX8998_LDO9 (1 << 4)
+#define MAX8998_LDO10 (1 << 3)
+#define MAX8998_LDO11 (1 << 2)
+#define MAX8998_LDO12 (1 << 1)
+#define MAX8998_LDO13 (1 << 0)
+/* ONOFF3 */
+#define MAX8998_LDO14 (1 << 7)
+#define MAX8998_LDO15 (1 << 6)
+#define MAX8998_LDO16 (1 << 5)
+#define MAX8998_LDO17 (1 << 4)
+
+
+static void init_pmic(void)
+{
+ unsigned char addr;
+ unsigned char val[2];
+
+ if (cpu_is_s5pc100())
+ return;
+
+ addr = 0xCC >> 1; /* max8998 */
+ if (max8998_probe())
+ return;
+
+ /* ONOFF1 */
+ i2c_read(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+ val[0] &= ~MAX8998_LDO3;
+ i2c_write(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+
+ /* ONOFF2 */
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ /*
+ * Disable LDO10(VPLL_1.1V), LDO11(CAM_IO_2.8V),
+ * LDO12(CAM_ISP_1.2V), LDO13(CAM_A_2.8V)
+ */
+ val[0] &= ~(MAX8998_LDO10 | MAX8998_LDO11 |
+ MAX8998_LDO12 | MAX8998_LDO13);
+
+ if (mach_is_goni())
+ val[0] |= MAX8998_LDO7; /* LDO7: VLCD_1.8V */
+
+ i2c_write(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ /* ONOFF3 */
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ /*
+ * Disable LDO14(CAM_CIF_1.8), LDO15(CAM_AF_3.3V),
+ * LDO16(VMIPI_1.8V), LDO17(CAM_8M_1.8V)
+ */
+ val[0] &= ~(MAX8998_LDO14 | MAX8998_LDO15 |
+ MAX8998_LDO16 | MAX8998_LDO17);
+
+ if (mach_is_goni())
+ val[0] |= MAX8998_LDO17; /* LDO17: VCC_3.0V_LCD */
+
+ i2c_write(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+}
+
+static void setup_power_down_mode_registers(void)
+{
+ struct s5pc110_gpio *gpio = (struct s5pc110_gpio *)S5PC110_GPIO_BASE;
+ struct s5p_gpio_bank *bank;
+ struct gpio_powermode *p;
+ int n_p;
+ struct gpio_external *ge;
+ int n_ge;
+ struct s5pc1xx_gpio_item *mr;
+ int n_mr;
+ int i;
+
+ if (cpu_is_s5pc100())
+ return;
+
+ /* Only Limo real and kessler supports worked for sleep currnet */
+ if (mach_is_aquila()) {
+ if (board_is_limo_real())
+ /* Support */;
+ else
+ return;
+ } else if (mach_is_goni()) {
+ /* Support */;
+ } else if (mach_is_geminus()) {
+ /* Support */;
+ } else {
+ return;
+ }
+
+ if (mach_is_aquila()) {
+ /* Aquila rev 0.8 or lower */
+ p = aquila_powerdown_modes;
+ ge = aquila_external_powerdown_modes;
+ mr = aquila_mirror_powerdown_mode;
+ n_p = ARRAY_SIZE(aquila_powerdown_modes);
+ n_ge = ARRAY_SIZE(aquila_external_powerdown_modes);
+ n_mr = ARRAY_SIZE(aquila_mirror_powerdown_mode);
+ } else if (mach_is_goni()) {
+ /* Aquila rev 0.9 */
+ p = kessler_powerdown_modes;
+ ge = kessler_external_powerdown_modes;
+ mr = kessler_mirror_powerdown_mode;
+ n_p = ARRAY_SIZE(kessler_powerdown_modes);
+ n_ge = ARRAY_SIZE(kessler_external_powerdown_modes);
+ n_mr = ARRAY_SIZE(kessler_mirror_powerdown_mode);
+ } else if (mach_is_geminus()) {
+ if (hwrevision(1)) {
+ /* Same as Aquila rev 0.9 */
+#if 0
+ p = kessler_powerdown_modes;
+ ge = kessler_external_powerdown_modes;
+ mr = kessler_mirror_powerdown_mode;
+ n_p = ARRAY_SIZE(kessler_powerdown_modes);
+ n_ge = ARRAY_SIZE(kessler_external_powerdown_modes);
+ n_mr = ARRAY_SIZE(kessler_mirror_powerdown_mode);
+#else
+ p = aquila_powerdown_modes;
+ ge = aquila_external_powerdown_modes;
+ mr = aquila_mirror_powerdown_mode;
+ n_p = ARRAY_SIZE(aquila_powerdown_modes);
+ n_ge = ARRAY_SIZE(aquila_external_powerdown_modes);
+ n_mr = ARRAY_SIZE(aquila_mirror_powerdown_mode);
+#endif
+ } else if (hwrevision(0)) {
+ /* Same as Aquila rev 0.8 or lower */
+ p = aquila_powerdown_modes;
+ ge = aquila_external_powerdown_modes;
+ mr = aquila_mirror_powerdown_mode;
+ n_p = ARRAY_SIZE(aquila_powerdown_modes);
+ n_ge = ARRAY_SIZE(aquila_external_powerdown_modes);
+ n_mr = ARRAY_SIZE(aquila_mirror_powerdown_mode);
+ } else {
+ return; /* Not supported */
+ }
+ }
+
+ bank = &gpio->gpio_a0;
+
+ for (i = 0; i < n_p; i++, p++, bank++) {
+ writel(p->conpdn, &bank->pdn_con);
+ writel(p->pudpdn, &bank->pdn_pull);
+ }
+ /* M299 */
+ writel(0xff0022b0, (unsigned int *)0xF0000000);
+ writel(0xff0022b0, (unsigned int *)0xF1400000);
+
+ bank = &gpio->gpio_h0;
+
+ for (i = 0; i < n_ge; i++) {
+ writel(ge->con, &bank->con);
+ writel(ge->dat, &bank->dat);
+ writel(ge->pud, &bank->pull);
+
+ bank++;
+ ge++;
+ }
+
+ for (i = 0; i < n_mr; i++) {
+ unsigned int reg = readl(&mr->bank->pdn_con);
+ reg &= ~(0x3 << (mr->number << 1));
+ if (readl(&mr->bank->dat) & (1 << mr->number))
+ reg |= 0x1 << (mr->number << 1);
+ writel(reg, &mr->bank->pdn_con);
+ mr++;
+ }
+}
+
+#ifdef CONFIG_LCD
+#include "../../../drivers/video/s5p-spi.h"
+
+extern void s6e63m0_set_platform_data(struct spi_platform_data *pd);
+extern void s6d16a0x_set_platform_data(struct spi_platform_data *pd);
+extern void ld9040_set_platform_data(struct spi_platform_data *pd);
+
+struct spi_platform_data spi_pd;
+
+struct s5pc110_gpio *gpio_base = (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
+
+void lcd_cfg_gpio(void)
+{
+ unsigned int i, f3_end = 4;
+
+ for (i = 0; i < 8; i++) {
+ /* set GPF0,1,2[0:7] for RGB Interface and Data lines (32bit) */
+ gpio_cfg_pin(&gpio_base->gpio_f0, i, GPIO_FUNC(2));
+ gpio_cfg_pin(&gpio_base->gpio_f1, i, GPIO_FUNC(2));
+ gpio_cfg_pin(&gpio_base->gpio_f2, i, GPIO_FUNC(2));
+ /* pull-up/down disable */
+ gpio_set_pull(&gpio_base->gpio_f0, i, GPIO_PULL_NONE);
+ gpio_set_pull(&gpio_base->gpio_f1, i, GPIO_PULL_NONE);
+ gpio_set_pull(&gpio_base->gpio_f2, i, GPIO_PULL_NONE);
+
+ /* drive strength to max (24bit) */
+ gpio_set_drv(&gpio_base->gpio_f0, i, GPIO_DRV_4X);
+ gpio_set_rate(&gpio_base->gpio_f0, i, GPIO_DRV_SLOW);
+ gpio_set_drv(&gpio_base->gpio_f1, i, GPIO_DRV_4X);
+ gpio_set_rate(&gpio_base->gpio_f1, i, GPIO_DRV_SLOW);
+ gpio_set_drv(&gpio_base->gpio_f2, i, GPIO_DRV_4X);
+ gpio_set_rate(&gpio_base->gpio_f2, i, GPIO_DRV_SLOW);
+ }
+
+ /* set DISPLAY_DE_B pin for dual rgb mode. */
+ if (board_is_media())
+ f3_end = 5;
+
+ for (i = 0; i < f3_end; i++) {
+ /* set GPF3[0:3] for RGB Interface and Data lines (32bit) */
+ gpio_cfg_pin(&gpio_base->gpio_f3, i, GPIO_PULL_UP);
+ /* pull-up/down disable */
+ gpio_set_pull(&gpio_base->gpio_f3, i, GPIO_PULL_NONE);
+ /* drive strength to max (24bit) */
+ gpio_set_drv(&gpio_base->gpio_f3, i, GPIO_DRV_4X);
+ gpio_set_rate(&gpio_base->gpio_f3, i, GPIO_DRV_SLOW);
+ }
+ /* display output path selection (only [1:0] valid) */
+ writel(0x2, 0xE0107008);
+
+ /* gpio pad configuration for LCD reset. */
+ gpio_cfg_pin(&gpio_base->gpio_mp0_5, 5, GPIO_OUTPUT);
+
+ /* gpio pad configuration for LCD ON. */
+ gpio_cfg_pin(&gpio_base->gpio_j1, 3, GPIO_OUTPUT);
+
+ /* LCD_BACKLIGHT_EN */
+ if (mach_is_geminus())
+ gpio_cfg_pin(&gpio_base->gpio_mp0_5, 0, GPIO_OUTPUT);
+ if (board_is_sdk() && hwrevision(0)) {
+ gpio_cfg_pin(&gpio_base->gpio_mp0_4, 4, GPIO_OUTPUT);
+ gpio_direction_output(&gpio_base->gpio_mp0_4, 4, 0);
+ }
+
+ /*
+ * gpio pad configuration for
+ * DISPLAY_CS, DISPLAY_CLK, DISPLAY_SO, DISPLAY_SI.
+ */
+ gpio_cfg_pin(&gpio_base->gpio_mp0_1, 1, GPIO_OUTPUT);
+ gpio_cfg_pin(&gpio_base->gpio_mp0_4, 1, GPIO_OUTPUT);
+ gpio_cfg_pin(&gpio_base->gpio_mp0_4, 2, GPIO_INPUT);
+ gpio_cfg_pin(&gpio_base->gpio_mp0_4, 3, GPIO_OUTPUT);
+
+ if (mach_is_aquila() || mach_is_goni()) {
+ spi_pd.cs_bank = &gpio_base->gpio_mp0_1;
+ spi_pd.cs_num = 1;
+ spi_pd.clk_bank = &gpio_base->gpio_mp0_4;
+ spi_pd.clk_num = 1;
+ spi_pd.si_bank = &gpio_base->gpio_mp0_4;
+ spi_pd.si_num = 3;
+ spi_pd.so_bank = &gpio_base->gpio_mp0_4;
+ spi_pd.so_num = 2;
+
+ if (board_is_sdk() && hwrevision(0))
+ s6d16a0x_set_platform_data(&spi_pd);
+ else if (board_is_sdk() && (hwrevision(3) || hwrevision(6)))
+ ld9040_set_platform_data(&spi_pd);
+ else {
+ s6e63m0_set_platform_data(&spi_pd);
+ if (board_is_media())
+ spi_pd.set_rev = 1;
+ }
+ }
+
+ if (mach_is_cypress()) {
+#if 0 /* universal cypress */
+ /* FLCD_CS */
+ gpio_cfg_pin(&gpio_base->gpio_mp0_1, 0, GPIO_OUTPUT);
+#endif
+ /* FLCD_CS_S */
+ gpio_cfg_pin(&gpio_base->gpio_mp0_5, 1, GPIO_OUTPUT);
+ /* FLCD_CLK */
+ gpio_cfg_pin(&gpio_base->gpio_mp0_4, 0, GPIO_OUTPUT);
+ /* FLCD_SDI */
+ gpio_cfg_pin(&gpio_base->gpio_mp0_4, 2, GPIO_OUTPUT);
+ /* FLCD_RST_S */
+ gpio_cfg_pin(&gpio_base->gpio_mp0_4, 5, GPIO_OUTPUT);
+ /* FLCD_ON_S */
+ gpio_cfg_pin(&gpio_base->gpio_g2, 2, GPIO_OUTPUT);
+#if 0 /* universal cypress */
+ pd_cs.bank = &gpio_base->gpio_mp0_1;
+ pd_cs.num = 0;
+#endif
+ spi_pd.cs_bank = &gpio_base->gpio_mp0_5;
+ spi_pd.cs_num = 1;
+ spi_pd.clk_bank = &gpio_base->gpio_mp0_4;
+ spi_pd.clk_num = 0;
+ spi_pd.si_bank = &gpio_base->gpio_mp0_4;
+ spi_pd.si_num = 2;
+
+ spi_pd.set_rev = 1;
+
+ /* these data would be sent to s6e63m0 lcd panel driver. */
+ s6e63m0_set_platform_data(&spi_pd);
+ }
+
+ return;
+}
+
+#define SWRST_REG 0x00
+#define LEDCON_REG 0x01
+#define LED_CUR_SET_REG 0x03
+#define LED_CUR_TR_REG 0x08
+
+#define SWRST 0x01
+#define NORMAL_MODE 0x09
+#define CUR_SET 0x63
+#define TR_SET 0x00
+void backlight_on(unsigned int onoff)
+{
+
+ unsigned char addr;
+ unsigned char val[2];
+ struct s5pc110_gpio *gpio = (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
+
+ if (onoff) {
+ if (mach_is_geminus())
+ gpio_set_value(&gpio->gpio_mp0_5, 0, 1);
+ } else {
+ if (mach_is_geminus())
+ gpio_set_value(&gpio->gpio_mp0_5, 0, 0);
+ }
+
+ if (mach_is_goni() && board_is_sdk() && hwrevision(0)) {
+ gpio_set_value(&gpio->gpio_mp0_4, 4, 1);
+ udelay(6);
+
+ i2c_set_bus_num(I2C_GPIO5);
+
+ addr = 0x76;
+ if (i2c_probe(addr)) {
+ if (i2c_probe(addr)) {
+ puts("Can't found s6d16a0x backlight i2c\n");
+ return;
+ }
+ }
+ val[0] = SWRST;
+ i2c_write(addr, SWRST_REG, 1, val, 1);
+ /* NORMAL MODE */
+ val[0] = CUR_SET;
+ i2c_write(addr, LED_CUR_SET_REG, 1, val, 1);
+ val[0] = TR_SET;
+ i2c_write(addr, LED_CUR_TR_REG, 1, val, 1);
+ val[0] = NORMAL_MODE;
+ i2c_write(addr, LEDCON_REG, 1, val, 1);
+ udelay(5000);
+ }
+}
+
+void reset_lcd(void)
+{
+ struct s5pc110_gpio *gpio = (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
+
+ if (mach_is_aquila() || mach_is_goni() || mach_is_geminus()) {
+ gpio_set_value(&gpio->gpio_mp0_5, 5, 1);
+ if (board_is_sdk() && (hwrevision(3) || hwrevision(6))) {
+ udelay(10000);
+ gpio_set_value(&gpio->gpio_mp0_5, 5, 0);
+ udelay(10000);
+ gpio_set_value(&gpio->gpio_mp0_5, 5, 1);
+ udelay(100);
+ }
+ }
+ if (mach_is_cypress())
+ gpio_set_value(&gpio->gpio_mp0_4, 5, 1);
+}
+
+void lcd_power_on(unsigned int onoff)
+{
+ struct s5pc110_gpio *gpio = (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
+ if (onoff) {
+ /* TSP_LDO_ON */
+ if (mach_is_aquila() || mach_is_geminus())
+ gpio_set_value(&gpio->gpio_j1, 3, 1);
+
+ if (mach_is_cypress())
+ gpio_set_value(&gpio->gpio_g2, 2, 1);
+
+ if (mach_is_goni()) {
+ unsigned char addr;
+ unsigned char val[2];
+ unsigned char val2[2];
+
+ gpio_set_value(&gpio->gpio_j1, 3, 1);
+
+ addr = 0xCC >> 1; /* max8998 */
+ if (max8998_probe())
+ return;
+
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ val[0] &= ~(MAX8998_LDO17);
+ val[0] |= MAX8998_LDO17; /* LDO17: VCC_3.0V_LCD */
+ i2c_write(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ val[0] |= MAX8998_LDO17;
+ val2[0] = 0xE;
+ i2c_write(addr, MAX8998_REG_LDO17, 1, val2, 1);
+ i2c_write(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ val[0] |= MAX8998_LDO7;
+ val2[0] = 0x2;
+ i2c_write(addr, MAX8998_REG_LDO7, 1, val2, 1);
+ i2c_write(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ }
+ } else {
+ if (mach_is_aquila() || mach_is_geminus())
+ gpio_set_value(&gpio->gpio_j1, 3, 0);
+
+ if (mach_is_cypress())
+ gpio_set_value(&gpio->gpio_g2, 2, 0);
+
+ if (mach_is_goni()) {
+ unsigned char addr;
+ unsigned char val[2];
+
+ gpio_set_value(&gpio->gpio_j1, 3, 0);
+
+ addr = 0xCC >> 1; /* max8998 */
+ if (max8998_probe())
+ return;
+
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ val[0] &= ~(MAX8998_LDO7);
+ i2c_write(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ val[0] &= ~(MAX8998_LDO17);
+ i2c_write(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ }
+ }
+}
+
+extern void s6e63m0_cfg_ldo(void);
+extern void s6e63m0_enable_ldo(unsigned int onoff);
+extern void s6d16a0x_cfg_ldo(void);
+extern void s6d16a0x_enable_ldo(unsigned int onoff);
+extern void ld9040_cfg_ldo(void);
+extern void ld9040_enable_ldo(unsigned int onoff);
+
+int s5p_no_lcd_support(void)
+{
+ if (mach_is_wmg160())
+ return 1;
+ return 0;
+}
+
+void init_panel_info(vidinfo_t *vid)
+{
+ vid->cfg_gpio = NULL;
+ vid->reset_lcd = NULL;
+ vid->backlight_on = NULL;
+ vid->lcd_power_on = NULL;
+
+ vid->cfg_ldo = NULL;
+ vid->enable_ldo = NULL;
+
+ vid->init_delay = 0;
+ vid->reset_delay = 0;
+ vid->power_on_delay = 0;
+
+ vid->vl_freq = 60;
+ vid->vl_col = 480;
+ vid->vl_row = 800;
+ vid->vl_width = 480;
+ vid->vl_height = 800;
+
+ vid->dual_lcd_enabled = 0;
+
+ if (board_is_media()) {
+ vid->vl_col = 960;
+ vid->vl_row = 800;
+ vid->vl_width = 960;
+ vid->vl_height = 800;
+
+ /* enable dual lcd mode. */
+ vid->dual_lcd_enabled = 1;
+ }
+
+ vid->vl_clkp = CONFIG_SYS_HIGH;
+ vid->vl_hsp = CONFIG_SYS_LOW;
+ vid->vl_vsp = CONFIG_SYS_LOW;
+ vid->vl_dp = CONFIG_SYS_HIGH;
+ vid->vl_bpix = 32;
+
+ /* S6E63M0 LCD Panel */
+ vid->vl_hspw = 2;
+ vid->vl_hbpd = 16;
+ vid->vl_hfpd = 16;
+
+ vid->vl_vspw = 2;
+ vid->vl_vbpd = 3;
+ vid->vl_vfpd = 28;
+
+ if (mach_is_aquila() || mach_is_goni()
+ || mach_is_cypress()) {
+ vid->cfg_gpio = lcd_cfg_gpio;
+ vid->reset_lcd = reset_lcd;
+ vid->backlight_on = backlight_on;
+ vid->lcd_power_on = lcd_power_on;
+ vid->cfg_ldo = s6e63m0_cfg_ldo;
+ vid->enable_ldo = s6e63m0_enable_ldo;
+
+ vid->init_delay = 25000;
+ vid->reset_delay = 120000;
+ }
+
+ if (board_is_sdk() && hwrevision(0)) {
+ vid->vl_freq = 100;
+ vid->vl_col = 320;
+ vid->vl_row = 480;
+ vid->vl_width = 320;
+ vid->vl_height = 480;
+
+ vid->vl_clkp = CONFIG_SYS_HIGH;
+ vid->vl_hsp = CONFIG_SYS_HIGH;
+ vid->vl_vsp = CONFIG_SYS_HIGH;
+ vid->vl_dp = CONFIG_SYS_LOW;
+ vid->vl_bpix = 32;
+
+ /* disable dual lcd mode. */
+ vid->dual_lcd_enabled = 0;
+
+ /* S6D16A0X LCD Panel */
+ vid->vl_hspw = 16;
+ vid->vl_hbpd = 24;
+ vid->vl_hfpd = 16;
+
+ vid->vl_vspw = 2;
+ vid->vl_vbpd = 2;
+ vid->vl_vfpd = 4;
+
+ vid->cfg_gpio = lcd_cfg_gpio;
+ vid->backlight_on = backlight_on;
+ vid->lcd_power_on = lcd_power_on;
+ vid->reset_lcd = reset_lcd;
+ vid->cfg_ldo = s6d16a0x_cfg_ldo;
+ vid->enable_ldo = s6d16a0x_enable_ldo;
+
+ vid->init_delay = 10000;
+ vid->power_on_delay = 10000;
+ vid->reset_delay = 1000;
+
+ }
+ if (board_is_sdk() && (hwrevision(3) || hwrevision(6))) {
+ vid->vl_freq = 60;
+ vid->vl_col = 480;
+ vid->vl_row = 800;
+ vid->vl_width = 480;
+ vid->vl_height = 800;
+ vid->vl_clkp = CONFIG_SYS_HIGH;
+ vid->vl_hsp = CONFIG_SYS_HIGH;
+ vid->vl_vsp = CONFIG_SYS_HIGH;
+ vid->vl_dp = CONFIG_SYS_HIGH;
+
+ vid->vl_bpix = 32;
+ /* disable dual lcd mode. */
+ vid->dual_lcd_enabled = 0;
+
+ /* LD9040 LCD Panel */
+ vid->vl_hspw = 2;
+ vid->vl_hbpd = 16;
+ vid->vl_hfpd = 16;
+
+ vid->vl_vspw = 2;
+ vid->vl_vbpd = 3;
+ vid->vl_vfpd = 28;
+
+ vid->cfg_gpio = lcd_cfg_gpio;
+ vid->backlight_on = NULL;
+ vid->lcd_power_on = lcd_power_on;
+ vid->reset_lcd = reset_lcd;
+ vid->cfg_ldo = ld9040_cfg_ldo;
+ vid->enable_ldo = ld9040_enable_ldo;
+
+ vid->init_delay = 0;
+ vid->power_on_delay = 30000;
+ vid->reset_delay = 20000;
+ }
+ if (mach_is_geminus()) {
+ vid->vl_freq = 60;
+ vid->vl_col = 1024,
+ vid->vl_row = 600,
+ vid->vl_width = 1024,
+ vid->vl_height = 600,
+ vid->vl_clkp = CONFIG_SYS_LOW,
+ vid->vl_hsp = CONFIG_SYS_HIGH,
+ vid->vl_vsp = CONFIG_SYS_HIGH,
+ vid->vl_dp = CONFIG_SYS_LOW,
+ vid->vl_bpix = 32,
+
+ vid->vl_hspw = 32,
+ vid->vl_hfpd = 48,
+ vid->vl_hbpd = 80,
+
+ vid->vl_vspw = 1,
+ vid->vl_vfpd = 3,
+ vid->vl_vbpd = 4,
+
+ vid->cfg_gpio = lcd_cfg_gpio;
+ vid->reset_lcd = reset_lcd;
+ vid->backlight_on = backlight_on;
+ vid->lcd_power_on = lcd_power_on;
+ }
+#if 0
+ vid->vl_freq = 60;
+ vid->vl_col = 480,
+ vid->vl_row = 800,
+ vid->vl_width = 480,
+ vid->vl_height = 800,
+ vid->vl_clkp = CONFIG_SYS_HIGH,
+ vid->vl_hsp = CONFIG_SYS_LOW,
+ vid->vl_vsp = CONFIG_SYS_LOW,
+ vid->vl_dp = CONFIG_SYS_HIGH,
+ vid->vl_bpix = 32,
+
+ /* tl2796 panel. */
+ vid->vl_hpw = 4,
+ vid->vl_blw = 8,
+ vid->vl_elw = 8,
+
+ vid->vl_vpw = 4,
+ vid->vl_bfw = 8,
+ vid->vl_efw = 8,
+#endif
+#if 0
+ vid->vl_freq = 60;
+ vid->vl_col = 1024,
+ vid->vl_row = 600,
+ vid->vl_width = 1024,
+ vid->vl_height = 600,
+ vid->vl_clkp = CONFIG_SYS_HIGH,
+ vid->vl_hsp = CONFIG_SYS_HIGH,
+ vid->vl_vsp = CONFIG_SYS_HIGH,
+ vid->vl_dp = CONFIG_SYS_LOW,
+ vid->vl_bpix = 32,
+
+ /* AMS701KA AMOLED Panel. */
+ vid->vl_hpw = 30,
+ vid->vl_blw = 114,
+ vid->vl_elw = 48,
+
+ vid->vl_vpw = 2,
+ vid->vl_bfw = 6,
+ vid->vl_efw = 8,
+#endif
+}
+#endif
+
+static void setup_meminfo(void)
+{
+ char meminfo[64] = {0, };
+ int count = 0, size, real;
+
+ size = gd->bd->bi_dram[0].size >> 20;
+ count += sprintf(meminfo + count, "mem=%dM", size);
+
+ /* Each Chip Select can't exceed the 256MiB */
+ size = gd->bd->bi_dram[1].size >> 20;
+ real = min(size, 256);
+ count += sprintf(meminfo + count, " mem=%dM@0x%x",
+ real, (unsigned int)gd->bd->bi_dram[1].start);
+
+ size -= real;
+ if (size > 0) {
+ count += sprintf(meminfo + count, " mem=%dM@0x%x", size,
+ (unsigned int)gd->bd->bi_dram[1].start + (real << 20));
+ }
+
+ setenv("meminfo", meminfo);
+}
+
+int misc_init_r(void)
+{
+#ifdef CONFIG_LCD
+ /* It should be located at first */
+ lcd_is_enabled = 0;
+
+ if (mach_is_aquila() || mach_is_goni()) {
+ if (board_is_sdk() && hwrevision(0))
+ setenv("lcdinfo", "lcd=s6d16a0x");
+ else if (board_is_sdk() && (hwrevision(3) || hwrevision(6)))
+ setenv("lcdinfo", "lcd=ld9040");
+ else if (board_is_media())
+ setenv("lcdinfo", "lcd=s6e63m0");
+ else
+ setenv("lcdinfo", "lcd=s6e63m0");
+ }
+ if (mach_is_geminus())
+ setenv("lcdinfo", "lcd=lms480jc01");
+ if (mach_is_cypress())
+ setenv("lcdinfo", "lcd=s6e63m0");
+#endif
+ setup_meminfo();
+
+ show_hw_revision();
+
+ /* Set proper PMIC pins */
+ pmic_pin_init();
+
+ /* Check auto burning */
+ check_auto_burn();
+
+ /* To power up I2C2 */
+ enable_ldos();
+
+ /* Enable T-Flash at Limo Real or Limo Universal */
+ enable_t_flash();
+
+ /* Setup Limo Real board GPIOs */
+ setup_limo_real_gpios();
+
+ /* Setup Media board GPIOs */
+ setup_media_gpios();
+
+ /* To usbdown automatically */
+ check_keypad();
+
+ /* check max8998 */
+ init_pmic();
+
+#ifdef CONFIG_S5PC1XXFB
+ display_device_info();
+#endif
+
+ setup_power_down_mode_registers();
+
+ /* check max17040 */
+ check_battery(0);
+
+ /* check fsa9480 */
+ check_micro_usb(0);
+
+ return 0;
+}
+#endif
+
+int board_init(void)
+{
+ /* Set Initial global variables */
+ s5pc110_gpio = (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
+
+ gd->bd->bi_arch_number = MACH_TYPE_AQUILA;
+ gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
+
+#ifdef CONFIG_LCD
+ /*
+ * set reserved memory region for framebuffer.
+ *
+ * this region wouldn't be rewrited by kernel so
+ * could avoid nosie screen filled by garbages
+ * after hibernation resume has been completed.
+ */
+ gd->fb_base = CONFIG_FB_RESERVED_MEM;
+#endif
+
+ /* Check H/W Revision */
+ check_hw_revision();
+
+ return 0;
+}
+
+int dram_init(void)
+{
+ unsigned int base, memconfig0, size;
+ unsigned int memconfig1, sz = 0;
+ int mem_3g = 0;
+
+ if (cpu_is_s5pc100()) {
+ /* In mem setup, we swap the bank. So below size is correct */
+ gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+ gd->bd->bi_dram[0].size = PHYS_SDRAM_2_SIZE;
+ gd->bd->bi_dram[1].start = S5PC100_PHYS_SDRAM_2;
+ size = 128;
+ } else {
+ /* In S5PC110, we can't swap the DMC0/1 */
+ gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+ gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
+
+ base = S5PC110_DMC1_BASE;
+ /* DMC configuration */
+ memconfig0 = readl(base + MEMCONFIG0_OFFSET);
+ gd->bd->bi_dram[1].start = memconfig0 & 0xFF000000;
+
+ size = (memconfig0 >> 16) & 0xFF;
+ size = ((unsigned char) ~size) + 1;
+
+ /*
+ * (0x07 + 1) * 16 = 128 MiB
+ * (0x0f + 1) * 16 = 256 MiB
+ */
+ size = size << 4;
+
+ /*
+ * Aquila Rev0.5 4G3G1G
+ * Aquila Rev0.8 4G3G1G
+ * Aquila Rev0.9 4G3G1G
+ * Limo SDK Rev 0.2 4G3G1G
+ * Limo SDK Rev 0.3 4G3G1G
+ * Limo SDK Rev 0.4 4G3G1G
+ * WMG160 Rev 0.7 4G3G1G
+ */
+ if (mach_is_aquila() || mach_is_goni()) {
+ if ((!board_is_sdk() && (hwrevision(5) ||
+ hwrevision(8) || hwrevision(9))) ||
+ (board_is_sdk() && !hwrevision(1)))
+ mem_3g = 1;
+ if (mach_is_goni () && board_is_s1()) {
+ mem_3g = 0;
+ sz = 0;
+ }
+ } else if (mach_is_wmg160() && !hwrevision(5)) {
+ mem_3g = 1;
+ }
+
+ if (mem_3g) {
+ memconfig1 = readl(base + MEMCONFIG1_OFFSET);
+
+ sz = (memconfig1 >> 16) & 0xFF;
+ sz = ((unsigned char) ~sz) + 1;
+ sz = sz << 4;
+ }
+ }
+ /*
+ * bi_dram[1].size contains all DMC1 memory size
+ */
+ gd->bd->bi_dram[1].size = (size + sz) << 20;
+
+ return 0;
+}
+
+/* Used for sleep test */
+static unsigned char saved_val[4][2];
+void board_sleep_init_late(void)
+{
+ /* CODEC_LDO_EN: GPF3[4] */
+ gpio_direction_output(&s5pc110_gpio->gpio_f3, 4, 0);
+ /* CODEC_XTAL_EN: GPH3[2] */
+ gpio_direction_output(&s5pc110_gpio->gpio_h3, 2, 0);
+
+ /* MMC T_FLASH off */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_5, 4, 0);
+ /* MHL off */
+ gpio_direction_output(&s5pc110_gpio->gpio_j2, 2, 0);
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_4, 7, 0);
+ /* MHL_ON for REV02 or higher */
+ gpio_direction_output(&s5pc110_gpio->gpio_j2, 3, 0);
+}
+
+void board_sleep_init(void)
+{
+ unsigned char addr;
+ unsigned char val[2];
+
+ addr = 0xCC >> 1;
+ if (max8998_probe())
+ return;
+
+ if (mach_is_goni()) {
+ /* Set ONOFF1 */
+ i2c_read(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+ saved_val[0][0] = val[0];
+ saved_val[0][1] = val[1];
+ val[0] &= ~((1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) |
+ (1 << 1) | (1 << 0));
+ i2c_write(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+
+ /* Set ONOFF2 */
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ saved_val[1][0] = val[0];
+ saved_val[1][1] = val[1];
+ val[0] &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 3) |
+ (1 << 2) | (1 << 1) | (1 << 0));
+ val[0] |= (1 << 7);
+ i2c_write(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+
+ /* Set ONOFF3 */
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ saved_val[2][0] = val[0];
+ saved_val[2][1] = val[1];
+ val[0] &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
+ i2c_write(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+
+ /* Set ONOFF4 */
+ i2c_read(addr, MAX8998_REG_ONOFF4, 1, val, 1);
+ saved_val[3][0] = val[0];
+ saved_val[3][1] = val[1];
+ val[0] &= ~((1 << 6) | (1 << 4));
+ i2c_write(addr, MAX8998_REG_ONOFF4, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF4, 1, val, 1);
+
+ printf("Turned off regulators with Kessler setting."
+ " Preparing to sleep. [%s:%d]\n",
+ __FILE__, __LINE__);
+ } else { /* Default */
+ /* Set ONOFF1 */
+ i2c_read(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+ saved_val[0][0] = val[0];
+ saved_val[0][1] = val[1];
+ val[0] &= ~((1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) |
+ (1 << 1) | (1 << 0));
+ i2c_write(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+
+ /* Set ONOFF2 */
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ saved_val[1][0] = val[0];
+ saved_val[1][1] = val[1];
+ val[0] &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 3) |
+ (1 << 2) | (1 << 1) | (1 << 0));
+ val[0] |= (1 << 7);
+ i2c_write(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+
+ /* Set ONOFF3 */
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ saved_val[2][0] = val[0];
+ saved_val[2][1] = val[1];
+ val[0] &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
+ i2c_write(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+
+ /* Set ONOFF4 */
+ i2c_read(addr, MAX8998_REG_ONOFF4, 1, val, 1);
+ saved_val[3][0] = val[0];
+ saved_val[3][1] = val[1];
+ val[0] &= ~((1 << 7) | (1 << 6) | (1 << 4));
+ i2c_write(addr, MAX8998_REG_ONOFF4, 1, val, 1);
+ i2c_read(addr, MAX8998_REG_ONOFF4, 1, val, 1);
+
+ printf("Turned off regulators with default(Aquila) setting."
+ " Preparing to sleep. [%s:%d]\n",
+ __FILE__, __LINE__);
+ }
+}
+
+void board_sleep_resume(void)
+{
+ unsigned char addr;
+ unsigned char val[2];
+
+ show_hw_revision();
+
+ addr = 0xCC >> 1;
+ if (max8998_probe())
+ return;
+
+ /* Set ONOFF1 */
+ i2c_write(addr, MAX8998_REG_ONOFF1, 1, saved_val[0], 1);
+ i2c_read(addr, MAX8998_REG_ONOFF1, 1, val, 1);
+ /* Set ONOFF2 */
+ i2c_write(addr, MAX8998_REG_ONOFF2, 1, saved_val[1], 1);
+ i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+ /* Set ONOFF3 */
+ i2c_write(addr, MAX8998_REG_ONOFF3, 1, saved_val[2], 1);
+ i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+ /* Set ONOFF4 */
+ i2c_write(addr, MAX8998_REG_ONOFF4, 1, saved_val[3], 1);
+ i2c_read(addr, MAX8998_REG_ONOFF4, 1, val, 1);
+ puts("Waked up.\n");
+
+ /* check max17040 */
+ check_battery(0);
+
+ /* check fsa9480 */
+ check_micro_usb(0);
+}
+
+#if defined(CONFIG_USB_GADGET_S3C_UDC_OTG)
+
+static int s5pc1xx_phy_control(int on)
+{
+ static int status;
+
+ if (on && !status) {
+#ifdef CONFIG_CMD_PMIC
+ run_command("pmic ldo 3 on", 0);
+#endif
+ /* S5PC110 */
+ if (board_is_limo_universal() ||
+ board_is_limo_real() ||
+ board_is_media()) {
+ /* check usb path */
+ if (board_is_limo_real() && !hwrevision(6))
+ check_mhl();
+ }
+
+ if (mach_is_tickertape())
+ /* USB_SEL: XM0ADDR_0: MP04[0] output mode */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_4, 0, 0);
+
+ /* USB Path to AP */
+ micro_usb_switch(0);
+ status = 1;
+ } else if (!on && status) {
+#ifdef CONFIG_CMD_PMIC
+ run_command("pmic ldo 3 off", 0);
+#endif
+ status = 0;
+ }
+ udelay(10000);
+
+ return 0;
+}
+
+struct s3c_plat_otg_data s5pc110_otg_data = {
+ .phy_control = s5pc1xx_phy_control,
+ .regs_phy = S5PC110_PHY_BASE,
+ .regs_otg = S5PC110_OTG_BASE,
+};
+
+int board_eth_init(bd_t *bis)
+{
+ int res = -1;
+
+ if (cpu_is_s5pc100())
+ return -1;
+
+ s3c_udc_probe(&s5pc110_otg_data);
+ if (usb_eth_initialize(bis) >= 0)
+ res = 0;
+ return res;
+}
+#endif
+
+#ifdef CONFIG_CMD_USBDOWN
+int usb_board_init(void)
+{
+#ifdef CONFIG_CMD_PMIC
+ run_command("pmic ldo 3 on", 0);
+#endif
+
+ if (cpu_is_s5pc100()) {
+#ifdef CONFIG_HARD_I2C
+ uchar val[2] = {0,};
+
+ /* PMIC */
+ if (i2c_read(0x66, 0, 1, val, 2)) {
+ puts("i2c_read error\n");
+ return 1;
+ }
+
+ val[0] |= (1 << 3);
+ val[1] |= (1 << 5);
+
+ if (i2c_write(0x66, 0, 1, val, 2)) {
+ puts("i2c_write error\n");
+ return 1;
+ }
+ i2c_read(0x66, 0, 1, val, 2);
+#endif
+ return 0;
+ }
+
+ /* S5PC110 */
+ if (board_is_limo_universal() ||
+ board_is_limo_real() ||
+ board_is_media()) {
+ /* check usb path */
+ if (board_is_limo_real() && !hwrevision(6))
+ check_mhl();
+ }
+
+ if (mach_is_tickertape())
+ /* USB_SEL: XM0ADDR_0: MP04[0] output mode */
+ gpio_direction_output(&s5pc110_gpio->gpio_mp0_4, 0, 0);
+
+ /* USB Path to AP */
+ micro_usb_switch(0);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_GENERIC_MMC
+int s5p_no_mmc_support(void)
+{
+ if (mach_is_wmg160() && hwrevision(5))
+ return 1;
+ return 0;
+}
+
+int board_mmc_init(bd_t *bis)
+{
+ int i;
+
+ if (s5p_no_mmc_support())
+ return -1;
+
+ /* MASSMEMORY_EN: XMSMDATA7: GPJ2[7] output high */
+ if (mach_is_goni() || mach_is_wmg160())
+ gpio_direction_output(&s5pc110_gpio->gpio_j2, 7, 1);
+
+ /*
+ * MMC0 GPIO
+ * GPG0[0] SD_0_CLK
+ * GPG0[1] SD_0_CMD
+ * GPG0[2] SD_0_CDn -> Not used
+ * GPG0[3:6] SD_0_DATA[0:3]
+ */
+ for (i = 0; i < 7; i++) {
+ if (i == 2)
+ continue;
+ /* GPG0[0:6] special function 2 */
+ gpio_cfg_pin(&s5pc110_gpio->gpio_g0, i, 0x2);
+ /* GPG0[0:6] pull disable */
+ gpio_set_pull(&s5pc110_gpio->gpio_g0, i, GPIO_PULL_NONE);
+ /* GPG0[0:6] drv 4x */
+ gpio_set_drv(&s5pc110_gpio->gpio_g0, i, GPIO_DRV_4X);
+ }
+
+ if (board_is_sdk() && hwrevision(6)) {
+ for (i = 3; i < 7; i++) {
+ /* GPG1[3:6] special function 3 */
+ gpio_cfg_pin(&s5pc110_gpio->gpio_g1, i, 0x3);
+ /* GPG1[3:6] pull disable */
+ gpio_set_pull(&s5pc110_gpio->gpio_g1,
+ i, GPIO_PULL_NONE);
+ /* GPG1[3:6] drv 4x */
+ gpio_set_drv(&s5pc110_gpio->gpio_g1, i, GPIO_DRV_4X);
+ }
+ }
+
+ if (mach_is_geminus()) {
+ gpio_direction_output(&s5pc110_gpio->gpio_j2, 7, 1);
+ gpio_set_pull(&s5pc110_gpio->gpio_j2, 7, GPIO_PULL_NONE);
+ }
+
+ return s5p_mmc_init(0);
+}
+#endif
+
+#ifdef CONFIG_CMD_PMIC
+static int pmic_status(void)
+{
+ unsigned char addr, val[2];
+ int reg, i;
+
+ addr = 0xCC >> 1;
+
+ if (max8998_probe())
+ return -1;
+
+ reg = 0x11;
+ i2c_read(addr, reg, 1, val, 1);
+ for (i = 7; i >= 4; i--)
+ printf("BUCK%d %s\n", 7 - i + 1,
+ val[0] & (1 << i) ? "on" : "off");
+ for (; i >= 0; i--)
+ printf("LDO%d %s\n", 5 - i,
+ val[0] & (1 << i) ? "on" : "off");
+ reg = 0x12;
+ i2c_read(addr, reg, 1, val, 1);
+ for (i = 7; i >= 0; i--)
+ printf("LDO%d %s\n", 7 - i + 6,
+ val[0] & (1 << i) ? "on" : "off");
+ reg = 0x13;
+ i2c_read(addr, reg, 1, val, 1);
+ for (i = 7; i >= 4; i--)
+ printf("LDO%d %s\n", 7 - i + 14,
+ val[0] & (1 << i) ? "on" : "off");
+
+ reg = 0xd;
+ i2c_read(addr, reg, 1, val, 1);
+ for (i = 7; i >= 6; i--)
+ printf("SAFEOUT%d %s\n", 7 - i + 1,
+ val[0] & (1 << i) ? "on" : "off");
+ return 0;
+}
+
+static int pmic_ldo_control(int buck, int ldo, int safeout, int on)
+{
+ unsigned char addr, val[2];
+ unsigned int reg, shift;
+
+ if (ldo) {
+ if (ldo < 2)
+ return -1;
+ if (ldo <= 5) {
+ reg = 0x11;
+ shift = 5 - ldo;
+ } else if (ldo <= 13) {
+ reg = 0x12;
+ shift = 13 - ldo;
+ } else if (ldo <= 17) {
+ reg = 0x13;
+ shift = 17 - ldo + 4;
+ } else
+ return -1;
+ } else if (buck) {
+ if (buck > 4)
+ return -1;
+ reg = 0x11;
+ shift = 4 - buck + 4;
+ } else if (safeout) {
+ if (safeout > 3)
+ return -1;
+ reg = 0xd;
+ shift = 8 - safeout;
+ } else
+ return -1;
+
+ addr = 0xCC >> 1;
+
+ if (max8998_probe())
+ return -1;
+
+ i2c_read(addr, reg, 1, val, 1);
+ if (on)
+ val[0] |= (1 << shift);
+ else
+ val[0] &= ~(1 << shift);
+ i2c_write(addr, reg, 1, val, 1);
+ i2c_read(addr, reg, 1, val, 1);
+
+ if (ldo)
+ printf("ldo %d value 0x%x, %s\n", ldo, val[0],
+ val[0] & (1 << shift) ? "on" : "off");
+ else if (buck)
+ printf("buck %d value 0x%x, %s\n", buck, val[0],
+ val[0] & (1 << shift) ? "on" : "off");
+ else if (safeout)
+ printf("safeout %d value 0x%x, %s\n", safeout, val[0],
+ val[0] & (1 << shift) ? "on" : "off");
+
+ return 0;
+}
+
+static int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int buck = 0, ldo = 0, safeout = 0, on = -1;
+
+ switch (argc) {
+ case 2:
+ if (strncmp(argv[1], "status", 6) == 0)
+ return pmic_status();
+ break;
+ case 4:
+ if (strncmp(argv[1], "ldo", 3) == 0)
+ ldo = simple_strtoul(argv[2], NULL, 10);
+ else if (strncmp(argv[1], "buck", 4) == 0)
+ buck = simple_strtoul(argv[2], NULL, 10);
+ else if (strncmp(argv[1], "safeout", 7) == 0)
+ safeout = simple_strtoul(argv[2], NULL, 10);
+ else
+ break;
+
+ if (strncmp(argv[3], "on", 2) == 0)
+ on = 1;
+ else if (strncmp(argv[3], "off", 3) == 0)
+ on = 0;
+ else
+ break;
+
+ return pmic_ldo_control(buck, ldo, safeout, on);
+
+ default:
+ break;
+ }
+
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD(
++ pmic, 4, 1, do_pmic,
+ "PMIC LDO & BUCK control",
+ "status - Display PMIC LDO & BUCK status\n"
+ "pmic ldo num on/off - Turn on/off the LDO\n"
+ "pmic buck num on/off - Turn on/off the BUCK\n"
+ "pmic safeout num on/off - Turn on/off the SAFEOUT\n"
+);
+#endif
+
+#ifdef CONFIG_CMD_DEVICE_POWER
+static int do_microusb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ switch (argc) {
+ case 2:
+ if (strncmp(argv[1], "cp", 2) == 0) {
+ micro_usb_switch(1);
+ pmic_ldo_control(0, 0, 2, 1);
+ setenv("usb", "cp");
+ } else if (strncmp(argv[1], "ap", 2) == 0) {
+ micro_usb_switch(0);
+ pmic_ldo_control(0, 0, 2, 0);
+ setenv("usb", "ap");
+ }
+ break;
+ default:
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ saveenv();
+
+ printf("USB Path is set to %s\n", getenv("usb"));
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ microusb, CONFIG_SYS_MAXARGS, 1, do_microusb,
+ "Micro USB Switch",
+ "cp - switch to CP\n"
+ "microusb ap - switch to AP\n"
+);
+#endif
#ifndef CONFIG_GENERIC_MMC
static int curr_device = -1;
- int do_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+ int do_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int dev;
- if (argc < 2) {
- cmd_usage(cmdtp);
- return 1;
- }
+ if (argc < 2)
+ return cmd_usage(cmdtp);
if (strcmp(argv[1], "init") == 0) {
if (argc == 2) {
} else if (argc == 3) {
dev = (int)simple_strtoul(argv[2], NULL, 10);
} else {
- cmd_usage(cmdtp);
- return 1;
+ return cmd_usage(cmdtp);
}
if (mmc_legacy_init(dev) != 0) {
#endif
curr_device = dev;
} else {
- cmd_usage(cmdtp);
- return 1;
+ return cmd_usage(cmdtp);
}
printf("mmc%d is current device\n", curr_device);
} else {
- cmd_usage(cmdtp);
- return 1;
+ return cmd_usage(cmdtp);
}
return 0;
printf("Rd Block Len: %d\n", mmc->read_bl_len);
printf("%s version %d.%d\n", IS_SD(mmc) ? "SD" : "MMC",
- (mmc->version >> 4) & 0xf, mmc->version & 0xf);
+ (mmc->version >> 4) & 0xf,
+ (mmc->version & 0xf) == EXT_CSD_REV_1_5 ?
+ 41 : (mmc->version & 0xf));
printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No");
- printf("Capacity: %lld\n", mmc->capacity);
+
+ if (mmc->high_capacity)
+ printf("Capacity: %lld MByte\n", mmc->capacity >> 11);
+ else
+ printf("Capacity: %lld\n", mmc->capacity);
printf("Bus Width: %d-bit\n", mmc->bus_width);
}
- int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+ int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct mmc *mmc;
int dev_num;
""
);
- int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int rc = 0;
printf("\nMMC write: dev # %d, block # %d, count %d ... ",
dev, blk, cnt);
- mmc_init(mmc);
+ /* Not initialize mmc in boot mode */
+ if (!(mmc->boot_config & 0x7))
+ mmc_init(mmc);
n = mmc->block_dev.block_write(dev, blk, cnt, addr);
printf("%d blocks written: %s\n",
n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? 0 : 1;
+ } else if (strcmp(argv[1], "boot") == 0) {
+ int dev = simple_strtoul(argv[2], NULL, 10);
+ u8 ack = simple_strtoul(argv[3], NULL, 10) & 0x1;
+ u8 enable = simple_strtoul(argv[4], NULL, 10) & 0x7;
+ u8 access = simple_strtoul(argv[5], NULL, 10) & 0x7;
+ struct mmc *mmc = find_mmc_device(dev);
+
+ if (!mmc)
+ return 1;
+
+ mmc_init(mmc);
+
+ /*
+ * BOOT_CONFIG[179]
+ * BOOT_ACK[6]
+ * 0x0: No boot acknowledge sent
+ * 0x1: Boot acknowledge sent
+ * BOOT_PARTITION_ENABLE[5:3]
+ * 0x0: Device not boot enabled
+ * 0x1: Boot partition 1 enabled for boot
+ * 0x2: Boot partition 2 enabled for boot
+ * 0x7: User area enabled for boot
+ * PARTITION_ACCESS[2:0]
+ * 0x0: No access to boot partition
+ * 0x1: R/W boot partition 1
+ * 0x2: R/W boot partition 2
+ * 0x3: R/W Replay Protected Memory Block
+ * 0x4: Access to General Purpose partition 1
+ * 0x5: Access to General Purpose partition 2
+ * 0x6: Access to General Purpose partition 3
+ * 0x7: Access to General Purpose partition 4
+ */
+ mmc->boot_config = (ack << 6) | (enable << 3) | access;
} else {
printf("Usage:\n%s\n", cmdtp->usage);
rc = 1;
"read <device num> addr blk# cnt\n"
"mmc write <device num> addr blk# cnt\n"
"mmc rescan <device num>\n"
- "mmc list - lists available devices");
+ "mmc list - lists available devices\n"
+ "mmc boot <device num> ack en access");
#endif
return ret;
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/**
* Format string describing supplied size. This routine does the opposite job
* to memsize_parse(). Size in bytes is converted to string and if possible
else
sprintf(buf, "%u", size);
}
+#endif
/**
* This routine does global indexing of all partitions. Resulting index for
return part_validate_eraseblock(id, part);
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/**
* Delete selected partition from the partion list of the specified device.
*
return 0;
}
+#endif
/**
* Delete all partitions from parts head list, free memory.
return 0;
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/**
* Add provided partition to the partition list of a given device.
*
return 0;
}
+#endif
/**
* Parse one partition definition, allocate memory and return pointer to this
return NULL;
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/**
* Add specified device to the global device list.
*
else
index_partitions();
}
+#endif
/**
* Parse device type, name and mtd-id. If syntax is ok allocate memory and
return device_delall(&devices);
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/*
* Search global mtdids list and find id of requested type and number.
*
return NULL;
}
+#endif
/**
* Search global mtdids list and find id of a requested mtd_id.
return 0;
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/**
* Process all devices and generate corresponding mtdparts string describing
* all partitions on all devices.
return ret;
}
+#endif
/**
* Format and print out a partition list for each device from global device
return 0;
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/**
* Find and delete partition. For partition id format see find_dev_and_part().
*
printf("partition %s not found\n", id);
return 1;
}
+#endif
/**
* Accept character string describing mtd partitions and call device_parse()
const char *ids, *parts;
const char *current_partition;
int ids_changed;
- char tmp_ep[PARTITION_MAXLEN];
+ char tmp_ep[PARTITION_MAXLEN+1];
debug("\n---mtdparts_init---\n");
if (!initialized) {
/* U-boot commands */
/***************************************************/
/* command line only */
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/**
* Routine implementing u-boot chpart command. Sets new current partition based
* on the user supplied partition id. For partition id format see find_dev_and_part().
* @param argv arguments list
* @return 0 on success, 1 otherwise
*/
- int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+ int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
/* command line only */
struct mtd_device *dev;
return 0;
}
+#endif
/**
* Routine implementing u-boot mtdparts command. Initialize/update default global
* @param argv arguments list
* @return 0 on success, 1 otherwise
*/
- int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
+#ifndef CONFIG_CMD_MTDPARTS_LITE
if (argc == 2) {
if (strcmp(argv[1], "default") == 0) {
setenv("mtdids", (char *)mtdids_default);
return mtd_devices_init();
}
}
+#endif
/* make sure we are in sync with env variables */
if (mtdparts_init() != 0)
return 0;
}
+#ifndef CONFIG_CMD_MTDPARTS_LITE
/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
#define PART_ADD_DESC_MAXLEN 64
return delete_partition(argv[2]);
}
+#endif
- cmd_usage(cmdtp);
- return 1;
+ return cmd_usage(cmdtp);
}
/***************************************************/
+#ifndef CONFIG_CMD_MTDPARTS_LITE
U_BOOT_CMD(
chpart, 2, 0, do_chpart,
"change active partition",
"<name> := '(' NAME ')'\n"
"<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)"
);
+#else
+U_BOOT_CMD(
+ mtdparts, 1, 0, do_mtdparts,
+ "define flash/nand partitions",
+ "\n"
+ " - list partition table\n"
+);
+#endif
/***************************************************/
return (*p != '\0' && *endptr == '\0') ? 1 : 0;
}
- static int arg_off_size(int argc, char *argv[], ulong *off, ssize_t *size)
-static int arg_off_size(int argc, char * const argv[], ulong *off, size_t *size)
++static int arg_off_size(int argc, char * const argv[], ulong *off, ssize_t *size)
{
if (argc >= 1) {
if (!(str2long(argv[0], off))) {
return 0;
}
-static int onenand_block_read(loff_t from, size_t len,
- size_t *retlen, u_char *buf, int oob)
+static int onenand_block_read(loff_t from, ssize_t len,
+ ssize_t *retlen, u_char *buf, int oob)
{
struct onenand_chip *this = mtd->priv;
- int blocks = (int) len >> this->erase_shift;
int blocksize = (1 << this->erase_shift);
loff_t ofs = from;
struct mtd_oob_ops ops = {
.retlen = 0,
};
+ ssize_t thislen;
int ret;
- if (oob)
- ops.ooblen = blocksize;
- else
- ops.len = blocksize;
+ while (len > 0) {
+ thislen = min_t(ssize_t, len, blocksize);
+ thislen = ALIGN(thislen, mtd->writesize);
- while (blocks) {
ret = mtd->block_isbad(mtd, ofs);
if (ret) {
printk("Bad blocks %d at 0x%x\n",
(u32)(ofs >> this->erase_shift), (u32)ofs);
ofs += blocksize;
+ /* FIXME need to check how to handle the 'len' */
+ len -= blocksize;
continue;
}
- if (oob)
+ if (oob) {
ops.oobbuf = buf;
- else
+ ops.ooblen = thislen;
+ } else {
ops.datbuf = buf;
+ ops.len = thislen;
+ }
ops.retlen = 0;
ret = mtd->read_oob(mtd, ofs, &ops);
if (ret) {
printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
- ofs += blocksize;
+ ofs += thislen;
continue;
}
- ofs += blocksize;
- buf += blocksize;
- blocks--;
+ ofs += thislen;
+ buf += thislen;
+ len -= thislen;
*retlen += ops.retlen;
}
return 0;
}
-static int onenand_block_write(loff_t to, size_t len,
- size_t *retlen, const u_char * buf)
+static int onenand_block_write(loff_t to, ssize_t len,
+ ssize_t *retlen, const u_char * buf)
{
struct onenand_chip *this = mtd->priv;
- int blocks = len >> this->erase_shift;
int blocksize = (1 << this->erase_shift);
+ struct mtd_oob_ops ops = {
+ .retlen = 0,
+ .oobbuf = NULL,
+ };
loff_t ofs;
- ssize_t thislen;
- size_t _retlen = 0;
++ size_t thislen;
int ret;
if (to == next_ofs) {
}
ofs = to;
- while (blocks) {
+ while (len > 0) {
- thislen = min_t(ssize_t, len, blocksize);
++ thislen = min_t(size_t, len, blocksize);
+ thislen = ALIGN(thislen, mtd->writesize);
+
ret = mtd->block_isbad(mtd, ofs);
if (ret) {
printk("Bad blocks %d at 0x%x\n",
goto next;
}
- ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
+ ops.datbuf = (u_char *) buf;
+ ops.len = thislen;
+ ops.retlen = 0;
+ ret = mtd->write_oob(mtd, ofs, &ops);
if (ret) {
printk("Write failed 0x%x, %d", (u32)ofs, ret);
- skip_ofs += blocksize;
+ skip_ofs += thislen;
goto next;
}
- buf += blocksize;
- blocks--;
- *retlen += _retlen;
+ buf += thislen;
+ len -= thislen;
+ *retlen += ops.retlen;
next:
ofs += blocksize;
}
end_block = mtd->size >> this->erase_shift;
blocks = start_block;
- ofs = start;
+ ofs = start_block << this->erase_shift;
while (blocks < end_block) {
printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs);
goto next;
}
- if (memcmp(buf, verify_buf, blocksize))
+ if (memcmp(buf, verify_buf, blocksize)) {
printk("\nRead/Write test failed at 0x%x\n", (u32)ofs);
-
+ break;
+ }
next:
ofs += blocksize;
blocks++;
p += 16;
}
puts("OOB:\n");
+ p = oobbuf;
i = mtd->oobsize >> 3;
while (i--) {
printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
return 0;
}
- static int do_onenand_info(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
printf("%s\n", mtd->name);
return 0;
}
- static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
ulong ofs;
return 0;
}
- static int do_onenand_read(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_read(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
char *s;
int oob = 0;
ulong addr, ofs;
- size_t len;
+ ssize_t len;
int ret = 0;
- size_t retlen = 0;
+ ssize_t retlen = 0;
if (argc < 3)
- {
- cmd_usage(cmdtp);
- return 1;
- }
+ return cmd_usage(cmdtp);
s = strchr(argv[0], '.');
if ((s != NULL) && (!strcmp(s, ".oob")))
return ret == 0 ? 0 : 1;
}
- static int do_onenand_write(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_write(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
ulong addr, ofs;
- size_t len;
+ ssize_t len;
int ret = 0;
- size_t retlen = 0;
+ ssize_t retlen = 0;
if (argc < 3)
- {
- cmd_usage(cmdtp);
- return 1;
- }
+ return cmd_usage(cmdtp);
addr = (ulong)simple_strtoul(argv[1], NULL, 16);
return ret == 0 ? 0 : 1;
}
- static int do_onenand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
ulong ofs;
int ret = 0;
- size_t len;
+ ssize_t len;
int force;
/*
return ret == 0 ? 0 : 1;
}
- static int do_onenand_test(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_test(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
ulong ofs;
int ret = 0;
- size_t len;
+ ssize_t len;
/*
* Syntax is:
return ret == 0 ? 0 : 1;
}
- static int do_onenand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
ulong ofs;
int ret = 0;
char *s;
if (argc < 2)
- {
- cmd_usage(cmdtp);
- return 1;
- }
+ return cmd_usage(cmdtp);
s = strchr(argv[0], '.');
ofs = (int)simple_strtoul(argv[1], NULL, 16);
return ret == 0 ? 1 : 0;
}
- static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
int ret = 0;
ulong addr;
argv += 2;
if (argc <= 0)
- {
- cmd_usage(cmdtp);
- return 1;
- }
+ return cmd_usage(cmdtp);
while (argc > 0) {
addr = simple_strtoul(*argv, NULL, 16);
return ret;
}
+static int do_onenand_lock(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ ulong start;
+ ssize_t size;
+ struct onenand_chip *this = mtd->priv;
+ loff_t ofs;
+ int status;
+ int status_mask = ONENAND_WP_LS|ONENAND_WP_LTS;
+
+ if (argc < 4) {
+ start = 0x0;
+ size = mtd->size;
+ } else {
+ if (arg_off_size(argc - 2, argv + 2, &start, &size))
+ return 1;
+ }
+
+ for (ofs = start; ofs < (start + size); ofs += mtd->erasesize) {
+ if (this->block_islock != NULL)
+ status = this->block_islock(mtd, ofs);
+ else
+ status = 0;
+
+ if (status & status_mask)
+ return (status & status_mask);
+ }
+
+ return 0;
+}
+
static cmd_tbl_t cmd_onenand_sub[] = {
U_BOOT_CMD_MKENT(info, 1, 0, do_onenand_info, "", ""),
U_BOOT_CMD_MKENT(bad, 1, 0, do_onenand_bad, "", ""),
U_BOOT_CMD_MKENT(test, 3, 0, do_onenand_test, "", ""),
U_BOOT_CMD_MKENT(dump, 2, 0, do_onenand_dump, "", ""),
U_BOOT_CMD_MKENT(markbad, CONFIG_SYS_MAXARGS, 0, do_onenand_markbad, "", ""),
+ U_BOOT_CMD_MKENT(lock, 3, 0, do_onenand_lock, "", ""),
};
-static int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
cmd_tbl_t *c;
c = find_cmd_tbl(argv[0], &cmd_onenand_sub[0], ARRAY_SIZE(cmd_onenand_sub));
- if (c) {
- return c->cmd(cmdtp, flag, argc, argv);
- } else {
- cmd_usage(cmdtp);
- return 1;
- }
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else
+ return cmd_usage(cmdtp);
}
U_BOOT_CMD(
--- /dev/null
- int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+/*
+ * USB Downloader for SAMSUNG Platform
+ *
+ * Copyright (C) 2007-2008 Samsung Electronics
+ * Minkyu Kang <mk7.kang@samsung.com>
+ *
+ */
+
+#include <common.h>
+#include <usbd.h>
+#include <asm/errno.h>
+#include <malloc.h>
+
+/* version of USB Downloader Application */
+#define APP_VERSION "1.5.3"
+
+#define OPS_READ 0
+#define OPS_WRITE 1
+
+#ifdef CONFIG_CMD_MTDPARTS
+#include <jffs2/load_kernel.h>
+static struct part_info *parts[16];
+#endif
+
+static const char pszMe[] = "usbd: ";
+
+static struct usbd_ops usbd_ops;
+
+static unsigned int part_id;
+static unsigned int write_part = 0;
+static unsigned long fs_offset = 0x0;
+
+#ifdef CONFIG_USE_YAFFS
+static unsigned int yaffs_len = 0;
+static unsigned char yaffs_data[2112];
+#define YAFFS_PAGE 2112
+#endif
+
+#define NAND_PAGE_SIZE 2048
+
+static unsigned long down_ram_addr;
+
+static int down_mode;
+
+/* cpu/${CPU} dependent */
+extern void do_reset(void);
+
+/* common commands */
+extern int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern int do_run(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]);
+
+int mtdparts_init(void);
+int find_dev_and_part(const char*, struct mtd_device**, u8*, struct part_info**);
+
+/* common/cmd_jffs2.c */
+extern struct list_head devices;
+
+static u8 count_mtdparts(void)
+{
+ struct list_head *dentry, *pentry;
+ struct mtd_device *dev;
+ u8 part_num = 0;
+
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+
+ /* list partitions for given device */
+ list_for_each(pentry, &dev->parts)
+ part_num++;
+ }
+
+ return part_num;
+}
+
+#ifdef CONFIG_CMD_UBI
+static int check_ubi_mode(void)
+{
+ char *env_ubifs;
+ int ubi_mode;
+
+ env_ubifs = getenv("ubi");
+ ubi_mode = !strcmp(env_ubifs, "enabled");
+
+ return ubi_mode;
+}
+#else
+#define check_ubi_mode() 0
+#endif
+
+#ifdef CONFIG_MTD_PARTITIONS
+static int get_part_info(void)
+{
+ struct mtd_device *dev;
+ u8 out_partnum;
+ char part_name[12];
+ char nand_name[12];
+ int i;
+ int part_num;
+ int ubi_mode = 0;
+
+#if defined(CONFIG_CMD_NAND)
+ sprintf(nand_name, "nand0");
+#elif defined(CONFIG_CMD_ONENAND)
+ sprintf(nand_name, "onenand0");
+#else
+ printf("Configure your NAND sub-system\n");
+ return 0;
+#endif
+
+ if (mtdparts_init())
+ return 0;
+
+ ubi_mode = check_ubi_mode();
+
+ part_num = count_mtdparts();
+ for (i = 0; i < part_num; i++) {
+ sprintf(part_name, "%s,%d", nand_name, i);
+
+ if (find_dev_and_part(part_name, &dev, &out_partnum, &parts[i]))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_part_id(char *name)
+{
+ int nparts = count_mtdparts();
+ int i;
+
+ for (i = 0; i < nparts; i++) {
+ if (strcmp(parts[i]->name, name) == 0)
+ return i;
+ }
+
+ printf("Error: Unknown partition -> %s\n", name);
+ return -1;
+}
+#else
+static int get_part_info(void)
+{
+ printf("Error: Can't get patition information\n");
+ return -EINVAL;
+}
+
+static int get_part_id(char *name)
+{
+ return 0;
+}
+#endif
+
+static void boot_cmd(char *addr)
+{
+ char *argv[] = { "bootm", addr };
+ do_bootm(NULL, 0, 2, argv);
+}
+
+static void run_cmd(char *cmd)
+{
+ char *argv[] = { "run", cmd };
+ do_run(NULL, 0, 2, argv);
+}
+
+#if defined(CONFIG_CMD_NAND)
+extern int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+#elif defined(CONFIG_CMD_ONENAND)
+extern int do_onenand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+#endif
+
+/* NAND erase and write using nand command */
+static int nand_cmd(int type, char *p1, char *p2, char *p3)
+{
+ int ret = 1;
+ char nand_name[12];
+ int (*nand_func) (cmd_tbl_t *, int, int, char **);
+
+#if defined(CONFIG_CMD_NAND)
+ sprintf(nand_name, "nand");
+ nand_func = do_nand;
+#elif defined(CONFIG_CMD_ONENAND)
+ sprintf(nand_name, "onenand");
+ nand_func = do_onenand;
+#else
+ printf("Configure your NAND sub-system\n");
+ return 0;
+#endif
+
+ if (type == 0) {
+ char *argv[] = {nand_name, "erase", p1, p2};
+ printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
+ ret = nand_func(NULL, 0, 4, argv);
+ } else if (type == 1) {
+ char *argv[] = {nand_name, "write", p1, p2, p3};
+ printf("%s %s %s %s %s\n", argv[0], argv[1], argv[2],
+ argv[3], argv[4]);
+ ret = nand_func(NULL, 0, 5, argv);
+ } else if (type == 2) {
+ char *argv[] = {nand_name, "write.yaffs", p1, p2, p3};
+ printf("%s %s %s %s %s\n", argv[0], argv[1], argv[2],
+ argv[3], argv[4]);
+ ret = nand_func(NULL, 0, 5, argv);
+ } else if (type == 3) {
+ char *argv[] = {nand_name, "lock", p1, p2};
+ printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
+ ret = nand_func(NULL, 0, 4, argv);
+ }
+
+ if (ret)
+ printf("Error: NAND Command\n");
+
+ return ret;
+}
+
+#ifdef CONFIG_CMD_UBI
+int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+
+int ubi_cmd(int part, char *p1, char *p2, char *p3)
+{
+ int ret = 1;
+
+ if (part == RAMDISK_PART_ID) {
+ char *argv[] = {"ubi", "write", p1, "rootfs.cramfs", p2, p3};
+ printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5]);
+ ret = do_ubi(NULL, 0, 6, argv);
+ } else if (part == FILESYSTEM_PART_ID) {
+ char *argv[] = {"ubi", "write", p1, "factoryfs.cramfs", p2, p3};
+ printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5]);
+ ret = do_ubi(NULL, 0, 6, argv);
+ } else if (part == FILESYSTEM2_PART_ID) {
+ char *argv[] = {"ubi", "write", p1, "datafs.ubifs", p2, p3};
+ printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5]);
+ ret = do_ubi(NULL, 0, 6, argv);
+ }
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_CMD_MMC
+#include <fat.h>
+
+extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+
+static int mmc_cmd(int ops, char *p1, char *p2, char *p3)
+{
+ int ret;
+
+ if (ops) {
+ char *argv[] = {"mmc", "write", "0", p1, p2, p3};
+ ret = do_mmcops(NULL, 0, 6, argv);
+ } else {
+ char *argv[] = {"mmc", "read", "0", p1, p2, p3};
+ ret = do_mmcops(NULL, 0, 6, argv);
+ }
+
+ return ret;
+}
+
+static unsigned int cur_blk_offset;
+static unsigned int cur_part_size;
+static unsigned int cur_partition;
+
+static unsigned int mmc_parts;
+static unsigned int mmc_part_write;
+
+struct partition_info {
+ u32 size;
+ u32 checksum;
+ u32 res;
+} __attribute__((packed));
+
+struct partition_header {
+ u8 fat32head[16]; /* RFSHEAD identifier */
+ struct partition_info partition[4];
+ u8 res[448]; /* reserved */
+} __attribute__((packed));
+
+struct partition_table {
+ u8 boot_flag;
+ u8 chs_begin[3];
+ u8 type_code;
+ u8 chs_end[3];
+ u32 lba_begin;
+ u32 num_sectors;
+} __attribute__((packed));
+
+struct mbr_table {
+ u8 boot_code[446];
+ struct partition_table partition[4];
+ u16 signature;
+} __attribute__((packed));
+
+#define MBR_OFFSET 0x10
+
+struct partition_header part_info;
+struct mbr_table mbr_info;
+
+static int write_mmc_partition(struct usbd_ops *usbd, u32 *ram_addr, u32 len)
+{
+ unsigned int blocks;
+ char offset[12], length[12], ramaddr[12];
+ int i;
+ int loop;
+ u32 cnt;
+ int ret;
+
+ if (cur_part_size > len) {
+ blocks = len / usbd->mmc_blk;
+ ret = -1;
+ } else {
+ blocks = cur_part_size / usbd->mmc_blk;
+ ret = len - cur_part_size;
+ }
+
+ if (len % usbd->mmc_blk)
+ blocks++;
+
+ loop = blocks / usbd->mmc_max;
+ if (blocks % usbd->mmc_max)
+ loop++;
+
+ for (i = 0; i < loop; i++) {
+ if (i == 0) {
+ cnt = blocks % usbd->mmc_max;
+ if (cnt == 0)
+ cnt = usbd->mmc_max;
+ } else {
+ cnt = usbd->mmc_max;
+ }
+
+ sprintf(length, "%x", cnt);
+ sprintf(offset, "%x", cur_blk_offset);
+ sprintf(ramaddr, "0x%x", *ram_addr);
+ mmc_cmd(OPS_WRITE, ramaddr, offset, length);
+
+ cur_blk_offset += cnt;
+
+ *ram_addr += (cnt * usbd->mmc_blk);
+ }
+
+ return ret;
+}
+
+static int write_file_mmc(struct usbd_ops *usbd, char *ramaddr, u32 len,
+ char *offset, char *length)
+{
+ u32 ram_addr;
+ int i;
+ int ret;
+
+ if (!usbd->mmc_total) {
+ printf("MMC is not supported!\n");
+ return 0;
+ }
+
+ ram_addr = (u32)down_ram_addr;
+
+ if (cur_blk_offset == 0) {
+ boot_sector *bs;
+ struct mbr_table *mbr;
+
+ memcpy(&part_info, (void *)ram_addr,
+ sizeof(struct partition_header));
+
+ ram_addr += sizeof(struct partition_header);
+ len -= sizeof(struct partition_header);
+ mbr = (struct mbr_table*)ram_addr;
+
+ /* modify sectors of p1 */
+ mbr->partition[0].num_sectors = usbd->mmc_total -
+ (MBR_OFFSET +
+ mbr->partition[1].num_sectors +
+ mbr->partition[2].num_sectors +
+ mbr->partition[3].num_sectors);
+
+ mmc_parts++;
+
+ /* modify lba_begin of p2 and p3 and p4 */
+ for (i = 1; i < 4; i++) {
+ if (part_info.partition[i].size == 0)
+ break;
+
+ mmc_parts++;
+ mbr->partition[i].lba_begin =
+ mbr->partition[i - 1].lba_begin +
+ mbr->partition[i - 1].num_sectors;
+ }
+
+ /* copy MBR */
+ memcpy(&mbr_info, mbr, sizeof(struct mbr_table));
+
+ printf("Total Size: 0x%08x #parts %d\n",
+ (unsigned int)usbd->mmc_total, mmc_parts);
+ for (i = 0; i < mmc_parts; i++) {
+ printf("p%d\t0x%08x\t0x%08x\n", i + 1,
+ mbr_info.partition[i].lba_begin,
+ mbr_info.partition[i].num_sectors);
+ }
+
+ /* write MBR */
+ sprintf(length, "%x", MBR_OFFSET);
+ sprintf(offset, "%x", 0);
+ sprintf(ramaddr, "0x%x", (u32)ram_addr);
+ ret = mmc_cmd(OPS_WRITE, ramaddr, offset, length);
+
+ ram_addr += (MBR_OFFSET * usbd->mmc_blk);
+ len -= (MBR_OFFSET * usbd->mmc_blk);
+
+ cur_blk_offset = MBR_OFFSET;
+ cur_partition = 0;
+ cur_part_size = part_info.partition[0].size;
+
+ /* modify p1's total sector */
+ bs = (boot_sector *)ram_addr;
+ bs->total_sect = mbr_info.partition[0].num_sectors;
+
+ printf("\nWrite Partition %d.. %d blocks\n",
+ cur_partition + 1,
+ part_info.partition[cur_partition].size /
+ (int)usbd->mmc_blk);
+ }
+
+ for (i = cur_partition; i < mmc_parts; i++) {
+ ret = write_mmc_partition(usbd, &ram_addr, len);
+
+ if (ret < 0) {
+ cur_part_size -= len;
+ break;
+ } else {
+ cur_partition++;
+ cur_part_size =
+ part_info.partition[cur_partition].size;
+ cur_blk_offset =
+ mbr_info.partition[cur_partition].lba_begin;
+
+ if (ret == 0)
+ break;
+ else
+ len = ret;
+
+ printf("\nWrite Partition %d.. %d blocks\n",
+ cur_partition + 1,
+ part_info.partition[cur_partition].size /
+ (int)usbd->mmc_blk);
+ }
+ }
+
+ return 0;
+}
+
+static int write_file_mmc_part(struct usbd_ops *usbd, char *ramaddr, u32 len,
+ char *offset, char *length)
+{
+ u32 ram_addr;
+ int ret;
+ int i;
+
+ ram_addr = (u32)down_ram_addr;
+
+ if (cur_blk_offset == 0) {
+ /* read MBR */
+ sprintf(length, "%x", MBR_OFFSET);
+ sprintf(offset, "%x", 0);
+ sprintf(ramaddr, "0x%x", (u32)&mbr_info);
+ ret = mmc_cmd(OPS_READ, ramaddr, offset, length);
+
+ for (i = 0; i < 4; i++) {
+ printf("p%d\t0x%08x\t0x%08x\n", i + 1,
+ mbr_info.partition[i].lba_begin,
+ mbr_info.partition[i].num_sectors);
+ }
+
+ cur_blk_offset = (unsigned int)
+ mbr_info.partition[mmc_part_write - 1].lba_begin;
+ cur_partition = mmc_part_write - 1;
+ cur_part_size = (unsigned int)len;
+
+ if (mmc_part_write == 1) {
+ ram_addr += sizeof(boot_sector);
+ cur_blk_offset += sizeof(boot_sector) / usbd->mmc_blk;
+ len -= sizeof(boot_sector);
+ }
+ }
+
+ printf("\nWrite Partition %d.. %d blocks\n",
+ cur_partition + 1,
+ len / (int)usbd->mmc_blk);
+
+ write_mmc_partition(usbd, &ram_addr, len);
+
+ return 0;
+}
+#endif
+
+static int write_file_system(char *ramaddr, ulong len, char *offset,
+ char *length, int part_num, int ubi_update)
+{
+#ifdef CONFIG_USE_YAFFS
+ int actual_len = 0;
+ int yaffs_write = 0;
+#endif
+ int ret = 0;
+
+#ifdef CONFIG_CMD_UBI
+ /* UBI Update */
+ if (ubi_update) {
+ sprintf(length, "0x%x", (uint)len);
+ ret = ubi_cmd(part_id, ramaddr, length, "cont");
+ return ret;
+ }
+#endif
+
+ /* Erase entire partition at the first writing */
+ if (write_part == 0 && ubi_update == 0) {
+ sprintf(offset, "0x%x", (uint)parts[part_num]->offset);
+ sprintf(length, "0x%x", (uint)parts[part_num]->size);
+ nand_cmd(0, offset, length, NULL);
+ }
+
+#ifdef CONFIG_USE_YAFFS
+ /* if using yaffs, wirte size must be 2112*X
+ * so, must have to realloc, and writing */
+ if (!strcmp("yaffs", getenv(parts[part_num]->name))) {
+ yaffs_write = 1;
+
+ memcpy((void *)down_ram_addr, yaffs_data, yaffs_len);
+
+ actual_len = len + yaffs_len;
+ yaffs_len = actual_len % YAFFS_PAGE;
+ len = actual_len - yaffs_len;
+
+ memset(yaffs_data, 0x00, YAFFS_PAGE);
+ memcpy(yaffs_data, (char *)down_ram_addr + len, yaffs_len);
+ }
+#endif
+
+ sprintf(offset, "0x%x", (uint)(parts[part_num]->offset + fs_offset));
+ sprintf(length, "0x%x", (uint)len);
+
+#ifdef CONFIG_USE_YAFFS
+ if (yaffs_write)
+ ret = nand_cmd(2, ramaddr, offset, length);
+ else
+ ret = nand_cmd(1, ramaddr, offset, length);
+
+ if (!strcmp("yaffs", getenv(parts[part_num]->name)))
+ fs_offset += len / YAFFS_PAGE * NAND_PAGE_SIZE;
+ else
+ fs_offset += len;
+
+#else
+ fs_offset += len;
+ ret = nand_cmd(1, ramaddr, offset, length);
+#endif
+
+ return ret;
+}
+
+/* Parsing received data packet and Process data */
+static int process_data(struct usbd_ops *usbd)
+{
+ ulong cmd = 0, arg = 0, ofs = 0, len = 0, flag = 0;
+ char offset[12], length[12], ramaddr[12];
+ int recvlen = 0;
+ unsigned int blocks = 0;
+ int ret = 0;
+ int ubi_update = 0;
+ int ubi_mode = 0;
+ int img_type;
+
+ sprintf(ramaddr, "0x%x", (uint) down_ram_addr);
+
+ /* Parse command */
+ cmd = *((ulong *) usbd->rx_data + 0);
+ arg = *((ulong *) usbd->rx_data + 1);
+ len = *((ulong *) usbd->rx_data + 2);
+ flag = *((ulong *) usbd->rx_data + 3);
+
+ /* Reset tx buffer */
+ memset(usbd->tx_data, 0, sizeof(usbd->tx_data));
+
+ ubi_mode = check_ubi_mode();
+
+ switch (cmd) {
+ case COMMAND_DOWNLOAD_IMAGE:
+ printf("\nCOMMAND_DOWNLOAD_IMAGE\n");
+
+#ifdef CONFIG_USE_YAFFS
+ usbd->recv_setup((char *)down_ram_addr + yaffs_len, (int)len);
+ printf("Download to 0x%08x, %d bytes\n",
+ (uint)down_ram_addr + yaffs_len, (int)len);
+#else
+ usbd->recv_setup((char *)down_ram_addr, (int)len);
+ printf("Download to 0x%08x, %d bytes\n",
+ (uint)down_ram_addr, (int)len);
+#endif
+ /* response */
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+
+ /* Receive image by using dma */
+ recvlen = usbd->recv_data();
+ if (recvlen < len) {
+ printf("Error: wrong image size -> %d/%d\n",
+ (int)recvlen, (int)len);
+
+ /* Retry this commad */
+ *((ulong *) usbd->tx_data) = STATUS_RETRY;
+ } else
+ *((ulong *) usbd->tx_data) = STATUS_DONE;
+
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ return 1;
+
+ /* Report partition info */
+ case COMMAND_PARTITION_SYNC:
+ part_id = arg;
+
+#ifdef CONFIG_CMD_UBI
+ if (ubi_mode) {
+ if (part_id == RAMDISK_PART_ID ||
+ part_id == FILESYSTEM_PART_ID ||
+ part_id == FILESYSTEM2_PART_ID) {
+ /* change to yaffs style */
+ get_part_info();
+ }
+ } else {
+ if (part_id == FILESYSTEM3_PART_ID) {
+ /* change ubi style */
+ get_part_info();
+ }
+ }
+#endif
+
+ if (part_id == FILESYSTEM3_PART_ID)
+ part_id = get_part_id("UBI");
+ else if (part_id == MODEM_PART_ID)
+ part_id = get_part_id("modem");
+ else if (part_id == KERNEL_PART_ID)
+ part_id = get_part_id("kernel");
+#ifdef CONFIG_MIRAGE
+ if (part_id)
+ part_id--;
+#endif
+ printf("COMMAND_PARTITION_SYNC - Part%d\n", part_id);
+
+ blocks = parts[part_id]->size / 1024 / 128;
+ printf("COMMAND_PARTITION_SYNC - Part%d, %d blocks\n",
+ part_id, blocks);
+
+ *((ulong *) usbd->tx_data) = blocks;
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ return 1;
+
+ case COMMAND_WRITE_PART_0:
+ /* Do nothing */
+ printf("COMMAND_WRITE_PART_0\n");
+ return 1;
+
+ case COMMAND_WRITE_PART_1:
+ printf("COMMAND_WRITE_PART_BOOT\n");
+ part_id = get_part_id("bootloader");
+ img_type = IMG_BOOT;
+ break;
+
+ case COMMAND_WRITE_PART_2:
+ case COMMAND_ERASE_PARAMETER:
+ printf("COMMAND_PARAMETER - not support!\n");
+ break;
+
+ case COMMAND_WRITE_PART_3:
+ printf("COMMAND_WRITE_KERNEL\n");
+ part_id = get_part_id("kernel");
+ img_type = IMG_KERNEL;
+ break;
+
+ case COMMAND_WRITE_PART_4:
+ printf("COMMAND_WRITE_ROOTFS\n");
+ part_id = get_part_id("Root");
+ img_type = IMG_FILESYSTEM;
+ ubi_update = arg;
+ break;
+
+ case COMMAND_WRITE_PART_5:
+ printf("COMMAND_WRITE_FACTORYFS\n");
+ part_id = get_part_id("Fact");
+ img_type = IMG_FILESYSTEM;
+ ubi_update = arg;
+ break;
+
+ case COMMAND_WRITE_PART_6:
+ printf("COMMAND_WRITE_DATAFS\n");
+ part_id = get_part_id("Data");
+ img_type = IMG_FILESYSTEM;
+ ubi_update = arg;
+ break;
+
+ case COMMAND_WRITE_PART_7:
+ printf("COMMAND_WRITE_UBI\n");
+ part_id = get_part_id("UBI");
+ img_type = IMG_FILESYSTEM;
+ ubi_update = 0;
+ /* someday, it will be deleted */
+ get_part_info();
+ break;
+
+ case COMMAND_WRITE_PART_8:
+ printf("COMMAND_WRITE_MODEM\n");
+ part_id = get_part_id("modem");
+ img_type = IMG_MODEM;
+ break;
+
+#ifdef CONFIG_CMD_MMC
+ case COMMAND_WRITE_PART_9:
+ printf("COMMAND_WRITE_MMC\n");
+ img_type = IMG_MMC;
+ mmc_part_write = arg;
+ break;
+#endif
+
+ case COMMAND_WRITE_UBI_INFO:
+ printf("COMMAND_WRITE_UBI_INFO\n");
+
+ if (ubi_mode) {
+#ifdef CONFIG_CMD_UBI
+ part_id = arg-1;
+ sprintf(length, "0x%x", (uint)len);
+ ret = ubi_cmd(part_id, ramaddr, length, "begin");
+ } else {
+#endif
+ printf("Error: Not UBI mode\n");
+ ret = 1;
+ }
+
+ *((ulong *) usbd->tx_data) = ret;
+ /* Write image success -> Report status */
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+
+ return !ret;
+ /* Download complete -> reset */
+ case COMMAND_RESET_PDA:
+ printf("\nDownload finished and Auto reset!\nWait........\n");
+
+ /* Stop USB */
+ usbd->usb_stop();
+
+ if (usbd->cpu_reset)
+ usbd->cpu_reset();
+ else
+ do_reset();
+
+ return 0;
+
+ /* Error */
+ case COMMAND_RESET_USB:
+ printf("\nError is occured!(maybe previous step)->\
+ Turn off and restart!\n");
+
+ /* Stop USB */
+ usbd->usb_stop();
+ return 0;
+
+ case COMMAND_RAM_BOOT:
+ usbd->usb_stop();
+ boot_cmd(ramaddr);
+ return 0;
+
+ case COMMAND_RAMDISK_MODE:
+ printf("COMMAND_RAMDISK_MODE\n");
+#ifdef CONFIG_RAMDISK_ADDR
+ if (arg) {
+ down_ram_addr = usbd->ram_addr;
+ } else {
+ down_ram_addr = CONFIG_RAMDISK_ADDR;
+ run_cmd("ramboot");
+ }
+#endif
+ return 1;
+
+#ifdef CONFIG_DOWN_PHONE
+ case COMMAND_DOWN_PHONE:
+ printf("COMMAND_RESET_PHONE\n");
+
+ usbd_phone_down();
+
+ *((ulong *) usbd->tx_data) = STATUS_DONE;
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ return 1;
+
+ case COMMAND_CHANGE_USB:
+ printf("COMMAND_CHANGE_USB\n");
+
+ /* Stop USB */
+ usbd->usb_stop();
+
+ usbd_path_change();
+
+ do_reset();
+ return 0;
+#endif
+ case COMMAND_CSA_CLEAR:
+ printf("COMMAND_CSA_CLEAR\n");
+ part_id = get_part_id("csa");
+ img_type = IMG_MODEM;
+ break;
+
+ case COMMAND_PROGRESS:
+ if (usbd->set_progress)
+ usbd->set_progress(arg);
+ return 1;
+
+ default:
+ printf("Error: Unknown command -> (%d)\n", (int)cmd);
+ return 1;
+ }
+
+ /* Erase and Write to NAND */
+ switch (img_type) {
+ case IMG_BOOT:
+ ofs = parts[part_id]->offset;
+#ifdef CONFIG_RECOVERY
+ {
+ /* block is fixed:
+ 1m = ipl(16k)+recovery(240k)+bootloader(768k)*/
+ long *buf = (long *)down_ram_addr;
+ u32 ofst;
+ u32 bootloader_edge = parts[part_id]->size;
+ u32 bootloader_addr = bootloader_edge >> 2;
+ u32 recovery_edge = bootloader_addr;
+ u32 recovery_addr = recovery_edge >> 4;
+ u32 ipl_addr = 0;
+
+ if (len > bootloader_addr) {
+ ofst = bootloader_addr / sizeof(buf);
+ if (*(buf + ofst) == 0xea000012) {
+ /* case: ipl + recovery + bootloader */
+ printf("target: ipl + recovery + loader\n");
+ ofs = ipl_addr;
+ } else {
+ /* case: unknown format */
+ printf("target: unknown\n");
+ *((ulong *) usbd->tx_data) = STATUS_ERROR;
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ return 0;
+ }
+ } else {
+ ofst = recovery_addr/sizeof(buf);
+ if (*(buf + ofst) == 0xea000012 &&
+ *(buf + ofst - 1) == 0x00000000) {
+ /* case: ipl + bootloader (old type) */
+ printf("target: ipl + bootloader\n");
+ ofs = ipl_addr;
+ } else {
+ /* case: bootloader only */
+ printf("target: bootloader\n");
+ ofs = bootloader_addr;
+
+ /* skip revision check */
+ down_mode = MODE_FORCE;
+ }
+ }
+
+ sprintf(offset, "%x", (uint)ofs);
+ sprintf(length, "%x", parts[part_id]->size);
+
+ /* check block is locked/locked-tight */
+ ret = nand_cmd(3, offset, length, NULL);
+ if (ret) {
+ printf("target is locked%s\n",
+ (ret == 1) ? "-tight" : "");
+ printf("-> try at recovery mode "
+ "to update 'system'.\n");
+ printf(" how-to: reset "
+ "while pressing volume up and down.\n");
+ *((ulong *) usbd->tx_data) = STATUS_ERROR;
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ return 0;
+ }
+ }
+#endif
+#ifdef CONFIG_S5PC1XX
+ /* Workaround: for prevent revision mismatch */
+ if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
+ int img_rev = 1;
+ long *img_header = (long *)down_ram_addr;
+
+ if (*img_header == 0xea000012)
+ img_rev = 0;
+ else if (*(img_header + 0x400) == 0xea000012)
+ img_rev = 2;
+
+ if (img_rev != s5pc1xx_get_cpu_rev()) {
+ printf("CPU revision mismatch!\n"
+ "bootloader is %s%s\n"
+ "download image is %s%s\n",
+ s5pc1xx_get_cpu_rev() ? "EVT1" : "EVT0",
+ s5pc1xx_get_cpu_rev() == 2 ? "-Fused" : "",
+ img_rev ? "EVT1" : "EVT0",
+ img_rev == 2 ? "-Fused" : "");
+ *((ulong *) usbd->tx_data) = STATUS_ERROR;
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ return 0;
+ }
+ }
+#endif
+#if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
+ /* Erase the environment also when write bootloader */
+ {
+ int param_id;
+ param_id = get_part_id("params");
+
+ if (param_id == -1) {
+ sprintf(offset, "%x", CONFIG_ENV_ADDR);
+ sprintf(length, "%x", CONFIG_ENV_SIZE);
+ } else {
+ sprintf(offset, "%x", parts[param_id]->offset);
+ sprintf(length, "%x", parts[param_id]->size);
+ }
+ nand_cmd(0, offset, length, NULL);
+ }
+#endif
+ sprintf(offset, "%x", (uint)ofs);
+ if (ofs != 0)
+ sprintf(length, "%x", parts[part_id]->size - (uint)ofs);
+ else
+ sprintf(length, "%x", parts[part_id]->size);
+
+ /* Erase */
+ nand_cmd(0, offset, length, NULL);
+ /* Write */
+ sprintf(length, "%x", (unsigned int) len);
+ ret = nand_cmd(1, ramaddr, offset, length);
+ break;
+
+ case IMG_KERNEL:
+ sprintf(offset, "%x", parts[part_id]->offset);
+ sprintf(length, "%x", parts[part_id]->size);
+
+ /* Erase */
+ nand_cmd(0, offset, length, NULL);
+ /* Write */
+ sprintf(length, "%x", (unsigned int) len);
+ ret = nand_cmd(1, ramaddr, offset, length);
+ break;
+
+ /* File Systems */
+ case IMG_FILESYSTEM:
+ /* Erase the qboot also when write ubi image */
+ {
+ int qboot_id;
+ qboot_id = get_part_id("qboot");
+
+ if (qboot_id != -1) {
+ sprintf(offset, "%x", parts[qboot_id]->offset);
+ sprintf(length, "%x", parts[qboot_id]->size);
+ nand_cmd(0, offset, length, NULL);
+ }
+ }
+ ret = write_file_system(ramaddr, len, offset, length,
+ part_id, ubi_update);
+ break;
+
+ case IMG_MODEM:
+ sprintf(offset, "%x", parts[part_id]->offset);
+ sprintf(length, "%x", parts[part_id]->size);
+
+ /* Erase */
+ if (!arg)
+ nand_cmd(0, offset, length, NULL);
+ else
+ printf("CSA Clear will be skipped temporary\n");
+
+ /* Write : arg (0 Modem) / (1 CSA) */
+ if (!arg) {
+ sprintf(length, "%x", (unsigned int) len);
+ ret = nand_cmd(1, ramaddr, offset, length);
+ }
+ break;
+
+#ifdef CONFIG_CMD_MMC
+ case IMG_MMC:
+ if (mmc_part_write)
+ ret = write_file_mmc_part(usbd, ramaddr,
+ len, offset, length);
+ else
+ ret = write_file_mmc(usbd, ramaddr,
+ len, offset, length);
+ break;
+#endif
+
+ default:
+ /* Retry? */
+ write_part--;
+ }
+
+ if (ret) {
+ /* Retry this commad */
+ *((ulong *) usbd->tx_data) = STATUS_RETRY;
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ return 1;
+ } else
+ *((ulong *) usbd->tx_data) = STATUS_DONE;
+
+ /* Write image success -> Report status */
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+
+ write_part++;
+
+ /* Reset write count for another image */
+ if (flag) {
+ write_part = 0;
+ fs_offset = 0;
+#ifdef CONFIG_USE_YAFFS
+ yaffs_len = 0;
+#endif
+ }
+
+ return 1;
+}
+
+static const char *recv_key = "SAMSUNG";
+static const char *tx_key = "MPL";
+
- "usbdown mode - specific mode (0: NORAML, 1: FORCE)\n"
++int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char * argv[])
+{
+ struct usbd_ops *usbd;
+ int err;
+
+ if (argc > 1)
+ down_mode = simple_strtoul(argv[1], NULL, 10);
+ else
+ down_mode = MODE_NORMAL;
+
+ printf("USB Downloader v%s\n", APP_VERSION);
+
+ /* get partition info */
+ err = get_part_info();
+ if (err)
+ return err;
+
+ /* interface setting */
+ usbd = usbd_set_interface(&usbd_ops);
+ down_ram_addr = usbd->ram_addr;
+
+ /* init the usb controller */
+ usbd->usb_init();
+
+ /* receive setting */
+ usbd->recv_setup(usbd->rx_data, usbd->rx_len);
+
+ /* detect the download request from Host PC */
+ if (usbd->recv_data()) {
+ if (strncmp(usbd->rx_data, recv_key, strlen(recv_key)) == 0) {
+ printf("Download request from the Host PC\n");
+ msleep(30);
+
+ strcpy(usbd->tx_data, tx_key);
+ usbd->send_data(usbd->tx_data, usbd->tx_len);
+ } else {
+ printf("No download request from the Host PC!! 1\n");
+ return 0;
+ }
+ } else {
+ printf("No download request from the Host PC!!\n");
+ return 0;
+ }
+
+ printf("Receive the packet\n");
+
+ /* receive the data from Host PC */
+ while (1) {
+ usbd->recv_setup(usbd->rx_data, usbd->rx_len);
+
+ if (usbd->recv_data()) {
+ if (process_data(usbd) == 0)
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
+ "Initialize USB device and Run USB Downloader (specific)",
+ "- normal mode\n"
++ "usbdown mode - specific mode (0: NORAML, 1: FORCE)"
+);
char *env_name_spec = "OneNAND";
#define ONENAND_MAX_ENV_SIZE 4096
-
#define ONENAND_ENV_SIZE(mtd) (ONENAND_MAX_ENV_SIZE - ENV_HEADER_SIZE)
#ifdef ENV_IS_EMBEDDED
struct erase_info instr = {
.callback = NULL,
};
- size_t retlen;
+ size_t retlen, len;
+
+ len = CONFIG_ENV_SIZE;
+
+ if (len < mtd->erasesize)
+ len = ALIGN(len, mtd->erasesize);
- instr.len = CONFIG_ENV_SIZE;
+ instr.len = len;
#ifdef CONFIG_ENV_ADDR_FLEX
if (FLEXONENAND(this)) {
env_addr = CONFIG_ENV_ADDR_FLEX;
#include <stdarg.h>
#include <linux/types.h>
#include <stdio_dev.h>
+#include <malloc.h>
#if defined(CONFIG_POST)
#include <post.h>
#endif
#include <lcd.h>
#include <watchdog.h>
- #if defined(CONFIG_PXA250)
+ #if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
#include <asm/byteorder.h>
#endif
static int lcd_init (void *lcdbase);
- static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]);
+ static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]);
static void *lcd_logo (void);
static int lcd_getbgcolor (void);
/************************************************************************/
/* ** GENERIC Initialization Routines */
/************************************************************************/
+int drv_lcd_init_resume (void)
+{
+ lcd_base = (void *)(gd->fb_base);
+
+ lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix)) / 8;
+
+ lcd_init (lcd_base); /* LCD initialization */
+
+ return 0;
+}
int drv_lcd_init (void)
{
lcd_base = (void *)(gd->fb_base);
- lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+ lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix / 8));
lcd_init (lcd_base); /* LCD initialization */
}
/*----------------------------------------------------------------------*/
- static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+ static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
#if LCD_BPP == LCD_MONOCHROME
/* Setting the palette */
ulong lcd_setmem (ulong addr)
{
ulong size;
- int line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+ int line_length = (panel_info.vl_col * (panel_info.vl_bpix)) / 8;
debug ("LCD panel info: %d x %d, %d bit/pix\n",
- panel_info.vl_col, panel_info.vl_row, NBITS (panel_info.vl_bpix) );
+ panel_info.vl_col, panel_info.vl_row, (panel_info.vl_bpix) );
size = line_length * panel_info.vl_row;
uchar *bmap;
uchar *fb;
ushort *fb16;
- #if defined(CONFIG_PXA250)
+ #if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
struct pxafb_info *fbi = &panel_info.pxa;
#elif defined(CONFIG_MPC823)
volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
bmap = &bmp_logo_bitmap[0];
fb = (uchar *)(lcd_base + y * lcd_line_length + x);
- if (NBITS(panel_info.vl_bpix) < 12) {
+ if ((panel_info.vl_bpix) < 12) {
/* Leave room for default color map */
- #if defined(CONFIG_PXA250)
+ #if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
cmap = (ushort *)fbi->palette;
#elif defined(CONFIG_MPC823)
cmap = (ushort *)&(cp->lcd_cmap[BMP_LOGO_OFFSET*sizeof(ushort)]);
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
#define BMP_ALIGN_CENTER 0x7FFF
#endif
+void lcd_display_clear(void)
+{
+ unsigned int *fb = lcd_base;
+ printf("Clean the display\n");
+
+ memset(fb, 0, panel_info.vl_row * panel_info.vl_col * panel_info.vl_bpix / 8);
+}
int lcd_display_bitmap(ulong bmp_image, int x, int y)
{
unsigned long pwidth = panel_info.vl_col;
unsigned colors, bpix, bmp_bpix;
unsigned long compression;
- #if defined(CONFIG_PXA250)
+ #if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
struct pxafb_info *fbi = &panel_info.pxa;
#elif defined(CONFIG_MPC823)
volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
colors = 1 << bmp_bpix;
compression = le32_to_cpu (bmp->header.compression);
- bpix = NBITS(panel_info.vl_bpix);
+ bpix = (panel_info.vl_bpix);
- if ((bpix != 1) && (bpix != 8) && (bpix != 16)) {
- printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ if ((bpix != 1) && (bpix != 8) && (bpix != 16) && (bpix != 32)) {
+ printf ("Error0: %d bit/pixel mode, but BMP has %d bit/pixel\n",
bpix, bmp_bpix);
return 1;
}
- /* We support displaying 8bpp BMPs on 16bpp LCDs */
- if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16)) {
- printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ /* We support displaying 8bpp BMPs on 16bpp LCDs and 4bpp BMPs on 32bpp LCDs */
+ if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16) && !(bpix == 32 && bmp_bpix == 4) ) {
+ printf ("Error1: %d bit/pixel mode, but BMP has %d bit/pixel\n",
bpix,
le16_to_cpu(bmp->header.bit_count));
return 1;
#if !defined(CONFIG_MCC200)
/* MCC200 LCD doesn't need CMAP, supports 1bpp b&w only */
if (bmp_bpix == 8) {
- #if defined(CONFIG_PXA250)
+ #if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
cmap = (ushort *)fbi->palette;
#elif defined(CONFIG_MPC823)
cmap = (ushort *)&(cp->lcd_cmap[255*sizeof(ushort)]);
#elif !defined(CONFIG_ATMEL_LCD)
- cmap = panel_info.cmap;
+ /* cmap = panel_info.cmap; */
+ cmap = (ushort *) malloc(1024);
#endif
cmap_base = cmap;
(y + height - 1) * lcd_line_length + x);
switch (bmp_bpix) {
+ case 4: /* Display 4b bmp at 32b lcd */
+ if (bpix == 32) {
+ /* 1. Get the color map */
+ unsigned int cmap_32[16];
+ unsigned int effective_width;
+
+ for (i=0; i<colors; ++i) {
+ bmp_color_table_entry_t cte = bmp->color_table[i];
+ cmap_32[i] = (cte.red << 0) | (cte.green << 8) |
+ (cte.blue << 16) | (cte.reserved << 24);
+ }
+
+ /* 2. Put'em on the screen */
+ lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix / 8));
+ fb = (uchar *) lcd_base;
+ fb += lcd_line_length * (y + height) + x * 4;
+
+ printf("Drawing the 32bit bmp.. @ 4b (%d,%d) of [%ldx%ld] in %d (%d color)\n",
+ x, y, width, height, lcd_line_length, colors);
+ effective_width = (width % 2) ? (width + 1) : width;
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+ int color_v;
+ color_v = bmap[(j + i * effective_width) / 2];
+ if ((j + i * effective_width) % 2)
+ color_v = color_v & 0xf;
+ else
+ color_v = (color_v >> 4) & 0xf;
+
+ memcpy(fb, cmap_32 + color_v, 4);
+ fb += 4;
+ }
+ fb -= (lcd_line_length + width * 4);
+ }
+ }
+ break;
case 1: /* pass through */
case 8:
if (bpix != 16)
WATCHDOG_RESET();
for (j = 0; j < width; j++) {
if (bpix != 16) {
- #if defined(CONFIG_PXA250) || defined(CONFIG_ATMEL_LCD)
+ #if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS || defined(CONFIG_ATMEL_LCD)
*(fb++) = *(bmap++);
#elif defined(CONFIG_MPC823) || defined(CONFIG_MCC200)
*(fb++) = 255 - *(bmap++);
}
break;
#endif /* CONFIG_BMP_16BPP */
+ case 32:
+ lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix / 8));
+ fb = (uchar *) lcd_base;
+ fb += lcd_line_length * (y + height) + x * 4;
+
+ printf("Drawing the 32bit bmp.. @ (%d,%d) of [%ldx%ld] in %d\n",
+ x, y, width, height, lcd_line_length);
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ }
+ //bmap += (padded_line - width) * 4;
+ fb -= (lcd_line_length + width * 4);
+ }
+ break;
default:
break;
#ifdef CONFIG_SPLASH_SCREEN
char *s;
ulong addr;
+ int allocated = 0;
static int do_splash = 1;
if (do_splash && (s = getenv("splashimage")) != NULL) {
if (!((bmp->header.signature[0]=='B') &&
(bmp->header.signature[1]=='M'))) {
addr = (ulong)gunzip_bmp(addr, &len);
+ if (addr)
+ allocated = 1;
}
#endif
if (lcd_display_bitmap (addr, x, y) == 0) {
+#ifdef CONFIG_VIDEO_BMP_GZIP
+ if (addr && allocated)
+ free((void *)addr);
+#endif
return ((void *)lcd_base);
}
+#ifdef CONFIG_VIDEO_BMP_GZIP
+ if (addr && allocated)
+ free((void *)addr);
+#endif
}
#endif /* CONFIG_SPLASH_SCREEN */
#endif
#include <i2c.h>
+ #if defined(CONFIG_SOFT_I2C_GPIO_SCL)
+ # include <asm/gpio.h>
+
+ # ifndef I2C_GPIO_SYNC
+ # define I2C_GPIO_SYNC
+ # endif
+
+ # ifndef I2C_INIT
+ # define I2C_INIT \
+ do { \
+ gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \
+ gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \
+ } while (0)
+ # endif
+
+ # ifndef I2C_ACTIVE
+ # define I2C_ACTIVE do { } while (0)
+ # endif
+
+ # ifndef I2C_TRISTATE
+ # define I2C_TRISTATE do { } while (0)
+ # endif
+
+ # ifndef I2C_READ
+ # define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA)
+ # endif
+
+ # ifndef I2C_SDA
+ # define I2C_SDA(bit) \
+ do { \
+ if (bit) \
+ gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \
+ else \
+ gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \
+ I2C_GPIO_SYNC; \
+ } while (0)
+ # endif
+
+ # ifndef I2C_SCL
+ # define I2C_SCL(bit) \
+ do { \
+ gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \
+ I2C_GPIO_SYNC; \
+ } while (0)
+ # endif
+
+ # ifndef I2C_DELAY
+ # define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */
+ # endif
+
+ #endif
+
/* #define DEBUG_I2C */
#ifdef DEBUG_I2C
}
/*-----------------------------------------------------------------------
+ * REPEATED START: Low -> High -> Low on SDA while SCL is High
+ */
+static void send_repeated_start(void)
+{
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
+
+ I2C_DELAY;
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SDA(0);
+ I2C_DELAY;
+
+ I2C_DELAY;
+ I2C_SDA(1);
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_SDA(0);
+ I2C_DELAY;
+}
+
+/*-----------------------------------------------------------------------
* STOP: Low -> High on SDA while SCL is High
*/
static void send_stop(void)
* stop/start sequence.
*/
#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START
- send_start();
+ send_repeated_start();
#else
send_stop();
send_start();
* High Level Configuration Options
* (easy to change)
*/
- #define CONFIG_ARMCORTEXA8 1 /* This is an ARM V7 CPU core */
+ #define CONFIG_ARMV7 1 /* This is an ARM V7 CPU core */
#define CONFIG_SAMSUNG 1 /* in a SAMSUNG core */
#define CONFIG_S5PC1XX 1 /* which is in a S5PC1XX Family */
#define CONFIG_S5PC100 1 /* which is in a S5PC100 */
#define CONFIG_ENV_SROM_BANK 3 /* Select SROM Bank-3 for Ethernet*/
#endif /* CONFIG_CMD_NET */
+/* USB Downloader */
+#define CONFIG_CMD_USBDOWN
+#define CONFIG_SAMSUNG_USB
+#define CONFIG_OTG_CLK_OSCC
+#define CONFIG_SYS_DOWN_ADDR CONFIG_SYS_SDRAM_BASE
+#define CONFIG_RAMDISK_ADDR 0x33000000
+
#endif /* __CONFIG_H */
u_char vl_wbf; /* Wait between frames */
} vidinfo_t;
- #elif defined CONFIG_PXA250
+ #elif defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
/*
* PXA LCD DMA descriptor
*/
u_long mmio; /* Memory mapped registers */
} vidinfo_t;
+#elif defined(CONFIG_S5PC1XXFB)
+
+typedef struct vidinfo {
+ ushort vl_col; /* Number of columns (i.e. 640) */
+ ushort vl_row; /* Number of rows (i.e. 480) */
+ ushort vl_width; /* Width of display area in millimeters */
+ ushort vl_height; /* Height of display area in millimeters */
+
+ /* LCD configuration register */
+ u_char vl_freq; /* Frequency */
+ u_char vl_clkp; /* Clock polarity */
+ u_char vl_oep; /* Output Enable polarity */
+ u_char vl_hsp; /* Horizontal Sync polarity */
+ u_char vl_vsp; /* Vertical Sync polarity */
+ u_char vl_dp; /* Data polarity */
+ u_char vl_bpix; /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8, 4 = 16 */
+
+ /* Horizontal control register. Timing from data sheet */
+ u_char vl_hspw; /* Horz sync pulse width */
+ u_char vl_hfpd; /* Wait before of line */
+ u_char vl_hbpd; /* Wait end of line */
+
+ /* Vertical control register. */
+ u_char vl_vspw; /* Vertical sync pulse width */
+ u_char vl_vfpd; /* Wait before of frame */
+ u_char vl_vbpd; /* Wait end of frame */
+
+ void (*cfg_gpio)(void);
+ void (*backlight_on)(unsigned int onoff);
+ void (*reset_lcd)(void);
+ void (*lcd_power_on)(unsigned int onoff);
+ void (*cfg_ldo)(void);
+ void (*enable_ldo)(unsigned int onoff);
+
+ unsigned int init_delay;
+ unsigned int power_on_delay;
+ unsigned int reset_delay;
+
+ unsigned int dual_lcd_enabled;
+} vidinfo_t;
+
#else
typedef struct vidinfo {
* EXT_CSD fields
*/
+#define EXT_CSD_BOOT_BUS_WIDTH 177 /* R/W/E */
+#define EXT_CSD_BOOT_CONFIG 179 /* R/W */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
+#define EXT_CSD_REV_1_0 0
+#define EXT_CSD_REV_1_1 1
+#define EXT_CSD_REV_1_2 2
+#define EXT_CSD_REV_1_3 3
+#define EXT_CSD_REV_1_4 4
+#define EXT_CSD_REV_1_5 5
+
/*
* EXT_CSD field definitions
*/
uint write_bl_len;
u64 capacity;
block_dev_desc_t block_dev;
+ uint boot_config;
int (*send_cmd)(struct mmc *mmc,
struct mmc_cmd *cmd, struct mmc_data *data);
void (*set_ios)(struct mmc *mmc);
int mmc_init(struct mmc *mmc);
int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);
struct mmc *find_mmc_device(int dev_num);
+ int mmc_set_dev(int dev_num);
void print_mmc_devices(char separator);
int board_mmc_getcd(u8 *cd, struct mmc *mmc);