From patchwork Tue Jul 3 09:38:07 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?=C5=81ukasz_Majewski?= X-Patchwork-Id: 168750 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 9C8FF2C00F5 for ; Tue, 3 Jul 2012 19:39:05 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9166A280D5; Tue, 3 Jul 2012 11:38:53 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id wn9a1chh8HYP; Tue, 3 Jul 2012 11:38:53 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3E18C280D6; Tue, 3 Jul 2012 11:38:40 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 7A47C280D9 for ; Tue, 3 Jul 2012 11:38:37 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Tsr0NuKteYNv for ; Tue, 3 Jul 2012 11:38:36 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) by theia.denx.de (Postfix) with ESMTP id 5ECA3280AD for ; Tue, 3 Jul 2012 11:38:30 +0200 (CEST) Received: from epcpsbgm2.samsung.com (mailout3.samsung.com [203.254.224.33]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0M6K00GO0W23DCU0@mailout3.samsung.com> for u-boot@lists.denx.de; Tue, 03 Jul 2012 18:38:28 +0900 (KST) X-AuditID: cbfee61b-b7f776d000002f3f-e9-4ff2bd94c7a8 Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 0F.ED.12095.49DB2FF4; Tue, 03 Jul 2012 18:38:28 +0900 (KST) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0M6K0019TW3PXE40@mmp2.samsung.com> for u-boot@lists.denx.de; Tue, 03 Jul 2012 18:38:28 +0900 (KST) From: Lukasz Majewski To: u-boot@lists.denx.de Date: Tue, 03 Jul 2012 11:38:07 +0200 Message-id: <1341308291-14663-4-git-send-email-l.majewski@samsung.com> X-Mailer: git-send-email 1.7.10 In-reply-to: <1341308291-14663-1-git-send-email-l.majewski@samsung.com> References: <1341308291-14663-1-git-send-email-l.majewski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrEJMWRmVeSWpSXmKPExsVy+t9jQd0pez/5G/Q06Fm83dvJ7sDocfbO DsYAxigum5TUnMyy1CJ9uwSujI6VMQVrYys+NL9jbmDs8Opi5OSQEDCRWPrlLyuELSZx4d56 ti5GLg4hgemMEs1TZzNDOIuZJBo7VjCDVLEJ6El8vvuUCcQWEZCQ+NV/lRHEZhYok9g75TXY JGGgqU82TWYBsVkEVCX+fv8OVs8r4CaxcvFbRoht8hJP7/exgdicAu4S97bvArOFgGquPJ3N NoGRdwEjwypG0dSC5ILipPRcI73ixNzi0rx0veT83E2MYJ8/k97BuKrB4hCjAAejEg+vxaZP /kKsiWXFlbmHGCU4mJVEeK9uAQrxpiRWVqUW5ccXleakFh9ilOZgURLnbbK+4C8kkJ5Ykpqd mlqQWgSTZeLglGpgtLSutL9ZEi1XEvXxwHyn4orHP/5YJegHrpsl8oFRiUUqPOBL+HPxXa83 3dtc8SQytLiAQ/5ORPVx7/CHF8ynhumyKcUceeHolnK8hXmj4EFxm70Tb1pd39GveVuws0XH 8LoQqzUrh2etooXoGrsPAgquV2dyL6nly9sqZ28vzNjl8P/syitKLMUZiYZazEXFiQCRZKeh 9QEAAA== X-TM-AS-MML: No Cc: Marek Vasut , Kyungmin Park Subject: [U-Boot] [PATCH 3/7] dfu: DFU backend implementation X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de New, separate driver at ./drivers/dfu has been added. It allows platform and storage independent operation of DFU. Signed-off-by: Lukasz Majewski Signed-off-by: Kyungmin Park Cc: Marek Vasut --- Makefile | 1 + drivers/dfu/Makefile | 43 ++++++++ drivers/dfu/dfu.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/dfu.h | 99 +++++++++++++++++++ 4 files changed, 402 insertions(+), 0 deletions(-) create mode 100644 drivers/dfu/Makefile create mode 100644 drivers/dfu/dfu.c create mode 100644 include/dfu.h diff --git a/Makefile b/Makefile index 0197239..c37dcf3 100644 --- a/Makefile +++ b/Makefile @@ -271,6 +271,7 @@ LIBS += drivers/pci/libpci.o LIBS += drivers/pcmcia/libpcmcia.o LIBS += drivers/power/libpower.o LIBS += drivers/spi/libspi.o +LIBS += drivers/dfu/libdfu.o ifeq ($(CPU),mpc83xx) LIBS += drivers/qe/libqe.o LIBS += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o diff --git a/drivers/dfu/Makefile b/drivers/dfu/Makefile new file mode 100644 index 0000000..7736485 --- /dev/null +++ b/drivers/dfu/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (C) 2012 Samsung Electronics +# Lukasz Majewski +# +# 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)/config.mk + +LIB = $(obj)libdfu.o + +COBJS-$(CONFIG_DFU_FUNCTION) += dfu.o + +SRCS := $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c new file mode 100644 index 0000000..63733fb --- /dev/null +++ b/drivers/dfu/dfu.c @@ -0,0 +1,259 @@ +/* + * dfu.c -- DFU back-end routines + * + * Copyright (C) 2012 Samsung Electronics + * authors: Andrzej Pietrasiewicz + * Lukasz Majewski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +static LIST_HEAD(dfu_list); +static int dfu_alt_num; + +static int dfu_find_alt_num(char *s) +{ + int i = 0; + + for (; *s; s++) + if (*s == ';') + i++; + + return ++i; +} + +static char *dfu_extract_entity(char** env) +{ + char *s = *env; + + strsep(env, ";"); + return s; +} + +char *dfu_extract_token(char** e, int *n) +{ + char *st = *e; + + debug("%s: %s\n", __func__, st); + + strsep(e, " "); + *n = *e - st; + + return st; +} + +static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) + dfu_buf[DFU_DATA_BUF_SIZE]; + +int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) +{ + static unsigned char *i_buf; + static int i_blk_seq_num; + long w_size = 0; + int ret = 0; + + debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", + __func__, dfu->name, buf, size, blk_seq_num, i_buf); + + if (blk_seq_num == 0) { + memset(dfu_buf, '\0', sizeof(dfu_buf)); + i_buf = dfu_buf; + i_blk_seq_num = 0; + } + + if (i_blk_seq_num++ != blk_seq_num) { + printf("%s: Wrong sequence number! [%d] [%d]\n", + __func__, i_blk_seq_num, blk_seq_num); + return -1; + } + + memcpy(i_buf, buf, size); + i_buf += size; + + if (size == 0) { + /* Integrity check (if needed) */ + debug("%s: %s %d [B] CRC32: 0x%x\n", __func__, dfu->name, + i_buf - dfu_buf, crc32(0, dfu_buf, i_buf - dfu_buf)); + + w_size = i_buf - dfu_buf; + ret = dfu->write_medium(dfu, dfu_buf, &w_size); + if (ret) + debug("%s: Write error!\n", __func__); + + i_blk_seq_num = 0; + i_buf = NULL; + return ret; + } + + return ret; +} + +int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) +{ + static unsigned char *i_buf; + static int i_blk_seq_num; + static long r_size; + static u32 crc; + int ret = 0; + + debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", + __func__, dfu->name, buf, size, blk_seq_num, i_buf); + + if (blk_seq_num == 0) { + i_buf = dfu_buf; + memset(dfu_buf, '\0', sizeof(dfu_buf)); + ret = dfu->read_medium(dfu, i_buf, &r_size); + debug("%s: %s %ld [B]\n", __func__, dfu->name, r_size); + i_blk_seq_num = 0; + /* Integrity check (if needed) */ + crc = crc32(0, dfu_buf, r_size); + } + + if (i_blk_seq_num++ != blk_seq_num) { + printf("%s: Wrong sequence number! [%d] [%d]\n", + __func__, i_blk_seq_num, blk_seq_num); + return -1; + } + + if (r_size >= size) { + memcpy(buf, i_buf, size); + i_buf += size; + r_size -= size; + return size; + } else { + memcpy(buf, i_buf, r_size); + i_buf += r_size; + debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, crc); + puts("UPLOAD ... done\n"); + puts("Ctrl+C to exit ...\n"); + + i_buf = NULL; + i_blk_seq_num = 0; + crc = 0; + return r_size; + } + return ret; +} + +static int dfu_fill_entity(struct dfu_entity *dfu, char* s, int alt, + char *interface, int num) +{ + char *st = NULL; + int n = 0; + + debug("%s: %s interface: %s num: %d\n", __func__, s, interface, num); + + st = dfu_extract_token(&s, &n); + strncpy((char *) &dfu->name, st, n); + + dfu->dev_num = num; + dfu->alt = alt; + + /* Specific for mmc device */ + if (strcmp(interface, "mmc") == 0) { + if (dfu_fill_entity_mmc(dfu, s)) + return -1; + } else { + printf("dfu: Device %s not supported\n", interface); + return -1; + } + + return 0; +} + +int dfu_config_entities(char *env, char *interface, int num) +{ + struct dfu_entity *dfu; + int i, ret; + char *s; + + dfu_alt_num = dfu_find_alt_num(env); + debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num); + + for (i = 0; i < dfu_alt_num; i++) { + dfu = calloc(sizeof(struct dfu_entity), 1); + + s = dfu_extract_entity(&env); + ret = dfu_fill_entity(dfu, s, i, interface, num); + if (ret) + return -1; + + list_add_tail(&dfu->list, &dfu_list); + } + + return 0; +} + +void dfu_free_entities(void) +{ + struct dfu_entity *dfu = NULL, *p = NULL; + + list_for_each_entry_safe_reverse(dfu, p, &dfu_list, list) { + list_del(&dfu->list); + free(dfu); + } + + INIT_LIST_HEAD(&dfu_list); +} + +static char *dfu_get_dev_type(enum dfu_device_type t) +{ + static char *dev_t[] = {NULL, "MMC", "ONENAND", "NAND" }; + return dev_t[t]; +} + +static char *dfu_get_layout(enum dfu_device_type l) +{ + static char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT" }; + return dfu_layout[l]; +} + +void dfu_show_entities(void) +{ + struct dfu_entity *dfu = NULL; + + puts("DFU alt settings list:\n"); + + list_for_each_entry(dfu, &dfu_list, list) { + printf("dev: %s alt: %d name: %s layout: %s\n", + dfu_get_dev_type(dfu->dev_type), dfu->alt, + dfu->name, dfu_get_layout(dfu->layout)); + } +} + +int dfu_get_alt_number(void) +{ + return dfu_alt_num; +} + +struct dfu_entity *dfu_get_entity(int alt) +{ + struct dfu_entity *dfu = NULL; + + list_for_each_entry(dfu, &dfu_list, list) { + if (dfu->alt == alt) + return dfu; + } + + return NULL; +} diff --git a/include/dfu.h b/include/dfu.h new file mode 100644 index 0000000..f7d823b --- /dev/null +++ b/include/dfu.h @@ -0,0 +1,99 @@ +/* + * dfu.h - DFU flashable area description + * + * Copyright (C) 2012 Samsung Electronics + * authors: Andrzej Pietrasiewicz + * Lukasz Majewski + * + * 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 __DFU_ENTITY_H_ +#define __DFU_ENTITY_H_ + +#include +#include +#include + +enum dfu_device_type { + MMC = 1, + ONENAND, + NAND +}; + +enum dfu_layout { + RAW_ADDR = 1, + FAT, + EXT, +}; + +struct mmc_internal_data { + /* RAW programming */ + unsigned int lba_start; + unsigned int lba_size; + unsigned int lba_blk_size; + + /* FAT/EXT */ + unsigned int dev; + unsigned int part; +}; + +static inline unsigned int get_mmc_blk_size(int dev) +{ + return find_mmc_device(dev)->read_bl_len; +} + +#define DFU_NAME_SIZE 32 +#define DFU_CMD_BUF_SIZE 128 +#define DFU_DATA_BUF_SIZE (1024*1024*4) /* 4 MiB */ + +struct dfu_entity { + char name[DFU_NAME_SIZE]; + int alt; + void *dev_private; + int dev_num; + enum dfu_device_type dev_type; + enum dfu_layout layout; + + union { + struct mmc_internal_data mmc; + } data; + + int (*read_medium)(struct dfu_entity *dfu, void *buf, long *len); + int (*write_medium)(struct dfu_entity *dfu, void *buf, long *len); + + struct list_head list; +}; + +int dfu_config_entities(char *s, char *interface, int num); +void dfu_free_entities(void); +void dfu_show_entities(void); +int dfu_get_alt_number(void); +struct dfu_entity *dfu_get_entity(int alt); +char *dfu_extract_token(char** e, int *n); + +int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num); +int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num); +/* Device specific */ +#ifdef CONFIG_DFU_MMC +extern int dfu_fill_entity_mmc(struct dfu_entity *dfu, char* s); +#else +static inline int dfu_fill_entity_mmc(struct dfu_entity *dfu, char* s) +{ + puts("MMC support not available!\n"); + return -1; +} +#endif +#endif /* __DFU_ENTITY_H_ */