Merge "platform: msm_shared: Remove references to thulium"
diff --git a/AndroidBoot.mk b/AndroidBoot.mk
index b158dec..1b336e3 100644
--- a/AndroidBoot.mk
+++ b/AndroidBoot.mk
@@ -20,7 +20,7 @@
ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),true)
VERIFIED_BOOT := VERIFIED_BOOT=1
else
- VERIFIED_BOOT := VERIFEID_BOOT=0
+ VERIFIED_BOOT := VERIFIED_BOOT=0
endif
ifneq ($(TARGET_BUILD_VARIANT),user)
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 3b8aead..5451150 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -759,18 +759,6 @@
set_tamper_flag(device.is_tampered);
#endif
- if(device.is_tampered)
- {
- write_device_info_mmc(&device);
- #ifdef TZ_TAMPER_FUSE
- set_tamper_fuse_cmd();
- #endif
- #ifdef ASSERT_ON_TAMPER
- dprintf(CRITICAL, "Device is tampered. Asserting..\n");
- ASSERT(0);
- #endif
- }
-
#if VERIFIED_BOOT
if(boot_verify_get_state() == RED)
{
@@ -788,6 +776,19 @@
}
}
#endif
+
+ if(device.is_tampered)
+ {
+ write_device_info_mmc(&device);
+ #ifdef TZ_TAMPER_FUSE
+ set_tamper_fuse_cmd();
+ #endif
+ #ifdef ASSERT_ON_TAMPER
+ dprintf(CRITICAL, "Device is tampered. Asserting..\n");
+ ASSERT(0);
+ #endif
+ }
+
}
static bool check_format_bit()
@@ -2335,6 +2336,30 @@
return;
}
+void cmd_updatevol(const char *vol_name, void *data, unsigned sz)
+{
+ struct ptentry *sys_ptn;
+ struct ptable *ptable;
+
+ ptable = flash_get_ptable();
+ if (ptable == NULL) {
+ fastboot_fail("partition table doesn't exist");
+ return;
+ }
+
+ sys_ptn = ptable_find(ptable, "system");
+ if (sys_ptn == NULL) {
+ fastboot_fail("system partition not found");
+ return;
+ }
+
+ sz = ROUND_TO_PAGE(sz, page_mask);
+ if (update_ubi_vol(sys_ptn, vol_name, data, sz))
+ fastboot_fail("update_ubi_vol failed");
+ else
+ fastboot_okay("");
+}
+
void cmd_flash_nand(const char *arg, void *data, unsigned sz)
{
struct ptentry *ptn;
@@ -2349,7 +2374,9 @@
ptn = ptable_find(ptable, arg);
if (ptn == NULL) {
- fastboot_fail("unknown partition name");
+ dprintf(INFO, "unknown partition name (%s). Trying updatevol\n",
+ arg);
+ cmd_updatevol(arg, data, sz);
return;
}
diff --git a/include/dev/flash-ubi.h b/include/dev/flash-ubi.h
index 50577cc..a8bf819 100644
--- a/include/dev/flash-ubi.h
+++ b/include/dev/flash-ubi.h
@@ -77,6 +77,8 @@
/* Erase counter header magic number (ASCII "UBI#") */
#define UBI_EC_HDR_MAGIC 0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
#define UBI_MAGIC "UBI#"
#define UBI_MAGIC_SIZE 0x04
@@ -129,30 +131,85 @@
#define UBI_MAX_VOLUMES 128
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
+#define UBI_VID_DYNAMIC 1
+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
#define UBI_FM_SB_VOLUME_ID (UBI_INTERNAL_VOL_START + 1)
+/* A record in the UBI volume table. */
+struct __attribute__ ((packed)) ubi_vtbl_record {
+ uint32_t reserved_pebs;
+ uint32_t alignment;
+ uint32_t data_pad;
+ uint8_t vol_type;
+ uint8_t upd_marker;
+ uint16_t name_len;
+#define UBI_VOL_NAME_MAX 127
+ uint8_t name[UBI_VOL_NAME_MAX+1];
+ uint8_t flags;
+ uint8_t padding[23];
+ uint32_t crc;
+};
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(uint32_t))
+
+/* PEB status */
+enum {
+ UBI_UNKNOWN = 0,
+ UBI_BAD_PEB,
+ UBI_FREE_PEB,
+ UBI_USED_PEB,
+ UBI_EMPTY_PEB
+};
+
+/**
+ * struct peb_info - In RAM info on a PEB
+ * @ec: erase counter
+ * @status: status of this PEB: UBI_BAD_PEB/USED/FREE/EMPTY
+ * @volume: if status = UBI_USED_PEB this is the volume
+ * ID this PEB belongs to -1 for any other status
+ */
+struct peb_info {
+ uint64_t ec;
+ int status;
+ int volume;
+};
+
/**
* struct ubi_scan_info - UBI scanning information.
- * @ec: erase counters or eraseblock status for all eraseblocks
+ * @pebs_data: info on all of partition PEBs
* @mean_ec: mean erase counter
+ * @vtbl_peb1: number of the first PEB holding the volume table
+ * (relative to the beginning of the partition)
+ * @vtbl_peb1: number of the second PEB holding the volume table
+ * (relative to the beginning of the partition)
* @bad_cnt: count of bad eraseblocks
- * @good_cnt: count of non-bad eraseblocks
* @empty_cnt: count of empty eraseblocks
+ * @free_cnt: count of free eraseblocks
+ * @used_cnt: count of used eraseblocks
+ * @fastmap_sb: PEB number holding FM superblock. If FM is not present: -1
* @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means
* undefined)
* @data_offs: data offset from the found EC headers (%-1 means undefined)
* @image_seq: image sequence
+ * @read_image_seq: image sequence read from NAND while scanning
*/
struct ubi_scan_info {
- uint64_t *ec;
+ struct peb_info *pebs_data;
uint64_t mean_ec;
+ int vtbl_peb1;
+ int vtbl_peb2;
int bad_cnt;
- int good_cnt;
int empty_cnt;
+ int free_cnt;
+ int used_cnt;
+ int fastmap_sb;
unsigned vid_hdr_offs;
unsigned data_offs;
uint32_t image_seq;
+ uint32_t read_image_seq;
};
int flash_ubi_img(struct ptentry *ptn, void *data, unsigned size);
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+ void *data, unsigned size);
#endif
diff --git a/include/dev/udc.h b/include/dev/udc.h
index 42ced0e..31d9755 100644
--- a/include/dev/udc.h
+++ b/include/dev/udc.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2009, Google Inc.
* All rights reserved.
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -50,6 +50,8 @@
#define UDC_TYPE_BULK_IN 1
#define UDC_TYPE_BULK_OUT 2
+#define UDC_TYPE_INTR_IN 3
+#define UDC_TYPE_INTR_OUT 4
struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt);
void udc_endpoint_free(struct udc_endpoint *ept);
diff --git a/platform/msm8952/acpuclock.c b/platform/msm8952/acpuclock.c
index ffb8b92..ff25ac0 100644
--- a/platform/msm8952/acpuclock.c
+++ b/platform/msm8952/acpuclock.c
@@ -38,24 +38,144 @@
void hsusb_clock_init(void)
{
+ int ret;
+ struct clk *iclk, *cclk;
+ ret = clk_get_set_enable("usb_iface_clk", 0, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set usb_iface_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+
+ ret = clk_get_set_enable("usb_core_clk", 80000000, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set usb_core_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+
+ mdelay(20);
+
+ iclk = clk_get("usb_iface_clk");
+ cclk = clk_get("usb_core_clk");
+
+ clk_disable(iclk);
+ clk_disable(cclk);
+
+ mdelay(20);
+
+ /* Start the block reset for usb */
+ writel(1, USB_HS_BCR);
+
+ mdelay(20);
+
+ /* Take usb block out of reset */
+ writel(0, USB_HS_BCR);
+
+ mdelay(20);
+
+ ret = clk_enable(iclk);
+
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set usb_iface_clk after async ret = %d\n", ret);
+ ASSERT(0);
+ }
+
+ ret = clk_enable(cclk);
+
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set usb_iface_clk after async ret = %d\n", ret);
+ ASSERT(0);
+ }
}
void clock_init_mmc(uint32_t interface)
{
+ char clk_name[64];
+ int ret;
+ snprintf(clk_name, sizeof(clk_name), "sdc%u_iface_clk", interface);
+
+ /* enable interface clock */
+ ret = clk_get_set_enable(clk_name, 0, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set sdc1_iface_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
}
/* Configure MMC clock */
void clock_config_mmc(uint32_t interface, uint32_t freq)
{
- mmc_boot_mci_clk_enable();
+ int ret = 1;
+ char clk_name[64];
+
+ snprintf(clk_name, sizeof(clk_name), "sdc%u_core_clk", interface);
+
+ if(freq == MMC_CLK_400KHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 400000, 1);
+ }
+ else if(freq == MMC_CLK_50MHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 50000000, 1);
+ }
+ else if(freq == MMC_CLK_177MHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 177770000, 1);
+ }
+ else if(freq == MMC_CLK_192MHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 192000000, 1);
+ }
+ else if(freq == MMC_CLK_200MHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 200000000, 1);
+ }
+ else if(freq == MMC_CLK_400MHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 384000000, 1);
+ }
+ else
+ {
+ dprintf(CRITICAL, "sdc frequency (%u) is not supported\n", freq);
+ ASSERT(0);
+ }
+
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set %s ret = %d\n", clk_name, ret);
+ ASSERT(0);
+ }
}
/* Configure UART clock based on the UART block id*/
void clock_config_uart_dm(uint8_t id)
{
+ int ret;
+ char iclk[64];
+ char cclk[64];
+ snprintf(iclk, sizeof(iclk), "uart%u_iface_clk", id);
+ snprintf(cclk, sizeof(cclk), "uart%u_core_clk", id);
+
+ ret = clk_get_set_enable(iclk, 0, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set %s ret = %d\n", iclk, ret);
+ ASSERT(0);
+ }
+
+ ret = clk_get_set_enable(cclk, 7372800, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set %s ret = %d\n", cclk, ret);
+ ASSERT(0);
+ }
}
/* Function to asynchronously reset CE.
@@ -63,16 +183,91 @@
*/
static void ce_async_reset(uint8_t instance)
{
+ /* Start the block reset for CE */
+ writel(1, GCC_CRYPTO_BCR);
+ udelay(2);
+
+ /* Take CE block out of reset */
+ writel(0, GCC_CRYPTO_BCR);
+
+ udelay(2);
}
void clock_ce_enable(uint8_t instance)
{
+ int ret;
+ char clk_name[64];
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_src_clk", instance);
+ ret = clk_get_set_enable(clk_name, 160000000, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set ce%u_src_clk ret = %d\n", instance, ret);
+ ASSERT(0);
+ }
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_core_clk", instance);
+ ret = clk_get_set_enable(clk_name, 0, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set ce%u_core_clk ret = %d\n", instance, ret);
+ ASSERT(0);
+ }
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_ahb_clk", instance);
+ ret = clk_get_set_enable(clk_name, 0, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set ce%u_ahb_clk ret = %d\n", instance, ret);
+ ASSERT(0);
+ }
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_axi_clk", instance);
+ ret = clk_get_set_enable(clk_name, 0, 1);
+ if(ret)
+ {
+ dprintf(CRITICAL, "failed to set ce%u_axi_clk ret = %d\n", instance, ret);
+ ASSERT(0);
+ }
+
+ /* Wait for 48 * #pipes cycles.
+ * This is necessary as immediately after an access control reset (boot up)
+ * or a debug re-enable, the Crypto core sequentially clears its internal
+ * pipe key storage memory. If pipe key initialization writes are attempted
+ * during this time, they may be overwritten by the internal clearing logic.
+ */
+ udelay(1);
}
void clock_ce_disable(uint8_t instance)
{
+ struct clk *ahb_clk;
+ struct clk *cclk;
+ struct clk *axi_clk;
+ struct clk *src_clk;
+ char clk_name[64];
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_src_clk", instance);
+ src_clk = clk_get(clk_name);
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_ahb_clk", instance);
+ ahb_clk = clk_get(clk_name);
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_axi_clk", instance);
+ axi_clk = clk_get(clk_name);
+
+ snprintf(clk_name, sizeof(clk_name), "ce%u_core_clk", instance);
+ cclk = clk_get(clk_name);
+
+ clk_disable(ahb_clk);
+ clk_disable(axi_clk);
+ clk_disable(cclk);
+ clk_disable(src_clk);
+
+ /* Some delay for the clocks to stabalize. */
+ udelay(1);
}
diff --git a/platform/msm8952/include/platform/iomap.h b/platform/msm8952/include/platform/iomap.h
index ac40933..f4712d7 100644
--- a/platform/msm8952/include/platform/iomap.h
+++ b/platform/msm8952/include/platform/iomap.h
@@ -62,6 +62,7 @@
#define MSM_SDC1_BASE (PERIPH_SS_BASE + 0x00024000)
#define MSM_SDC2_BASE (PERIPH_SS_BASE + 0x00064000)
+/* UART */
#define BLSP1_UART0_BASE (PERIPH_SS_BASE + 0x000AF000)
#define BLSP1_UART1_BASE (PERIPH_SS_BASE + 0x000B0000)
#define MSM_USB_BASE (PERIPH_SS_BASE + 0x000DB000)
@@ -84,12 +85,18 @@
/* CRYPTO ENGINE */
#define MSM_CE1_BASE 0x073A000
#define MSM_CE1_BAM_BASE 0x0704000
-
+#define GCC_CRYPTO_BCR (CLK_CTL_BASE + 0x16000)
+#define GCC_CRYPTO_CMD_RCGR (CLK_CTL_BASE + 0x16004)
+#define GCC_CRYPTO_CFG_RCGR (CLK_CTL_BASE + 0x16008)
+#define GCC_CRYPTO_CBCR (CLK_CTL_BASE + 0x1601C)
+#define GCC_CRYPTO_AXI_CBCR (CLK_CTL_BASE + 0x16020)
+#define GCC_CRYPTO_AHB_CBCR (CLK_CTL_BASE + 0x16024)
/* GPLL */
#define GPLL0_STATUS (CLK_CTL_BASE + 0x2101C)
#define APCS_GPLL_ENA_VOTE (CLK_CTL_BASE + 0x45000)
#define APCS_CLOCK_BRANCH_ENA_VOTE (CLK_CTL_BASE + 0x45004)
+#define GPLL4_MODE (CLK_CTL_BASE + 0x24000)
/* SDCC */
#define SDC1_HDRV_PULL_CTL (TLMM_BASE_ADDR + 0x10A000)
@@ -102,6 +109,25 @@
#define SDCC1_N (CLK_CTL_BASE + 0x42010) /* n */
#define SDCC1_D (CLK_CTL_BASE + 0x42014) /* d */
+/* SDHCI */
+#define MSM_SDC1_SDHCI_BASE (PERIPH_SS_BASE + 0x00024900)
+#define MSM_SDC2_SDHCI_BASE (PERIPH_SS_BASE + 0x00064900)
+
+#define SDCC_MCI_HC_MODE (0x00000078)
+#define SDCC_HC_PWRCTL_STATUS_REG (0x000000DC)
+#define SDCC_HC_PWRCTL_MASK_REG (0x000000E0)
+#define SDCC_HC_PWRCTL_CLEAR_REG (0x000000E4)
+#define SDCC_HC_PWRCTL_CTL_REG (0x000000E8)
+
+#define SDCC2_BCR (CLK_CTL_BASE + 0x43000) /* block reset */
+#define SDCC2_APPS_CBCR (CLK_CTL_BASE + 0x43018) /* branch control */
+#define SDCC2_AHB_CBCR (CLK_CTL_BASE + 0x4301C)
+#define SDCC2_CMD_RCGR (CLK_CTL_BASE + 0x43004) /* cmd */
+#define SDCC2_CFG_RCGR (CLK_CTL_BASE + 0x43008) /* cfg */
+#define SDCC2_M (CLK_CTL_BASE + 0x4300C) /* m */
+#define SDCC2_N (CLK_CTL_BASE + 0x43010) /* n */
+#define SDCC2_D (CLK_CTL_BASE + 0x43014) /* d */
+
/* UART */
#define BLSP1_AHB_CBCR (CLK_CTL_BASE + 0x1008)
#define BLSP1_UART2_APPS_CBCR (CLK_CTL_BASE + 0x302C)
diff --git a/platform/msm8952/include/platform/irqs.h b/platform/msm8952/include/platform/irqs.h
index 31da373..810f113 100644
--- a/platform/msm8952/include/platform/irqs.h
+++ b/platform/msm8952/include/platform/irqs.h
@@ -46,6 +46,8 @@
#define USB1_HS_BAM_IRQ (GIC_SPI_START + 135)
#define USB1_HS_IRQ (GIC_SPI_START + 134)
+#define SDCC1_PWRCTL_IRQ (GIC_SPI_START + 138)
+#define SDCC2_PWRCTL_IRQ (GIC_SPI_START + 221)
/* Retrofit universal macro names */
#define INT_USB_HS USB1_HS_IRQ
diff --git a/platform/msm8952/msm8952-clock.c b/platform/msm8952/msm8952-clock.c
index ed39611..f464cc8 100644
--- a/platform/msm8952/msm8952-clock.c
+++ b/platform/msm8952/msm8952-clock.c
@@ -111,6 +111,21 @@
},
};
+static struct pll_vote_clk gpll4_clk_src =
+{
+ .en_reg = (void *) APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(5),
+ .status_reg = (void *) GPLL4_MODE,
+ .status_mask = BIT(30),
+ .parent = &cxo_clk_src.c,
+
+ .c = {
+ .rate = 1152000000,
+ .dbg_name = "gpll4_clk_src",
+ .ops = &clk_ops_pll_vote,
+ },
+};
+
/* SDCC Clocks */
static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk[] =
{
@@ -121,8 +136,8 @@
F( 50000000, gpll0, 16, 0, 0),
F(100000000, gpll0, 8, 0, 0),
F(177770000, gpll0, 4.5, 0, 0),
- F(200000000, gpll0, 4, 0, 0),
- F(400000000, gpll4, 3, 0, 0),
+ F(192000000, gpll0, 6, 0, 0),
+ F(384000000, gpll4, 3, 0, 0),
F_END
};
@@ -135,7 +150,7 @@
.d_reg = (uint32_t *) SDCC1_D,
.set_rate = clock_lib2_rcg_set_rate_mnd,
- .freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+ .freq_tbl = ftbl_gcc_sdcc1_apps_clk,
.current_freq = &rcg_dummy_freq,
.c = {
diff --git a/platform/msm8952/platform.c b/platform/msm8952/platform.c
index 4648638..1ee7cdc 100644
--- a/platform/msm8952/platform.c
+++ b/platform/msm8952/platform.c
@@ -29,12 +29,16 @@
#include <debug.h>
#include <reg.h>
#include <platform/iomap.h>
+#include <platform/irqs.h>
+#include <platform/clock.h>
#include <qgic.h>
#include <qtimer.h>
#include <mmu.h>
#include <arch/arm/mmu.h>
#include <smem.h>
#include <board.h>
+#include <boot_stats.h>
+#include <platform.h>
#define MSM_IOMAP_SIZE ((MSM_IOMAP_END - MSM_IOMAP_BASE)/MB)
#define APPS_SS_SIZE ((APPS_SS_END - APPS_SS_BASE)/MB)
@@ -66,6 +70,7 @@
void platform_early_init(void)
{
board_init();
+ platform_clock_init();
qgic_init();
qtimer_init();
scm_init();
diff --git a/platform/msm8952/rules.mk b/platform/msm8952/rules.mk
index ebae71e..a337b97 100644
--- a/platform/msm8952/rules.mk
+++ b/platform/msm8952/rules.mk
@@ -12,13 +12,14 @@
DEFINES += PERIPH_BLK_BLSP=1
DEFINES += WITH_CPU_EARLY_INIT=0 WITH_CPU_WARM_BOOT=0 \
- MMC_SLOT=$(MMC_SLOT)
+ MMC_SLOT=$(MMC_SLOT) SSD_ENABLE
INCLUDES += -I$(LOCAL_DIR)/include -I$(LK_TOP_DIR)/platform/msm_shared/include
OBJS += \
$(LOCAL_DIR)/platform.o \
$(LOCAL_DIR)/acpuclock.o \
+ $(LOCAL_DIR)/msm8952-clock.o \
$(LOCAL_DIR)/gpio.o
LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld
diff --git a/platform/msm8996/platform.c b/platform/msm8996/platform.c
index a1c2dde..a82357b 100644
--- a/platform/msm8996/platform.c
+++ b/platform/msm8996/platform.c
@@ -142,3 +142,8 @@
return readl(USB3_PHY_REVISION_ID3) << 24 | readl(USB3_PHY_REVISION_ID2) << 16 |
readl(USB3_PHY_REVISION_ID1) << 8 | readl(USB3_PHY_REVISION_ID0);
}
+
+uint32_t platform_get_max_periph()
+{
+ return 256;
+}
diff --git a/platform/msm_shared/flash-ubi.c b/platform/msm_shared/flash-ubi.c
index 0051a3a..9b9dd51 100644
--- a/platform/msm_shared/flash-ubi.c
+++ b/platform/msm_shared/flash-ubi.c
@@ -118,6 +118,30 @@
}
/**
+ * calc_data_len - calculate how much real data is stored in the buffer
+ * @page_size: min I/O of the device
+ * @buf: a buffer with the contents of the physical eraseblock
+ * @len: the buffer length
+ *
+ * This function calculates how much "real data" is stored in @buf and
+ * returns the length (in number of pages). Continuous 0xFF bytes at the end
+ * of the buffer are not considered as "real data".
+ */
+static int calc_data_len(int page_size, const void *buf, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--)
+ if (((const uint8_t *)buf)[i] != 0xFF)
+ break;
+
+ /* The resulting length must be aligned to the minimum flash I/O size */
+ len = i + 1;
+ len = (len + page_size - 1) / page_size;
+ return len;
+}
+
+/**
* read_ec_hdr - read and check an erase counter header.
* @peb: number of the physical erase block to read the header for
* @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter
@@ -209,6 +233,141 @@
}
/**
+ * read_vid_hdr - read and check an Volume identifier header.
+ * @peb: number of the physical erase block to read the header for
+ * @vid_hdr: a &struct ubi_vid_hdr object where to store the read header
+ * @vid_hdr_offset: offset of the VID header from the beginning of the PEB
+ * (in bytes)
+ *
+ * This function reads the volume identifier header from physical
+ * eraseblock @peb and stores it in @vid_hdr. This function also checks the
+ * validity of the read header.
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ * 1 - if the PEB is free (no VID hdr)
+ */
+static int read_vid_hdr(uint32_t peb, struct ubi_vid_hdr *vid_hdr,
+ int vid_hdr_offset)
+{
+ unsigned char *spare, *tmp_buf;
+ int ret = -1;
+ uint32_t crc, magic;
+ int page_size = flash_page_size();
+ int num_pages_per_blk = flash_block_size()/page_size;
+
+ spare = (unsigned char *)malloc(flash_spare_size());
+ if (!spare)
+ {
+ dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+ return ret;
+ }
+
+ tmp_buf = (unsigned char *)malloc(page_size);
+ if (!tmp_buf)
+ {
+ dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+ goto out_tmp_buf;
+ }
+
+ if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+ dprintf(CRITICAL, "read_vid_hdr: Bad block @ %d\n", peb);
+ goto out;
+ }
+
+ if (qpic_nand_read(peb * num_pages_per_blk + vid_hdr_offset/page_size,
+ 1, tmp_buf, spare)) {
+ dprintf(CRITICAL, "read_vid_hdr: Read %d failed \n", peb);
+ goto out;
+ }
+ memcpy(vid_hdr, tmp_buf, UBI_VID_HDR_SIZE);
+
+ if (check_pattern((void *)vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+ ret = 1;
+ goto out;
+ }
+
+ magic = BE32(vid_hdr->magic);
+ if (magic != UBI_VID_HDR_MAGIC) {
+ dprintf(CRITICAL,
+ "read_vid_hdr: Wrong magic at peb-%d Expected: %d, received %d\n",
+ peb, UBI_VID_HDR_MAGIC, BE32(vid_hdr->magic));
+ goto out;
+ }
+
+ crc = mtd_crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+ if (BE32(vid_hdr->hdr_crc) != crc) {
+ dprintf(CRITICAL,
+ "read_vid_hdr: Wrong crc at peb-%d: calculated %d, received %d\n",
+ peb,crc, BE32(vid_hdr->hdr_crc));
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(tmp_buf);
+out_tmp_buf:
+ free(spare);
+ return ret;
+}
+
+/**
+ * read_leb_data - read data section of the PEB (LEB).
+ * @peb: number of the physical erase block to read the data for
+ * @leb_data: a buffer where to store the read data at
+ * @leb_size: LEB size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int read_leb_data(uint32_t peb, void *leb_data,
+ int leb_size, int data_offset)
+{
+ unsigned char *spare, *tmp_buf;
+ int ret = -1;
+ int page_size = flash_page_size();
+ int block_size = flash_block_size();
+ int num_pages_per_blk = block_size/page_size;
+
+ spare = (unsigned char *)malloc(flash_spare_size());
+ if (!spare)
+ {
+ dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+ return ret;
+ }
+
+ tmp_buf = (unsigned char *)malloc(leb_size);
+ if (!tmp_buf)
+ {
+ dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+ goto out_tmp_buf;
+ }
+
+ if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+ dprintf(CRITICAL, "read_leb_data: Bad block @ %d\n", peb);
+ goto out;
+ }
+
+ if (qpic_nand_read(peb * num_pages_per_blk + data_offset/page_size,
+ leb_size/page_size, tmp_buf, spare)) {
+ dprintf(CRITICAL, "read_leb_data: Read %d failed \n", peb);
+ goto out;
+ }
+ memcpy(leb_data, tmp_buf, leb_size);
+
+ ret = 0;
+out:
+ free(tmp_buf);
+out_tmp_buf:
+ free(spare);
+ return ret;
+}
+
+/**
* write_ec_header() - Write provided ec_header for given PEB
* @peb: number of the physical erase block to write the header to
* @new_ech: the ec_header to write
@@ -247,6 +406,97 @@
}
/**
+ * write_vid_header() - Write provided vid_header for given PEB
+ * @peb: number of the physical erase block to write the header to
+ * @new_vidh: the vid_header to write
+ * @offset: vid_hdr offset in bytes from the beginning of the PEB
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int write_vid_header(uint32_t peb,
+ struct ubi_vid_hdr *new_vidh, int offset)
+{
+ unsigned page_size = flash_page_size();
+ int num_pages_per_blk = flash_block_size()/page_size;
+ unsigned char *buf;
+ int ret = 0;
+
+ buf = malloc(sizeof(uint8_t) * page_size);
+ if (!buf) {
+ dprintf(CRITICAL, "write_vid_header: Mem allocation failed\n");
+ return -1;
+ }
+
+ memset(buf, 0, page_size);
+ ASSERT(page_size > sizeof(*new_vidh));
+ memcpy(buf, new_vidh, UBI_VID_HDR_SIZE);
+ ret = qpic_nand_write(peb * num_pages_per_blk + offset/page_size,
+ 1, buf, 0);
+ if (ret) {
+ dprintf(CRITICAL,
+ "write_vid_header: qpic_nand_write failed with %d\n", ret);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ free(buf);
+ return ret;
+}
+
+/**
+ * write_leb_data - write data section of the PEB (LEB).
+ * @peb: number of the physical erase block to write the data for
+ * @leb_data: a data buffer to write
+ * @size: data size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int write_leb_data(uint32_t peb, void *data,
+ int size, int data_offset)
+{
+ unsigned char *tmp_buf;
+ int ret = -1;
+ int num_pages;
+ int page_size = flash_page_size();
+ int block_size = flash_block_size();
+ int num_pages_per_blk = block_size/page_size;
+
+ tmp_buf = (unsigned char *)malloc(block_size - data_offset);
+ if (!tmp_buf)
+ {
+ dprintf(CRITICAL, "write_leb_data: Mem allocation failed\n");
+ return -1;
+ }
+
+ if (size < block_size - data_offset)
+ num_pages = size / page_size;
+ else
+ num_pages = calc_data_len(page_size, data,
+ block_size - data_offset);
+ memcpy(tmp_buf, data, num_pages * page_size);
+ ret = qpic_nand_write(peb * num_pages_per_blk + data_offset/page_size,
+ num_pages, tmp_buf, 0);
+ if (ret) {
+ dprintf(CRITICAL,
+ "write_vid_header: qpic_nand_write failed with %d\n", ret);
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(tmp_buf);
+ return ret;
+}
+
+/**
* scan_partition() - Collect the ec_headers info of a given partition
* @ptn: partition to read the headers of
*
@@ -257,7 +507,8 @@
{
struct ubi_scan_info *si;
struct ubi_ec_hdr *ec_hdr;
- unsigned i, curr_peb;
+ struct ubi_vid_hdr vid_hdr;
+ unsigned i;
unsigned long long sum = 0;
int page_size = flash_page_size();
int ret;
@@ -270,13 +521,13 @@
}
memset((void *)si, 0, sizeof(*si));
- si->ec = malloc(ptn->length * sizeof(uint64_t));
- if (!si->ec) {
+ si->pebs_data = malloc(ptn->length * sizeof(struct peb_info));
+ if (!si->pebs_data) {
dprintf(CRITICAL,"scan_partition: (%s) Memory allocation failed\n",
ptn->name);
- goto out_failed_ec;
+ goto out_failed_pebs;
}
- memset((void *)si->ec, 0, ptn->length * sizeof(uint64_t));
+ memset((void *)si->pebs_data, 0, ptn->length * sizeof(struct peb_info));
ec_hdr = malloc(UBI_EC_HDR_SIZE);
if (!ec_hdr) {
@@ -285,16 +536,18 @@
goto out_failed;
}
- curr_peb = ptn->start;
si->vid_hdr_offs = 0;
si->image_seq = rand() & UBI_IMAGE_SEQ_BASE;
-
+ si->vtbl_peb1 = -1;
+ si->vtbl_peb2 = -1;
+ si->fastmap_sb = -1;
for (i = 0; i < ptn->length; i++){
- ret = read_ec_hdr(curr_peb + i, ec_hdr);
+ ret = read_ec_hdr(ptn->start + i, ec_hdr);
switch (ret) {
case 1:
si->empty_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].status = UBI_EMPTY_PEB;
break;
case 0:
if (!si->vid_hdr_offs) {
@@ -304,44 +557,83 @@
si->vid_hdr_offs % page_size ||
si->data_offs % page_size) {
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
si->vid_hdr_offs = 0;
continue;
}
if (BE32(ec_hdr->vid_hdr_offset) != si->vid_hdr_offs) {
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
continue;
}
if (BE32(ec_hdr->data_offset) != si->data_offs) {
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
continue;
}
}
- si->good_cnt++;
- si->ec[i] = BE64(ec_hdr->ec);
+ si->read_image_seq = BE32(ec_hdr->image_seq);
+ si->pebs_data[i].ec = BE64(ec_hdr->ec);
+ /* Now read the VID header to find if the peb is free */
+ ret = read_vid_hdr(ptn->start + i, &vid_hdr,
+ BE32(ec_hdr->vid_hdr_offset));
+ switch (ret) {
+ case 1:
+ si->pebs_data[i].status = UBI_FREE_PEB;
+ si->free_cnt++;
+ break;
+ case 0:
+ si->pebs_data[i].status = UBI_USED_PEB;
+ si->pebs_data[i].volume = BE32(vid_hdr.vol_id);
+ if (BE32(vid_hdr.vol_id) == UBI_LAYOUT_VOLUME_ID) {
+ if (si->vtbl_peb1 == -1)
+ si->vtbl_peb1 = i;
+ else if (si->vtbl_peb2 == -1)
+ si->vtbl_peb2 = i;
+ else
+ dprintf(CRITICAL,
+ "scan_partition: Found > 2 copies of vtbl");
+ }
+ if (BE32(vid_hdr.vol_id) == UBI_FM_SB_VOLUME_ID)
+ si->fastmap_sb = i;
+ si->used_cnt++;
+ break;
+ case -1:
+ default:
+ si->bad_cnt++;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].status = UBI_BAD_PEB;
+ break;
+ }
break;
case -1:
default:
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].status = UBI_BAD_PEB;
break;
}
}
+ /* Sanity check */
+ if (si->bad_cnt + si->empty_cnt + si->free_cnt + si->used_cnt != (int)ptn->length) {
+ dprintf(CRITICAL,"scan_partition: peb count doesn't sum up \n");
+ goto out_failed;
+ }
+
/*
* If less then 95% of the PEBs were "bad" (didn't have valid
* ec header), then set mean_ec = UBI_DEF_ERACE_COUNTER.
*/
sum = 0;
- if (si->good_cnt && (double)(si->good_cnt / ptn->length) * 100 > 95) {
+ if ((si->free_cnt + si->used_cnt) &&
+ (double)((si->free_cnt + si->used_cnt) / ptn->length) * 100 > 95) {
for (i = 0; i < ptn->length; i++) {
- if (si->ec[i] == UBI_MAX_ERASECOUNTER)
+ if (si->pebs_data[i].ec == UBI_MAX_ERASECOUNTER)
continue;
- sum += si->ec[i];
+ sum += si->pebs_data[i].ec;
}
- si->mean_ec = sum / si->good_cnt;
+ si->mean_ec = sum / (si->free_cnt + si->used_cnt);
} else {
si->mean_ec = UBI_DEF_ERACE_COUNTER;
}
@@ -349,8 +641,8 @@
return si;
out_failed:
- free(si->ec);
-out_failed_ec:
+ free(si->pebs_data);
+out_failed_pebs:
free(si);
return NULL;
}
@@ -369,8 +661,8 @@
{
uint32_t crc;
- if (si->ec[index] < UBI_MAX_ERASECOUNTER)
- old_ech->ec = BE64(si->ec[index] + 1);
+ if (si->pebs_data[index].ec < UBI_MAX_ERASECOUNTER)
+ old_ech->ec = BE64(si->pebs_data[index].ec + 1);
else
old_ech->ec = BE64(si->mean_ec);
@@ -386,28 +678,25 @@
old_ech->hdr_crc = BE32(crc);
}
-/**
- * calc_data_len - calculate how much real data is stored in the buffer
- * @page_size: min I/O of the device
- * @buf: a buffer with the contents of the physical eraseblock
- * @len: the buffer length
- *
- * This function calculates how much "real data" is stored in @buf and
- * returns the length (in number of pages). Continuous 0xFF bytes at the end
- * of the buffer are not considered as "real data".
- */
-static int calc_data_len(int page_size, const void *buf, int len)
+
+static void update_vid_header(struct ubi_vid_hdr *vid_hdr,
+ const struct ubi_scan_info *si, uint32_t vol_id,
+ uint32_t lnum, uint32_t data_pad)
{
- int i;
+ uint32_t crc;
- for (i = len - 1; i >= 0; i--)
- if (((const uint8_t *)buf)[i] != 0xFF)
- break;
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->sqnum = BE64(si->image_seq);
+ vid_hdr->vol_id = BE32(vol_id);
+ vid_hdr->lnum = BE32(lnum);
+ vid_hdr->compat = 0;
+ vid_hdr->data_pad = BE32(data_pad);
- /* The resulting length must be aligned to the minimum flash I/O size */
- len = i + 1;
- len = (len + page_size - 1) / page_size;
- return len;
+ vid_hdr->magic = BE32(UBI_VID_HDR_MAGIC);
+ vid_hdr->version = UBI_VERSION;
+ crc = mtd_crc32(UBI_CRC32_INIT,
+ (const void *)vid_hdr, UBI_VID_HDR_SIZE_CRC);
+ vid_hdr->hdr_crc = BE32(crc);
}
/**
@@ -450,7 +739,7 @@
int ret;
if (need_erase && qpic_nand_blk_erase(peb_num * num_pages_per_blk)) {
- dprintf(INFO, "flash_ubi_img: erase of %d failed\n", peb_num);
+ dprintf(INFO, "ubi_erase_peb: erase of %d failed\n", peb_num);
return -1;
}
memset(&new_ech, 0xff, sizeof(new_ech));
@@ -459,10 +748,11 @@
/* Write new ec_header */
ret = write_ec_header(peb_num, &new_ech);
if (ret) {
- dprintf(CRITICAL, "flash_ubi_img: write ec_header to %d failed\n",
+ dprintf(CRITICAL, "ubi_erase_peb: write ec_header to %d failed\n",
peb_num);
return -1;
}
+ si->pebs_data[peb_num - ptn_start].status = UBI_FREE_PEB;
return 0;
}
@@ -609,7 +899,224 @@
}
out:
- free(si->ec);
+ free(si->pebs_data);
free(si);
return ret;
}
+
+/**
+ * find_volume() - Find given volume in a partition by it's name
+ * @si: pointer to struct ubi_scan_info
+ * @ptn_start: PEB number the partition begins at
+ * @vol_name: name of the volume to search for
+ * @vol_info: info obout the found volume
+ *
+ * This functions reads the volume table, then iterates over all its records
+ * and searches for a volume with a given name. If found, the volume table
+ * record describing this volume is returned at @vol_info. The volume
+ * id returned as a return code of the function.
+ *
+ * Returns:
+ * -1 - if the volume was not found
+ * volume in dex when found
+ */
+static int find_volume(struct ubi_scan_info *si, int ptn_start,
+ const char *vol_name, struct ubi_vtbl_record *vol_info)
+{
+ int i, vtbl_records, vtbl_peb, ret = -1;
+ int block_size = flash_block_size();
+ void *leb_data;
+ struct ubi_vtbl_record *curr_vol;
+
+ if (si->vtbl_peb1 < 0) {
+ dprintf(CRITICAL,"find_volume: vtbl not found \n");
+ return -1;
+ }
+ vtbl_peb = si->vtbl_peb1;
+
+ vtbl_records = (block_size - si->data_offs) / UBI_VTBL_RECORD_SIZE;
+ if (vtbl_records > UBI_MAX_VOLUMES)
+ vtbl_records = UBI_MAX_VOLUMES;
+
+ leb_data = malloc(block_size - si->data_offs);
+ if (!leb_data) {
+ dprintf(CRITICAL,"find_volume: Memory allocation failed\n");
+ goto out_free_leb;
+ }
+retry:
+ /* First read the volume table */
+ if (read_leb_data(vtbl_peb + ptn_start, leb_data,
+ block_size - si->data_offs, si->data_offs)) {
+ dprintf(CRITICAL,"find_volume: read_leb_data failed\n");
+ if (vtbl_peb == si->vtbl_peb1 && si->vtbl_peb2 != -1) {
+ vtbl_peb = si->vtbl_peb2;
+ goto retry;
+ }
+ goto out_free_leb;
+ }
+
+ /* Now search for the required volume ID */
+ for (i = 0; i < vtbl_records; i++) {
+ curr_vol = (struct ubi_vtbl_record *)
+ (leb_data + UBI_VTBL_RECORD_SIZE*i);
+ if (!curr_vol->vol_type)
+ break;
+ if (!strcmp((char *)curr_vol->name, vol_name)) {
+ ret = i;
+ memcpy((void*)vol_info, curr_vol, sizeof(struct ubi_vtbl_record));
+ break;
+ }
+ }
+
+out_free_leb:
+ free(leb_data);
+ return ret;
+}
+
+/**
+ * write_one_peb() - writes data to a PEB, including VID header
+ * @curr_peb - PEB to write to
+ * @ptn_start: number of first PEB of the partition
+ * @si: pointer to struct ubi_scan_info
+ * @idx: index of required PEB in si->pebs_data array
+ * @lnum: lun number this LEB belongs to
+ * @vol_id: volume ID this PEB belongs to
+ * @data: data to write
+ * @size: size of the data
+ *
+ * Assumption: EC header correctly written and PEB erased
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int write_one_peb(int curr_peb, int ptn_start,
+ struct ubi_scan_info *si,
+ int lnum, int vol_id, void* data, int size)
+{
+ int ret;
+ struct ubi_vid_hdr vidh;
+
+ memset((void *)&vidh, 0, UBI_VID_HDR_SIZE);
+ update_vid_header(&vidh, si, vol_id, lnum, 0);
+ if (write_vid_header(curr_peb + ptn_start, &vidh, si->vid_hdr_offs)) {
+ dprintf(CRITICAL,
+ "update_ubi_vol: write_vid_header for peb %d failed \n",
+ curr_peb);
+ ret = -1;
+ goto out;
+ }
+
+ /* now write the data */
+ ret = write_leb_data(curr_peb + ptn_start, data, size, si->data_offs);
+ if (ret)
+ dprintf(CRITICAL, "update_ubi_vol: writing data to peb-%d failed\n",
+ curr_peb);
+ else
+ si->pebs_data[curr_peb].status = UBI_USED_PEB;
+out:
+ return ret;
+}
+
+/**
+ * update_ubi_vol() - Write the provided (UBI) image to given volume
+ * @ptn: partition holding the required volume
+ * @data: the image to write
+ * @size: size of the image to write
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+ void *data, unsigned size)
+{
+ struct ubi_scan_info *si;
+ int vol_id, vol_pebs, curr_peb = 0, ret = -1;
+ unsigned block_size = flash_block_size();
+ void *img_peb;
+ struct ubi_vtbl_record curr_vol;
+ int img_pebs, lnum = 0;
+
+ si = scan_partition(ptn);
+ if (!si) {
+ dprintf(CRITICAL, "update_ubi_vol: scan_partition failed\n");
+ return -1;
+ }
+ if (si->read_image_seq)
+ si->image_seq = si->read_image_seq;
+
+ vol_id = find_volume(si, ptn->start, vol_name, &curr_vol);
+ if (vol_id == -1) {
+ dprintf(CRITICAL, "update_ubi_vol: dint find volume\n");
+ goto out;
+ }
+ if (si->fastmap_sb > -1 &&
+ ubi_erase_peb(ptn->start + si->fastmap_sb, 1, si, ptn->start)) {
+ dprintf(CRITICAL, "update_ubi_vol: fastmap invalidation failed\n");
+ goto out;
+ }
+
+ img_pebs = size / (block_size - si->data_offs);
+ if (size % (block_size - si->data_offs))
+ img_pebs++;
+
+ vol_pebs = BE32(curr_vol.reserved_pebs);
+ if (img_pebs > vol_pebs) {
+ dprintf(CRITICAL,
+ "update_ubi_vol: Provided image is too big. Requires %d PEBs, avail. only %d\n",
+ img_pebs, vol_pebs);
+ goto out;
+ }
+
+ /* First erase all volume used PEBs */
+ curr_peb = 0;
+ while (curr_peb < (int)ptn->length) {
+ if (si->pebs_data[curr_peb].status != UBI_USED_PEB ||
+ si->pebs_data[curr_peb].volume != vol_id) {
+ curr_peb++;
+ continue;
+ }
+ if (ubi_erase_peb(ptn->start + curr_peb, 1, si, ptn->start))
+ goto out;
+ curr_peb++;
+ }
+
+ /* Flash the image */
+ img_peb = data;
+ lnum = 0;
+ for (curr_peb = 0;
+ curr_peb < (int)ptn->length && size && vol_pebs;
+ curr_peb++) {
+ if (si->pebs_data[curr_peb].status != UBI_FREE_PEB &&
+ si->pebs_data[curr_peb].status != UBI_EMPTY_PEB)
+ continue;
+
+ if (write_one_peb(curr_peb, ptn->start, si,
+ lnum++, vol_id, img_peb,
+ (size < block_size - si->data_offs ? size :
+ block_size - si->data_offs))) {
+ dprintf(CRITICAL, "update_ubi_vol: write_one_peb failed\n");
+ goto out;
+ }
+ if (size < block_size - si->data_offs)
+ size = 0;
+ else
+ size -= (block_size - si->data_offs);
+ vol_pebs--;
+ img_peb += block_size - si->data_offs;
+ }
+
+ if (size) {
+ dprintf(CRITICAL,
+ "update_ubi_vol: Not enough available PEBs for writing the volume\n");
+ goto out;
+ }
+ ret = 0;
+out:
+ free(si->pebs_data);
+ free(si);
+ return ret;
+}
+
+
diff --git a/platform/msm_shared/include/spmi.h b/platform/msm_shared/include/spmi.h
index 5e6deb4..85cd66a 100644
--- a/platform/msm_shared/include/spmi.h
+++ b/platform/msm_shared/include/spmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012,2014 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -101,8 +101,6 @@
#define SPMI_CMD_DEV_DESC_BLK_MASTER_READ 0x10
#define SPMI_CMD_DEV_DESC_BLK_SLAVE_READ 0x11
-/* Max number of Peripherals supported by SPMI */
-#define MAX_PERIPH 128
#define PMIC_ARB_SPMI_HW_VERSION (SPMI_BASE + 0xF000)
enum spmi_geni_cmd_return_value{
diff --git a/platform/msm_shared/reboot.c b/platform/msm_shared/reboot.c
index abe2ce9..fb29ab5 100644
--- a/platform/msm_shared/reboot.c
+++ b/platform/msm_shared/reboot.c
@@ -122,7 +122,7 @@
/* For Reboot-bootloader and Dload cases do a warm reset
* For Reboot cases do a hard reset
*/
- if((reboot_reason == FASTBOOT_MODE) || (reboot_reason == DLOAD))
+ if((reboot_reason == FASTBOOT_MODE) || (reboot_reason == DLOAD) || (reboot_reason == RECOVERY_MODE))
reset_type = PON_PSHOLD_WARM_RESET;
else
reset_type = PON_PSHOLD_HARD_RESET;
diff --git a/platform/msm_shared/reboot.h b/platform/msm_shared/reboot.h
index cf03b27..7156c01 100644
--- a/platform/msm_shared/reboot.h
+++ b/platform/msm_shared/reboot.h
@@ -27,6 +27,7 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define FASTBOOT_MODE 0x77665500
+#define RECOVERY_MODE 0x77665502
#define ALARM_BOOT 0x77665503
#define RTC_TRG 4
#define PON_SOFT_RB_SPARE 0x88F
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index 7e2cb3a..fe90e5d 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -549,7 +549,14 @@
$(LOCAL_DIR)/qpic_nand.o \
$(LOCAL_DIR)/scm.o \
$(LOCAL_DIR)/dev_tree.o \
- $(LOCAL_DIR)/gpio.o
+ $(LOCAL_DIR)/gpio.o \
+ $(LOCAL_DIR)/dload_util.o \
+ $(LOCAL_DIR)/shutdown_detect.o \
+ $(LOCAL_DIR)/certificate.o \
+ $(LOCAL_DIR)/image_verify.o \
+ $(LOCAL_DIR)/crypto_hash.o \
+ $(LOCAL_DIR)/crypto5_eng.o \
+ $(LOCAL_DIR)/crypto5_wrapper.o
endif
ifeq ($(ENABLE_BOOT_CONFIG_SUPPORT), 1)
diff --git a/platform/msm_shared/spmi.c b/platform/msm_shared/spmi.c
index d82fbb9..7408a9d 100644
--- a/platform/msm_shared/spmi.c
+++ b/platform/msm_shared/spmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2014-2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -34,6 +34,7 @@
#include <platform/irqs.h>
#include <platform/interrupts.h>
#include <malloc.h>
+#include <platform.h>
#define PMIC_ARB_V2 0x20010000
#define CHNL_IDX(sid, pid) ((sid << 8) | pid)
@@ -44,10 +45,11 @@
static spmi_callback callback;
static uint32_t pmic_arb_ver;
static uint8_t *chnl_tbl;
+static uint32_t max_peripherals;
static void spmi_lookup_chnl_number()
{
- int i;
+ uint32_t i;
uint8_t slave_id = 0;
uint8_t ppid_address = 0;
/* We need a max of sid (4 bits) + pid (8bits) of uint8_t's */
@@ -57,7 +59,7 @@
chnl_tbl = (uint8_t *) malloc(chnl_tbl_sz);
ASSERT(chnl_tbl);
- for(i = 0; i < MAX_PERIPH ; i++)
+ for(i = 0; i < max_peripherals; i++)
{
#if SPMI_CORE_V2
slave_id = (readl(PMIC_ARB_REG_CHLN(i)) & 0xf0000) >> 16;
@@ -74,6 +76,7 @@
{
/* Read the version numver */
pmic_arb_ver = readl(PMIC_ARB_SPMI_HW_VERSION);
+ max_peripherals = platform_get_max_periph();
if (pmic_arb_ver < PMIC_ARB_V2)
{
diff --git a/platform/msm_shared/usb30_dwc.c b/platform/msm_shared/usb30_dwc.c
index 6f419cd..5ae8801 100644
--- a/platform/msm_shared/usb30_dwc.c
+++ b/platform/msm_shared/usb30_dwc.c
@@ -1730,7 +1730,7 @@
ep->bytes_queued = 0;
- if (ep->type == EP_TYPE_CONTROL)
+ if (ep->type == EP_TYPE_CONTROL || ep->type == EP_TYPE_INTERRUPT)
{
memset(trb, 0, sizeof(dwc_trb_t));
diff --git a/platform/msm_shared/usb30_dwc.h b/platform/msm_shared/usb30_dwc.h
index 1a69a61..14402e7 100644
--- a/platform/msm_shared/usb30_dwc.h
+++ b/platform/msm_shared/usb30_dwc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -379,7 +379,7 @@
} dwc_notify_event_t;
/* maximum number of endpoints supported. */
-#define DWC_MAX_NUM_OF_EP 4
+#define DWC_MAX_NUM_OF_EP 8
/* length of setup packet */
#define DWC_SETUP_PKT_LEN 8
diff --git a/platform/msm_shared/usb30_udc.c b/platform/msm_shared/usb30_udc.c
index 0e5e1b0..d9d18a2 100644
--- a/platform/msm_shared/usb30_udc.c
+++ b/platform/msm_shared/usb30_udc.c
@@ -559,7 +559,7 @@
ep->number = ept->num;
ep->dir = ept->in;
- ep->type = EP_TYPE_BULK; /* the only one supported */
+ ep->type = ept->type;
ep->max_pkt_size = ept->maxpkt;
ep->burst_size = ept->maxburst;
ep->zlp = 0; /* TODO: zlp could be made part of ept */
@@ -848,6 +848,7 @@
static struct udc_endpoint *_udc_endpoint_alloc(uint8_t num,
uint8_t in,
+ uint8_t type,
uint16_t max_pkt)
{
struct udc_endpoint *ept;
@@ -858,6 +859,7 @@
ept->maxpkt = max_pkt;
ept->num = num;
+ ept->type = type;
ept->in = !!in;
ept->maxburst = 4; /* no performance improvement is seen beyond burst size of 4 */
ept->trb_count = 66; /* each trb can transfer (16MB - 1). 65 for 1GB transfer + 1 for roundup/zero length pkt. */
@@ -881,8 +883,16 @@
if (type == UDC_TYPE_BULK_IN) {
in = 1;
+ type = EP_TYPE_BULK;
} else if (type == UDC_TYPE_BULK_OUT) {
in = 0;
+ type = EP_TYPE_BULK;
+ } else if (type == UDC_TYPE_INTR_IN) {
+ in = 1;
+ type = EP_TYPE_INTERRUPT;
+ } else if (type == UDC_TYPE_INTR_OUT){
+ in = 0;
+ type = EP_TYPE_INTERRUPT;
} else {
return 0;
}
@@ -891,7 +901,7 @@
uint32_t bit = in ? EPT_TX(n) : EPT_RX(n);
if (udc->ept_alloc_table & bit)
continue;
- ept = _udc_endpoint_alloc(n, in, maxpkt);
+ ept = _udc_endpoint_alloc(n, in, type, maxpkt);
if (ept)
udc->ept_alloc_table |= bit;
return ept;
diff --git a/platform/msm_shared/usb30_udc.h b/platform/msm_shared/usb30_udc.h
index 02e86fa..97ef7e8 100644
--- a/platform/msm_shared/usb30_udc.h
+++ b/platform/msm_shared/usb30_udc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, 2015 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -84,6 +84,7 @@
struct udc_endpoint {
struct udc_endpoint *next;
uint8_t num;
+ uint8_t type;
uint8_t in;
uint16_t maxpkt;
uint32_t maxburst; /* max pkts that this ep can transfer before waiting for ack. */
diff --git a/project/msm8952.mk b/project/msm8952.mk
index 926697c..1a27c22 100644
--- a/project/msm8952.mk
+++ b/project/msm8952.mk
@@ -23,11 +23,11 @@
#DEFINES += WITH_DEBUG_FBCON=1
DEFINES += DEVICE_TREE=1
#DEFINES += MMC_BOOT_BAM=1
-#DEFINES += CRYPTO_BAM=1
+DEFINES += CRYPTO_BAM=1
DEFINES += SPMI_CORE_V2=1
DEFINES += ABOOT_IGNORE_BOOT_HEADER_ADDRS=1
-#DEFINES += BAM_V170=1
+DEFINES += BAM_V170=1
#Enable the feature of long press power on
#DEFINES += LONG_PRESS_POWER_ON=1
@@ -35,7 +35,7 @@
#Disable thumb mode
ENABLE_THUMB := false
-#ENABLE_SDHCI_SUPPORT := 1
+ENABLE_SDHCI_SUPPORT := 1
ifeq ($(ENABLE_SDHCI_SUPPORT),1)
DEFINES += MMC_SDHCI_SUPPORT=1
diff --git a/target/init.c b/target/init.c
index 97809cc..9191572 100644
--- a/target/init.c
+++ b/target/init.c
@@ -59,6 +59,11 @@
return 0;
}
+__WEAK int update_ubi_vol(void)
+{
+ return 0;
+}
+
__WEAK int target_is_emmc_boot(void)
{
#if _EMMC_BOOT
diff --git a/target/msm8952/init.c b/target/msm8952/init.c
index c61c631..445e132 100644
--- a/target/msm8952/init.c
+++ b/target/msm8952/init.c
@@ -60,23 +60,91 @@
#define FASTBOOT_MODE 0x77665500
#define PON_SOFT_RB_SPARE 0x88F
-static uint32_t mmc_sdc_base[] =
+#define CE1_INSTANCE 1
+#define CE_EE 1
+#define CE_FIFO_SIZE 64
+#define CE_READ_PIPE 3
+#define CE_WRITE_PIPE 2
+#define CE_READ_PIPE_LOCK_GRP 0
+#define CE_WRITE_PIPE_LOCK_GRP 0
+#define CE_ARRAY_SIZE 20
+
+struct mmc_device *dev;
+
+static uint32_t mmc_pwrctl_base[] =
{ MSM_SDC1_BASE, MSM_SDC2_BASE };
+static uint32_t mmc_sdhci_base[] =
+ { MSM_SDC1_SDHCI_BASE, MSM_SDC2_SDHCI_BASE };
+
+static uint32_t mmc_sdc_pwrctl_irq[] =
+ { SDCC1_PWRCTL_IRQ, SDCC2_PWRCTL_IRQ };
void target_early_init(void)
{
#if WITH_DEBUG_UART
- uart_dm_init(1, 0, BLSP1_UART1_BASE);
+ uart_dm_init(2, 0, BLSP1_UART1_BASE);
#endif
}
-void target_mmc_caps(struct mmc_host *host)
+static void set_sdc_power_ctrl()
{
- host->caps.ddr_mode = 0;
- host->caps.hs200_mode = 0;
- host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
- host->caps.hs_clk_rate = MMC_CLK_50MHZ;
+ /* Drive strength configs for sdc pins */
+ struct tlmm_cfgs sdc1_hdrv_cfg[] =
+ {
+ { SDC1_CLK_HDRV_CTL_OFF, TLMM_CUR_VAL_16MA, TLMM_HDRV_MASK, 0},
+ { SDC1_CMD_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK, 0},
+ { SDC1_DATA_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK , 0},
+ };
+
+ /* Pull configs for sdc pins */
+ struct tlmm_cfgs sdc1_pull_cfg[] =
+ {
+ { SDC1_CLK_PULL_CTL_OFF, TLMM_NO_PULL, TLMM_PULL_MASK, 0},
+ { SDC1_CMD_PULL_CTL_OFF, TLMM_PULL_UP, TLMM_PULL_MASK, 0},
+ { SDC1_DATA_PULL_CTL_OFF, TLMM_PULL_UP, TLMM_PULL_MASK, 0},
+ };
+
+ /* Set the drive strength & pull control values */
+ tlmm_set_hdrive_ctrl(sdc1_hdrv_cfg, ARRAY_SIZE(sdc1_hdrv_cfg));
+ tlmm_set_pull_ctrl(sdc1_pull_cfg, ARRAY_SIZE(sdc1_pull_cfg));
+}
+
+void target_sdc_init()
+{
+ struct mmc_config_data config;
+
+ /* Set drive strength & pull ctrl values */
+ set_sdc_power_ctrl();
+
+ /* Try slot 1*/
+ config.slot = 1;
+ config.bus_width = DATA_BUS_WIDTH_8BIT;
+ config.max_clk_rate = MMC_CLK_177MHZ;
+ config.sdhc_base = mmc_sdhci_base[config.slot - 1];
+ config.pwrctl_base = mmc_pwrctl_base[config.slot - 1];
+ config.pwr_irq = mmc_sdc_pwrctl_irq[config.slot - 1];
+ config.hs400_support = 1;
+
+ if (!(dev = mmc_init(&config))) {
+ /* Try slot 2 */
+ config.slot = 2;
+ config.max_clk_rate = MMC_CLK_200MHZ;
+ config.sdhc_base = mmc_sdhci_base[config.slot - 1];
+ config.pwrctl_base = mmc_pwrctl_base[config.slot - 1];
+ config.pwr_irq = mmc_sdc_pwrctl_irq[config.slot - 1];
+ config.hs400_support = 0;
+
+ if (!(dev = mmc_init(&config))) {
+ dprintf(CRITICAL, "mmc init failed!");
+ ASSERT(0);
+ }
+ }
+}
+
+void *target_mmc_device()
+{
+ return (void *) dev;
}
/* Return 1 if vol_up pressed */
@@ -144,23 +212,18 @@
target_keystatus();
- /* Trying Slot 1*/
- slot = 1;
- base_addr = mmc_sdc_base[slot - 1];
- if (mmc_boot_main(slot, base_addr))
+ target_sdc_init();
+ if (partition_read_table())
{
-
- /* Trying Slot 2 next */
- slot = 2;
- base_addr = mmc_sdc_base[slot - 1];
- if (mmc_boot_main(slot, base_addr)) {
- dprintf(CRITICAL, "mmc init failed!");
+ dprintf(CRITICAL, "Error reading the partition table info\n");
ASSERT(0);
- }
}
+
#if LONG_PRESS_POWER_ON
shutdown_detect();
#endif
+ if (target_use_signed_kernel())
+ target_crypto_init_params();
}
void target_serialno(unsigned char *buf)
@@ -314,8 +377,129 @@
if (is_cold_boot &&
(!(pon_reason & HARD_RST)) &&
(!(pon_reason & KPDPWR_N)) &&
- ((pon_reason & USB_CHG) || (pon_reason & DC_CHG) || (pon_reason & CBLPWR_N)))
+ ((pon_reason & USB_CHG)))
return 1;
else
return 0;
}
+
+void target_uninit(void)
+{
+ mmc_put_card_to_sleep(dev);
+ sdhci_mode_disable(&dev->host);
+ if (crypto_initialized())
+ crypto_eng_cleanup();
+
+ if (target_is_ssd_enabled())
+ clock_ce_disable(CE1_INSTANCE);
+}
+
+void target_usb_init(void)
+{
+ uint32_t val;
+
+ /* Select and enable external configuration with USB PHY */
+ ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_SET);
+
+ /* Enable sess_vld */
+ val = readl(USB_GENCONFIG_2) | GEN2_SESS_VLD_CTRL_EN;
+ writel(val, USB_GENCONFIG_2);
+
+ /* Enable external vbus configuration in the LINK */
+ val = readl(USB_USBCMD);
+ val |= SESS_VLD_CTRL;
+ writel(val, USB_USBCMD);
+}
+
+void target_usb_stop(void)
+{
+ /* Disable VBUS mimicing in the controller. */
+ ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_CLEAR);
+}
+
+/* Do any target specific intialization needed before entering fastboot mode */
+void target_fastboot_init(void)
+{
+ if (target_is_ssd_enabled()) {
+ clock_ce_enable(CE1_INSTANCE);
+ target_load_ssd_keystore();
+ }
+}
+
+void target_load_ssd_keystore(void)
+{
+ uint64_t ptn;
+ int index;
+ uint64_t size;
+ uint32_t *buffer = NULL;
+
+ if (!target_is_ssd_enabled())
+ return;
+
+ index = partition_get_index("ssd");
+
+ ptn = partition_get_offset(index);
+ if (ptn == 0){
+ dprintf(CRITICAL, "Error: ssd partition not found\n");
+ return;
+ }
+
+ size = partition_get_size(index);
+ if (size == 0) {
+ dprintf(CRITICAL, "Error: invalid ssd partition size\n");
+ return;
+ }
+
+ buffer = memalign(CACHE_LINE, ROUNDUP(size, CACHE_LINE));
+ if (!buffer) {
+ dprintf(CRITICAL, "Error: allocating memory for ssd buffer\n");
+ return;
+ }
+
+ if (mmc_read(ptn, buffer, size)) {
+ dprintf(CRITICAL, "Error: cannot read data\n");
+ free(buffer);
+ return;
+ }
+
+ clock_ce_enable(CE1_INSTANCE);
+ scm_protect_keystore(buffer, size);
+ clock_ce_disable(CE1_INSTANCE);
+ free(buffer);
+}
+
+crypto_engine_type board_ce_type(void)
+{
+ return CRYPTO_ENGINE_TYPE_HW;
+}
+
+/* Set up params for h/w CE. */
+void target_crypto_init_params()
+{
+ struct crypto_init_params ce_params;
+
+ /* Set up base addresses and instance. */
+ ce_params.crypto_instance = CE1_INSTANCE;
+ ce_params.crypto_base = MSM_CE1_BASE;
+ ce_params.bam_base = MSM_CE1_BAM_BASE;
+
+ /* Set up BAM config. */
+ ce_params.bam_ee = CE_EE;
+ ce_params.pipes.read_pipe = CE_READ_PIPE;
+ ce_params.pipes.write_pipe = CE_WRITE_PIPE;
+ ce_params.pipes.read_pipe_grp = CE_READ_PIPE_LOCK_GRP;
+ ce_params.pipes.write_pipe_grp = CE_WRITE_PIPE_LOCK_GRP;
+
+ /* Assign buffer sizes. */
+ ce_params.num_ce = CE_ARRAY_SIZE;
+ ce_params.read_fifo_size = CE_FIFO_SIZE;
+ ce_params.write_fifo_size = CE_FIFO_SIZE;
+
+ /* BAM is initialized by TZ for this platform.
+ * Do not do it again as the initialization address space
+ * is locked.
+ */
+ ce_params.do_bam_init = 0;
+
+ crypto_init_params(&ce_params);
+}