From ab927518fb1115228f72743cf245a2b6742dcb05 Mon Sep 17 00:00:00 2001 From: SangHee Kim Date: Mon, 26 Apr 2010 14:29:56 +0900 Subject: [PATCH] recovery: serial: add driver mv common.h to recovery.h --- cpu/arm_cortexa8/start.S | 2 +- recovery/Makefile | 2 + recovery/board/samsung/universal/universal.c | 35 +++-- recovery/common.h | 19 --- recovery/config.mk | 1 + recovery/drivers/serial/Makefile | 45 ++++++ recovery/drivers/serial/serial_s5pc1xx.c | 197 +++++++++++++++++++++++++++ recovery/drivers/usb/Makefile | 2 +- recovery/drivers/usb/s5p_usb_downloader.c | 15 +- recovery/recovery.c | 19 ++- recovery/recovery.h | 19 +++ recovery/serial.c | 69 ++++++++++ recovery/usbd.c | 20 ++- 13 files changed, 408 insertions(+), 37 deletions(-) delete mode 100644 recovery/common.h create mode 100644 recovery/drivers/serial/Makefile create mode 100644 recovery/drivers/serial/serial_s5pc1xx.c create mode 100644 recovery/recovery.h create mode 100644 recovery/serial.c diff --git a/cpu/arm_cortexa8/start.S b/cpu/arm_cortexa8/start.S index e91c82e..466d649 100644 --- a/cpu/arm_cortexa8/start.S +++ b/cpu/arm_cortexa8/start.S @@ -175,7 +175,7 @@ stack_setup: sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 @ leave 3 words for abort-stack -#endif /* CONFIG_ONENAND_IPL || CONFIG_RECOVERY_BLOCK */ +#endif /* CONFIG_ONENAND_IPL */ and sp, sp, #~7 @ 8 byte alinged for (ldr/str)d #if !defined(CONFIG_ONENAND_IPL) && !defined(CONFIG_RECOVERY_BLOCK) diff --git a/recovery/Makefile b/recovery/Makefile index 144a3b6..9bf2bb0 100644 --- a/recovery/Makefile +++ b/recovery/Makefile @@ -23,12 +23,14 @@ TEXT_BASE_256K = 0x3403C000 OBJS = recovery.o OBJS += onenand.o OBJS += usbd.o +OBJS += serial.o SRCS := $(OBJS:.o=.c) OBJS := $(addprefix $(obj),$(OBJS)) LIBS = drivers/onenand/libonenand.a LIBS += drivers/usb/libusb.a +LIBS += drivers/serial/libserial.a LIBS := $(addprefix $(recoveryobj),$(LIBS)) .PHONY : $(LIBS) $(TIMESTAMP_FILE) $(VERSION_FILE) diff --git a/recovery/board/samsung/universal/universal.c b/recovery/board/samsung/universal/universal.c index f84e926..c17d079 100644 --- a/recovery/board/samsung/universal/universal.c +++ b/recovery/board/samsung/universal/universal.c @@ -21,19 +21,25 @@ */ #include -#include #include #include #include #include #include -#include "../../../onenand.h" +#include "recovery.h" +#include "onenand.h" + +#ifdef RECOVERY_DEBUG +#define PUTS(s) serial_puts (DEBUG_MARK""s) +#else +#define PUTS(s) +#endif typedef int (init_fnc_t) (void); DECLARE_GLOBAL_DATA_PTR; -static struct s5pc110_gpio *s5pc110_gpio; +static struct s5pc110_gpio *gpio_base = (struct s5pc110_gpio *) S5PC110_GPIO_BASE; static void sdelay(unsigned long usec) { @@ -67,13 +73,13 @@ static int check_keypad(void) for (i = 0; i < row_num; i++) { /* 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); + gpio_cfg_pin(&gpio_base->gpio_h3, i, 0x3); + gpio_set_pull(&gpio_base->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); + gpio_cfg_pin(&gpio_base->gpio_h2, i, 0x3); reg = S5PC110_KEYPAD_BASE; col_mask = S5PC110_KEYIFCOLEN_MASK; @@ -142,11 +148,15 @@ static int check_block(void) int board_check_condition(void) { - if (check_keypad()) + if (check_keypad()) { + PUTS("manual mode\n"); return 1; + } - if (check_block()) + if (check_block()) { + PUTS("bootloader image broken\n"); return 1; + } return 0; } @@ -172,6 +182,11 @@ int board_load_uboot(unsigned char *buf) void board_recovery_init(void) { - /* Set Initial global variables */ - s5pc110_gpio = (struct s5pc110_gpio *) S5PC110_GPIO_BASE; + /* set GPIO to enable UART2 */ + gpio_cfg_pin(&gpio_base->gpio_a1, 0, 0x2); + gpio_cfg_pin(&gpio_base->gpio_a1, 1, 0x2); + + /* UART_SEL MP0_5[7] at S5PC110 */ + gpio_direction_output(&gpio_base->gpio_mp0_5, 7, 0x1); + gpio_set_pull(&gpio_base->gpio_mp0_5, 7, GPIO_PULL_DOWN); } diff --git a/recovery/common.h b/recovery/common.h deleted file mode 100644 index b6960f7..0000000 --- a/recovery/common.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * (C) Copyright 2010 Samsung Electronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#ifndef __COMMON_H -#define __COMMON_H - -/* board/.../... */ - -extern int board_check_condition(void); -extern int board_load_uboot(unsigned char *buf); -extern void board_recovery_init(void); - -#endif diff --git a/recovery/config.mk b/recovery/config.mk index c3afb0f..76be7a8 100644 --- a/recovery/config.mk +++ b/recovery/config.mk @@ -188,6 +188,7 @@ CPPFLAGS += -fno-builtin -ffreestanding -nostdinc \ CPPFLAGS += -I$(TOPDIR)/$(RECOVERY_BLOCK) CPPFLAGS += -DCONFIG_RECOVERY_BLOCK -D__HAVE_ARCH_MEMCPY32 +CPPFLAGS += -DRECOVERY_DEBUG ifdef BUILD_TAG CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \ diff --git a/recovery/drivers/serial/Makefile b/recovery/drivers/serial/Makefile new file mode 100644 index 0000000..af7a5e3 --- /dev/null +++ b/recovery/drivers/serial/Makefile @@ -0,0 +1,45 @@ +# +# Copyright (C) 2005-2007 Samsung Electronics. +# Sanghee Kim +# +# 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 $(TOPDIR)/$(RECOVERY_BLOCK)/config.mk + +LIB := $(obj)libserial.a + +COBJS-$(CONFIG_S5PC1XX) += serial_s5pc1xx.o + +COBJS := $(sort $(COBJS-y)) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/recovery/drivers/serial/serial_s5pc1xx.c b/recovery/drivers/serial/serial_s5pc1xx.c new file mode 100644 index 0000000..9164140 --- /dev/null +++ b/recovery/drivers/serial/serial_s5pc1xx.c @@ -0,0 +1,197 @@ +/* + * (C) Copyright 2009 SAMSUNG Electronics + * Minkyu Kang + * Heungjun Kim + * + * based on drivers/serial/s3c64xx.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +static inline struct s5pc1xx_uart *s5pc1xx_get_base_uart(int dev_index) +{ + u32 offset = dev_index * sizeof(struct s5pc1xx_uart); + + return (struct s5pc1xx_uart *)(S5PC110_UART_BASE + offset); +} + +/* + * The coefficient, used to calculate the baudrate on S3C6400 UARTs is + * calculated as + * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT + * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1, + * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants: + */ +static const int udivslot[] = { + 0, + 0x0080, + 0x0808, + 0x0888, + 0x2222, + 0x4924, + 0x4a52, + 0x54aa, + 0x5555, + 0xd555, + 0xd5d5, + 0xddd5, + 0xdddd, + 0xdfdd, + 0xdfdf, + 0xffdf, +}; + +void serial_setbrg_dev(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + /* baudrate: 115200*/ + writel(0x23, &uart->ubrdiv); + writew(udivslot[2], &uart->udivslot); +} + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + */ +int serial_init_dev(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + /* reset and enable FIFOs, set triggers to the maximum */ + writel(0, &uart->ufcon); + writel(0, &uart->umcon); + /* 8N1 */ + writel(0x3, &uart->ulcon); + /* No interrupts, no DMA, pure polling */ + writel(0x245, &uart->ucon); + + serial_setbrg_dev(dev_index); + + return 0; +} + +static int serial_err_check(const int dev_index, int op) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + unsigned int mask; + + /* + * UERSTAT + * Break Detect [3] + * Frame Err [2] : receive operation + * Parity Err [1] : receive operation + * Overrun Err [0] : receive operation + */ + if (op) + mask = 0x8; + else + mask = 0xf; + + return readl(&uart->uerstat) & mask; +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc_dev(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + /* wait for character to arrive */ + while (!(readl(&uart->utrstat) & 0x1)) { + if (serial_err_check(dev_index, 0)) + return 0; + } + + return (int)(readl(&uart->urxh) & 0xff); +} + +/* + * Output a single byte to the serial port. + */ +void serial_putc_dev(const char c, const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + /* wait for room in the tx FIFO */ + while (!(readl(&uart->utrstat) & 0x2)) { + if (serial_err_check(dev_index, 1)) + return; + } + + writel(c, &uart->utxh); + + /* If \n, also do \r */ + if (c == '\n') + serial_putc_dev('\r', dev_index); +} + +/* + * Test whether a character is in the RX buffer + */ +int serial_tstc_dev(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + return (int)(readl(&uart->utrstat) & 0x1); +} + +void serial_puts_dev(const char *s, const int dev_index) +{ + while (*s) + serial_putc_dev(*s++, dev_index); +} + +/* Multi serial device functions */ +#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \ +int s5p_serial##port##_init(void) { return serial_init_dev(port); } \ +void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \ +int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \ +int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \ +void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \ +void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); } + +#define INIT_S5P_SERIAL_STRUCTURE(port, name, bus) { \ + name, \ + bus, \ + s5p_serial##port##_init, \ + s5p_serial##port##_setbrg, \ + s5p_serial##port##_getc, \ + s5p_serial##port##_tstc, \ + s5p_serial##port##_putc, \ + s5p_serial##port##_puts, } + +DECLARE_S5P_SERIAL_FUNCTIONS(0); +struct serial_device s5pc1xx_serial0_device = + INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0", "S5PUART0"); +DECLARE_S5P_SERIAL_FUNCTIONS(1); +struct serial_device s5pc1xx_serial1_device = + INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1", "S5PUART1"); +DECLARE_S5P_SERIAL_FUNCTIONS(2); +struct serial_device s5pc1xx_serial2_device = + INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2", "S5PUART2"); +DECLARE_S5P_SERIAL_FUNCTIONS(3); +struct serial_device s5pc1xx_serial3_device = + INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3", "S5PUART3"); diff --git a/recovery/drivers/usb/Makefile b/recovery/drivers/usb/Makefile index 2140d76..21c1b5e 100644 --- a/recovery/drivers/usb/Makefile +++ b/recovery/drivers/usb/Makefile @@ -27,7 +27,7 @@ LIB := $(obj)libusb.a COBJS-$(CONFIG_S5PC1XX) += s5p_usb_hs_otg.o s5p_usb_downloader.o -SRCS := $(COBJS:.o=.c) +SRCS := $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(COBJS-y)) all: $(LIB) diff --git a/recovery/drivers/usb/s5p_usb_downloader.c b/recovery/drivers/usb/s5p_usb_downloader.c index 56a3d18..8a9b422 100644 --- a/recovery/drivers/usb/s5p_usb_downloader.c +++ b/recovery/drivers/usb/s5p_usb_downloader.c @@ -20,9 +20,16 @@ */ #include +#include "recovery.h" #include "usbd.h" #include "s5p_usb_hs_otg.h" +#ifdef RECOVERY_DEBUG +#define PUTS(s) serial_puts (DEBUG_MARK"usb: "s) +#else +#define PUTS(s) +#endif + #define TX_DATA_LEN 4 #define RX_DATA_LEN 64 @@ -56,11 +63,15 @@ static void s5p_usb_clear_dnfile_info(void) /* start the usb controller */ static void usb_init(void) { - if (usb_board_init()) + if (usb_board_init()) { + PUTS("Failed to usb_board_init\n"); return; + } s5p_usbctl_init(); + PUTS("USB Start!!\n"); + while (!s5p_usb_connected) { if (s5p_usb_detect_irq()) { s5p_udc_int_hndlr(); @@ -69,6 +80,8 @@ static void usb_init(void) } s5p_usb_clear_dnfile_info(); + + PUTS("Connected!!\n"); } static void usb_stop(void) diff --git a/recovery/recovery.c b/recovery/recovery.c index 1e8c842..688fdd6 100644 --- a/recovery/recovery.c +++ b/recovery/recovery.c @@ -23,10 +23,16 @@ #include #include -#include "common.h" +#include "recovery.h" #include "usbd.h" #include "onenand.h" +#ifdef RECOVERY_DEBUG +#define PUTS(s) serial_puts (DEBUG_MARK""s) +#else +#define PUTS(s) +#endif + typedef int (init_fnc_t)(void); static void normal_boot(void) @@ -42,11 +48,13 @@ static void normal_boot(void) static void recovery_boot(void) { + PUTS("Recovery Mode\n"); + /* usb download and write image */ do_usbd_down(); /* reboot */ - reset_cpu(0); + /* reset_cpu(0); */ } void start_recovery_boot(void) @@ -55,10 +63,13 @@ void start_recovery_boot(void) mem_malloc_init(_armboot_start - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN); - onenand_init(); - board_recovery_init(); + onenand_init(); + + serial_init(); + serial_puts("\n"); + if (board_check_condition()) recovery_boot(); else diff --git a/recovery/recovery.h b/recovery/recovery.h new file mode 100644 index 0000000..c4ca3a9 --- /dev/null +++ b/recovery/recovery.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * Sanghee Kim + * + * Common header for Recovery Block + */ + +#ifndef _RECOVERY_H +#define _RECOVERY_H + +#define DEBUG_MARK "Recovery: " + +/* board/.../... */ + +extern int board_check_condition(void); +extern int board_load_uboot(unsigned char *buf); +extern void board_recovery_init(void); + +#endif diff --git a/recovery/serial.c b/recovery/serial.c new file mode 100644 index 0000000..347b90d --- /dev/null +++ b/recovery/serial.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2010 Samsung Electronics + * Sanghee Kim + * + * 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 +#include + +static struct serial_device *serial_current = NULL; + +struct serial_device *__default_serial_console (void) +{ + return &s5pc1xx_serial2_device; +} + +struct serial_device *default_serial_console(void) __attribute__((weak, alias("__default_serial_console"))); + +void serial_putc(const char c) +{ + if (!serial_current) { + struct serial_device *dev = default_serial_console (); + + dev->putc (c); + return; + } + + serial_current->putc (c); +} + +void serial_puts(const char *s) +{ + if (!serial_current) { + struct serial_device *dev = default_serial_console (); + + dev->puts (s); + return; + } + + serial_current->puts (s); +} + +int serial_init(void) +{ + if (!serial_current) { + struct serial_device *dev = default_serial_console (); + + return dev->init (); + } + + return serial_current->init (); +} diff --git a/recovery/usbd.c b/recovery/usbd.c index 51d9b17..bd4f7cc 100644 --- a/recovery/usbd.c +++ b/recovery/usbd.c @@ -7,9 +7,16 @@ */ #include +#include "recovery.h" #include "usbd.h" #include "onenand.h" +#ifdef RECOVERY_DEBUG +#define PUTS(s) serial_puts (DEBUG_MARK"usb: "s) +#else +#define PUTS(s) +#endif + static struct usbd_ops usbd_ops; static unsigned long down_ram_addr; @@ -54,6 +61,7 @@ static int process_data(struct usbd_ops *usbd) switch (cmd) { case COMMAND_DOWNLOAD_IMAGE: + PUTS("COMMAND_DOWNLOAD_IMAGE\n"); usbd->recv_setup((char *)down_ram_addr, (int)len); /* response */ @@ -63,8 +71,10 @@ static int process_data(struct usbd_ops *usbd) recvlen = usbd->recv_data(); /* Retry this commad */ - if (recvlen < len) + if (recvlen < len) { + PUTS("Error: wrong image size\n"); *((ulong *) usbd->tx_data) = STATUS_RETRY; + } else *((ulong *) usbd->tx_data) = STATUS_DONE; @@ -77,11 +87,14 @@ static int process_data(struct usbd_ops *usbd) return 1; case COMMAND_WRITE_PART_1: + PUTS("COMMAND_WRITE_PART_BOOT\n"); img_type = IMG_BOOT; break; /* Download complete -> reset */ case COMMAND_RESET_PDA: + PUTS("Download finished and Auto reset!\n"); + PUTS("Wait........\n"); /* Stop USB */ usbd->usb_stop(); @@ -92,6 +105,8 @@ static int process_data(struct usbd_ops *usbd) /* Error */ case COMMAND_RESET_USB: + PUTS("Error is occured!(maybe previous step)->\ + Turn off and restart!\n"); /* Stop USB */ usbd->usb_stop(); return 0; @@ -129,6 +144,7 @@ int do_usbd_down(void) { struct usbd_ops *usbd; + PUTS("USB Downloader\n"); /* interface setting */ usbd = usbd_set_interface(&usbd_ops); down_ram_addr = usbd->ram_addr; @@ -145,6 +161,8 @@ int do_usbd_down(void) else return 0; + PUTS("Receive the packet\n"); + /* receive the data from Host PC */ while (1) { usbd->recv_setup(usbd->rx_data, usbd->rx_len); -- 2.7.4