aboutsummaryrefslogtreecommitdiff
path: root/pdl/pdl-2/pdl_command.c
diff options
context:
space:
mode:
Diffstat (limited to 'pdl/pdl-2/pdl_command.c')
-rw-r--r--pdl/pdl-2/pdl_command.c571
1 files changed, 571 insertions, 0 deletions
diff --git a/pdl/pdl-2/pdl_command.c b/pdl/pdl-2/pdl_command.c
new file mode 100644
index 0000000000..a6c06c17b0
--- /dev/null
+++ b/pdl/pdl-2/pdl_command.c
@@ -0,0 +1,571 @@
+#include <common.h>
+#include <version.h>
+#include <asm/types.h>
+#include "packet.h"
+#include <linux/string.h>
+#include <malloc.h>
+#include <asm/arch/mtdparts_def.h>
+#include <asm/arch/rda_sys.h>
+#include <asm/arch/rda_crypto.h>
+#include <asm/arch/hw_test.h>
+#include <asm/arch/prdinfo.h>
+#include "cmd_defs.h"
+#include "pdl_debug.h"
+#include "pdl.h"
+#include "pdl_command.h"
+#include "pdl_nand.h"
+#include "pdl_emmc.h"
+#include <linux/mtd/mtd.h>
+
+#define MAX_PART_NAME 30
+#define MAX_TEST_LIST_SIZE 60
+
+#ifdef CONFIG_PDL_FORCE_HW_TEST_FULL
+static int hw_tested = 0;
+static int hw_test_run(const char *test_list, int fast_mode);
+#endif
+
+uint8_t pdl_extended_status = 0;
+
+static int media_type = MEDIA_NAND;
+int sys_connect(struct pdl_packet *packet, void *arg)
+{
+ pdl_info("connect with pc\n");
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+struct exec_file_info {
+ unsigned long start_address;
+ unsigned long total_size;
+ unsigned long recv_size;
+ unsigned long next_address;
+};
+static struct exec_file_info exec_file;
+static int frame_count = -1;
+
+int data_start(struct pdl_packet *packet, void *arg)
+{
+ unsigned long start_addr = packet->cmd_header.data_addr;
+ unsigned long file_size = packet->cmd_header.data_size;
+ int ret;
+ char part_name[MAX_PART_NAME + 1] = {'\0'};
+
+ strncpy(part_name, (char *)packet->data, MAX_PART_NAME);
+ frame_count = -1;
+
+#ifdef CONFIG_PDL_FORCE_HW_TEST_FULL
+ if(!hw_tested &&
+ strstr(part_name, "system")) {
+ ret = hw_test_run("all", 0);
+ if(ret) {
+ pdl_send_rsp(ret);
+ return 0;
+ }
+ hw_tested = 1;
+ }
+#endif
+
+ if (strlen(part_name) == 0) {
+ pdl_info("invalid partition name\n");
+ pdl_send_rsp(INVALID_PARTITION);
+ return -1;
+ }
+
+
+ /* the image is pdl1.bin or pdl2.bin */
+ memset(&exec_file, 0, sizeof(exec_file));
+ if(strncmp(part_name, "pdl", 3) == 0 ||
+ strncmp(part_name, "PDL", 3) == 0) {
+ exec_file.start_address = start_addr;
+ exec_file.total_size = file_size;
+ exec_file.recv_size = 0;
+ exec_file.next_address = start_addr;
+
+ pdl_send_rsp(ACK);
+ return 0;
+ }
+
+ if (media_type == MEDIA_MMC)
+ ret = emmc_data_start(part_name, file_size);
+ else
+ ret = nand_data_start(part_name, file_size);
+ if (ret) {
+ pdl_send_rsp(ret);
+ return -1;
+ }
+
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+int data_midst(struct pdl_packet *packet, void *arg)
+{
+ u32 size = packet->cmd_header.data_size;
+ int ret;
+ u32 frame_num = packet->cmd_header.data_addr;
+
+ /* pdl1.bin or pdl2.bin */
+ if(exec_file.total_size > 0) {
+ if ((exec_file.recv_size + size) > exec_file.total_size) {
+ pdl_send_rsp(INVALID_SIZE);
+ return 0;
+ }
+
+ memcpy((void *)exec_file.next_address, packet->data, size);
+ exec_file.next_address += size;
+ exec_file.recv_size += size;
+
+ pdl_dbg("write to addr %lx, receive size %ld\n", exec_file.next_address,
+ exec_file.recv_size);
+
+ pdl_send_rsp(ACK);
+ return 0;
+ }
+
+ /* check frame number */
+ if(frame_count >= 0) {
+ if(frame_num < frame_count) { /* ignore this frame */
+ pdl_send_rsp(ACK);
+ return 0;
+ }
+ if(frame_num > frame_count) {
+ pdl_send_rsp(PACKET_ERROR);
+ pdl_error("expect frame %d, not %d\n", frame_count, frame_num);
+ return -1;
+ }
+ } else {
+ frame_count = frame_num;
+ }
+
+ pdl_dbg("frame count %u\n", frame_count);
+ frame_count++;
+ if (media_type == MEDIA_MMC)
+ ret = emmc_data_midst(packet->data, size);
+ else
+ ret = nand_data_midst(packet->data, size);
+ if (ret) {
+ pdl_send_rsp(ret);
+ return -1;
+ }
+
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+int data_end(struct pdl_packet *packet, void *arg)
+{
+ int ret;
+ uint32_t data_size = packet->cmd_header.data_size;
+ uint32_t data_crc = 0;
+
+ /* pdl1.bin or pdl2.bin */
+ if(exec_file.total_size > 0) {
+ pdl_info("receive pdl1/pdl2 finish\n");
+ pdl_send_rsp(ACK);
+ return 0;
+ }
+
+ frame_count = -1;
+ if(data_size == 4)
+ memcpy((void *)&data_crc, (void *)packet->data, 4);
+
+ if (media_type == MEDIA_MMC)
+ ret = emmc_data_end(data_crc);
+ else
+ ret = nand_data_end(data_crc);
+ if (ret) {
+ pdl_send_rsp(ret);
+ return -1;
+ }
+
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+static unsigned long
+do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[])
+{
+ return entry (argc, argv);
+}
+
+int data_exec(struct pdl_packet *packet, void *arg)
+{
+#ifdef CONFIG_SIGNATURE_CHECK_IMAGE
+ pdl_info("Verify executable 0x%lx, #%ld\n",
+ exec_file.start_address,exec_file.recv_size);
+ if (image_sign_verify((const void *)exec_file.start_address,
+ exec_file.recv_size)) {
+ printf("Verify failed, aborting execute.\n");
+ pdl_send_rsp(VERIFY_ERROR);
+ return 0;
+ }
+#endif
+ pdl_info("Execute download from 0x%lx\n", exec_file.start_address);
+ do_go_exec((void *)exec_file.start_address, 1, NULL);
+ return 0;
+}
+
+int read_partition(struct pdl_packet *packet, void *arg)
+{
+ size_t size = packet->cmd_header.data_size;
+ char part_name[MAX_PART_NAME + 1] = {'\0'};
+ int ret;
+ size_t actual_len = 0;
+ unsigned char *data;
+
+ strncpy(part_name, (char *)packet->data, MAX_PART_NAME);
+ if (strlen(part_name) == 0) {
+ pdl_info("invalid partition name\n");
+ pdl_send_rsp(INVALID_PARTITION);
+ return -1;
+ }
+
+ pdl_info("%s from %s\n", __func__, part_name);
+
+ data = malloc(size);
+ if (!data) {
+ pdl_info("no memory!\n");
+ pdl_send_rsp(NO_MEMORY);
+ return -1;
+ }
+
+ if (media_type == MEDIA_MMC)
+ ret = emmc_read_partition(part_name, data, size,
+ &actual_len);
+ else
+ ret = nand_read_partition(part_name, data, size,
+ &actual_len);
+ if (ret) {
+ pdl_send_rsp(ret);
+ ret = -1;
+ goto out;
+ }
+
+ pdl_send_pkt(data, actual_len);
+ pdl_dbg("send ok\n");
+out:
+ free(data);
+ return ret;
+}
+
+extern int mtdparts_ptbl_check(int *same);
+extern int mmc_check_parts(int *same);
+int check_partition_table(struct pdl_packet *packet, void *arg)
+{
+ int ret;
+ int same = 0;
+ unsigned char data;
+
+ if (media_type == MEDIA_MMC)
+ ret = mmc_check_parts(&same);
+ else
+ ret = mtdparts_ptbl_check(&same);
+
+ if(ret) {
+ pdl_send_rsp(DEVICE_ERROR);
+ return -1;
+ }
+
+ data = (u8)(same & 0xff);
+ pdl_send_pkt(&data, 1);
+ return 0;
+}
+
+int read_partition_table(struct pdl_packet *packet, void *arg)
+{
+ u32 size;
+ const char *parts = getenv("mtdparts");
+
+ pdl_info("%s, parts %s\n", __func__, parts);
+
+ size = strlen(parts);
+ pdl_send_pkt((const u8*)parts, size);
+ return 0;
+}
+extern struct mtd_device *current_mtd_dev;
+
+int format_flash(struct pdl_packet *packet, void *arg)
+{
+ int ret;
+
+ pdl_info("format the whole flash part\n");
+
+ if (media_type == MEDIA_MMC)
+ ret = emmc_format_flash();
+ else
+ ret = nand_format_flash();
+ if (ret) {
+ pdl_send_rsp(ret);
+ return -1;
+ }
+
+#ifdef CONFIG_PDL_FORCE_HW_TEST_FULL
+ if(!hw_tested) {
+ ret = hw_test_run("all", 0);
+ if(ret) {
+ pdl_send_rsp(ret);
+ return 0;
+ }
+ hw_tested = 1;
+ }
+#endif
+
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+int read_image_attr(struct pdl_packet *packet, void *arg)
+{
+ const char attrs[] = IMAGE_ATTR;
+
+ pdl_info("fs image attrs: %s\n", attrs);
+
+ pdl_send_pkt((const u8*)attrs, sizeof(attrs));
+ return 0;
+}
+
+int erase_partition(struct pdl_packet *packet, void *arg)
+{
+ int ret;
+ char part_name[MAX_PART_NAME + 1] = {'\0'};
+
+ strncpy(part_name, (char *)packet->data, MAX_PART_NAME);
+
+ if (strlen(part_name) == 0) {
+ pdl_info("invalid partition name\n");
+ pdl_send_rsp(INVALID_PARTITION);
+ return -1;
+ }
+
+ if (media_type == MEDIA_MMC)
+ ret = emmc_erase_partition(part_name);
+ else
+ ret = nand_erase_partition(part_name);
+ if (ret) {
+ pdl_send_rsp(ret);
+ return -1;
+ }
+
+ /* if the part is 'userdata', erase 'fat' part also */
+ if (strcmp(part_name, "userdata") == 0) {
+ strcpy(part_name, "fat");
+ if (media_type == MEDIA_MMC)
+ emmc_erase_partition(part_name);
+ else
+ nand_erase_partition(part_name);
+ }
+
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+int get_pdl_version(struct pdl_packet *packet, void *arg)
+{
+ u32 flag = packet->cmd_header.data_addr;
+ u32 size;
+#define MAX_VER_LEN 100
+ char str[MAX_VER_LEN+1];
+
+ memset(str, 0, MAX_VER_LEN + 1);
+ strncpy(str, version_string, MAX_VER_LEN);
+
+#ifdef BUILD_DISPLAY_ID
+ /* return BUILD_DISPLAY_ID instead of pdl version */
+ if(flag == 1)
+ strncpy(str, BUILD_DISPLAY_ID, MAX_VER_LEN);
+#endif
+
+ pdl_info("send version string: [%s]\n", str);
+
+ size = strlen(str) + 1;
+ pdl_send_pkt((const u8*)str, size);
+ return 0;
+}
+
+int reset_machine(struct pdl_packet *packet, void *arg)
+{
+ pdl_info("reset machine....\n");
+
+ u8 reboot_mode = REBOOT_TO_NORMAL_MODE;
+ if (packet->cmd_header.data_size == 1) {
+ reboot_mode = packet->data[0];
+ }
+ switch (reboot_mode) {
+ case REBOOT_TO_NORMAL_MODE:
+ case REBOOT_TO_DOWNLOAD_MODE:
+ case REBOOT_TO_FASTBOOT_MODE:
+ case REBOOT_TO_RECOVERY_MODE:
+ case REBOOT_TO_CALIB_MODE:
+ break;
+ default:
+ reboot_mode = REBOOT_TO_NORMAL_MODE;
+ }
+
+ pdl_info("reboot_mode: %d\n", reboot_mode);
+ pdl_send_rsp(ACK); // cheat and send ack before reset
+
+ rda_reboot(reboot_mode);
+
+ /* should never here */
+ return 0;
+}
+
+int poweroff_machine(struct pdl_packet *packet, void *arg)
+{
+ pdl_info("waiting USB cable plug out...\n");
+ while(usb_cable_connected()){
+ mdelay(20);
+ }
+ pdl_info("machine power off...\n");
+ shutdown_system();
+ return 0;
+}
+
+int recv_image_list(struct pdl_packet *packet, void *arg)
+{
+ pdl_info("receive download image list...\n");
+ pdl_info("\t%s\n", (char *)packet->data);
+ prdinfo_init((char *)packet->data);
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+static int hw_test_run(const char *test_list, int fast_mode)
+{
+ int __attribute__((unused)) test_all = 0;
+
+ if(!test_list)
+ return HW_TEST_ERROR;
+
+ if(strcmp(test_list, "all") == 0)
+ test_all = 1;
+
+ pdl_info("start %s hardware test...[%s]\n", fast_mode ? "fast" : "full", test_list);
+
+#ifdef CONFIG_VPU_STA_TEST
+ if(test_all || strstr(test_list, "vpu")) {
+ vpu_sta_test(fast_mode ? 10 : 200);
+ pdl_info("VPU stable test..pass!\n");
+ }
+#endif
+
+#ifdef CONFIG_VPU_MD5_TEST
+ if(test_all || strstr(test_list, "vpu_md5")) {
+ int ret = vpu_md5_test(fast_mode ? 10 : 200);
+ if(ret)
+ return MD5_ERROR;
+ pdl_info("VPU MD5 test..pass!\n");
+ }
+#endif
+
+#ifdef CONFIG_CPU_TEST
+ if(test_all || strstr(test_list, "cpu")) {
+ cpu_pll_test(fast_mode ? 2000 : 4000);
+ pdl_info("CPU test..pass!\n");
+ }
+#endif
+
+ pdl_info("end %s hardware test.\n", fast_mode ? "fast" : "full");
+ return ACK;
+}
+
+int hw_test(struct pdl_packet *packet, void *arg)
+{
+ unsigned long param_size = packet->cmd_header.data_size;
+ char test_list[MAX_TEST_LIST_SIZE + 1] = {'\0'};
+ int ret = 0;
+
+ if(param_size > 0)
+ strncpy(test_list, (char *)packet->data, MAX_TEST_LIST_SIZE);
+ else
+ strcpy(test_list, "all");
+
+ ret = hw_test_run(test_list, 0);
+ pdl_send_rsp(ret);
+ return 0;
+}
+
+int get_pdl_log(struct pdl_packet *packet, void *arg)
+{
+ u32 size;
+
+ pdl_info("get pdl log\n");
+
+ size = strlen(pdl_log_buff) + 1;
+ pdl_send_pkt((const u8*)pdl_log_buff, size);
+ return 0;
+}
+
+int download_finish(struct pdl_packet *packet, void *arg)
+{
+ u32 ftm_tag = packet->cmd_header.data_addr;
+ pdl_info("download finish!\n");
+
+ prdinfo_set_pdl_result(1, ftm_tag);
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+int set_pdl_dbg(struct pdl_packet *packet, void *arg)
+{
+ u32 dbg_settings = packet->cmd_header.data_addr;
+
+ pdl_info("%s, dbg_settings :%x\n", __func__, dbg_settings);
+
+ if (dbg_settings & PDL_DBG_PDL) {
+ pdl_info("open pdl debug\n");
+ pdl_dbg_pdl = 1;
+ }
+
+ if (dbg_settings & PDL_DBG_PDL_VERBOSE) {
+ pdl_info("open pdl verbose debug\n");
+ pdl_dbg_pdl = 1;
+ pdl_vdbg_pdl = 1;
+ }
+
+ if (dbg_settings & PDL_DBG_USB_EP0) {
+ pdl_info("open pdl usb ep0 debug\n");
+ pdl_dbg_usb_ep0 = 1;
+ }
+
+ if (dbg_settings & PDL_DBG_RW_CHECK) {
+ pdl_info("open pdl flash write/read/compare debug\n");
+ pdl_dbg_rw_check = 1;
+ }
+
+ if (dbg_settings & PDL_DBG_USB_SERIAL) {
+ pdl_info("open pdl usb serial debug\n");
+ pdl_dbg_usb_serial = 1;
+ }
+
+ if (dbg_settings & PDL_DBG_FACTORY_PART) {
+ pdl_info("open pdl factory part debug\n");
+ pdl_dbg_factory_part = 1;
+ }
+ if (dbg_settings & PDL_EXTENDED_STATUS) {
+ pdl_info("Enable extended status\n");
+ pdl_extended_status = 1;
+ }
+
+ pdl_send_rsp(ACK);
+ return 0;
+}
+
+int pdl_command_init(void)
+{
+ int ret;
+
+ media_type = rda_media_get();
+ if (media_type == MEDIA_MMC) {
+ ret = pdl_emmc_init();
+ } else {
+ ret = pdl_nand_init();
+ }
+
+#ifdef CONFIG_PDL_FORCE_HW_TEST
+ ret = hw_test_run("all", 1);
+#endif
+
+ return ret;
+}